From 7c04148a1f3394c7553d386773a9aa536506facc Mon Sep 17 00:00:00 2001 From: Fraser Waters Date: Sat, 13 Feb 2021 18:22:39 +0000 Subject: [PATCH] Move signer_list in JSON response for api_version 2 See https://github.com/ripple/xrpl-dev-portal/issues/938 for context. --- RELEASENOTES.md | 4 + src/ripple/rpc/handlers/AccountInfo.cpp | 15 +++- src/test/rpc/AccountInfo_test.cpp | 114 ++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 856fa788640..5c760c4b080 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -7,6 +7,10 @@ This document contains the release notes for `rippled`, the reference server imp Have new ideas? Need help with setting up your node? Come visit us [here](https://github.com/ripple/rippled/issues/new/choose) +# Change log + +- API version 2 will now return `signer_lists` in the root of the `account_info` response, no longer nested under `account_data`. + # Releases ## Version 1.7.2 diff --git a/src/ripple/rpc/handlers/AccountInfo.cpp b/src/ripple/rpc/handlers/AccountInfo.cpp index e20e828a919..ee192935856 100644 --- a/src/ripple/rpc/handlers/AccountInfo.cpp +++ b/src/ripple/rpc/handlers/AccountInfo.cpp @@ -109,8 +109,19 @@ doAccountInfo(RPC::JsonContext& context) if (sleSigners) jvSignerList.append(sleSigners->getJson(JsonOptions::none)); - result[jss::account_data][jss::signer_lists] = - std::move(jvSignerList); + // Documentation states this is returned as part of the account_info + // response, but previously the code put it under account_data. We + // can move this to the documentated location from apiVersion 2 + // onwards. + if (context.apiVersion == 1) + { + result[jss::account_data][jss::signer_lists] = + std::move(jvSignerList); + } + else + { + result[jss::signer_lists] = std::move(jvSignerList); + } } // Return queue info if that is requested if (queue) diff --git a/src/test/rpc/AccountInfo_test.cpp b/src/test/rpc/AccountInfo_test.cpp index 42e23a4adf2..8ce8270ad20 100644 --- a/src/test/rpc/AccountInfo_test.cpp +++ b/src/test/rpc/AccountInfo_test.cpp @@ -188,6 +188,119 @@ class AccountInfo_test : public beast::unit_test::suite } } + // Test the "signer_lists" argument in account_info, with api_version 2. + void + testSignerListsApiVersion2() + { + using namespace jtx; + Env env{*this, envconfig([](std::unique_ptr c) { + c->loadFromString("\n[beta_rpc_api]\n1\n"); + return c; + })}; + Account const alice{"alice"}; + env.fund(XRP(1000), alice); + + auto const withoutSigners = std::string("{ ") + + "\"api_version\": 2, \"account\": \"" + alice.human() + "\"}"; + + auto const withSigners = std::string("{ ") + + "\"api_version\": 2, \"account\": \"" + alice.human() + "\", " + + "\"signer_lists\": true }"; + + // Alice has no SignerList yet. + { + // account_info without the "signer_lists" argument. + auto const info = env.rpc("json", "account_info", withoutSigners); + BEAST_EXPECT(info.isMember(jss::result)); + BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists)); + } + { + // account_info with the "signer_lists" argument. + auto const info = env.rpc("json", "account_info", withSigners); + BEAST_EXPECT(info.isMember(jss::result)); + auto const& data = info[jss::result]; + BEAST_EXPECT(data.isMember(jss::signer_lists)); + auto const& signerLists = data[jss::signer_lists]; + BEAST_EXPECT(signerLists.isArray()); + BEAST_EXPECT(signerLists.size() == 0); + } + + // Give alice a SignerList. + Account const bogie{"bogie"}; + + Json::Value const smallSigners = signers(alice, 2, {{bogie, 3}}); + env(smallSigners); + { + // account_info without the "signer_lists" argument. + auto const info = env.rpc("json", "account_info", withoutSigners); + BEAST_EXPECT(info.isMember(jss::result)); + BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists)); + } + { + // account_info with the "signer_lists" argument. + auto const info = env.rpc("json", "account_info", withSigners); + BEAST_EXPECT(info.isMember(jss::result)); + auto const& data = info[jss::result]; + BEAST_EXPECT(data.isMember(jss::signer_lists)); + auto const& signerLists = data[jss::signer_lists]; + BEAST_EXPECT(signerLists.isArray()); + BEAST_EXPECT(signerLists.size() == 1); + auto const& signers = signerLists[0u]; + BEAST_EXPECT(signers.isObject()); + BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 2); + auto const& signerEntries = signers[sfSignerEntries.jsonName]; + BEAST_EXPECT(signerEntries.size() == 1); + auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName]; + BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3); + } + + // Give alice a big signer list + Account const demon{"demon"}; + Account const ghost{"ghost"}; + Account const haunt{"haunt"}; + Account const jinni{"jinni"}; + Account const phase{"phase"}; + Account const shade{"shade"}; + Account const spook{"spook"}; + + Json::Value const bigSigners = signers( + alice, + 4, + { + {bogie, 1}, + {demon, 1}, + {ghost, 1}, + {haunt, 1}, + {jinni, 1}, + {phase, 1}, + {shade, 1}, + {spook, 1}, + }); + env(bigSigners); + { + // account_info with the "signer_lists" argument. + auto const info = env.rpc("json", "account_info", withSigners); + BEAST_EXPECT(info.isMember(jss::result)); + auto const& data = info[jss::result]; + BEAST_EXPECT(data.isMember(jss::signer_lists)); + auto const& signerLists = data[jss::signer_lists]; + BEAST_EXPECT(signerLists.isArray()); + BEAST_EXPECT(signerLists.size() == 1); + auto const& signers = signerLists[0u]; + BEAST_EXPECT(signers.isObject()); + BEAST_EXPECT(signers[sfSignerQuorum.jsonName] == 4); + auto const& signerEntries = signers[sfSignerEntries.jsonName]; + BEAST_EXPECT(signerEntries.size() == 8); + for (unsigned i = 0u; i < 8; ++i) + { + auto const& entry = signerEntries[i][sfSignerEntry.jsonName]; + BEAST_EXPECT(entry.size() == 2); + BEAST_EXPECT(entry.isMember(sfAccount.jsonName)); + BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1); + } + } + } + // Test the "signer_lists" argument in account_info, version 2 API. void testSignerListsV2() @@ -604,6 +717,7 @@ class AccountInfo_test : public beast::unit_test::suite { testErrors(); testSignerLists(); + testSignerListsApiVersion2(); testSignerListsV2(); testSimpleGrpc(); testErrorsGrpc();