Optimize trust line caching:

The existing trust line caching code was suboptimal in that it stored
redundant information, pinned SLEs into memory and required multiple
memory allocations per cached object.

This commit eliminates redundant data, reducing the size of cached
objects and unpinning SLEs from memory, and uses value_types to
avoid the need for `std::shared_ptr`. As a result of these changes, the
effective size of a cached object, includes the overhead of the memory
allocator and the `std::shared_ptr` should be reduced by at least 64
bytes. This is significant, as there can easily be tens of millions
of these objects.
This commit is contained in:
seelabs
2022-01-23 14:47:51 -05:00
committed by Nik Bougalis
parent 59f5844381
commit 4d5459d041
13 changed files with 255 additions and 214 deletions

View File

@@ -395,7 +395,7 @@ target_sources (rippled PRIVATE
src/ripple/app/paths/Pathfinder.cpp src/ripple/app/paths/Pathfinder.cpp
src/ripple/app/paths/RippleCalc.cpp src/ripple/app/paths/RippleCalc.cpp
src/ripple/app/paths/RippleLineCache.cpp src/ripple/app/paths/RippleLineCache.cpp
src/ripple/app/paths/RippleState.cpp src/ripple/app/paths/TrustLine.cpp
src/ripple/app/paths/impl/BookStep.cpp src/ripple/app/paths/impl/BookStep.cpp
src/ripple/app/paths/impl/DirectStep.cpp src/ripple/app/paths/impl/DirectStep.cpp
src/ripple/app/paths/impl/PaySteps.cpp src/ripple/app/paths/impl/PaySteps.cpp

View File

@@ -33,24 +33,16 @@ accountSourceCurrencies(
if (includeXRP) if (includeXRP)
currencies.insert(xrpCurrency()); currencies.insert(xrpCurrency());
// List of ripple lines. for (auto const& rspEntry : lrCache->getRippleLines(account))
auto& rippleLines = lrCache->getRippleLines(account);
for (auto const& item : rippleLines)
{ {
auto rspEntry = (RippleState*)item.get(); auto& saBalance = rspEntry.getBalance();
assert(rspEntry);
if (!rspEntry)
continue;
auto& saBalance = rspEntry->getBalance();
// Filter out non // Filter out non
if (saBalance > beast::zero if (saBalance > beast::zero
// Have IOUs to send. // Have IOUs to send.
|| (rspEntry->getLimitPeer() || (rspEntry.getLimitPeer()
// Peer extends credit. // Peer extends credit.
&& ((-saBalance) < rspEntry->getLimitPeer()))) // Credit left. && ((-saBalance) < rspEntry.getLimitPeer()))) // Credit left.
{ {
currencies.insert(saBalance.getCurrency()); currencies.insert(saBalance.getCurrency());
} }
@@ -72,19 +64,11 @@ accountDestCurrencies(
currencies.insert(xrpCurrency()); currencies.insert(xrpCurrency());
// Even if account doesn't exist // Even if account doesn't exist
// List of ripple lines. for (auto const& rspEntry : lrCache->getRippleLines(account))
auto& rippleLines = lrCache->getRippleLines(account);
for (auto const& item : rippleLines)
{ {
auto rspEntry = (RippleState*)item.get(); auto& saBalance = rspEntry.getBalance();
assert(rspEntry);
if (!rspEntry)
continue;
auto& saBalance = rspEntry->getBalance(); if (saBalance < rspEntry.getLimit()) // Can take more
if (saBalance < rspEntry->getLimit()) // Can take more
currencies.insert(saBalance.getCurrency()); currencies.insert(saBalance.getCurrency());
} }

View File

@@ -717,30 +717,27 @@ Pathfinder::getPathsOut(
{ {
count = app_.getOrderBookDB().getBookSize(issue); count = app_.getOrderBookDB().getBookSize(issue);
for (auto const& item : mRLCache->getRippleLines(account)) for (auto const& rspEntry : mRLCache->getRippleLines(account))
{ {
RippleState* rspEntry = (RippleState*)item.get(); if (currency != rspEntry.getLimit().getCurrency())
if (currency != rspEntry->getLimit().getCurrency())
{ {
} }
else if ( else if (
rspEntry->getBalance() <= beast::zero && rspEntry.getBalance() <= beast::zero &&
(!rspEntry->getLimitPeer() || (!rspEntry.getLimitPeer() ||
-rspEntry->getBalance() >= rspEntry->getLimitPeer() || -rspEntry.getBalance() >= rspEntry.getLimitPeer() ||
(bAuthRequired && !rspEntry->getAuth()))) (bAuthRequired && !rspEntry.getAuth())))
{ {
} }
else if ( else if (isDstCurrency && dstAccount == rspEntry.getAccountIDPeer())
isDstCurrency && dstAccount == rspEntry->getAccountIDPeer())
{ {
count += 10000; // count a path to the destination extra count += 10000; // count a path to the destination extra
} }
else if (rspEntry->getNoRipplePeer()) else if (rspEntry.getNoRipplePeer())
{ {
// This probably isn't a useful path out // This probably isn't a useful path out
} }
else if (rspEntry->getFreezePeer()) else if (rspEntry.getFreezePeer())
{ {
// Not a useful path out // Not a useful path out
} }
@@ -940,15 +937,9 @@ Pathfinder::addLink(
AccountCandidates candidates; AccountCandidates candidates;
candidates.reserve(rippleLines.size()); candidates.reserve(rippleLines.size());
for (auto const& item : rippleLines) for (auto const& rs : rippleLines)
{ {
auto* rs = dynamic_cast<RippleState const*>(item.get()); auto const& acct = rs.getAccountIDPeer();
if (!rs)
{
JLOG(j_.error()) << "Couldn't decipher RippleState";
continue;
}
auto const& acct = rs->getAccountIDPeer();
if (hasEffectiveDestination && (acct == mDstAccount)) if (hasEffectiveDestination && (acct == mDstAccount))
{ {
@@ -963,18 +954,18 @@ Pathfinder::addLink(
continue; continue;
} }
if ((uEndCurrency == rs->getLimit().getCurrency()) && if ((uEndCurrency == rs.getLimit().getCurrency()) &&
!currentPath.hasSeen(acct, uEndCurrency, acct)) !currentPath.hasSeen(acct, uEndCurrency, acct))
{ {
// path is for correct currency and has not been seen // path is for correct currency and has not been seen
if (rs->getBalance() <= beast::zero && if (rs.getBalance() <= beast::zero &&
(!rs->getLimitPeer() || (!rs.getLimitPeer() ||
-rs->getBalance() >= rs->getLimitPeer() || -rs.getBalance() >= rs.getLimitPeer() ||
(bRequireAuth && !rs->getAuth()))) (bRequireAuth && !rs.getAuth())))
{ {
// path has no credit // path has no credit
} }
else if (bIsNoRippleOut && rs->getNoRipple()) else if (bIsNoRippleOut && rs.getNoRipple())
{ {
// Can't leave on this path // Can't leave on this path
} }

View File

@@ -18,6 +18,7 @@
//============================================================================== //==============================================================================
#include <ripple/app/paths/RippleLineCache.h> #include <ripple/app/paths/RippleLineCache.h>
#include <ripple/app/paths/TrustLine.h>
#include <ripple/ledger/OpenView.h> #include <ripple/ledger/OpenView.h>
namespace ripple { namespace ripple {
@@ -30,18 +31,17 @@ RippleLineCache::RippleLineCache(std::shared_ptr<ReadView const> const& ledger)
mLedger = std::make_shared<OpenView>(&*ledger, ledger); mLedger = std::make_shared<OpenView>(&*ledger, ledger);
} }
std::vector<RippleState::pointer> const& std::vector<PathFindTrustLine> const&
RippleLineCache::getRippleLines(AccountID const& accountID) RippleLineCache::getRippleLines(AccountID const& accountID)
{ {
AccountKey key(accountID, hasher_(accountID)); AccountKey key(accountID, hasher_(accountID));
std::lock_guard sl(mLock); std::lock_guard sl(mLock);
auto [it, inserted] = auto [it, inserted] = lines_.emplace(key, std::vector<PathFindTrustLine>());
lines_.emplace(key, std::vector<RippleState::pointer>());
if (inserted) if (inserted)
it->second = getRippleStateItems(accountID, *mLedger); it->second = PathFindTrustLine::getItems(accountID, *mLedger);
return it->second; return it->second;
} }

View File

@@ -21,8 +21,10 @@
#define RIPPLE_APP_PATHS_RIPPLELINECACHE_H_INCLUDED #define RIPPLE_APP_PATHS_RIPPLELINECACHE_H_INCLUDED
#include <ripple/app/ledger/Ledger.h> #include <ripple/app/ledger/Ledger.h>
#include <ripple/app/paths/RippleState.h> #include <ripple/app/paths/TrustLine.h>
#include <ripple/basics/CountedObject.h>
#include <ripple/basics/hardened_hash.h> #include <ripple/basics/hardened_hash.h>
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
@@ -31,7 +33,7 @@
namespace ripple { namespace ripple {
// Used by Pathfinder // Used by Pathfinder
class RippleLineCache class RippleLineCache : public CountedObject<RippleLineCache>
{ {
public: public:
explicit RippleLineCache(std::shared_ptr<ReadView const> const& l); explicit RippleLineCache(std::shared_ptr<ReadView const> const& l);
@@ -42,7 +44,7 @@ public:
return mLedger; return mLedger;
} }
std::vector<RippleState::pointer> const& std::vector<PathFindTrustLine> const&
getRippleLines(AccountID const& accountID); getRippleLines(AccountID const& accountID);
private: private:
@@ -90,7 +92,7 @@ private:
}; };
}; };
hash_map<AccountKey, std::vector<RippleState::pointer>, AccountKey::Hash> hash_map<AccountKey, std::vector<PathFindTrustLine>, AccountKey::Hash>
lines_; lines_;
}; };

View File

@@ -1,85 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/app/main/Application.h>
#include <ripple/app/paths/RippleState.h>
#include <ripple/protocol/STAmount.h>
#include <cstdint>
#include <memory>
namespace ripple {
RippleState::pointer
RippleState::makeItem(
AccountID const& accountID,
std::shared_ptr<SLE const> sle)
{
// VFALCO Does this ever happen in practice?
if (!sle || sle->getType() != ltRIPPLE_STATE)
return {};
return std::make_shared<RippleState>(std::move(sle), accountID);
}
RippleState::RippleState(
std::shared_ptr<SLE const>&& sle,
AccountID const& viewAccount)
: sle_(std::move(sle))
, mFlags(sle_->getFieldU32(sfFlags))
, mLowLimit(sle_->getFieldAmount(sfLowLimit))
, mHighLimit(sle_->getFieldAmount(sfHighLimit))
, mLowID(mLowLimit.getIssuer())
, mHighID(mHighLimit.getIssuer())
, lowQualityIn_(sle_->getFieldU32(sfLowQualityIn))
, lowQualityOut_(sle_->getFieldU32(sfLowQualityOut))
, highQualityIn_(sle_->getFieldU32(sfHighQualityIn))
, highQualityOut_(sle_->getFieldU32(sfHighQualityOut))
, mBalance(sle_->getFieldAmount(sfBalance))
{
mViewLowest = (mLowID == viewAccount);
if (!mViewLowest)
mBalance.negate();
}
Json::Value
RippleState::getJson(int)
{
Json::Value ret(Json::objectValue);
ret["low_id"] = to_string(mLowID);
ret["high_id"] = to_string(mHighID);
return ret;
}
std::vector<RippleState::pointer>
getRippleStateItems(AccountID const& accountID, ReadView const& view)
{
std::vector<RippleState::pointer> items;
forEachItem(
view,
accountID,
[&items, &accountID](std::shared_ptr<SLE const> const& sleCur) {
auto ret = RippleState::makeItem(accountID, sleCur);
if (ret)
items.push_back(ret);
});
return items;
}
} // namespace ripple

View File

@@ -0,0 +1,113 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/app/main/Application.h>
#include <ripple/app/paths/TrustLine.h>
#include <ripple/protocol/STAmount.h>
#include <cstdint>
#include <memory>
namespace ripple {
TrustLineBase::TrustLineBase(
std::shared_ptr<SLE const> const& sle,
AccountID const& viewAccount)
: key_(sle->key())
, mLowLimit(sle->getFieldAmount(sfLowLimit))
, mHighLimit(sle->getFieldAmount(sfHighLimit))
, mBalance(sle->getFieldAmount(sfBalance))
, mFlags(sle->getFieldU32(sfFlags))
, mViewLowest(mLowLimit.getIssuer() == viewAccount)
{
if (!mViewLowest)
mBalance.negate();
}
Json::Value
TrustLineBase::getJson(int)
{
Json::Value ret(Json::objectValue);
ret["low_id"] = to_string(mLowLimit.getIssuer());
ret["high_id"] = to_string(mHighLimit.getIssuer());
return ret;
}
std::optional<PathFindTrustLine>
PathFindTrustLine::makeItem(
AccountID const& accountID,
std::shared_ptr<SLE const> const& sle)
{
if (!sle || sle->getType() != ltRIPPLE_STATE)
return {};
return std::optional{PathFindTrustLine{sle, accountID}};
}
namespace detail {
template <class T>
std::vector<T>
getTrustLineItems(AccountID const& accountID, ReadView const& view)
{
std::vector<T> items;
forEachItem(
view,
accountID,
[&items, &accountID](std::shared_ptr<SLE const> const& sleCur) {
auto ret = T::makeItem(accountID, sleCur);
if (ret)
items.push_back(std::move(*ret));
});
return items;
}
} // namespace detail
std::vector<PathFindTrustLine>
PathFindTrustLine::getItems(AccountID const& accountID, ReadView const& view)
{
return detail::getTrustLineItems<PathFindTrustLine>(accountID, view);
}
RPCTrustLine::RPCTrustLine(
std::shared_ptr<SLE const> const& sle,
AccountID const& viewAccount)
: TrustLineBase(sle, viewAccount)
, lowQualityIn_(sle->getFieldU32(sfLowQualityIn))
, lowQualityOut_(sle->getFieldU32(sfLowQualityOut))
, highQualityIn_(sle->getFieldU32(sfHighQualityIn))
, highQualityOut_(sle->getFieldU32(sfHighQualityOut))
{
}
std::optional<RPCTrustLine>
RPCTrustLine::makeItem(
AccountID const& accountID,
std::shared_ptr<SLE const> const& sle)
{
if (!sle || sle->getType() != ltRIPPLE_STATE)
return {};
return std::optional{RPCTrustLine{sle, accountID}};
}
std::vector<RPCTrustLine>
RPCTrustLine::getItems(AccountID const& accountID, ReadView const& view)
{
return detail::getTrustLineItems<RPCTrustLine>(accountID, view);
}
} // namespace ripple

View File

@@ -20,12 +20,14 @@
#ifndef RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED #ifndef RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED
#define RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED #define RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED
#include <ripple/basics/CountedObject.h>
#include <ripple/ledger/View.h> #include <ripple/ledger/View.h>
#include <ripple/protocol/Rate.h> #include <ripple/protocol/Rate.h>
#include <ripple/protocol/STAmount.h> #include <ripple/protocol/STAmount.h>
#include <ripple/protocol/STLedgerEntry.h> #include <ripple/protocol/STLedgerEntry.h>
#include <cstdint> #include <cstdint>
#include <memory> // <memory> #include <optional>
namespace ripple { namespace ripple {
@@ -34,30 +36,32 @@ namespace ripple {
"low" account and a "high" account. This wraps the "low" account and a "high" account. This wraps the
SLE and expresses its data from the perspective of SLE and expresses its data from the perspective of
a chosen account on the line. a chosen account on the line.
This wrapper is primarily used in the path finder and there can easily be
tens of millions of instances of this class. When modifying this class think
carefully about the memory implications.
*/ */
// VFALCO TODO Rename to TrustLine class TrustLineBase
class RippleState
{ {
public: protected:
// VFALCO Why is this shared_ptr? // This class should not be instantiated directly. Use one of the derived
using pointer = std::shared_ptr<RippleState>; // classes.
TrustLineBase(
std::shared_ptr<SLE const> const& sle,
AccountID const& viewAccount);
~TrustLineBase() = default;
TrustLineBase(TrustLineBase const&) = default;
TrustLineBase&
operator=(TrustLineBase const&) = delete;
TrustLineBase(TrustLineBase&&) = default;
public: public:
RippleState() = delete;
virtual ~RippleState() = default;
static RippleState::pointer
makeItem(AccountID const& accountID, std::shared_ptr<SLE const> sle);
// Must be public, for make_shared
RippleState(std::shared_ptr<SLE const>&& sle, AccountID const& viewAccount);
/** Returns the state map key for the ledger entry. */ /** Returns the state map key for the ledger entry. */
uint256 uint256 const&
key() const key() const
{ {
return sle_->key(); return key_;
} }
// VFALCO Take off the "get" from each function name // VFALCO Take off the "get" from each function name
@@ -65,13 +69,13 @@ public:
AccountID const& AccountID const&
getAccountID() const getAccountID() const
{ {
return mViewLowest ? mLowID : mHighID; return mViewLowest ? mLowLimit.getIssuer() : mHighLimit.getIssuer();
} }
AccountID const& AccountID const&
getAccountIDPeer() const getAccountIDPeer() const
{ {
return !mViewLowest ? mLowID : mHighID; return !mViewLowest ? mLowLimit.getIssuer() : mHighLimit.getIssuer();
} }
// True, Provided auth to peer. // True, Provided auth to peer.
@@ -137,6 +141,52 @@ public:
return !mViewLowest ? mLowLimit : mHighLimit; return !mViewLowest ? mLowLimit : mHighLimit;
} }
Json::Value
getJson(int);
protected:
uint256 key_;
STAmount const mLowLimit;
STAmount const mHighLimit;
STAmount mBalance;
std::uint32_t mFlags;
bool mViewLowest;
};
// This wrapper is used for the path finder
class PathFindTrustLine final : public TrustLineBase,
public CountedObject<PathFindTrustLine>
{
using TrustLineBase::TrustLineBase;
public:
PathFindTrustLine() = delete;
static std::optional<PathFindTrustLine>
makeItem(AccountID const& accountID, std::shared_ptr<SLE const> const& sle);
static std::vector<PathFindTrustLine>
getItems(AccountID const& accountID, ReadView const& view);
};
// This wrapper is used for the `AccountLines` command and includes the quality
// in and quality out values.
class RPCTrustLine final : public TrustLineBase,
public CountedObject<RPCTrustLine>
{
using TrustLineBase::TrustLineBase;
public:
RPCTrustLine() = delete;
RPCTrustLine(
std::shared_ptr<SLE const> const& sle,
AccountID const& viewAccount);
Rate const& Rate const&
getQualityIn() const getQualityIn() const
{ {
@@ -149,33 +199,19 @@ public:
return mViewLowest ? lowQualityOut_ : highQualityOut_; return mViewLowest ? lowQualityOut_ : highQualityOut_;
} }
Json::Value static std::optional<RPCTrustLine>
getJson(int); makeItem(AccountID const& accountID, std::shared_ptr<SLE const> const& sle);
static std::vector<RPCTrustLine>
getItems(AccountID const& accountID, ReadView const& view);
private: private:
std::shared_ptr<SLE const> sle_;
bool mViewLowest;
std::uint32_t mFlags;
STAmount const& mLowLimit;
STAmount const& mHighLimit;
AccountID const& mLowID;
AccountID const& mHighID;
Rate lowQualityIn_; Rate lowQualityIn_;
Rate lowQualityOut_; Rate lowQualityOut_;
Rate highQualityIn_; Rate highQualityIn_;
Rate highQualityOut_; Rate highQualityOut_;
STAmount mBalance;
}; };
std::vector<RippleState::pointer>
getRippleStateItems(AccountID const& accountID, ReadView const& view);
} // namespace ripple } // namespace ripple
#endif #endif

View File

@@ -18,7 +18,7 @@
//============================================================================== //==============================================================================
#include <ripple/app/main/Application.h> #include <ripple/app/main/Application.h>
#include <ripple/app/paths/RippleState.h> #include <ripple/app/paths/TrustLine.h>
#include <ripple/ledger/ReadView.h> #include <ripple/ledger/ReadView.h>
#include <ripple/net/RPCErr.h> #include <ripple/net/RPCErr.h>
#include <ripple/protocol/ErrorCodes.h> #include <ripple/protocol/ErrorCodes.h>
@@ -58,15 +58,13 @@ doAccountCurrencies(RPC::JsonContext& context)
return rpcError(rpcACT_NOT_FOUND); return rpcError(rpcACT_NOT_FOUND);
std::set<Currency> send, receive; std::set<Currency> send, receive;
for (auto const& item : getRippleStateItems(accountID, *ledger)) for (auto const& rspEntry : RPCTrustLine::getItems(accountID, *ledger))
{ {
auto const rspEntry = item.get(); STAmount const& saBalance = rspEntry.getBalance();
STAmount const& saBalance = rspEntry->getBalance(); if (saBalance < rspEntry.getLimit())
if (saBalance < rspEntry->getLimit())
receive.insert(saBalance.getCurrency()); receive.insert(saBalance.getCurrency());
if ((-saBalance) < rspEntry->getLimitPeer()) if ((-saBalance) < rspEntry.getLimitPeer())
send.insert(saBalance.getCurrency()); send.insert(saBalance.getCurrency());
} }

View File

@@ -18,7 +18,7 @@
//============================================================================== //==============================================================================
#include <ripple/app/main/Application.h> #include <ripple/app/main/Application.h>
#include <ripple/app/paths/RippleState.h> #include <ripple/app/paths/TrustLine.h>
#include <ripple/ledger/ReadView.h> #include <ripple/ledger/ReadView.h>
#include <ripple/net/RPCErr.h> #include <ripple/net/RPCErr.h>
#include <ripple/protocol/ErrorCodes.h> #include <ripple/protocol/ErrorCodes.h>
@@ -32,18 +32,17 @@ namespace ripple {
struct VisitData struct VisitData
{ {
std::vector<RippleState::pointer> items; std::vector<RPCTrustLine> items;
AccountID const& accountID; AccountID const& accountID;
bool hasPeer; bool hasPeer;
AccountID const& raPeerAccount; AccountID const& raPeerAccount;
bool ignoreDefault; bool ignoreDefault;
uint32_t foundCount; uint32_t foundCount;
RippleState::pointer lastFound;
}; };
void void
addLine(Json::Value& jsonLines, RippleState const& line) addLine(Json::Value& jsonLines, RPCTrustLine const& line)
{ {
STAmount const& saBalance(line.getBalance()); STAmount const& saBalance(line.getBalance());
STAmount const& saLimit(line.getLimit()); STAmount const& saLimit(line.getLimit());
@@ -140,7 +139,7 @@ doAccountLines(RPC::JsonContext& context)
Json::Value& jsonLines(result[jss::lines] = Json::arrayValue); Json::Value& jsonLines(result[jss::lines] = Json::arrayValue);
VisitData visitData = { VisitData visitData = {
{}, accountID, hasPeer, raPeerAccount, ignoreDefault, 0, nullptr}; {}, accountID, hasPeer, raPeerAccount, ignoreDefault, 0};
uint256 startAfter = beast::zero; uint256 startAfter = beast::zero;
std::uint64_t startHint = 0; std::uint64_t startHint = 0;
@@ -194,18 +193,6 @@ doAccountLines(RPC::JsonContext& context)
limit + 1, limit + 1,
[&visitData, &count, &marker, &limit, &nextHint]( [&visitData, &count, &marker, &limit, &nextHint](
std::shared_ptr<SLE const> const& sleCur) { std::shared_ptr<SLE const> const& sleCur) {
bool ignore = false;
if (visitData.ignoreDefault)
{
if (sleCur->getFieldAmount(sfLowLimit).getIssuer() ==
visitData.accountID)
ignore =
!(sleCur->getFieldU32(sfFlags) & lsfLowReserve);
else
ignore = !(
sleCur->getFieldU32(sfFlags) & lsfHighReserve);
}
if (!sleCur) if (!sleCur)
{ {
assert(false); assert(false);
@@ -219,17 +206,32 @@ doAccountLines(RPC::JsonContext& context)
RPC::getStartHint(sleCur, visitData.accountID); RPC::getStartHint(sleCur, visitData.accountID);
} }
if (sleCur->getType() != ltRIPPLE_STATE)
return true;
bool ignore = false;
if (visitData.ignoreDefault)
{
if (sleCur->getFieldAmount(sfLowLimit).getIssuer() ==
visitData.accountID)
ignore =
!(sleCur->getFieldU32(sfFlags) & lsfLowReserve);
else
ignore = !(
sleCur->getFieldU32(sfFlags) & lsfHighReserve);
}
if (!ignore && count <= limit) if (!ignore && count <= limit)
{ {
auto const line = auto const line =
RippleState::makeItem(visitData.accountID, sleCur); RPCTrustLine::makeItem(visitData.accountID, sleCur);
if (line != nullptr && if (line &&
(!visitData.hasPeer || (!visitData.hasPeer ||
visitData.raPeerAccount == visitData.raPeerAccount ==
line->getAccountIDPeer())) line->getAccountIDPeer()))
{ {
visitData.items.emplace_back(line); visitData.items.emplace_back(*line);
} }
} }
@@ -253,7 +255,7 @@ doAccountLines(RPC::JsonContext& context)
result[jss::account] = context.app.accountIDCache().toBase58(accountID); result[jss::account] = context.app.accountIDCache().toBase58(accountID);
for (auto const& item : visitData.items) for (auto const& item : visitData.items)
addLine(jsonLines, *item.get()); addLine(jsonLines, item);
context.loadType = Resource::feeMediumBurdenRPC; context.loadType = Resource::feeMediumBurdenRPC;
return result; return result;

View File

@@ -18,7 +18,7 @@
//============================================================================== //==============================================================================
#include <ripple/app/main/Application.h> #include <ripple/app/main/Application.h>
#include <ripple/app/paths/RippleState.h> #include <ripple/app/paths/TrustLine.h>
#include <ripple/ledger/ReadView.h> #include <ripple/ledger/ReadView.h>
#include <ripple/protocol/AccountID.h> #include <ripple/protocol/AccountID.h>
#include <ripple/protocol/ErrorCodes.h> #include <ripple/protocol/ErrorCodes.h>
@@ -144,7 +144,7 @@ doGatewayBalances(RPC::JsonContext& context)
{ {
forEachItem( forEachItem(
*ledger, accountID, [&](std::shared_ptr<SLE const> const& sle) { *ledger, accountID, [&](std::shared_ptr<SLE const> const& sle) {
auto rs = RippleState::makeItem(accountID, sle); auto rs = PathFindTrustLine::makeItem(accountID, sle);
if (!rs) if (!rs)
return; return;

View File

@@ -19,7 +19,7 @@
#include <ripple/app/main/Application.h> #include <ripple/app/main/Application.h>
#include <ripple/app/misc/LoadFeeTrack.h> #include <ripple/app/misc/LoadFeeTrack.h>
#include <ripple/app/paths/RippleState.h> #include <ripple/app/paths/TrustLine.h>
#include <ripple/ledger/ReadView.h> #include <ripple/ledger/ReadView.h>
#include <ripple/net/RPCErr.h> #include <ripple/net/RPCErr.h>
#include <ripple/protocol/ErrorCodes.h> #include <ripple/protocol/ErrorCodes.h>

View File

@@ -20,7 +20,7 @@
#include <ripple/app/ledger/LedgerMaster.h> #include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/app/ledger/OpenLedger.h> #include <ripple/app/ledger/OpenLedger.h>
#include <ripple/app/misc/Transaction.h> #include <ripple/app/misc/Transaction.h>
#include <ripple/app/paths/RippleState.h> #include <ripple/app/paths/TrustLine.h>
#include <ripple/app/rdb/RelationalDBInterface.h> #include <ripple/app/rdb/RelationalDBInterface.h>
#include <ripple/ledger/View.h> #include <ripple/ledger/View.h>
#include <ripple/net/RPCErr.h> #include <ripple/net/RPCErr.h>