From 92281a4edeab0f4fd43e7773a0e7cd882bf5649f Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 16 Oct 2025 12:02:25 -0400 Subject: [PATCH 1/6] refactor: replace string JSONs with Json::Value (#5886) There are some tests that write out JSONs as a string instead of using the Json::Value library, which are cleaned up by this change. Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com> --- src/test/app/TxQ_test.cpp | 39 +- src/test/rpc/AccountInfo_test.cpp | 67 ++- src/test/rpc/AccountLines_test.cpp | 847 +++++++++++++---------------- 3 files changed, 443 insertions(+), 510 deletions(-) diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index 190acfeddf..ebc9c7d413 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -3081,16 +3081,23 @@ public: env.fund(XRP(1000000), alice); env.close(); - auto const withQueue = - R"({ "account": ")" + alice.human() + R"(", "queue": true })"; - auto const withoutQueue = R"({ "account": ")" + alice.human() + R"("})"; - auto const prevLedgerWithQueue = R"({ "account": ")" + alice.human() + - R"(", "queue": true, "ledger_index": 3 })"; + Json::Value withQueue; + withQueue[jss::account] = alice.human(); + withQueue[jss::queue] = true; + + Json::Value withoutQueue; + withoutQueue[jss::account] = alice.human(); + + Json::Value prevLedgerWithQueue; + prevLedgerWithQueue[jss::account] = alice.human(); + prevLedgerWithQueue[jss::queue] = true; + prevLedgerWithQueue[jss::ledger_index] = 3; BEAST_EXPECT(env.current()->info().seq > 3); { // account_info without the "queue" argument. - auto const info = env.rpc("json", "account_info", withoutQueue); + auto const info = + env.rpc("json", "account_info", to_string(withoutQueue)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -3098,7 +3105,8 @@ public: } { // account_info with the "queue" argument. - auto const info = env.rpc("json", "account_info", withQueue); + auto const info = + env.rpc("json", "account_info", to_string(withQueue)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -3120,7 +3128,8 @@ public: checkMetrics(*this, env, 0, 6, 4, 3); { - auto const info = env.rpc("json", "account_info", withQueue); + auto const info = + env.rpc("json", "account_info", to_string(withQueue)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -3149,7 +3158,8 @@ public: checkMetrics(*this, env, 4, 6, 4, 3); { - auto const info = env.rpc("json", "account_info", withQueue); + auto const info = + env.rpc("json", "account_info", to_string(withQueue)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -3212,7 +3222,8 @@ public: checkMetrics(*this, env, 1, 8, 5, 4); { - auto const info = env.rpc("json", "account_info", withQueue); + auto const info = + env.rpc("json", "account_info", to_string(withQueue)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -3276,7 +3287,8 @@ public: checkMetrics(*this, env, 1, 8, 5, 4); { - auto const info = env.rpc("json", "account_info", withQueue); + auto const info = + env.rpc("json", "account_info", to_string(withQueue)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -3344,7 +3356,7 @@ public: { auto const info = - env.rpc("json", "account_info", prevLedgerWithQueue); + env.rpc("json", "account_info", to_string(prevLedgerWithQueue)); BEAST_EXPECT( info.isMember(jss::result) && RPC::contains_error(info[jss::result])); @@ -3356,7 +3368,8 @@ public: checkMetrics(*this, env, 0, 10, 0, 5); { - auto const info = env.rpc("json", "account_info", withQueue); + auto const info = + env.rpc("json", "account_info", to_string(withQueue)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); diff --git a/src/test/rpc/AccountInfo_test.cpp b/src/test/rpc/AccountInfo_test.cpp index 18c8bf5a1c..32a1202622 100644 --- a/src/test/rpc/AccountInfo_test.cpp +++ b/src/test/rpc/AccountInfo_test.cpp @@ -58,10 +58,10 @@ public: { // account_info with an account that's not in the ledger. Account const bogie{"bogie"}; - auto const info = env.rpc( - "json", - "account_info", - R"({ "account": ")" + bogie.human() + R"("})"); + Json::Value params; + params[jss::account] = bogie.human(); + auto const info = + env.rpc("json", "account_info", to_string(params)); BEAST_EXPECT( info[jss::result][jss::error_code] == rpcACT_NOT_FOUND); BEAST_EXPECT( @@ -128,16 +128,18 @@ public: Account const alice{"alice"}; env.fund(XRP(1000), alice); - auto const withoutSigners = - std::string("{ ") + "\"account\": \"" + alice.human() + "\"}"; + Json::Value withoutSigners; + withoutSigners[jss::account] = alice.human(); - auto const withSigners = std::string("{ ") + "\"account\": \"" + - alice.human() + "\", " + "\"signer_lists\": true }"; + Json::Value withSigners; + withSigners[jss::account] = alice.human(); + withSigners[jss::signer_lists] = true; // Alice has no SignerList yet. { // account_info without the "signer_lists" argument. - auto const info = env.rpc("json", "account_info", withoutSigners); + auto const info = + env.rpc("json", "account_info", to_string(withoutSigners)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -146,7 +148,8 @@ public: } { // account_info with the "signer_lists" argument. - auto const info = env.rpc("json", "account_info", withSigners); + auto const info = + env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -164,7 +167,8 @@ public: env(smallSigners); { // account_info without the "signer_lists" argument. - auto const info = env.rpc("json", "account_info", withoutSigners); + auto const info = + env.rpc("json", "account_info", to_string(withoutSigners)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -173,7 +177,8 @@ public: } { // account_info with the "signer_lists" argument. - auto const info = env.rpc("json", "account_info", withSigners); + auto const info = + env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -216,7 +221,8 @@ public: env(bigSigners); { // account_info with the "signer_lists" argument. - auto const info = env.rpc("json", "account_info", withSigners); + auto const info = + env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT( info.isMember(jss::result) && info[jss::result].isMember(jss::account_data)); @@ -250,12 +256,14 @@ public: Account const alice{"alice"}; env.fund(XRP(1000), alice); - auto const withoutSigners = std::string("{ ") + - "\"api_version\": 2, \"account\": \"" + alice.human() + "\"}"; + Json::Value withoutSigners; + withoutSigners[jss::api_version] = 2; + withoutSigners[jss::account] = alice.human(); - auto const withSigners = std::string("{ ") + - "\"api_version\": 2, \"account\": \"" + alice.human() + "\", " + - "\"signer_lists\": true }"; + Json::Value withSigners; + withSigners[jss::api_version] = 2; + withSigners[jss::account] = alice.human(); + withSigners[jss::signer_lists] = true; auto const withSignersAsString = std::string("{ ") + "\"api_version\": 2, \"account\": \"" + alice.human() + "\", " + @@ -264,13 +272,15 @@ public: // Alice has no SignerList yet. { // account_info without the "signer_lists" argument. - auto const info = env.rpc("json", "account_info", withoutSigners); + auto const info = + env.rpc("json", "account_info", to_string(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); + auto const info = + env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT(info.isMember(jss::result)); auto const& data = info[jss::result]; BEAST_EXPECT(data.isMember(jss::signer_lists)); @@ -286,13 +296,15 @@ public: env(smallSigners); { // account_info without the "signer_lists" argument. - auto const info = env.rpc("json", "account_info", withoutSigners); + auto const info = + env.rpc("json", "account_info", to_string(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); + auto const info = + env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT(info.isMember(jss::result)); auto const& data = info[jss::result]; BEAST_EXPECT(data.isMember(jss::signer_lists)); @@ -340,7 +352,8 @@ public: env(bigSigners); { // account_info with the "signer_lists" argument. - auto const info = env.rpc("json", "account_info", withSigners); + auto const info = + env.rpc("json", "account_info", to_string(withSigners)); BEAST_EXPECT(info.isMember(jss::result)); auto const& data = info[jss::result]; BEAST_EXPECT(data.isMember(jss::signer_lists)); @@ -567,10 +580,10 @@ public: auto getAccountFlag = [&env]( std::string_view fName, Account const& account) { - auto const info = env.rpc( - "json", - "account_info", - R"({"account" : ")" + account.human() + R"("})"); + Json::Value params; + params[jss::account] = account.human(); + auto const info = + env.rpc("json", "account_info", to_string(params)); std::optional res; if (info[jss::result][jss::status] == "success" && diff --git a/src/test/rpc/AccountLines_test.cpp b/src/test/rpc/AccountLines_test.cpp index 9215f4087a..10d8c1b4ac 100644 --- a/src/test/rpc/AccountLines_test.cpp +++ b/src/test/rpc/AccountLines_test.cpp @@ -46,11 +46,11 @@ public: } { // account_lines with a malformed account. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": )" - R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})"); + Json::Value params; + params[jss::account] = + "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( lines[jss::result][jss::error_message] == RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); @@ -77,10 +77,10 @@ public: Account const alice{"alice"}; { // account_lines on an unfunded account. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + R"("})"); + Json::Value params; + params[jss::account] = alice.human(); + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( lines[jss::result][jss::error_message] == RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message]); @@ -92,33 +92,31 @@ public: { // alice is funded but has no lines. An empty array is returned. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + R"("})"); + Json::Value params; + params[jss::account] = alice.human(); + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0); } { // Specify a ledger that doesn't exist. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("ledger_index": "nonsense"})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::ledger_index] = "nonsense"; + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( lines[jss::result][jss::error_message] == "ledgerIndexMalformed"); } { // Specify a different ledger that doesn't exist. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("ledger_index": 50000})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::ledger_index] = 50000; + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( lines[jss::result][jss::error_message] == "ledgerNotFound"); } @@ -183,24 +181,20 @@ public: LedgerInfo const& info, int count) { // Get account_lines by ledger index. - auto const linesSeq = env.rpc( - "json", - "account_lines", - R"({"account": ")" + account.human() + - R"(", )" - R"("ledger_index": )" + - std::to_string(info.seq) + "}"); + Json::Value paramsSeq; + paramsSeq[jss::account] = account.human(); + paramsSeq[jss::ledger_index] = info.seq; + auto const linesSeq = + env.rpc("json", "account_lines", to_string(paramsSeq)); BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count); // Get account_lines by ledger hash. - auto const linesHash = env.rpc( - "json", - "account_lines", - R"({"account": ")" + account.human() + - R"(", )" - R"("ledger_hash": ")" + - to_string(info.hash) + R"("})"); + Json::Value paramsHash; + paramsHash[jss::account] = account.human(); + paramsHash[jss::ledger_hash] = to_string(info.hash); + auto const linesHash = + env.rpc("json", "account_lines", to_string(paramsHash)); BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count); }; @@ -217,37 +211,31 @@ public: { // Surprisingly, it's valid to specify both index and hash, in // which case the hash wins. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("ledger_hash": ")" + - to_string(ledger4Info.hash) + - R"(", )" - R"("ledger_index": )" + - std::to_string(ledger58Info.seq) + "}"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::ledger_hash] = to_string(ledger4Info.hash); + params[jss::ledger_index] = ledger58Info.seq; + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26); } { // alice should have 52 trust lines in the current ledger. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + R"("})"); + Json::Value params; + params[jss::account] = alice.human(); + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52); } { // alice should have 26 trust lines with gw1. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("peer": ")" + - gw1.human() + R"("})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::peer] = gw1.human(); + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26); @@ -257,99 +245,87 @@ public: } { // Use a malformed peer. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("peer": )" - R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::peer] = + "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( lines[jss::result][jss::error_message] == RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); } { // A negative limit should fail. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("limit": -1})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::limit] = -1; + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( lines[jss::result][jss::error_message] == RPC::expected_field_message(jss::limit, "unsigned integer")); } { // Limit the response to 1 trust line. - auto const linesA = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("limit": 1})"); + Json::Value paramsA; + paramsA[jss::account] = alice.human(); + paramsA[jss::limit] = 1; + auto const linesA = + env.rpc("json", "account_lines", to_string(paramsA)); BEAST_EXPECT(linesA[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1); // Pick up from where the marker left off. We should get 51. auto marker = linesA[jss::result][jss::marker].asString(); - auto const linesB = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("marker": ")" + - marker + R"("})"); + Json::Value paramsB; + paramsB[jss::account] = alice.human(); + paramsB[jss::marker] = marker; + auto const linesB = + env.rpc("json", "account_lines", to_string(paramsB)); BEAST_EXPECT(linesB[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51); // Go again from where the marker left off, but set a limit of 3. - auto const linesC = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("limit": 3, )" - R"("marker": ")" + - marker + R"("})"); + Json::Value paramsC; + paramsC[jss::account] = alice.human(); + paramsC[jss::limit] = 3; + paramsC[jss::marker] = marker; + auto const linesC = + env.rpc("json", "account_lines", to_string(paramsC)); BEAST_EXPECT(linesC[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3); // Mess with the marker so it becomes bad and check for the error. marker[5] = marker[5] == '7' ? '8' : '7'; - auto const linesD = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("marker": ")" + - marker + R"("})"); + Json::Value paramsD; + paramsD[jss::account] = alice.human(); + paramsD[jss::marker] = marker; + auto const linesD = + env.rpc("json", "account_lines", to_string(paramsD)); BEAST_EXPECT( linesD[jss::result][jss::error_message] == RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); } { // A non-string marker should also fail. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("marker": true})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::marker] = true; + auto const lines = + env.rpc("json", "account_lines", to_string(params)); BEAST_EXPECT( lines[jss::result][jss::error_message] == RPC::expected_field_message(jss::marker, "string")); } { // Check that the flags we expect from alice to gw2 are present. - auto const lines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("limit": 10, )" - R"("peer": ")" + - gw2.human() + R"("})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::limit] = 10; + params[jss::peer] = gw2.human(); + auto const lines = + env.rpc("json", "account_lines", to_string(params)); auto const& line = lines[jss::result][jss::lines][0u]; BEAST_EXPECT(line[jss::freeze].asBool() == true); BEAST_EXPECT(line[jss::deep_freeze].asBool() == true); @@ -358,14 +334,12 @@ public: } { // Check that the flags we expect from gw2 to alice are present. - auto const linesA = env.rpc( - "json", - "account_lines", - R"({"account": ")" + gw2.human() + - R"(", )" - R"("limit": 1, )" - R"("peer": ")" + - alice.human() + R"("})"); + Json::Value paramsA; + paramsA[jss::account] = gw2.human(); + paramsA[jss::limit] = 1; + paramsA[jss::peer] = alice.human(); + auto const linesA = + env.rpc("json", "account_lines", to_string(paramsA)); auto const& lineA = linesA[jss::result][jss::lines][0u]; BEAST_EXPECT(lineA[jss::freeze_peer].asBool() == true); BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool() == true); @@ -375,17 +349,13 @@ public: // Continue from the returned marker to make sure that works. BEAST_EXPECT(linesA[jss::result].isMember(jss::marker)); auto const marker = linesA[jss::result][jss::marker].asString(); - auto const linesB = env.rpc( - "json", - "account_lines", - R"({"account": ")" + gw2.human() + - R"(", )" - R"("limit": 25, )" - R"("marker": ")" + - marker + - R"(", )" - R"("peer": ")" + - alice.human() + R"("})"); + Json::Value paramsB; + paramsB[jss::account] = gw2.human(); + paramsB[jss::limit] = 25; + paramsB[jss::marker] = marker; + paramsB[jss::peer] = alice.human(); + auto const linesB = + env.rpc("json", "account_lines", to_string(paramsB)); BEAST_EXPECT(linesB[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25); BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker)); @@ -425,12 +395,11 @@ public: // signerlist is first. This is only a (reliable) coincidence of // object naming. So if any of alice's objects are renamed this // may fail. - Json::Value const aliceObjects = env.rpc( - "json", - "account_objects", - R"({"account": ")" + alice.human() + - R"(", )" - R"("limit": 10})"); + Json::Value aliceObjectsParams; + aliceObjectsParams[jss::account] = alice.human(); + aliceObjectsParams[jss::limit] = 10; + Json::Value const aliceObjects = + env.rpc("json", "account_objects", to_string(aliceObjectsParams)); Json::Value const& aliceSignerList = aliceObjects[jss::result][jss::account_objects][0u]; if (!(aliceSignerList[sfLedgerEntryType.jsonName] == jss::SignerList)) @@ -445,10 +414,11 @@ public: // Get account_lines for alice. Limit at 1, so we get a marker // pointing to her SignerList. - auto const aliceLines1 = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + R"(", "limit": 1})"); + Json::Value aliceLines1Params; + aliceLines1Params[jss::account] = alice.human(); + aliceLines1Params[jss::limit] = 1; + auto const aliceLines1 = + env.rpc("json", "account_lines", to_string(aliceLines1Params)); BEAST_EXPECT(aliceLines1[jss::result].isMember(jss::marker)); // Verify that the marker points at the signer list. @@ -459,21 +429,21 @@ public: BEAST_EXPECT(markerIndex == aliceSignerList[jss::index].asString()); // When we fetch Alice's remaining lines we should find one and no more. - auto const aliceLines2 = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + R"(", "marker": ")" + - aliceMarker + R"("})"); + Json::Value aliceLines2Params; + aliceLines2Params[jss::account] = alice.human(); + aliceLines2Params[jss::marker] = aliceMarker; + auto const aliceLines2 = + env.rpc("json", "account_lines", to_string(aliceLines2Params)); BEAST_EXPECT(aliceLines2[jss::result][jss::lines].size() == 1); BEAST_EXPECT(!aliceLines2[jss::result].isMember(jss::marker)); // Get account lines for beckys account, using alices SignerList as a // marker. This should cause an error. - auto const beckyLines = env.rpc( - "json", - "account_lines", - R"({"account": ")" + becky.human() + R"(", "marker": ")" + - aliceMarker + R"("})"); + Json::Value beckyLinesParams; + beckyLinesParams[jss::account] = becky.human(); + beckyLinesParams[jss::marker] = aliceMarker; + auto const beckyLines = + env.rpc("json", "account_lines", to_string(beckyLinesParams)); BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message)); } @@ -525,12 +495,11 @@ public: env.close(); // Get account_lines for alice. Limit at 1, so we get a marker. - auto const linesBeg = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("limit": 2})"); + Json::Value linesBegParams; + linesBegParams[jss::account] = alice.human(); + linesBegParams[jss::limit] = 2; + auto const linesBeg = + env.rpc("json", "account_lines", to_string(linesBegParams)); BEAST_EXPECT( linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD"); BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker)); @@ -541,13 +510,11 @@ public: // Since alice paid all her EUR to cheri, alice should no longer // have a trust line to gw1. So the old marker should now be invalid. - auto const linesEnd = env.rpc( - "json", - "account_lines", - R"({"account": ")" + alice.human() + - R"(", )" - R"("marker": ")" + - linesBeg[jss::result][jss::marker].asString() + R"("})"); + Json::Value linesEndParams; + linesEndParams[jss::account] = alice.human(); + linesEndParams[jss::marker] = linesBeg[jss::result][jss::marker]; + auto const linesEnd = + env.rpc("json", "account_lines", to_string(linesEndParams)); BEAST_EXPECT( linesEnd[jss::result][jss::error_message] == RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); @@ -726,12 +693,11 @@ public: } BEAST_EXPECT(expectedLines == foundLines); + Json::Value aliceObjectsParams2; + aliceObjectsParams2[jss::account] = alice.human(); + aliceObjectsParams2[jss::limit] = 200; Json::Value const aliceObjects = env.rpc( - "json", - "account_objects", - R"({"account": ")" + alice.human() + - R"(", )" - R"("limit": 200})"); + "json", "account_objects", to_string(aliceObjectsParams2)); BEAST_EXPECT(aliceObjects.isMember(jss::result)); BEAST_EXPECT( !aliceObjects[jss::result].isMember(jss::error_message)); @@ -751,12 +717,11 @@ public: iterations == expectedIterations, std::to_string(iterations)); // Get becky's objects just to confirm that they're symmetrical + Json::Value beckyObjectsParams; + beckyObjectsParams[jss::account] = becky.human(); + beckyObjectsParams[jss::limit] = 200; Json::Value const beckyObjects = env.rpc( - "json", - "account_objects", - R"({"account": ")" + becky.human() + - R"(", )" - R"("limit": 200})"); + "json", "account_objects", to_string(beckyObjectsParams)); BEAST_EXPECT(beckyObjects.isMember(jss::result)); BEAST_EXPECT( !beckyObjects[jss::result].isMember(jss::error_message)); @@ -782,13 +747,11 @@ public: Env env(*this); { // account_lines with mal-formed json2 (missing id field). - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0")" - " }"); + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); BEAST_EXPECT( @@ -797,14 +760,12 @@ public: } { // account_lines with no account. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5)" - " }"); + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( lines[jss::error][jss::message] == RPC::missing_field_error(jss::account)[jss::error_message]); @@ -817,16 +778,16 @@ public: } { // account_lines with a malformed account. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": )" - R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})"); + Json::Value params; + params[jss::account] = + "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( lines[jss::error][jss::message] == RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); @@ -840,16 +801,15 @@ public: Account const alice{"alice"}; { // account_lines on an unfunded account. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + R"("}})"); + Json::Value params; + params[jss::account] = alice.human(); + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( lines[jss::error][jss::message] == RPC::make_error(rpcACT_NOT_FOUND)[jss::error_message]); @@ -867,16 +827,15 @@ public: { // alice is funded but has no lines. An empty array is returned. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + R"("}})"); + Json::Value params; + params[jss::account] = alice.human(); + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0); BEAST_EXPECT( @@ -888,18 +847,16 @@ public: } { // Specify a ledger that doesn't exist. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("ledger_index": "nonsense"}})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::ledger_index] = "nonsense"; + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( lines[jss::error][jss::message] == "ledgerIndexMalformed"); BEAST_EXPECT( @@ -911,18 +868,16 @@ public: } { // Specify a different ledger that doesn't exist. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("ledger_index": 50000}})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::ledger_index] = 50000; + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::error][jss::message] == "ledgerNotFound"); BEAST_EXPECT( lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0"); @@ -992,19 +947,16 @@ public: LedgerInfo const& info, int count) { // Get account_lines by ledger index. - auto const linesSeq = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - account.human() + - R"(", )" - R"("ledger_index": )" + - std::to_string(info.seq) + "}}"); + Json::Value paramsSeq; + paramsSeq[jss::account] = account.human(); + paramsSeq[jss::ledger_index] = info.seq; + Json::Value requestSeq; + requestSeq[jss::method] = "account_lines"; + requestSeq[jss::jsonrpc] = "2.0"; + requestSeq[jss::ripplerpc] = "2.0"; + requestSeq[jss::id] = 5; + requestSeq[jss::params] = paramsSeq; + auto const linesSeq = env.rpc("json2", to_string(requestSeq)); BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count); BEAST_EXPECT( @@ -1016,19 +968,16 @@ public: BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5); // Get account_lines by ledger hash. - auto const linesHash = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - account.human() + - R"(", )" - R"("ledger_hash": ")" + - to_string(info.hash) + R"("}})"); + Json::Value paramsHash; + paramsHash[jss::account] = account.human(); + paramsHash[jss::ledger_hash] = to_string(info.hash); + Json::Value requestHash; + requestHash[jss::method] = "account_lines"; + requestHash[jss::jsonrpc] = "2.0"; + requestHash[jss::ripplerpc] = "2.0"; + requestHash[jss::id] = 5; + requestHash[jss::params] = paramsHash; + auto const linesHash = env.rpc("json2", to_string(requestHash)); BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count); BEAST_EXPECT( @@ -1053,22 +1002,17 @@ public: { // Surprisingly, it's valid to specify both index and hash, in // which case the hash wins. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("ledger_hash": ")" + - to_string(ledger4Info.hash) + - R"(", )" - R"("ledger_index": )" + - std::to_string(ledger58Info.seq) + "}}"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::ledger_hash] = to_string(ledger4Info.hash); + params[jss::ledger_index] = ledger58Info.seq; + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26); BEAST_EXPECT( @@ -1080,16 +1024,15 @@ public: } { // alice should have 52 trust lines in the current ledger. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + R"("}})"); + Json::Value params; + params[jss::account] = alice.human(); + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52); BEAST_EXPECT( @@ -1101,19 +1044,16 @@ public: } { // alice should have 26 trust lines with gw1. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("peer": ")" + - gw1.human() + R"("}})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::peer] = gw1.human(); + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT(lines[jss::result][jss::lines].isArray()); BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26); BEAST_EXPECT( @@ -1125,19 +1065,17 @@ public: } { // Use a malformed peer. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("peer": )" - R"("n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"}})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::peer] = + "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj"; + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( lines[jss::error][jss::message] == RPC::make_error(rpcACT_MALFORMED)[jss::error_message]); @@ -1150,18 +1088,16 @@ public: } { // A negative limit should fail. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("limit": -1}})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::limit] = -1; + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( lines[jss::error][jss::message] == RPC::expected_field_message(jss::limit, "unsigned integer")); @@ -1174,18 +1110,16 @@ public: } { // Limit the response to 1 trust line. - auto const linesA = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("limit": 1}})"); + Json::Value paramsA; + paramsA[jss::account] = alice.human(); + paramsA[jss::limit] = 1; + Json::Value requestA; + requestA[jss::method] = "account_lines"; + requestA[jss::jsonrpc] = "2.0"; + requestA[jss::ripplerpc] = "2.0"; + requestA[jss::id] = 5; + requestA[jss::params] = paramsA; + auto const linesA = env.rpc("json2", to_string(requestA)); BEAST_EXPECT(linesA[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1); BEAST_EXPECT( @@ -1197,19 +1131,16 @@ public: // Pick up from where the marker left off. We should get 51. auto marker = linesA[jss::result][jss::marker].asString(); - auto const linesB = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("marker": ")" + - marker + R"("}})"); + Json::Value paramsB; + paramsB[jss::account] = alice.human(); + paramsB[jss::marker] = marker; + Json::Value requestB; + requestB[jss::method] = "account_lines"; + requestB[jss::jsonrpc] = "2.0"; + requestB[jss::ripplerpc] = "2.0"; + requestB[jss::id] = 5; + requestB[jss::params] = paramsB; + auto const linesB = env.rpc("json2", to_string(requestB)); BEAST_EXPECT(linesB[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51); BEAST_EXPECT( @@ -1220,20 +1151,17 @@ public: BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5); // Go again from where the marker left off, but set a limit of 3. - auto const linesC = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("limit": 3, )" - R"("marker": ")" + - marker + R"("}})"); + Json::Value paramsC; + paramsC[jss::account] = alice.human(); + paramsC[jss::limit] = 3; + paramsC[jss::marker] = marker; + Json::Value requestC; + requestC[jss::method] = "account_lines"; + requestC[jss::jsonrpc] = "2.0"; + requestC[jss::ripplerpc] = "2.0"; + requestC[jss::id] = 5; + requestC[jss::params] = paramsC; + auto const linesC = env.rpc("json2", to_string(requestC)); BEAST_EXPECT(linesC[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3); BEAST_EXPECT( @@ -1245,19 +1173,16 @@ public: // Mess with the marker so it becomes bad and check for the error. marker[5] = marker[5] == '7' ? '8' : '7'; - auto const linesD = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("marker": ")" + - marker + R"("}})"); + Json::Value paramsD; + paramsD[jss::account] = alice.human(); + paramsD[jss::marker] = marker; + Json::Value requestD; + requestD[jss::method] = "account_lines"; + requestD[jss::jsonrpc] = "2.0"; + requestD[jss::ripplerpc] = "2.0"; + requestD[jss::id] = 5; + requestD[jss::params] = paramsD; + auto const linesD = env.rpc("json2", to_string(requestD)); BEAST_EXPECT( linesD[jss::error][jss::message] == RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); @@ -1270,18 +1195,16 @@ public: } { // A non-string marker should also fail. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("marker": true}})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::marker] = true; + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); BEAST_EXPECT( lines[jss::error][jss::message] == RPC::expected_field_message(jss::marker, "string")); @@ -1294,20 +1217,17 @@ public: } { // Check that the flags we expect from alice to gw2 are present. - auto const lines = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("limit": 10, )" - R"("peer": ")" + - gw2.human() + R"("}})"); + Json::Value params; + params[jss::account] = alice.human(); + params[jss::limit] = 10; + params[jss::peer] = gw2.human(); + Json::Value request; + request[jss::method] = "account_lines"; + request[jss::jsonrpc] = "2.0"; + request[jss::ripplerpc] = "2.0"; + request[jss::id] = 5; + request[jss::params] = params; + auto const lines = env.rpc("json2", to_string(request)); auto const& line = lines[jss::result][jss::lines][0u]; BEAST_EXPECT(line[jss::freeze].asBool() == true); BEAST_EXPECT(line[jss::deep_freeze].asBool() == true); @@ -1322,20 +1242,17 @@ public: } { // Check that the flags we expect from gw2 to alice are present. - auto const linesA = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - gw2.human() + - R"(", )" - R"("limit": 1, )" - R"("peer": ")" + - alice.human() + R"("}})"); + Json::Value paramsA; + paramsA[jss::account] = gw2.human(); + paramsA[jss::limit] = 1; + paramsA[jss::peer] = alice.human(); + Json::Value requestA; + requestA[jss::method] = "account_lines"; + requestA[jss::jsonrpc] = "2.0"; + requestA[jss::ripplerpc] = "2.0"; + requestA[jss::id] = 5; + requestA[jss::params] = paramsA; + auto const linesA = env.rpc("json2", to_string(requestA)); auto const& lineA = linesA[jss::result][jss::lines][0u]; BEAST_EXPECT(lineA[jss::freeze_peer].asBool() == true); BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool() == true); @@ -1351,23 +1268,18 @@ public: // Continue from the returned marker to make sure that works. BEAST_EXPECT(linesA[jss::result].isMember(jss::marker)); auto const marker = linesA[jss::result][jss::marker].asString(); - auto const linesB = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - gw2.human() + - R"(", )" - R"("limit": 25, )" - R"("marker": ")" + - marker + - R"(", )" - R"("peer": ")" + - alice.human() + R"("}})"); + Json::Value paramsB; + paramsB[jss::account] = gw2.human(); + paramsB[jss::limit] = 25; + paramsB[jss::marker] = marker; + paramsB[jss::peer] = alice.human(); + Json::Value requestB; + requestB[jss::method] = "account_lines"; + requestB[jss::jsonrpc] = "2.0"; + requestB[jss::ripplerpc] = "2.0"; + requestB[jss::id] = 5; + requestB[jss::params] = paramsB; + auto const linesB = env.rpc("json2", to_string(requestB)); BEAST_EXPECT(linesB[jss::result][jss::lines].isArray()); BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25); BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker)); @@ -1430,18 +1342,16 @@ public: env.close(); // Get account_lines for alice. Limit at 1, so we get a marker. - auto const linesBeg = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("limit": 2}})"); + Json::Value linesBegParams; + linesBegParams[jss::account] = alice.human(); + linesBegParams[jss::limit] = 2; + Json::Value linesBegRequest; + linesBegRequest[jss::method] = "account_lines"; + linesBegRequest[jss::jsonrpc] = "2.0"; + linesBegRequest[jss::ripplerpc] = "2.0"; + linesBegRequest[jss::id] = 5; + linesBegRequest[jss::params] = linesBegParams; + auto const linesBeg = env.rpc("json2", to_string(linesBegRequest)); BEAST_EXPECT( linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD"); BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker)); @@ -1458,19 +1368,16 @@ public: // Since alice paid all her EUR to cheri, alice should no longer // have a trust line to gw1. So the old marker should now be invalid. - auto const linesEnd = env.rpc( - "json2", - "{ " - R"("method" : "account_lines",)" - R"("jsonrpc" : "2.0",)" - R"("ripplerpc" : "2.0",)" - R"("id" : 5,)" - R"("params": )" - R"({"account": ")" + - alice.human() + - R"(", )" - R"("marker": ")" + - linesBeg[jss::result][jss::marker].asString() + R"("}})"); + Json::Value linesEndParams; + linesEndParams[jss::account] = alice.human(); + linesEndParams[jss::marker] = linesBeg[jss::result][jss::marker]; + Json::Value linesEndRequest; + linesEndRequest[jss::method] = "account_lines"; + linesEndRequest[jss::jsonrpc] = "2.0"; + linesEndRequest[jss::ripplerpc] = "2.0"; + linesEndRequest[jss::id] = 5; + linesEndRequest[jss::params] = linesEndParams; + auto const linesEnd = env.rpc("json2", to_string(linesEndRequest)); BEAST_EXPECT( linesEnd[jss::error][jss::message] == RPC::make_error(rpcINVALID_PARAMS)[jss::error_message]); From b4c894c1baa784aa21131fbf5f2792225247d606 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 17 Oct 2025 06:18:53 +0900 Subject: [PATCH 2/6] refactor: Autofill signature for Simulate RPC (#5852) This change enables autofilling of signature-related fields in the Simulate RPC. Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com> --- src/xrpld/rpc/handlers/Simulate.cpp | 63 ++++++++++++++++------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/src/xrpld/rpc/handlers/Simulate.cpp b/src/xrpld/rpc/handlers/Simulate.cpp index 092b0b4562..35cb7587d4 100644 --- a/src/xrpld/rpc/handlers/Simulate.cpp +++ b/src/xrpld/rpc/handlers/Simulate.cpp @@ -72,39 +72,23 @@ getAutofillSequence(Json::Value const& tx_json, RPC::JsonContext& context) } static std::optional -autofillTx(Json::Value& tx_json, RPC::JsonContext& context) +autofillSignature(Json::Value& sigObject) { - if (!tx_json.isMember(jss::Fee)) - { - // autofill Fee - // Must happen after all the other autofills happen - // Error handling/messaging works better that way - auto feeOrError = RPC::getCurrentNetworkFee( - context.role, - context.app.config(), - context.app.getFeeTrack(), - context.app.getTxQ(), - context.app, - tx_json); - if (feeOrError.isMember(jss::error)) - return feeOrError; - tx_json[jss::Fee] = feeOrError; - } - - if (!tx_json.isMember(jss::SigningPubKey)) + if (!sigObject.isMember(jss::SigningPubKey)) { // autofill SigningPubKey - tx_json[jss::SigningPubKey] = ""; + sigObject[jss::SigningPubKey] = ""; } - if (tx_json.isMember(jss::Signers)) + if (sigObject.isMember(jss::Signers)) { - if (!tx_json[jss::Signers].isArray()) + if (!sigObject[jss::Signers].isArray()) return RPC::invalid_field_error("tx.Signers"); // check multisigned signers - for (unsigned index = 0; index < tx_json[jss::Signers].size(); index++) + for (unsigned index = 0; index < sigObject[jss::Signers].size(); + index++) { - auto& signer = tx_json[jss::Signers][index]; + auto& signer = sigObject[jss::Signers][index]; if (!signer.isObject() || !signer.isMember(jss::Signer) || !signer[jss::Signer].isObject()) return RPC::invalid_field_error( @@ -129,16 +113,41 @@ autofillTx(Json::Value& tx_json, RPC::JsonContext& context) } } - if (!tx_json.isMember(jss::TxnSignature)) + if (!sigObject.isMember(jss::TxnSignature)) { // autofill TxnSignature - tx_json[jss::TxnSignature] = ""; + sigObject[jss::TxnSignature] = ""; } - else if (tx_json[jss::TxnSignature] != "") + else if (sigObject[jss::TxnSignature] != "") { // Transaction must not be signed return rpcError(rpcTX_SIGNED); } + return std::nullopt; +} + +static std::optional +autofillTx(Json::Value& tx_json, RPC::JsonContext& context) +{ + if (!tx_json.isMember(jss::Fee)) + { + // autofill Fee + // Must happen after all the other autofills happen + // Error handling/messaging works better that way + auto feeOrError = RPC::getCurrentNetworkFee( + context.role, + context.app.config(), + context.app.getFeeTrack(), + context.app.getTxQ(), + context.app, + tx_json); + if (feeOrError.isMember(jss::error)) + return feeOrError; + tx_json[jss::Fee] = feeOrError; + } + + if (auto error = autofillSignature(tx_json)) + return *error; if (!tx_json.isMember(jss::Sequence)) { From 0b113f371fafb4fa34fe7cb1f61d8cbc0dbe5764 Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Fri, 17 Oct 2025 14:40:10 +0100 Subject: [PATCH 3/6] refactor: Update pre-commit workflow to latest version (#5902) Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com> --- .github/workflows/pre-commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index da0fb02c19..66ee2f3334 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -9,7 +9,7 @@ on: jobs: # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. run-hooks: - uses: XRPLF/actions/.github/workflows/pre-commit.yml@af1b0f0d764cda2e5435f5ac97b240d4bd4d95d3 + uses: XRPLF/actions/.github/workflows/pre-commit.yml@a8d7472b450eb53a1e5228f64552e5974457a21a with: runs_on: ubuntu-latest container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-a8c7be1" }' From b64707f53b5f06cc508327eecddee847152e80cc Mon Sep 17 00:00:00 2001 From: Bart Date: Fri, 17 Oct 2025 10:09:47 -0400 Subject: [PATCH 4/6] chore: Add support for RHEL 8 (#5880) Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com> --- .github/scripts/strategy-matrix/linux.json | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/scripts/strategy-matrix/linux.json b/.github/scripts/strategy-matrix/linux.json index b8da322118..317fa640b2 100644 --- a/.github/scripts/strategy-matrix/linux.json +++ b/.github/scripts/strategy-matrix/linux.json @@ -73,47 +73,61 @@ "compiler_version": "20", "image_sha": "6948666" }, + { + "distro_name": "rhel", + "distro_version": "8", + "compiler_name": "gcc", + "compiler_version": "14", + "image_sha": "10e69b4" + }, + { + "distro_name": "rhel", + "distro_version": "8", + "compiler_name": "clang", + "compiler_version": "any", + "image_sha": "10e69b4" + }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "12", - "image_sha": "6948666" + "image_sha": "10e69b4" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "13", - "image_sha": "6948666" + "image_sha": "10e69b4" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "6948666" + "image_sha": "10e69b4" }, { "distro_name": "rhel", "distro_version": "9", "compiler_name": "clang", "compiler_version": "any", - "image_sha": "6948666" + "image_sha": "10e69b4" }, { "distro_name": "rhel", "distro_version": "10", "compiler_name": "gcc", "compiler_version": "14", - "image_sha": "6948666" + "image_sha": "10e69b4" }, { "distro_name": "rhel", "distro_version": "10", "compiler_name": "clang", "compiler_version": "any", - "image_sha": "6948666" + "image_sha": "10e69b4" }, { "distro_name": "ubuntu", From 55235572261a8bb8148fe77ecfa79ba00fa0b0bc Mon Sep 17 00:00:00 2001 From: Bart Date: Fri, 17 Oct 2025 12:04:58 -0400 Subject: [PATCH 5/6] chore: Clean up Conan variables in CI (#5903) This change sanitizes inputs by setting them as environment variables, and adjusts the number of CPUs used for building. Namely, GitHub inputs should be sanitized, per recommendation by Semgrep, as using them directly poses a security risk. A recent change further overrode the global configuration by having builds use all cores, but as we have noticed an increased number of job cancelation this change updates it to use all cores less one. Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com> --- .github/actions/build-deps/action.yml | 6 +++--- .github/workflows/reusable-notify-clio.yml | 4 +++- conan/global.conf | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/actions/build-deps/action.yml b/.github/actions/build-deps/action.yml index 7b2a3c385a..d99ea77bf5 100644 --- a/.github/actions/build-deps/action.yml +++ b/.github/actions/build-deps/action.yml @@ -28,6 +28,7 @@ runs: BUILD_DIR: ${{ inputs.build_dir }} BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }} BUILD_TYPE: ${{ inputs.build_type }} + VERBOSITY: ${{ inputs.verbosity }} run: | echo 'Installing dependencies.' mkdir -p '${{ env.BUILD_DIR }}' @@ -38,7 +39,6 @@ runs: --options:host='&:tests=True' \ --options:host='&:xrpld=True' \ --settings:all build_type='${{ env.BUILD_TYPE }}' \ - --conf:all tools.build:verbosity='${{ inputs.verbosity }}' \ - --conf:all tools.compilation:verbosity='${{ inputs.verbosity }}' \ - --conf:all tools.build:jobs=$(nproc) \ + --conf:all tools.build:verbosity='${{ env.VERBOSITY }}' \ + --conf:all tools.compilation:verbosity='${{ env.VERBOSITY }}' \ .. diff --git a/.github/workflows/reusable-notify-clio.yml b/.github/workflows/reusable-notify-clio.yml index 99009d953e..fe749beac9 100644 --- a/.github/workflows/reusable-notify-clio.yml +++ b/.github/workflows/reusable-notify-clio.yml @@ -64,7 +64,9 @@ jobs: conan_remote_name: ${{ inputs.conan_remote_name }} conan_remote_url: ${{ inputs.conan_remote_url }} - name: Log into Conan remote - run: conan remote login ${{ inputs.conan_remote_name }} "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}" + env: + CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }} + run: conan remote login ${{ env.CONAN_REMOTE_NAME }} "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}" - name: Upload package env: CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }} diff --git a/conan/global.conf b/conan/global.conf index 41ac76da89..a184adf629 100644 --- a/conan/global.conf +++ b/conan/global.conf @@ -3,4 +3,4 @@ core:non_interactive=True core.download:parallel={{ os.cpu_count() }} core.upload:parallel={{ os.cpu_count() }} -tools.build:jobs={{ (os.cpu_count() * 4/5) | int }} +tools.build:jobs={{ os.cpu_count() - 1 }} From afb6e0e41b456365645f02a19569947956d1382a Mon Sep 17 00:00:00 2001 From: Bart Date: Fri, 17 Oct 2025 12:17:02 -0400 Subject: [PATCH 6/6] chore: Set fail fast to false, except for when the merge group is used (#5897) This PR sets the fail-fast strategy option to false (it defaults to true), unless it is run by a merge group. Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com> --- .github/workflows/on-pr.yml | 1 + .github/workflows/on-trigger.yml | 1 + .github/workflows/reusable-build-test.yml | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/on-pr.yml b/.github/workflows/on-pr.yml index 47323ee4a7..6d74486e96 100644 --- a/.github/workflows/on-pr.yml +++ b/.github/workflows/on-pr.yml @@ -103,6 +103,7 @@ jobs: if: ${{ needs.should-run.outputs.go == 'true' }} uses: ./.github/workflows/reusable-build-test.yml strategy: + fail-fast: false matrix: os: [linux, macos, windows] with: diff --git a/.github/workflows/on-trigger.yml b/.github/workflows/on-trigger.yml index 9d2ea81520..c1f6839d2d 100644 --- a/.github/workflows/on-trigger.yml +++ b/.github/workflows/on-trigger.yml @@ -65,6 +65,7 @@ jobs: build-test: uses: ./.github/workflows/reusable-build-test.yml strategy: + fail-fast: ${{ github.event_name == 'merge_group' }} matrix: os: [linux, macos, windows] with: diff --git a/.github/workflows/reusable-build-test.yml b/.github/workflows/reusable-build-test.yml index 5bc9cf2557..c6e991df79 100644 --- a/.github/workflows/reusable-build-test.yml +++ b/.github/workflows/reusable-build-test.yml @@ -42,7 +42,7 @@ jobs: - generate-matrix uses: ./.github/workflows/reusable-build-test-config.yml strategy: - fail-fast: false + fail-fast: ${{ github.event_name == 'merge_group' }} matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} max-parallel: 10 with: