From 3eba6003a5fdbd2f8f7277908abe104415abe596 Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 25 Jan 2018 11:29:03 -0800 Subject: [PATCH 1/3] Allow account_objects RPC to filter by "check" (RIPD-1589): Fixes #2350 issue on GitHub. --- src/ripple/protocol/JsonFields.h | 1 + src/ripple/rpc/impl/RPCHelpers.cpp | 9 +- src/test/rpc/AccountObjects_test.cpp | 215 +++++++++++++++++++++++++++ 3 files changed, 221 insertions(+), 4 deletions(-) diff --git a/src/ripple/protocol/JsonFields.h b/src/ripple/protocol/JsonFields.h index 950298eb85b..0592be32403 100644 --- a/src/ripple/protocol/JsonFields.h +++ b/src/ripple/protocol/JsonFields.h @@ -104,6 +104,7 @@ JSS ( cancel_after ); // out: AccountChannels JSS ( can_delete ); // out: CanDelete JSS ( channel_id ); // out: AccountChannels JSS ( channels ); // out: AccountChannels +JSS ( check ); // in: AccountObjects JSS ( check_nodes ); // in: LedgerCleaner JSS ( clear ); // in/out: FetchInfo JSS ( close_flags ); // out: LedgerToJson diff --git a/src/ripple/rpc/impl/RPCHelpers.cpp b/src/ripple/rpc/impl/RPCHelpers.cpp index 6ca2e88f678..db1fd986c6e 100644 --- a/src/ripple/rpc/impl/RPCHelpers.cpp +++ b/src/ripple/rpc/impl/RPCHelpers.cpp @@ -671,19 +671,20 @@ chooseLedgerEntryType(Json::Value const& params) if (params.isMember(jss::type)) { static - std::array, 11> const types + std::array, 12> const types { { { jss::account, ltACCOUNT_ROOT }, { jss::amendments, ltAMENDMENTS }, + { jss::check, ltCHECK }, { jss::directory, ltDIR_NODE }, + { jss::escrow, ltESCROW }, { jss::fee, ltFEE_SETTINGS }, { jss::hashes, ltLEDGER_HASHES }, { jss::offer, ltOFFER }, + { jss::payment_channel, ltPAYCHAN }, { jss::signer_list, ltSIGNER_LIST }, { jss::state, ltRIPPLE_STATE }, - { jss::ticket, ltTICKET }, - { jss::escrow, ltESCROW }, - { jss::payment_channel, ltPAYCHAN } + { jss::ticket, ltTICKET } } }; auto const& p = params[jss::type]; diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 3feff341a81..2cb800d3b62 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -316,10 +316,225 @@ class AccountObjects_test : public beast::unit_test::suite } } + void testObjectTypes() + { + testcase ("object types"); + + // Give gw a bunch of ledger objects and make sure we can retrieve + // them by type. + using namespace jtx; + + Account const alice { "alice" }; + Account const gw{ "gateway" }; + auto const USD = gw["USD"]; + + // Test for ticket account objects when they are supported. + Env env(*this, supported_amendments().set(featureTickets)); + + // Make a lambda we can use to get "account_objects" easily. + auto acct_objs = [&env] (Account const& acct, char const* type) + { + Json::Value params; + params[jss::account] = acct.human(); + params[jss::type] = type; + params[jss::ledger_index] = "validated"; + return env.rpc("json", "account_objects", to_string(params)); + }; + + // Make a lambda that easily identifies empty account objects. + auto acct_objs_is_empty = + [&env, &acct_objs] (Account const& acct, char const* type) + { + Json::Value const resp = acct_objs (acct, type); + + bool const isArray = resp["result"]["account_objects"].isArray(); + return isArray && (resp["result"]["account_objects"].size() == 0); + }; + + env.fund(XRP(10000), gw, alice); + env.close(); + + // Since the account is empty now, all account objects should come + // back null or empty. + BEAST_EXPECT (acct_objs_is_empty (gw, jss::account)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::amendments)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::check)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::directory)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::escrow)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::fee)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::hashes)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::offer)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::payment_channel)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::signer_list)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::state)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::ticket)); + + // Set up a trust line so we can find it. + env.trust(USD(1000), alice); + env.close(); + env(pay(gw, alice, USD(5))); + env.close(); + { + // Find the trustline and make sure it's the right one. + Json::Value const resp = acct_objs (gw, jss::state); + + BEAST_EXPECT (resp["result"]["account_objects"].isArray()); + BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); + + auto const& state = resp["result"]["account_objects"][0u]; + BEAST_EXPECT (state["Balance"]["value"].asInt() == -5); + BEAST_EXPECT (state["HighLimit"]["value"].asInt() == 1000); + } + { + // gw writes a check for USD(10) to alice. + Json::Value jvCheck; + jvCheck[sfAccount.jsonName] = gw.human(); + jvCheck[sfSendMax.jsonName] = USD(10).value().getJson(0); + jvCheck[sfDestination.jsonName] = alice.human(); + jvCheck[sfTransactionType.jsonName] = "CheckCreate"; + jvCheck[sfFlags.jsonName] = tfUniversal; + env (jvCheck); + env.close(); + } + { + // Find the check. + Json::Value const resp = acct_objs (gw, jss::check); + + BEAST_EXPECT (resp["result"]["account_objects"].isArray()); + BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); + + auto const& check = resp["result"]["account_objects"][0u]; + BEAST_EXPECT (check["Account"] == gw.human()); + BEAST_EXPECT (check["Destination"] == alice.human()); + BEAST_EXPECT (check["SendMax"]["value"].asInt() == 10); + } + { + // gw creates an escrow that we can look for in the ledger. + Json::Value jvEscrow; + jvEscrow[jss::TransactionType] = "EscrowCreate"; + jvEscrow[jss::Flags] = tfUniversal; + jvEscrow[jss::Account] = gw.human(); + jvEscrow[jss::Destination] = gw.human(); + jvEscrow[jss::Amount] = XRP(100).value().getJson(0); + jvEscrow["FinishAfter"] = + env.now().time_since_epoch().count() + 1; + env (jvEscrow); + env.close(); + } + { + // Find the escrow. + Json::Value const resp = acct_objs (gw, jss::escrow); + + BEAST_EXPECT (resp["result"]["account_objects"].isArray()); + BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); + + auto const& escrow = resp["result"]["account_objects"][0u]; + BEAST_EXPECT (escrow["Account"] == gw.human()); + BEAST_EXPECT (escrow["Destination"] == gw.human()); + BEAST_EXPECT (escrow["Amount"].asInt() == 100'000'000); + } + // gw creates an offer that we can look for in the ledger. + env (offer (gw, USD (7), XRP (14))); + env.close(); + { + // Find the offer. + Json::Value const resp = acct_objs (gw, jss::offer); + + BEAST_EXPECT (resp["result"]["account_objects"].isArray()); + BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); + + auto const& offer = resp["result"]["account_objects"][0u]; + BEAST_EXPECT (offer["Account"] == gw.human()); + BEAST_EXPECT (offer["TakerGets"].asInt() == 14'000'000); + BEAST_EXPECT (offer["TakerPays"]["value"].asInt() == 7); + } + { + // Create a payment channel from qw to alice that we can look for. + Json::Value jvPayChan; + jvPayChan[jss::TransactionType] = "PaymentChannelCreate"; + jvPayChan[jss::Flags] = tfUniversal; + jvPayChan[jss::Account] = gw.human (); + jvPayChan[jss::Destination] = alice.human (); + jvPayChan[jss::Amount] = XRP (300).value().getJson (0); + jvPayChan["SettleDelay"] = 24 * 60 * 60; + jvPayChan["PublicKey"] = strHex (gw.pk().slice ()); + env (jvPayChan); + env.close(); + } + { + // Find the payment channel. + Json::Value const resp = acct_objs (gw, jss::payment_channel); + + BEAST_EXPECT (resp["result"]["account_objects"].isArray()); + BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); + + auto const& payChan = resp["result"]["account_objects"][0u]; + BEAST_EXPECT (payChan["Account"] == gw.human()); + BEAST_EXPECT (payChan["Amount"].asInt() == 300'000'000); + BEAST_EXPECT (payChan["SettleDelay"].asInt() == 24 * 60 * 60); + } + // Make gw multisigning by adding a signerList. + env (signers (gw, 6, { { alice, 7} })); + env.close(); + { + // Find the signer list. + Json::Value const resp = acct_objs (gw, jss::signer_list); + + BEAST_EXPECT (resp["result"]["account_objects"].isArray()); + BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); + + auto const& signerList = resp["result"]["account_objects"][0u]; + BEAST_EXPECT (signerList["SignerQuorum"] == 6); + auto const& entry = signerList["SignerEntries"][0u]["SignerEntry"]; + BEAST_EXPECT (entry["Account"] == alice.human()); + BEAST_EXPECT (entry["SignerWeight"].asInt() == 7); + } + // Create a Ticket for gw. + env (ticket::create (gw, gw)); + env.close(); + { + // Find the ticket. + Json::Value const resp = acct_objs (gw, jss::ticket); + + BEAST_EXPECT (resp["result"]["account_objects"].isArray()); + BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); + + auto const& ticket = resp["result"]["account_objects"][0u]; + BEAST_EXPECT (ticket["Account"] == gw.human()); + BEAST_EXPECT (ticket["LedgerEntryType"] == "Ticket"); + BEAST_EXPECT (ticket["Sequence"].asInt() == 8); + } + // Run up the number of directory entries so gw has two + // directory nodes. + for (int d = 1'000'032; d >= 1'000'000; d -= 1) + { + env (offer (gw, USD (1), drops (d))); + env.close(); + } + + // Make a lambda that easily identifies null account objects. + auto acct_objs_is_null = + [&env, &acct_objs] (Account const& acct, char const* type) + { + Json::Value const resp = acct_objs (acct, type); + return resp["result"]["account_objects"].isNull(); + }; + + // Verify that the non-returning types still don't return anything. + // Note that, interestingly, they now return a null object rather + // than an empty array. Not sure what triggers that... + BEAST_EXPECT (acct_objs_is_null (gw, jss::account)); + BEAST_EXPECT (acct_objs_is_null (gw, jss::amendments)); + BEAST_EXPECT (acct_objs_is_null (gw, jss::directory)); + BEAST_EXPECT (acct_objs_is_null (gw, jss::fee)); + BEAST_EXPECT (acct_objs_is_null (gw, jss::hashes)); + } + void run() override { testErrors(); testUnsteppedThenStepped(); + testObjectTypes(); } }; From 5f922bf61e5e5cd388efe83e8cd530a69e594a98 Mon Sep 17 00:00:00 2001 From: Brad Chase Date: Mon, 29 Jan 2018 13:14:57 -0500 Subject: [PATCH 2/3] [FOLD] Initialize account_objects as json array --- src/ripple/rpc/impl/RPCHelpers.cpp | 2 +- src/test/rpc/AccountObjects_test.cpp | 20 +++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/ripple/rpc/impl/RPCHelpers.cpp b/src/ripple/rpc/impl/RPCHelpers.cpp index db1fd986c6e..c7686f511d1 100644 --- a/src/ripple/rpc/impl/RPCHelpers.cpp +++ b/src/ripple/rpc/impl/RPCHelpers.cpp @@ -97,7 +97,7 @@ getAccountObjects(ReadView const& ledger, AccountID const& account, return false; std::uint32_t i = 0; - auto& jvObjects = jvResult[jss::account_objects]; + auto& jvObjects = (jvResult[jss::account_objects] = Json::arrayValue); for (;;) { auto const& entries = dir->getFieldV256 (sfIndexes); diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 2cb800d3b62..362534c0eff 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -512,22 +512,12 @@ class AccountObjects_test : public beast::unit_test::suite env.close(); } - // Make a lambda that easily identifies null account objects. - auto acct_objs_is_null = - [&env, &acct_objs] (Account const& acct, char const* type) - { - Json::Value const resp = acct_objs (acct, type); - return resp["result"]["account_objects"].isNull(); - }; - // Verify that the non-returning types still don't return anything. - // Note that, interestingly, they now return a null object rather - // than an empty array. Not sure what triggers that... - BEAST_EXPECT (acct_objs_is_null (gw, jss::account)); - BEAST_EXPECT (acct_objs_is_null (gw, jss::amendments)); - BEAST_EXPECT (acct_objs_is_null (gw, jss::directory)); - BEAST_EXPECT (acct_objs_is_null (gw, jss::fee)); - BEAST_EXPECT (acct_objs_is_null (gw, jss::hashes)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::account)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::amendments)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::directory)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::fee)); + BEAST_EXPECT (acct_objs_is_empty (gw, jss::hashes)); } void run() override From ff81627e01f4d3d3fb6f7a06b3f12af7fa6cbb96 Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 1 Feb 2018 16:50:14 -0800 Subject: [PATCH 3/3] [FOLD] Address review comments --- src/test/rpc/AccountObjects_test.cpp | 145 ++++++++++++--------------- 1 file changed, 65 insertions(+), 80 deletions(-) diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 362534c0eff..ccd86d407fa 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -318,7 +318,7 @@ class AccountObjects_test : public beast::unit_test::suite void testObjectTypes() { - testcase ("object types"); + testcase("object types"); // Give gw a bunch of ledger objects and make sure we can retrieve // them by type. @@ -341,33 +341,31 @@ class AccountObjects_test : public beast::unit_test::suite return env.rpc("json", "account_objects", to_string(params)); }; - // Make a lambda that easily identifies empty account objects. - auto acct_objs_is_empty = - [&env, &acct_objs] (Account const& acct, char const* type) + // Make a lambda that easily identifies the size of account objects. + auto acct_objs_is_size = [&env, &acct_objs] + (Json::Value const& resp, unsigned size) { - Json::Value const resp = acct_objs (acct, type); - - bool const isArray = resp["result"]["account_objects"].isArray(); - return isArray && (resp["result"]["account_objects"].size() == 0); + return resp[jss::result][jss::account_objects].isArray() && + (resp[jss::result][jss::account_objects].size() == size); }; env.fund(XRP(10000), gw, alice); env.close(); // Since the account is empty now, all account objects should come - // back null or empty. - BEAST_EXPECT (acct_objs_is_empty (gw, jss::account)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::amendments)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::check)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::directory)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::escrow)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::fee)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::hashes)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::offer)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::payment_channel)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::signer_list)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::state)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::ticket)); + // back empty. + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::account), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::amendments), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::check), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::directory), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::escrow), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::fee), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::hashes), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::offer), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::payment_channel), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::signer_list), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::state), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::ticket), 0)); // Set up a trust line so we can find it. env.trust(USD(1000), alice); @@ -377,13 +375,11 @@ class AccountObjects_test : public beast::unit_test::suite { // Find the trustline and make sure it's the right one. Json::Value const resp = acct_objs (gw, jss::state); + BEAST_EXPECT (acct_objs_is_size (resp, 1)); - BEAST_EXPECT (resp["result"]["account_objects"].isArray()); - BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); - - auto const& state = resp["result"]["account_objects"][0u]; - BEAST_EXPECT (state["Balance"]["value"].asInt() == -5); - BEAST_EXPECT (state["HighLimit"]["value"].asInt() == 1000); + auto const& state = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT (state[sfBalance.jsonName][jss::value].asInt() == -5); + BEAST_EXPECT (state[sfHighLimit.jsonName][jss::value].asUInt() == 1000); } { // gw writes a check for USD(10) to alice. @@ -399,14 +395,12 @@ class AccountObjects_test : public beast::unit_test::suite { // Find the check. Json::Value const resp = acct_objs (gw, jss::check); + BEAST_EXPECT (acct_objs_is_size (resp, 1)); - BEAST_EXPECT (resp["result"]["account_objects"].isArray()); - BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); - - auto const& check = resp["result"]["account_objects"][0u]; - BEAST_EXPECT (check["Account"] == gw.human()); - BEAST_EXPECT (check["Destination"] == alice.human()); - BEAST_EXPECT (check["SendMax"]["value"].asInt() == 10); + auto const& check = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT (check[sfAccount.jsonName] == gw.human()); + BEAST_EXPECT (check[sfDestination.jsonName] == alice.human()); + BEAST_EXPECT (check[sfSendMax.jsonName][jss::value].asUInt() == 10); } { // gw creates an escrow that we can look for in the ledger. @@ -416,7 +410,7 @@ class AccountObjects_test : public beast::unit_test::suite jvEscrow[jss::Account] = gw.human(); jvEscrow[jss::Destination] = gw.human(); jvEscrow[jss::Amount] = XRP(100).value().getJson(0); - jvEscrow["FinishAfter"] = + jvEscrow[sfFinishAfter.jsonName] = env.now().time_since_epoch().count() + 1; env (jvEscrow); env.close(); @@ -424,14 +418,12 @@ class AccountObjects_test : public beast::unit_test::suite { // Find the escrow. Json::Value const resp = acct_objs (gw, jss::escrow); + BEAST_EXPECT (acct_objs_is_size (resp, 1)); - BEAST_EXPECT (resp["result"]["account_objects"].isArray()); - BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); - - auto const& escrow = resp["result"]["account_objects"][0u]; - BEAST_EXPECT (escrow["Account"] == gw.human()); - BEAST_EXPECT (escrow["Destination"] == gw.human()); - BEAST_EXPECT (escrow["Amount"].asInt() == 100'000'000); + auto const& escrow = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT (escrow[sfAccount.jsonName] == gw.human()); + BEAST_EXPECT (escrow[sfDestination.jsonName] == gw.human()); + BEAST_EXPECT (escrow[sfAmount.jsonName].asUInt() == 100'000'000); } // gw creates an offer that we can look for in the ledger. env (offer (gw, USD (7), XRP (14))); @@ -439,14 +431,12 @@ class AccountObjects_test : public beast::unit_test::suite { // Find the offer. Json::Value const resp = acct_objs (gw, jss::offer); + BEAST_EXPECT (acct_objs_is_size (resp, 1)); - BEAST_EXPECT (resp["result"]["account_objects"].isArray()); - BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); - - auto const& offer = resp["result"]["account_objects"][0u]; - BEAST_EXPECT (offer["Account"] == gw.human()); - BEAST_EXPECT (offer["TakerGets"].asInt() == 14'000'000); - BEAST_EXPECT (offer["TakerPays"]["value"].asInt() == 7); + auto const& offer = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT (offer[sfAccount.jsonName] == gw.human()); + BEAST_EXPECT (offer[sfTakerGets.jsonName].asUInt() == 14'000'000); + BEAST_EXPECT (offer[sfTakerPays.jsonName][jss::value].asUInt() == 7); } { // Create a payment channel from qw to alice that we can look for. @@ -456,22 +446,20 @@ class AccountObjects_test : public beast::unit_test::suite jvPayChan[jss::Account] = gw.human (); jvPayChan[jss::Destination] = alice.human (); jvPayChan[jss::Amount] = XRP (300).value().getJson (0); - jvPayChan["SettleDelay"] = 24 * 60 * 60; - jvPayChan["PublicKey"] = strHex (gw.pk().slice ()); + jvPayChan[sfSettleDelay.jsonName] = 24 * 60 * 60; + jvPayChan[sfPublicKey.jsonName] = strHex (gw.pk().slice ()); env (jvPayChan); env.close(); } { // Find the payment channel. Json::Value const resp = acct_objs (gw, jss::payment_channel); + BEAST_EXPECT (acct_objs_is_size (resp, 1)); - BEAST_EXPECT (resp["result"]["account_objects"].isArray()); - BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); - - auto const& payChan = resp["result"]["account_objects"][0u]; - BEAST_EXPECT (payChan["Account"] == gw.human()); - BEAST_EXPECT (payChan["Amount"].asInt() == 300'000'000); - BEAST_EXPECT (payChan["SettleDelay"].asInt() == 24 * 60 * 60); + auto const& payChan = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT (payChan[sfAccount.jsonName] == gw.human()); + BEAST_EXPECT (payChan[sfAmount.jsonName].asUInt() == 300'000'000); + BEAST_EXPECT (payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60); } // Make gw multisigning by adding a signerList. env (signers (gw, 6, { { alice, 7} })); @@ -479,15 +467,14 @@ class AccountObjects_test : public beast::unit_test::suite { // Find the signer list. Json::Value const resp = acct_objs (gw, jss::signer_list); - - BEAST_EXPECT (resp["result"]["account_objects"].isArray()); - BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); - - auto const& signerList = resp["result"]["account_objects"][0u]; - BEAST_EXPECT (signerList["SignerQuorum"] == 6); - auto const& entry = signerList["SignerEntries"][0u]["SignerEntry"]; - BEAST_EXPECT (entry["Account"] == alice.human()); - BEAST_EXPECT (entry["SignerWeight"].asInt() == 7); + BEAST_EXPECT (acct_objs_is_size (resp, 1)); + + auto const& signerList = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT (signerList[sfSignerQuorum.jsonName] == 6); + auto const& entry = + signerList[sfSignerEntries.jsonName][0u][sfSignerEntry.jsonName]; + BEAST_EXPECT (entry[sfAccount.jsonName] == alice.human()); + BEAST_EXPECT (entry[sfSignerWeight.jsonName].asUInt() == 7); } // Create a Ticket for gw. env (ticket::create (gw, gw)); @@ -495,29 +482,27 @@ class AccountObjects_test : public beast::unit_test::suite { // Find the ticket. Json::Value const resp = acct_objs (gw, jss::ticket); + BEAST_EXPECT (acct_objs_is_size (resp, 1)); - BEAST_EXPECT (resp["result"]["account_objects"].isArray()); - BEAST_EXPECT (resp["result"]["account_objects"].size() == 1); - - auto const& ticket = resp["result"]["account_objects"][0u]; - BEAST_EXPECT (ticket["Account"] == gw.human()); - BEAST_EXPECT (ticket["LedgerEntryType"] == "Ticket"); - BEAST_EXPECT (ticket["Sequence"].asInt() == 8); + auto const& ticket = resp[jss::result][jss::account_objects][0u]; + BEAST_EXPECT (ticket[sfAccount.jsonName] == gw.human()); + BEAST_EXPECT (ticket[sfLedgerEntryType.jsonName] == "Ticket"); + BEAST_EXPECT (ticket[sfSequence.jsonName].asUInt() == 8); } // Run up the number of directory entries so gw has two // directory nodes. - for (int d = 1'000'032; d >= 1'000'000; d -= 1) + for (int d = 1'000'032; d >= 1'000'000; --d) { env (offer (gw, USD (1), drops (d))); env.close(); } // Verify that the non-returning types still don't return anything. - BEAST_EXPECT (acct_objs_is_empty (gw, jss::account)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::amendments)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::directory)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::fee)); - BEAST_EXPECT (acct_objs_is_empty (gw, jss::hashes)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::account), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::amendments), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::directory), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::fee), 0)); + BEAST_EXPECT (acct_objs_is_size (acct_objs (gw, jss::hashes), 0)); } void run() override