mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
Add filtering to Account Objects (RIPD-868)
This commit is contained in:
committed by
Vinnie Falco
parent
e0ad66d967
commit
ca07a1230b
@@ -3313,6 +3313,11 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\rpc\impl\DoPrint.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\rpc\impl\GetAccountObjects.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\rpc\impl\GetAccountObjects.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\rpc\impl\Handler.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
||||
@@ -3873,6 +3873,12 @@
|
||||
<ClInclude Include="..\..\src\ripple\rpc\impl\DoPrint.h">
|
||||
<Filter>ripple\rpc\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\rpc\impl\GetAccountObjects.cpp">
|
||||
<Filter>ripple\rpc\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\rpc\impl\GetAccountObjects.h">
|
||||
<Filter>ripple\rpc\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\rpc\impl\Handler.cpp">
|
||||
<Filter>ripple\rpc\impl</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -246,18 +246,6 @@ 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);
|
||||
|
||||
@@ -1130,64 +1118,6 @@ 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,10 +165,6 @@ 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;
|
||||
|
||||
|
||||
@@ -803,7 +803,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_objects", &RPCParser::parseAccountItems, 1, 5 },
|
||||
{ "account_offers", &RPCParser::parseAccountItems, 1, 4 },
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 1, 8 },
|
||||
{ "book_offers", &RPCParser::parseBookOffers, 2, 7 },
|
||||
|
||||
@@ -354,7 +354,8 @@ JSS ( tx_signing_hash ); // out: TransactionSign
|
||||
JSS ( tx_unsigned ); // out: TransactionSign
|
||||
JSS ( txn_count ); // out: NetworkOPs
|
||||
JSS ( txs ); // out: TxHistory
|
||||
JSS ( type ); // rpc; out: NetworkOPs, LedgerEntrySet
|
||||
JSS ( type ); // in: AccountObjects
|
||||
// out: NetworkOPs, LedgerEntrySet
|
||||
// paths/Node.cpp, OverlayImpl, Logic
|
||||
JSS ( type_hex ); // out: STPathSet
|
||||
JSS ( unl ); // out: UnlList
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/rpc/impl/Tuning.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/rpc/impl/GetAccountObjects.h>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -29,10 +34,12 @@ namespace ripple {
|
||||
account_index: <integer> // optional, defaults to 0
|
||||
ledger_hash: <string> // optional
|
||||
ledger_index: <string | unsigned integer> // optional
|
||||
type: <string> // optional, defaults to all account objects types
|
||||
limit: <integer> // optional
|
||||
marker: <opaque> // optional, resume previous query
|
||||
}
|
||||
*/
|
||||
|
||||
Json::Value doAccountObjects (RPC::Context& context)
|
||||
{
|
||||
auto const& params = context.params;
|
||||
@@ -40,17 +47,17 @@ Json::Value doAccountObjects (RPC::Context& context)
|
||||
return RPC::missing_field_error (jss::account);
|
||||
|
||||
Ledger::pointer ledger;
|
||||
Json::Value result = RPC::lookupLedger (params, ledger, context.netOps);
|
||||
auto result = RPC::lookupLedger (params, ledger, context.netOps);
|
||||
if (ledger == nullptr)
|
||||
return result;
|
||||
|
||||
RippleAddress rippleAddress;
|
||||
RippleAddress raAccount;
|
||||
{
|
||||
bool bIndex;
|
||||
std::string const strIdent = params[jss::account].asString ();
|
||||
int const iIndex = context.params.isMember (jss::account_index)
|
||||
auto const strIdent = params[jss::account].asString ();
|
||||
auto iIndex = context.params.isMember (jss::account_index)
|
||||
? context.params[jss::account_index].asUInt () : 0;
|
||||
Json::Value const jv = RPC::accountFromString(ledger, rippleAddress, bIndex,
|
||||
auto jv = RPC::accountFromString (ledger, raAccount, bIndex,
|
||||
strIdent, iIndex, false, context.netOps);
|
||||
if (! jv.empty ())
|
||||
{
|
||||
@@ -61,10 +68,42 @@ Json::Value doAccountObjects (RPC::Context& context)
|
||||
}
|
||||
}
|
||||
|
||||
if (! ledger->hasAccount (rippleAddress))
|
||||
if (! ledger->hasAccount (raAccount))
|
||||
return rpcError (rpcACT_NOT_FOUND);
|
||||
|
||||
unsigned int limit;
|
||||
auto type = ltINVALID;
|
||||
if (params.isMember (jss::type))
|
||||
{
|
||||
using filter_types = std::vector <std::pair <std::string, LedgerEntryType>>;
|
||||
static
|
||||
beast::static_initializer <filter_types> const types ([]() -> filter_types {
|
||||
return {
|
||||
{ "account", ltACCOUNT_ROOT },
|
||||
{ "amendments", ltAMENDMENTS },
|
||||
{ "directory", ltDIR_NODE },
|
||||
{ "fee", ltFEE_SETTINGS },
|
||||
{ "hashes", ltLEDGER_HASHES },
|
||||
{ "offer", ltOFFER },
|
||||
{ "state", ltRIPPLE_STATE },
|
||||
{ "ticket", ltTICKET }
|
||||
};
|
||||
}());
|
||||
|
||||
auto const& p = params[jss::type];
|
||||
if (! p.isString ())
|
||||
return RPC::expected_field_error (jss::type, "string");
|
||||
|
||||
auto const filter = p.asString ();
|
||||
auto iter = std::find_if (types->begin (), types->end (),
|
||||
[&filter](decltype (types->front ())& t)
|
||||
{ return t.first == filter; });
|
||||
if (iter == types->end ())
|
||||
return RPC::invalid_field_error (jss::type);
|
||||
|
||||
type = iter->second;
|
||||
}
|
||||
|
||||
auto limit = RPC::Tuning::defaultObjectsPerRequest;
|
||||
if (params.isMember (jss::limit))
|
||||
{
|
||||
auto const& jvLimit = params[jss::limit];
|
||||
@@ -80,112 +119,37 @@ Json::Value doAccountObjects (RPC::Context& context)
|
||||
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;
|
||||
|
||||
uint256 dirIndex;
|
||||
uint256 entryIndex;
|
||||
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];
|
||||
|
||||
auto 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;
|
||||
}
|
||||
std::stringstream ss (marker.asString ());
|
||||
std::string s;
|
||||
if (!std::getline(ss, s, ','))
|
||||
return RPC::invalid_field_error (jss::marker);
|
||||
|
||||
if (! dirIndex.SetHex (s))
|
||||
return RPC::invalid_field_error (jss::marker);
|
||||
|
||||
if (! std::getline (ss, s, ','))
|
||||
return RPC::invalid_field_error (jss::marker);
|
||||
|
||||
// Caller provided the first object (startAfter), add it as first result
|
||||
result[jss::account_objects].append (sleObj->getJson (0));
|
||||
if (! entryIndex.SetHex (s))
|
||||
return RPC::invalid_field_error (jss::marker);
|
||||
}
|
||||
else
|
||||
|
||||
if (! RPC::getAccountObjects (*ledger, raAccount.getAccountID (), type,
|
||||
dirIndex, entryIndex, limit, result))
|
||||
{
|
||||
// We have no start point, limit should be one higher than requested.
|
||||
++reserve;
|
||||
return RPC::invalid_field_error (jss::marker);
|
||||
}
|
||||
|
||||
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:
|
||||
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 ();
|
||||
|
||||
result[jss::account] = raAccount.humanAccountID ();
|
||||
context.loadType = Resource::feeMediumBurdenRPC;
|
||||
return result;
|
||||
}
|
||||
|
||||
109
src/ripple/rpc/impl/GetAccountObjects.cpp
Normal file
109
src/ripple/rpc/impl/GetAccountObjects.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 <ripple/rpc/impl/GetAccountObjects.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
bool
|
||||
getAccountObjects (Ledger const& ledger, Account const& account,
|
||||
LedgerEntryType const type, uint256 dirIndex, uint256 const& entryIndex,
|
||||
std::uint32_t const limit, Json::Value& jvResult)
|
||||
{
|
||||
auto const rootDirIndex = getOwnerDirIndex (account);
|
||||
auto found = false;
|
||||
|
||||
if (dirIndex.isZero ())
|
||||
{
|
||||
dirIndex = rootDirIndex;
|
||||
found = true;
|
||||
}
|
||||
|
||||
auto dir = ledger.getDirNode (dirIndex);
|
||||
if (dir == nullptr)
|
||||
return false;
|
||||
|
||||
std::uint32_t i = 0;
|
||||
auto& jvObjects = jvResult[jss::account_objects];
|
||||
for (;;)
|
||||
{
|
||||
auto const& entries = dir->getFieldV256 (sfIndexes);
|
||||
auto iter = entries.begin ();
|
||||
|
||||
if (! found)
|
||||
{
|
||||
iter = std::find (iter, entries.end (), entryIndex);
|
||||
if (iter == entries.end ())
|
||||
return false;
|
||||
|
||||
found = true;
|
||||
}
|
||||
|
||||
for (; iter != entries.end (); ++iter)
|
||||
{
|
||||
auto const sleNode = ledger.getSLEi (*iter);
|
||||
if (type == ltINVALID || sleNode->getType () == type)
|
||||
{
|
||||
jvObjects.append (sleNode->getJson (0));
|
||||
|
||||
if (++i == limit)
|
||||
{
|
||||
if (++iter != entries.end ())
|
||||
{
|
||||
jvResult[jss::limit] = limit;
|
||||
jvResult[jss::marker] = to_string (dirIndex) + ',' +
|
||||
to_string (*iter);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto const nodeIndex = dir->getFieldU64 (sfIndexNext);
|
||||
if (nodeIndex == 0)
|
||||
return true;
|
||||
|
||||
dirIndex = getDirNodeIndex (rootDirIndex, nodeIndex);
|
||||
dir = ledger.getDirNode (dirIndex);
|
||||
if (dir == nullptr)
|
||||
return true;
|
||||
|
||||
if (i == limit)
|
||||
{
|
||||
auto const& e = dir->getFieldV256 (sfIndexes);
|
||||
if (! e.empty ())
|
||||
{
|
||||
jvResult[jss::limit] = limit;
|
||||
jvResult[jss::marker] = to_string (dirIndex) + ',' +
|
||||
to_string (*e.begin ());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
|
||||
45
src/ripple/rpc/impl/GetAccountObjects.h
Normal file
45
src/ripple/rpc/impl/GetAccountObjects.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RPC_ACCOUNT_OBJECTS_H_INCLUDED
|
||||
#define RIPPLE_RPC_ACCOUNT_OBJECTS_H_INCLUDED
|
||||
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
/** Gathers all objects for an account in a ledger.
|
||||
@param ledger Ledger to search account objects.
|
||||
@param account Account to find objects for.
|
||||
@param type Gathers objects of this type. ltINVALID gathers all types.
|
||||
@param dirIndex Begin gathering account objects from this directory.
|
||||
@param entryIndex Begin gathering objects from this directory node.
|
||||
@param limit Maximum number of objects to find.
|
||||
@param jvResult A JSON result that holds the request objects.
|
||||
*/
|
||||
bool
|
||||
getAccountObjects (Ledger const& ledger, Account const& account,
|
||||
LedgerEntryType const type, uint256 dirIndex, uint256 const& entryIndex,
|
||||
std::uint32_t const limit, Json::Value& jvResult);
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -94,6 +94,7 @@
|
||||
|
||||
#include <ripple/rpc/impl/AccountFromString.cpp>
|
||||
#include <ripple/rpc/impl/Accounts.cpp>
|
||||
#include <ripple/rpc/impl/GetAccountObjects.cpp>
|
||||
#include <ripple/rpc/impl/Handler.cpp>
|
||||
#include <ripple/rpc/impl/KeypairForSignature.cpp>
|
||||
#include <ripple/rpc/impl/LegacyPathFind.cpp>
|
||||
|
||||
Reference in New Issue
Block a user