From 7e7664c29a616da308c13fc9f4aadaf300488fc2 Mon Sep 17 00:00:00 2001 From: Joseph Busch Date: Thu, 19 Sep 2019 12:21:59 -0500 Subject: [PATCH] Add deletion_blockers_only param to account_objects RPC command --- src/ripple/protocol/jss.h | 1 + src/ripple/rpc/handlers/AccountObjects.cpp | 49 +++++++++++++++++++--- src/ripple/rpc/impl/RPCHelpers.cpp | 17 ++++++-- src/ripple/rpc/impl/RPCHelpers.h | 6 +-- src/test/rpc/AccountObjects_test.cpp | 40 ++++++++++++++++++ 5 files changed, 101 insertions(+), 12 deletions(-) diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index 9b79a904df..aba9711037 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -182,6 +182,7 @@ JSS ( dbKBLedger ); // out: getCounts JSS ( dbKBTotal ); // out: getCounts JSS ( dbKBTransaction ); // out: getCounts JSS ( debug_signing ); // in: TransactionSign +JSS ( deletion_blockers_only ); // in: AccountObjects JSS ( delivered_amount ); // out: insertDeliveredAmount JSS ( deposit_authorized ); // out: deposit_authorized JSS ( deposit_preauth ); // in: AccountObjects, LedgerData diff --git a/src/ripple/rpc/handlers/AccountObjects.cpp b/src/ripple/rpc/handlers/AccountObjects.cpp index 2f54971b92..0c35071ed7 100644 --- a/src/ripple/rpc/handlers/AccountObjects.cpp +++ b/src/ripple/rpc/handlers/AccountObjects.cpp @@ -72,12 +72,49 @@ Json::Value doAccountObjects (RPC::Context& context) if (! ledger->exists(keylet::account (accountID))) return rpcError (rpcACT_NOT_FOUND); - auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params); - if (rpcStatus) + boost::optional> typeFilter; + + if (params.isMember(jss::deletion_blockers_only) && + params[jss::deletion_blockers_only].asBool()) { - result.clear(); - rpcStatus.inject(result); - return result; + struct { + Json::StaticString name; + LedgerEntryType type; + } static constexpr deletionBlockers[] = { + { jss::check, ltCHECK }, + { jss::escrow, ltESCROW }, + { jss::payment_channel, ltPAYCHAN }, + { jss::state, ltRIPPLE_STATE } + }; + + typeFilter.emplace(); + typeFilter->reserve(std::size(deletionBlockers)); + + for (auto [name, type] : deletionBlockers) + { + if (params.isMember(jss::type) && + name != params[jss::type]) + { + continue; + } + + typeFilter->push_back(type); + } + } + else + { + auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params); + + if (rpcStatus) + { + result.clear(); + rpcStatus.inject(result); + return result; + } + else if (type != ltINVALID) + { + typeFilter = std::vector({ type }); + } } unsigned int limit; @@ -107,7 +144,7 @@ Json::Value doAccountObjects (RPC::Context& context) return RPC::invalid_field_error (jss::marker); } - if (! RPC::getAccountObjects (*ledger, accountID, type, + if (! RPC::getAccountObjects (*ledger, accountID, typeFilter, dirIndex, entryIndex, limit, result)) { result[jss::account_objects] = Json::arrayValue; diff --git a/src/ripple/rpc/impl/RPCHelpers.cpp b/src/ripple/rpc/impl/RPCHelpers.cpp index 85ae18f607..b1b83d6f06 100644 --- a/src/ripple/rpc/impl/RPCHelpers.cpp +++ b/src/ripple/rpc/impl/RPCHelpers.cpp @@ -82,8 +82,8 @@ accountFromString( bool getAccountObjects(ReadView const& ledger, AccountID const& account, - LedgerEntryType const type, uint256 dirIndex, uint256 const& entryIndex, - std::uint32_t const limit, Json::Value& jvResult) + boost::optional> const& typeFilter, uint256 dirIndex, + uint256 const& entryIndex, std::uint32_t const limit, Json::Value& jvResult) { auto const rootDirIndex = getOwnerDirIndex (account); auto found = false; @@ -117,7 +117,18 @@ getAccountObjects(ReadView const& ledger, AccountID const& account, for (; iter != entries.end (); ++iter) { auto const sleNode = ledger.read(keylet::child(*iter)); - if (type == ltINVALID || sleNode->getType () == type) + + auto typeMatchesFilter = [] ( + std::vector const& typeFilter, + LedgerEntryType ledgerType) + { + auto it = std::find(typeFilter.begin(), typeFilter.end(), + ledgerType); + return it != typeFilter.end(); + }; + + if (!typeFilter.has_value() || + typeMatchesFilter(typeFilter.value(), sleNode->getType())) { jvObjects.append (sleNode->getJson (JsonOptions::none)); diff --git a/src/ripple/rpc/impl/RPCHelpers.h b/src/ripple/rpc/impl/RPCHelpers.h index 6fed508256..63d09d15ea 100644 --- a/src/ripple/rpc/impl/RPCHelpers.h +++ b/src/ripple/rpc/impl/RPCHelpers.h @@ -55,7 +55,7 @@ accountFromString (AccountID& result, std::string const& strIdent, /** Gathers all objects for an account in a ledger. @param ledger Ledger to search account objects. @param account AccountID to find objects for. - @param type Gathers objects of this type. ltINVALID gathers all types. + @param typeFilter Gathers objects of these types. empty 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. @@ -63,8 +63,8 @@ accountFromString (AccountID& result, std::string const& strIdent, */ bool getAccountObjects (ReadView const& ledger, AccountID const& account, - LedgerEntryType const type, uint256 dirIndex, uint256 const& entryIndex, - std::uint32_t const limit, Json::Value& jvResult); + boost::optional> const& typeFilter, uint256 dirIndex, + uint256 const& entryIndex, std::uint32_t const limit, Json::Value& jvResult); /** Look up a ledger from a request and fill a Json::Result with either an error, or data representing a ledger. diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 3ae162429d..a5c81eaa5c 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -494,6 +494,46 @@ public: BEAST_EXPECT (ticket[sfLedgerEntryType.jsonName] == jss::Ticket); BEAST_EXPECT (ticket[sfSequence.jsonName].asUInt() == 9); } + { + // See how "deletion_blockers_only" handles gw's directory. + Json::Value params; + params[jss::account] = gw.human(); + params[jss::deletion_blockers_only] = true; + auto resp = env.rpc("json", "account_objects", to_string(params)); + + constexpr Json::StaticString const expectedLedgerTypes[] = { + jss::Escrow, jss::Check, jss::RippleState, jss::PayChannel + }; + constexpr auto expectedAccountObjects{ + static_cast(std::size(expectedLedgerTypes)) + }; + + if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects))) + { + auto const& aobjs = resp[jss::result][jss::account_objects]; + for (std::uint32_t i = 0; i < expectedAccountObjects; ++i) + { + BEAST_EXPECT( + aobjs[i]["LedgerEntryType"] == expectedLedgerTypes[i]); + } + } + } + { + // See how "deletion_blockers_only" with `type` handles gw's directory. + Json::Value params; + params[jss::account] = gw.human(); + params[jss::deletion_blockers_only] = true; + params[jss::type] = jss::escrow; + auto resp = env.rpc("json", "account_objects", to_string(params)); + + if (BEAST_EXPECT(acct_objs_is_size(resp, 1u))) + { + auto const& aobjs = resp[jss::result][jss::account_objects]; + BEAST_EXPECT( + aobjs[0u]["LedgerEntryType"] == jss::Escrow); + } + } + // Run up the number of directory entries so gw has two // directory nodes. for (int d = 1'000'032; d >= 1'000'000; --d)