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/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", 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/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" }' 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: 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 }} 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]); 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)) {