mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
RPC account_objects (RIPD-777)
General RPC command that can retrieve objects in the account root. * Add account objects integration test. * Support tickets. * Add removeElement in Json::Value
This commit is contained in:
committed by
Vinnie Falco
parent
0b5582ed0d
commit
4d0ed3d857
@@ -246,6 +246,18 @@ public:
|
||||
// Account functions
|
||||
//
|
||||
|
||||
/** This method gathers all objects for an account in a ledger.
|
||||
@param lpLedger Ledger to be searched for account objects.
|
||||
@param accountID Account to find objects for.
|
||||
@param startAfter Begin gathering account objects after this one.
|
||||
@param hint Provides further granularity to startAfter.
|
||||
@param limit Maximum number of objects to find.
|
||||
@param func Function called on every object found.
|
||||
*/
|
||||
bool getAccountObjects (Ledger::pointer lpLedger,
|
||||
Account const& accountID, uint256 const& startAfter,
|
||||
std::uint64_t const hint, unsigned int limit,
|
||||
std::function <bool (SLE::ref)> func) const override;
|
||||
AccountState::pointer getAccountState (
|
||||
Ledger::ref lrLedger, RippleAddress const& accountID);
|
||||
SLE::pointer getGenerator (
|
||||
@@ -1121,6 +1133,64 @@ int NetworkOPsImp::findTransactionsByDestination (
|
||||
// Account functions
|
||||
//
|
||||
|
||||
bool NetworkOPsImp::getAccountObjects (Ledger::pointer lpLedger,
|
||||
Account const& accountID, uint256 const& startAfter,
|
||||
std::uint64_t const hint, unsigned int limit,
|
||||
std::function <bool (SLE::ref)> func) const
|
||||
{
|
||||
auto const rootIndex = getOwnerDirIndex (accountID);
|
||||
auto currentIndex = rootIndex;
|
||||
bool found = true;
|
||||
|
||||
if (startAfter.isNonZero ())
|
||||
{
|
||||
found = false;
|
||||
|
||||
auto const hintIndex = getDirNodeIndex (rootIndex, hint);
|
||||
SLE::pointer hintDir = lpLedger->getSLEi (hintIndex);
|
||||
if (hintDir != nullptr)
|
||||
{
|
||||
for (auto const& node : hintDir->getFieldV256 (sfIndexes))
|
||||
{
|
||||
if (node == startAfter)
|
||||
{
|
||||
// We found the hint, we can start here
|
||||
currentIndex = hintIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto const sleNode = lpLedger->getDirNode (currentIndex);
|
||||
|
||||
if (sleNode == nullptr)
|
||||
return found;
|
||||
|
||||
for (auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
|
||||
{
|
||||
if (! found)
|
||||
{
|
||||
if (uDirEntry == startAfter)
|
||||
found = true;
|
||||
}
|
||||
else if (func (lpLedger->getSLEi (uDirEntry)) && limit-- <= 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t const uNodeDir (sleNode->getFieldU64 (sfIndexNext));
|
||||
|
||||
if (uNodeDir == 0)
|
||||
return found;
|
||||
|
||||
currentIndex = getDirNodeIndex (rootIndex, uNodeDir);
|
||||
}
|
||||
}
|
||||
|
||||
AccountState::pointer NetworkOPsImp::getAccountState (
|
||||
Ledger::ref lrLedger, RippleAddress const& accountID)
|
||||
{
|
||||
|
||||
@@ -165,6 +165,10 @@ public:
|
||||
// Account functions
|
||||
//
|
||||
|
||||
virtual bool getAccountObjects(Ledger::pointer lpLedger,
|
||||
Account const& accountID, uint256 const& startAfter,
|
||||
std::uint64_t const hint, unsigned int limit,
|
||||
std::function <bool (SLE::ref)> func) const = 0;
|
||||
virtual AccountState::pointer getAccountState (Ledger::ref lrLedger,
|
||||
RippleAddress const& accountID) = 0;
|
||||
virtual SLE::pointer getGenerator (Ledger::ref lrLedger,
|
||||
|
||||
@@ -813,6 +813,7 @@ public:
|
||||
{ "account_currencies", &RPCParser::parseAccountCurrencies, 1, 2 },
|
||||
{ "account_info", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_lines", &RPCParser::parseAccountLines, 1, 5 },
|
||||
{ "account_objects", &RPCParser::parseAccountItems, 1, 4 },
|
||||
{ "account_offers", &RPCParser::parseAccountItems, 1, 4 },
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 1, 8 },
|
||||
{ "book_offers", &RPCParser::parseBookOffers, 2, 7 },
|
||||
|
||||
@@ -59,8 +59,10 @@ JSS ( account_data ); // out: AccountInfo
|
||||
JSS ( account_hash ); // out: LedgerToJson
|
||||
JSS ( account_id ); // out: WalletPropose
|
||||
JSS ( account_index ); // in: AccountCurrencies, AccountOffers,
|
||||
// AccountInfo, AccountLines, OwnerInfo
|
||||
// AccountInfo, AccountLines,
|
||||
// AccountObjects, OwnerInfo
|
||||
// out: AccountOffers
|
||||
JSS ( account_objects ); // out: AccountObjects
|
||||
JSS ( account_root ); // in: LedgerEntry
|
||||
JSS ( accounts ); // in: LedgerEntry, Subscribe,
|
||||
// handlers/Ledger, Unsubscribe
|
||||
@@ -200,7 +202,7 @@ JSS ( ledger_min ); // in, out: AccountTx*
|
||||
JSS ( ledger_time ); // out: NetworkOPs
|
||||
JSS ( levels ); // LogLevels
|
||||
JSS ( limit ); // in/out: AccountTx*, AccountOffers,
|
||||
// AccountLines;
|
||||
// AccountLines, AccountObjects
|
||||
// in: LedgerData, BookOffers
|
||||
JSS ( limit_peer ); // out: AccountLines
|
||||
JSS ( lines ); // out: AccountLines
|
||||
@@ -214,7 +216,8 @@ JSS ( load_fee ); // out: LoadFeeTrackImp
|
||||
JSS ( local ); // out: resource/Logic.h
|
||||
JSS ( local_txs ); // out: GetCounts
|
||||
JSS ( marker ); // in/out: AccountTx, AccountOffers,
|
||||
// AccountLines, LedgerData
|
||||
// AccountLines, AccountObjects,
|
||||
// LedgerData
|
||||
// in: BookOffers
|
||||
JSS ( master_key ); // out: WalletPropose
|
||||
JSS ( master_seed ); // out: WalletPropose
|
||||
|
||||
194
src/ripple/rpc/handlers/AccountObjects.cpp
Normal file
194
src/ripple/rpc/handlers/AccountObjects.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2014 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 <BeastConfig.h>
|
||||
#include <ripple/rpc/impl/Tuning.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** General RPC command that can retrieve objects in the account root.
|
||||
{
|
||||
account: <account>|<account_public_key>
|
||||
account_index: <integer> // optional, defaults to 0
|
||||
ledger_hash: <string> // optional
|
||||
ledger_index: <string | unsigned integer> // optional
|
||||
limit: <integer> // optional
|
||||
marker: <opaque> // optional, resume previous query
|
||||
}
|
||||
*/
|
||||
Json::Value doAccountObjects (RPC::Context& context)
|
||||
{
|
||||
auto const& params = context.params;
|
||||
if (! params.isMember (jss::account))
|
||||
return RPC::missing_field_error (jss::account);
|
||||
|
||||
Ledger::pointer ledger;
|
||||
Json::Value result = RPC::lookupLedger (params, ledger, context.netOps);
|
||||
if (ledger == nullptr)
|
||||
return result;
|
||||
|
||||
RippleAddress rippleAddress;
|
||||
{
|
||||
bool bIndex;
|
||||
std::string const strIdent = params[jss::account].asString ();
|
||||
int const iIndex = context.params.isMember (jss::account_index)
|
||||
? context.params[jss::account_index].asUInt () : 0;
|
||||
Json::Value const jv = RPC::accountFromString(ledger, rippleAddress, bIndex,
|
||||
strIdent, iIndex, false, context.netOps);
|
||||
if (! jv.empty ())
|
||||
{
|
||||
for (auto it = jv.begin (); it != jv.end (); ++it)
|
||||
result[it.memberName ()] = it.key ();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (! ledger->hasAccount (rippleAddress))
|
||||
return rpcError (rpcACT_NOT_FOUND);
|
||||
|
||||
unsigned int limit;
|
||||
if (params.isMember (jss::limit))
|
||||
{
|
||||
auto const& jvLimit = params[jss::limit];
|
||||
if (! jvLimit.isIntegral ())
|
||||
return RPC::expected_field_error (jss::limit, "unsigned integer");
|
||||
|
||||
limit = jvLimit.isUInt () ? jvLimit.asUInt () :
|
||||
std::max (0, jvLimit.asInt ());
|
||||
|
||||
if (context.role != Role::ADMIN)
|
||||
{
|
||||
limit = std::max (RPC::Tuning::minObjectsPerRequest,
|
||||
std::min (limit, RPC::Tuning::maxObjectsPerRequest));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
limit = RPC::Tuning::defaultObjectsPerRequest;
|
||||
}
|
||||
|
||||
Account const& raAccount = rippleAddress.getAccountID ();
|
||||
unsigned int reserve = limit;
|
||||
uint256 startAfter;
|
||||
std::uint64_t startHint = 0;
|
||||
|
||||
if (params.isMember (jss::marker))
|
||||
{
|
||||
// We have a start point. Use limit - 1 from the result and use the
|
||||
// very last one for the resume.
|
||||
Json::Value const& marker = params[jss::marker];
|
||||
|
||||
if (! marker.isString ())
|
||||
return RPC::expected_field_error (jss::marker, "string");
|
||||
|
||||
startAfter.SetHex (marker.asString ());
|
||||
SLE::pointer sleObj = ledger->getSLEi (startAfter);
|
||||
|
||||
if (sleObj == nullptr)
|
||||
return rpcError (rpcINVALID_PARAMS);
|
||||
|
||||
switch (sleObj->getType ())
|
||||
{
|
||||
case ltRIPPLE_STATE:
|
||||
if (sleObj->getFieldAmount (sfLowLimit).getIssuer () == raAccount)
|
||||
startHint = sleObj->getFieldU64 (sfLowNode);
|
||||
else if (sleObj->getFieldAmount (sfHighLimit).getIssuer () == raAccount)
|
||||
startHint = sleObj->getFieldU64 (sfHighNode);
|
||||
else
|
||||
return rpcError (rpcINVALID_PARAMS);
|
||||
|
||||
break;
|
||||
|
||||
case ltOFFER:
|
||||
startHint = sleObj->getFieldU64 (sfOwnerNode);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Caller provided the first object (startAfter), add it as first result
|
||||
result[jss::account_objects].append (sleObj->getJson (0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have no start point, limit should be one higher than requested.
|
||||
++reserve;
|
||||
}
|
||||
|
||||
Json::Value jv = Json::nullValue;
|
||||
|
||||
if (! context.netOps.getAccountObjects(ledger, raAccount, startAfter,
|
||||
startHint, reserve, [&](SLE::ref sleCur)
|
||||
{
|
||||
if (! jv.isNull ())
|
||||
result[jss::account_objects].append (jv);
|
||||
|
||||
switch (sleCur->getType ())
|
||||
{
|
||||
case ltRIPPLE_STATE:
|
||||
case ltOFFER: // Deprecated
|
||||
jv = sleCur->getJson (0);
|
||||
return true;
|
||||
|
||||
case ltTICKET:
|
||||
{
|
||||
jv = sleCur->getJson (0);
|
||||
|
||||
Account const acc (sleCur->getFieldAccount160 (sfAccount));
|
||||
uint32_t const seq (sleCur->getFieldU32 (sfSequence));
|
||||
jv[jss::index] = to_string (getTicketIndex (acc, seq));
|
||||
return true;
|
||||
}
|
||||
|
||||
// case ltACCOUNT_ROOT:
|
||||
// case ltDIR_NODE:
|
||||
// case ltGENERATOR_MAP:
|
||||
default:
|
||||
if (! jv.isNull ())
|
||||
jv = Json::nullValue;
|
||||
return false;
|
||||
}
|
||||
}))
|
||||
{
|
||||
return rpcError (rpcINVALID_PARAMS);
|
||||
}
|
||||
|
||||
if (! jv.isNull ())
|
||||
{
|
||||
if (result[jss::account_objects].size () == limit)
|
||||
{
|
||||
result[jss::limit] = limit;
|
||||
result[jss::marker] = jv[jss::index];
|
||||
}
|
||||
else
|
||||
{
|
||||
result[jss::account_objects].append (jv);
|
||||
}
|
||||
}
|
||||
|
||||
result[jss::account] = rippleAddress.humanAccountID ();
|
||||
|
||||
context.loadType = Resource::feeMediumBurdenRPC;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -25,6 +25,7 @@ namespace ripple {
|
||||
Json::Value doAccountCurrencies (RPC::Context&);
|
||||
Json::Value doAccountInfo (RPC::Context&);
|
||||
Json::Value doAccountLines (RPC::Context&);
|
||||
Json::Value doAccountObjects (RPC::Context&);
|
||||
Json::Value doAccountOffers (RPC::Context&);
|
||||
Json::Value doAccountTx (RPC::Context&);
|
||||
Json::Value doAccountTxSwitch (RPC::Context&);
|
||||
|
||||
@@ -100,6 +100,7 @@ HandlerTable HANDLERS({
|
||||
{ "account_info", byRef (&doAccountInfo), Role::USER, NEEDS_CURRENT_LEDGER },
|
||||
{ "account_currencies", byRef (&doAccountCurrencies), Role::USER, NEEDS_CURRENT_LEDGER },
|
||||
{ "account_lines", byRef (&doAccountLines), Role::USER, NEEDS_CURRENT_LEDGER },
|
||||
{ "account_objects", byRef (&doAccountObjects), Role::USER, NEEDS_CURRENT_LEDGER },
|
||||
{ "account_offers", byRef (&doAccountOffers), Role::USER, NEEDS_CURRENT_LEDGER },
|
||||
{ "account_tx", byRef (&doAccountTxSwitch), Role::USER, NEEDS_NETWORK_CONNECTION },
|
||||
{ "blacklist", byRef (&doBlackList), Role::ADMIN, NO_CONDITION },
|
||||
|
||||
@@ -27,42 +27,57 @@ namespace RPC {
|
||||
/** @{ */
|
||||
namespace Tuning {
|
||||
|
||||
/** Default account lines return per request to the
|
||||
account_lines command when no limit param is specified
|
||||
/** Default account objects returned per request from the
|
||||
account_objects command when no limit param is specified
|
||||
*/
|
||||
unsigned int const defaultLinesPerRequest (200);
|
||||
static unsigned int const defaultObjectsPerRequest (200);
|
||||
|
||||
/** Minimum account lines return per request to the
|
||||
account_lines command. Specified in the limit param.
|
||||
/** Minimum account objects returned per request from the
|
||||
account_objects command. Specified in the limit param.
|
||||
*/
|
||||
unsigned int const minLinesPerRequest (10);
|
||||
static unsigned int const minObjectsPerRequest (10);
|
||||
|
||||
/** Maximum account lines return per request to the
|
||||
account_lines command. Specified in the limit param.
|
||||
/** Maximum account objects returned per request from the
|
||||
account_objects command. Specified in the limit param.
|
||||
*/
|
||||
unsigned int const maxLinesPerRequest (400);
|
||||
static unsigned int const maxObjectsPerRequest (400);
|
||||
|
||||
/** Default offers return per request to the account_offers command
|
||||
when no limit param is specified
|
||||
/** Default account lines returned per request from the
|
||||
account_lines command when no limit param is specified
|
||||
*/
|
||||
unsigned int const defaultOffersPerRequest (200);
|
||||
static unsigned int const defaultLinesPerRequest (200);
|
||||
|
||||
/** Minimum offers return per request to the account_offers command.
|
||||
Specified in the limit param.
|
||||
/** Minimum account lines returned per request from the
|
||||
account_lines command. Specified in the limit param.
|
||||
*/
|
||||
unsigned int const minOffersPerRequest (10);
|
||||
static unsigned int const minLinesPerRequest (10);
|
||||
|
||||
/** Maximum offers return per request to the account_lines command.
|
||||
Specified in the limit param.
|
||||
/** Maximum account lines returned per request from the
|
||||
account_lines command. Specified in the limit param.
|
||||
*/
|
||||
unsigned int const maxOffersPerRequest (400);
|
||||
static unsigned int const maxLinesPerRequest (400);
|
||||
|
||||
int const defaultAutoFillFeeMultiplier (10);
|
||||
int const maxPathfindsInProgress (2);
|
||||
int const maxPathfindJobCount (50);
|
||||
int const maxJobQueueClients (500);
|
||||
int const maxValidatedLedgerAge (120);
|
||||
int const maxRequestSize (1000000);
|
||||
/** Default offers returned per request from the
|
||||
account_offers command when no limit param is specified.
|
||||
*/
|
||||
static unsigned int const defaultOffersPerRequest (200);
|
||||
|
||||
/** Minimum offers returned per request from the
|
||||
account_offers command. Specified in the limit param.
|
||||
*/
|
||||
static unsigned int const minOffersPerRequest (10);
|
||||
|
||||
/** Maximum offers returned per request from the
|
||||
account_lines command. Specified in the limit param.
|
||||
*/
|
||||
static unsigned int const maxOffersPerRequest (400);
|
||||
|
||||
static int const defaultAutoFillFeeMultiplier (10);
|
||||
static int const maxPathfindsInProgress (2);
|
||||
static int const maxPathfindJobCount (50);
|
||||
static int const maxJobQueueClients (500);
|
||||
static int const maxValidatedLedgerAge (120);
|
||||
static int const maxRequestSize (1000000);
|
||||
|
||||
} // Tuning
|
||||
/** @} */
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <ripple/rpc/handlers/AccountCurrencies.cpp>
|
||||
#include <ripple/rpc/handlers/AccountInfo.cpp>
|
||||
#include <ripple/rpc/handlers/AccountLines.cpp>
|
||||
#include <ripple/rpc/handlers/AccountObjects.cpp>
|
||||
#include <ripple/rpc/handlers/AccountOffers.cpp>
|
||||
#include <ripple/rpc/handlers/AccountTx.cpp>
|
||||
#include <ripple/rpc/handlers/AccountTxOld.cpp>
|
||||
|
||||
Reference in New Issue
Block a user