From d78f740250e8d10fe326fecc2025f86efe56f7ed Mon Sep 17 00:00:00 2001 From: Miguel Portilla Date: Thu, 11 Sep 2014 13:13:26 -0400 Subject: [PATCH] Add account_offers paging (RIPD-344) --- src/ripple/net/impl/RPCCall.cpp | 2 +- src/ripple/rpc/handlers/AccountOffers.cpp | 151 +++++++++++++++++----- 2 files changed, 122 insertions(+), 31 deletions(-) diff --git a/src/ripple/net/impl/RPCCall.cpp b/src/ripple/net/impl/RPCCall.cpp index fdc9d49f7..0bde8e7f1 100644 --- a/src/ripple/net/impl/RPCCall.cpp +++ b/src/ripple/net/impl/RPCCall.cpp @@ -801,7 +801,7 @@ public: { "account_currencies", &RPCParser::parseAccountCurrencies, 1, 2 }, { "account_info", &RPCParser::parseAccountItems, 1, 2 }, { "account_lines", &RPCParser::parseAccountLines, 1, 5 }, - { "account_offers", &RPCParser::parseAccountItems, 1, 2 }, + { "account_offers", &RPCParser::parseAccountItems, 1, 4 }, { "account_tx", &RPCParser::parseAccountTransactions, 1, 8 }, { "book_offers", &RPCParser::parseBookOffers, 2, 7 }, { "connect", &RPCParser::parseConnect, 1, 2 }, diff --git a/src/ripple/rpc/handlers/AccountOffers.cpp b/src/ripple/rpc/handlers/AccountOffers.cpp index 45985820f..561cfe143 100644 --- a/src/ripple/rpc/handlers/AccountOffers.cpp +++ b/src/ripple/rpc/handlers/AccountOffers.cpp @@ -17,49 +17,41 @@ */ //============================================================================== +#include namespace ripple { -static void offerAdder (Json::Value& jvLines, SLE::ref offer) -{ - if (offer->getType () == ltOFFER) - { - Json::Value& obj = jvLines.append (Json::objectValue); - offer->getFieldAmount (sfTakerPays).setJson (obj[jss::taker_pays]); - offer->getFieldAmount (sfTakerGets).setJson (obj[jss::taker_gets]); - obj[jss::seq] = offer->getFieldU32 (sfSequence); - obj[jss::flags] = offer->getFieldU32 (sfFlags); - } -} - // { // account: | // account_index: // optional, defaults to 0. // ledger_hash : // ledger_index : +// limit: integer // optional +// marker: opaque // optional, resume previous query // } Json::Value doAccountOffers (RPC::Context& context) { - Ledger::pointer ledger; - Json::Value result - = RPC::lookupLedger (context.params_, ledger, context.netOps_); + auto const& params (context.params_); - if (!ledger) + Ledger::pointer ledger; + Json::Value result (RPC::lookupLedger (params, ledger, context.netOps_)); + + if (! ledger) return result; - if (!context.params_.isMember (jss::account)) + if (! params.isMember (jss::account)) return RPC::missing_field_error ("account"); - std::string strIdent = context.params_[jss::account].asString (); - bool bIndex = context.params_.isMember (jss::account_index); - int iIndex = bIndex ? context.params_[jss::account_index].asUInt () : 0; + std::string strIdent (params[jss::account].asString ()); + bool bIndex (params.isMember (jss::account_index)); + int iIndex (bIndex ? params[jss::account_index].asUInt () : 0); - RippleAddress raAccount; + RippleAddress raAccount; result = RPC::accountFromString ( ledger, raAccount, bIndex, strIdent, iIndex, false, context.netOps_); - if (!result.empty ()) + if (! result.empty ()) return result; // Get info on account. @@ -69,17 +61,116 @@ Json::Value doAccountOffers (RPC::Context& context) if (bIndex) result[jss::account_index] = iIndex; - if (!ledger->hasAccount (raAccount)) + if (! ledger->hasAccount (raAccount)) return rpcError (rpcACT_NOT_FOUND); + + unsigned int limit; + if (params.isMember (jss::limit)) + { + limit = std::max (RPC::Tuning::minOffersPerRequest, + std::min (params[jss::limit].asUInt (), + RPC::Tuning::maxOffersPerRequest)); + } + else + { + limit = RPC::Tuning::defaultOffersPerRequest; + } + + uint256 const rootIndex (Ledger::getOwnerDirIndex (raAccount.getAccountID ())); + std::uint32_t resumeSeq; + uint256 currentIndex; + bool resume (true); + + if (params.isMember (jss::marker)) + { + Json::Value const& marker (params[jss::marker]); + + if (! marker.isObject () || marker.size () != 2 || + ! marker.isMember (jss::seq) || ! marker[jss::seq].isIntegral () || + ! marker.isMember (jss::account_index) || + ! marker[jss::account_index].isString ()) + { + return rpcError (rpcACT_MALFORMED); + } + + resumeSeq = marker[jss::seq].asUInt (); + currentIndex = Ledger::getDirNodeIndex (rootIndex, + uintFromHex (marker[jss::account_index].asString ())); + + resume = false; + } + else + { + currentIndex = rootIndex; + } + + Json::Value& jvsOffers(result[jss::offers] = Json::arrayValue); + unsigned int i (0); + bool process (true); + + while (process) + { + SLE::pointer ownerDir (ledger->getSLEi (currentIndex)); + + if (!ownerDir || ownerDir->getType () != ltDIR_NODE) + break; + + for (auto const& node : ownerDir->getFieldV256 (sfIndexes).peekValue ()) + { + SLE::ref offer (ledger->getSLEi (node)); + + if (offer->getType () == ltOFFER) + { + std::uint32_t const seq (offer->getFieldU32 (sfSequence)); + + if (!resume && resumeSeq == seq) + resume = true; + + if (resume) + { + if (i < limit) + { + Json::Value& obj (jvsOffers.append (Json::objectValue)); + offer->getFieldAmount (sfTakerPays).setJson ( + obj[jss::taker_pays]); + offer->getFieldAmount (sfTakerGets).setJson ( + obj[jss::taker_gets]); + obj[jss::seq] = seq; + obj[jss::flags] = offer->getFieldU32 (sfFlags); + + ++i; + } + else + { + result[jss::limit] = limit; + + Json::Value& marker (result[jss::marker] = Json::objectValue); + marker[jss::seq] = seq; + marker[jss::account_index] = strHex( + ownerDir->getFieldU64 (sfIndexPrevious)); + + process = false; + break; + } + } + } + } + + if (process) + { + std::uint64_t const uNodeNext(ownerDir->getFieldU64(sfIndexNext)); + + if (!uNodeNext) + break; + + currentIndex = Ledger::getDirNodeIndex(rootIndex, uNodeNext); + } + } + + if (!resume) + return rpcError (rpcACT_MALFORMED); - Json::Value& jvsOffers = (result[jss::offers] = Json::arrayValue); - auto adder = std::bind ( - &offerAdder, - std::ref (jvsOffers), - std::placeholders::_1); - ledger->visitAccountItems (raAccount.getAccountID (), adder); context.loadType_ = Resource::feeMediumBurdenRPC; - return result; }