From 365a1307b396c4a261463a292861a46f1d515502 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Fri, 15 Mar 2024 00:03:37 +0100 Subject: [PATCH 01/12] fix AccountObjects test --- src/test/rpc/AccountObjects_test.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 2714d2c35..8a784b884 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -34,19 +34,19 @@ namespace test { static char const* bobs_account_objects[] = { R"json({ "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK", - "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000", + "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000", "BookNode" : "0", "Flags" : 65536, "LedgerEntryType" : "Offer", "OwnerNode" : "0", - "Sequence" : 6, + "Sequence" : 4, "TakerGets" : { "currency" : "USD", - "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK", + "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW", "value" : "1" }, "TakerPays" : "100000000", - "index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E" + "index" : "A984D036A0E562433A8377CA57D1A1E056E58C0D04818F8DFD3A1AA3F217DD82" })json", R"json({ "Balance" : { @@ -94,19 +94,19 @@ static char const* bobs_account_objects[] = { })json", R"json({ "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK", - "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000", + "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000", "BookNode" : "0", "Flags" : 65536, "LedgerEntryType" : "Offer", "OwnerNode" : "0", - "Sequence" : 7, + "Sequence" : 3, "TakerGets" : { "currency" : "USD", - "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW", + "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK", "value" : "1" }, "TakerPays" : "100000000", - "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1" + "index" : "E11029302EE744401427793A4F37BCB18F698D55C96851BEC5ABBD6242CF03D7" })json"}; class AccountObjects_test : public beast::unit_test::suite @@ -328,9 +328,7 @@ class AccountObjects_test : public beast::unit_test::suite aobj.removeMember("PreviousTxnID"); aobj.removeMember("PreviousTxnLgrSeq"); - BEAST_EXPECT(aobj == bobj[i]); - params[jss::marker] = resp[jss::result][jss::marker]; } } @@ -734,7 +732,7 @@ class AccountObjects_test : public beast::unit_test::suite auto const& ticket = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(ticket[sfAccount.jsonName] == gw.human()); BEAST_EXPECT(ticket[sfLedgerEntryType.jsonName] == jss::Ticket); - BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() == 13); + BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() == 10); } { // Create a uri token. @@ -856,7 +854,7 @@ class AccountObjects_test : public beast::unit_test::suite run() override { using namespace jtx; - FeatureBitset const all{supported_amendments() - featureXahauGenesis}; + FeatureBitset const all{supported_amendments()}; testErrors(all); testUnsteppedThenStepped(all); testUnsteppedThenSteppedWithNFTs(all); From a9559c82ba27c4aa2081bf62a77c351c46f7c62a Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Fri, 15 Mar 2024 00:04:13 +0100 Subject: [PATCH 02/12] add AccountNamespace test --- Builds/CMake/RippledCore.cmake | 1 + src/ripple/protocol/impl/ErrorCodes.cpp | 1 + src/ripple/protocol/jss.h | 1 + src/ripple/rpc/handlers/AccountNamespace.cpp | 1 - src/test/rpc/AccountNamespace_test.cpp | 247 +++++++++++++++++++ 5 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 src/test/rpc/AccountNamespace_test.cpp diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index c3fd51bc7..cc3441af5 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -983,6 +983,7 @@ if (tests) src/test/rpc/AccountLinesRPC_test.cpp src/test/rpc/AccountObjects_test.cpp src/test/rpc/AccountOffers_test.cpp + src/test/rpc/AccountNamespace_test.cpp src/test/rpc/AccountSet_test.cpp src/test/rpc/AccountTx_test.cpp src/test/rpc/AmendmentBlocked_test.cpp diff --git a/src/ripple/protocol/impl/ErrorCodes.cpp b/src/ripple/protocol/impl/ErrorCodes.cpp index a1844890c..bc31b21b8 100644 --- a/src/ripple/protocol/impl/ErrorCodes.cpp +++ b/src/ripple/protocol/impl/ErrorCodes.cpp @@ -108,6 +108,7 @@ constexpr static ErrorInfo unorderedErrorInfos[]{ {rpcSTREAM_MALFORMED, "malformedStream", "Stream malformed.", 400}, {rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now.", 503}, {rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found.", 404}, + {rpcNAMESPACE_NOT_FOUND, "namespaceNotFound", "Namespace not found.", 404}, {rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method.", 405}}; // clang-format on diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index 31cf8385b..18f486595 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -161,6 +161,7 @@ JSS(account_data); // out: AccountInfo JSS(account_flags); // out: AccountInfo JSS(account_hash); // out: LedgerToJson JSS(account_id); // out: WalletPropose +JSS(account_namespace); // out: AccountNamespace JSS(account_nfts); // out: AccountNFTs JSS(account_objects); // out: AccountObjects JSS(account_root); // in: LedgerEntry diff --git a/src/ripple/rpc/handlers/AccountNamespace.cpp b/src/ripple/rpc/handlers/AccountNamespace.cpp index 625fa15e9..c7c969867 100644 --- a/src/ripple/rpc/handlers/AccountNamespace.cpp +++ b/src/ripple/rpc/handlers/AccountNamespace.cpp @@ -42,7 +42,6 @@ namespace ripple { namespace_id: ledger_hash: // optional ledger_index: // optional - type: // optional, defaults to all account objects types limit: // optional marker: // optional, resume previous query } diff --git a/src/test/rpc/AccountNamespace_test.cpp b/src/test/rpc/AccountNamespace_test.cpp new file mode 100644 index 000000000..18e14bbc1 --- /dev/null +++ b/src/test/rpc/AccountNamespace_test.cpp @@ -0,0 +1,247 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 XRPL-Labs + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include + +namespace ripple { +namespace test { + +class AccountNamespace_test : public beast::unit_test::suite +{ +public: + void + testErrors(FeatureBitset features) + { + testcase("error cases"); + + using namespace jtx; + Env env(*this); + + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const carol{"carol"}; + env.fund(XRP(1000), alice, bob); + env.close(); + + auto const ns = uint256::fromVoid( + (std::array{ + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU}) + .data()); + + { + // account_namespace with no account. + auto const info = env.rpc("json", "account_namespace", "{ }"); + BEAST_EXPECT( + info[jss::result][jss::error_message] == + "Missing field 'account'."); + } + { + // account_namespace missing filed namespace_id. + Json::Value params; + params[jss::account] = alice.human(); + auto const info = env.rpc( + "json", + "account_namespace", + to_string(params)); + BEAST_EXPECT( + info[jss::result][jss::error_message] == "Missing field 'namespace_id'."); + } + { + // account_namespace with a malformed account string. + Json::Value params; + params[jss::account] = "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV"; + params[jss::namespace_id] = ""; + auto const info = env.rpc( + "json", + "account_namespace", + to_string(params)); + BEAST_EXPECT( + info[jss::result][jss::error_message] == "Disallowed seed."); + } + { + // account_namespace with an invalid namespace_id. + Json::Value params; + params[jss::account] = alice.human(); + params[jss::namespace_id] = "DEADBEEF"; + auto const info = env.rpc( + "json", + "account_namespace", + to_string(params)); + BEAST_EXPECT( + info[jss::result][jss::error_message] == "Invalid parameters."); + } + { + // account_namespace with an account that's not in the ledger. + Json::Value params; + params[jss::account] = carol.human(); + params[jss::namespace_id] = to_string(ns); + auto const info = env.rpc( + "json", + "account_namespace", + to_string(params)); + BEAST_EXPECT( + info[jss::result][jss::error_message] == "Account not found."); + } + { + // account_namespace with a namespace that doesnt exist. + Json::Value params; + params[jss::account] = alice.human(); + params[jss::namespace_id] = to_string(ns); + auto const info = env.rpc( + "json", + "account_namespace", + to_string(params)); + BEAST_EXPECT( + info[jss::result][jss::error_message] == "Namespace not found."); + } + // test errors on marker + { + + auto const key = uint256::fromVoid( + (std::array{ + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 'k', 'e', 'y', 0x00U}) + .data()); + + auto const ns = uint256::fromVoid( + (std::array{ + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU}) + .data()); + + auto const nons = uint256::fromVoid( + (std::array{ + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFFU}) + .data()); + + // Lambda to create a hook. + auto setHook = [](test::jtx::Account const& account) { + std::string const createCodeHex = + "0061736D01000000011B0460027F7F017F60047F7F7F7F017E60037F7F7E01" + "7E60017F017E02270303656E76025F67000003656E760973746174655F7365" + "74000103656E76066163636570740002030201030503010002062B077F0141" + "9088040B7F004180080B7F00418A080B7F004180080B7F00419088040B7F00" + "41000B7F0041010B07080104686F6F6B00030AE7800001E3800002017F017E" + "230041106B220124002001200036020C41012200200010001A200141800828" + "0000360208200141046A410022002F0088083B010020012000280084083602" + "004100200020014106200141086A4104100110022102200141106A24002002" + "0B0B1001004180080B096B65790076616C7565"; + std::string ns_str = + "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECA" + "FE"; + Json::Value jv = + ripple::test::jtx::hook(account, {{hso(createCodeHex)}}, 0); + jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns_str; + return jv; + }; + + env(setHook(bob), fee(XRP(1)), ter(tesSUCCESS)); + env.close(); + + env(pay(alice, bob, XRP(1)), fee(XRP(1)), ter(tesSUCCESS)); + env.close(); + + Json::Value params; + params[jss::account] = bob.human(); + params[jss::namespace_id] = to_string(ns); + params[jss::limit] = 1; + auto resp = env.rpc("json", "account_namespace", to_string(params)); + + auto resume_marker = resp[jss::result][jss::marker]; + std::string mark = to_string(resume_marker); + params[jss::marker] = 10; + resp = env.rpc("json", "account_namespace", to_string(params)); + BEAST_EXPECT( + resp[jss::result][jss::error_message] == + "Invalid field 'marker', not string."); + + params[jss::marker] = "This is a string with no comma"; + resp = env.rpc("json", "account_namespace", to_string(params)); + BEAST_EXPECT( + resp[jss::result][jss::error_message] == + "Invalid field 'marker'."); + + params[jss::marker] = "This string has a comma, but is not hex"; + resp = env.rpc("json", "account_namespace", to_string(params)); + BEAST_EXPECT( + resp[jss::result][jss::error_message] == + "Invalid field 'marker'."); + + params[jss::marker] = std::string(&mark[1U], 64); + resp = env.rpc("json", "account_namespace", to_string(params)); + BEAST_EXPECT( + resp[jss::result][jss::error_message] == + "Invalid field 'marker'."); + + params[jss::marker] = std::string(&mark[1U], 65); + resp = env.rpc("json", "account_namespace", to_string(params)); + BEAST_EXPECT( + resp[jss::result][jss::error_message] == + "Invalid field 'marker'."); + + params[jss::marker] = std::string(&mark[1U], 65) + "not hex"; + resp = env.rpc("json", "account_namespace", to_string(params)); + BEAST_EXPECT( + resp[jss::result][jss::error_message] == + "Invalid field 'marker'."); + + params[jss::marker] = std::string(&mark[1U], 128); + resp = env.rpc("json", "account_namespace", to_string(params)); + BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'."); + } + + // test error on limit -ve + { + Account const bob{"bob"}; + Json::Value params; + params[jss::account] = bob.human(); + params[jss::namespace_id] = to_string(ns); + params[jss::limit] = -1; + auto resp = env.rpc("json", "account_namespace", to_string(params)); + BEAST_EXPECT( + resp[jss::result][jss::error_message] == + "Invalid field 'limit', not unsigned integer."); + } + } + + void + run() override + { + using namespace test::jtx; + FeatureBitset const all{supported_amendments()}; + testErrors(all); + } +}; + +BEAST_DEFINE_TESTSUITE(AccountNamespace, rpc, ripple); + +} // namespace test +} // namespace ripple From 379948c041389430d1487785bb07380060ccb457 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Fri, 15 Mar 2024 00:04:28 +0100 Subject: [PATCH 03/12] add tshCollectFlag --- src/ripple/rpc/handlers/AccountInfo.cpp | 3 ++- src/test/rpc/AccountInfo_test.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ripple/rpc/handlers/AccountInfo.cpp b/src/ripple/rpc/handlers/AccountInfo.cpp index 524777e38..5b85fc257 100644 --- a/src/ripple/rpc/handlers/AccountInfo.cpp +++ b/src/ripple/rpc/handlers/AccountInfo.cpp @@ -78,7 +78,7 @@ doAccountInfo(RPC::JsonContext& context) return jvAccepted; static constexpr std:: - array, 9> + array, 10> lsFlags{ {{"defaultRipple", lsfDefaultRipple}, {"depositAuth", lsfDepositAuth}, @@ -88,6 +88,7 @@ doAccountInfo(RPC::JsonContext& context) {"noFreeze", lsfNoFreeze}, {"passwordSpent", lsfPasswordSpent}, {"requireAuthorization", lsfRequireAuth}, + {"tshCollect", lsfTshCollect}, {"requireDestinationTag", lsfRequireDestTag}}}; static constexpr std:: diff --git a/src/test/rpc/AccountInfo_test.cpp b/src/test/rpc/AccountInfo_test.cpp index 78aa9e646..5c9e32328 100644 --- a/src/test/rpc/AccountInfo_test.cpp +++ b/src/test/rpc/AccountInfo_test.cpp @@ -516,7 +516,7 @@ class AccountInfo_test : public beast::unit_test::suite }; static constexpr std:: - array, 7> + array, 8> asFlags{ {{"defaultRipple", asfDefaultRipple}, {"depositAuth", asfDepositAuth}, @@ -524,6 +524,7 @@ class AccountInfo_test : public beast::unit_test::suite {"globalFreeze", asfGlobalFreeze}, {"noFreeze", asfNoFreeze}, {"requireAuthorization", asfRequireAuth}, + {"tshCollect", asfTshCollect}, {"requireDestinationTag", asfRequireDest}}}; for (auto& asf : asFlags) From f731946323f7b754d7771a4d3976e5c25c2d1abe Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Fri, 15 Mar 2024 08:43:04 +0100 Subject: [PATCH 04/12] clang-format --- src/test/rpc/AccountNamespace_test.cpp | 109 +++++++++++++------------ 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/src/test/rpc/AccountNamespace_test.cpp b/src/test/rpc/AccountNamespace_test.cpp index 18e14bbc1..b63b52e68 100644 --- a/src/test/rpc/AccountNamespace_test.cpp +++ b/src/test/rpc/AccountNamespace_test.cpp @@ -31,7 +31,7 @@ class AccountNamespace_test : public beast::unit_test::suite testErrors(FeatureBitset features) { testcase("error cases"); - + using namespace jtx; Env env(*this); @@ -42,12 +42,12 @@ class AccountNamespace_test : public beast::unit_test::suite env.close(); auto const ns = uint256::fromVoid( - (std::array{ - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU}) - .data()); + (std::array{ + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU}) + .data()); { // account_namespace with no account. @@ -60,22 +60,20 @@ class AccountNamespace_test : public beast::unit_test::suite // account_namespace missing filed namespace_id. Json::Value params; params[jss::account] = alice.human(); - auto const info = env.rpc( - "json", - "account_namespace", - to_string(params)); + auto const info = + env.rpc("json", "account_namespace", to_string(params)); BEAST_EXPECT( - info[jss::result][jss::error_message] == "Missing field 'namespace_id'."); + info[jss::result][jss::error_message] == + "Missing field 'namespace_id'."); } { // account_namespace with a malformed account string. Json::Value params; - params[jss::account] = "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV"; + params[jss::account] = + "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV"; params[jss::namespace_id] = ""; - auto const info = env.rpc( - "json", - "account_namespace", - to_string(params)); + auto const info = + env.rpc("json", "account_namespace", to_string(params)); BEAST_EXPECT( info[jss::result][jss::error_message] == "Disallowed seed."); } @@ -84,10 +82,8 @@ class AccountNamespace_test : public beast::unit_test::suite Json::Value params; params[jss::account] = alice.human(); params[jss::namespace_id] = "DEADBEEF"; - auto const info = env.rpc( - "json", - "account_namespace", - to_string(params)); + auto const info = + env.rpc("json", "account_namespace", to_string(params)); BEAST_EXPECT( info[jss::result][jss::error_message] == "Invalid parameters."); } @@ -96,10 +92,8 @@ class AccountNamespace_test : public beast::unit_test::suite Json::Value params; params[jss::account] = carol.human(); params[jss::namespace_id] = to_string(ns); - auto const info = env.rpc( - "json", - "account_namespace", - to_string(params)); + auto const info = + env.rpc("json", "account_namespace", to_string(params)); BEAST_EXPECT( info[jss::result][jss::error_message] == "Account not found."); } @@ -108,54 +102,61 @@ class AccountNamespace_test : public beast::unit_test::suite Json::Value params; params[jss::account] = alice.human(); params[jss::namespace_id] = to_string(ns); - auto const info = env.rpc( - "json", - "account_namespace", - to_string(params)); + auto const info = + env.rpc("json", "account_namespace", to_string(params)); BEAST_EXPECT( - info[jss::result][jss::error_message] == "Namespace not found."); + info[jss::result][jss::error_message] == + "Namespace not found."); } // test errors on marker { - auto const key = uint256::fromVoid( (std::array{ - 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, - 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, - 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, - 0x00U, 0x00U, 0x00U, 0x00U, 'k', 'e', 'y', 0x00U}) + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 'k', 'e', 'y', 0x00U}) .data()); auto const ns = uint256::fromVoid( (std::array{ - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU}) + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU}) .data()); auto const nons = uint256::fromVoid( (std::array{ - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, - 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFFU}) + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, + 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFFU}) .data()); // Lambda to create a hook. auto setHook = [](test::jtx::Account const& account) { std::string const createCodeHex = - "0061736D01000000011B0460027F7F017F60047F7F7F7F017E60037F7F7E01" - "7E60017F017E02270303656E76025F67000003656E760973746174655F7365" - "74000103656E76066163636570740002030201030503010002062B077F0141" - "9088040B7F004180080B7F00418A080B7F004180080B7F00419088040B7F00" - "41000B7F0041010B07080104686F6F6B00030AE7800001E3800002017F017E" - "230041106B220124002001200036020C41012200200010001A200141800828" - "0000360208200141046A410022002F0088083B010020012000280084083602" - "004100200020014106200141086A4104100110022102200141106A24002002" + "0061736D01000000011B0460027F7F017F60047F7F7F7F017E60037F7F" + "7E01" + "7E60017F017E02270303656E76025F67000003656E760973746174655F" + "7365" + "74000103656E76066163636570740002030201030503010002062B077F" + "0141" + "9088040B7F004180080B7F00418A080B7F004180080B7F00419088040B" + "7F00" + "41000B7F0041010B07080104686F6F6B00030AE7800001E3800002017F" + "017E" + "230041106B220124002001200036020C41012200200010001A20014180" + "0828" + "0000360208200141046A410022002F0088083B01002001200028008408" + "3602" + "004100200020014106200141086A4104100110022102200141106A2400" + "2002" "0B0B1001004180080B096B65790076616C7565"; std::string ns_str = - "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECA" + "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECA" + "FECA" "FE"; Json::Value jv = ripple::test::jtx::hook(account, {{hso(createCodeHex)}}, 0); @@ -215,7 +216,9 @@ class AccountNamespace_test : public beast::unit_test::suite params[jss::marker] = std::string(&mark[1U], 128); resp = env.rpc("json", "account_namespace", to_string(params)); - BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'."); + BEAST_EXPECT( + resp[jss::result][jss::error_message] == + "Invalid field 'marker'."); } // test error on limit -ve From 3821c9c44547bf22869bbde6aa89e0723212af5d Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Thu, 21 Mar 2024 13:16:13 +0100 Subject: [PATCH 05/12] add missing ledger entries --- src/ripple/protocol/jss.h | 2 + src/ripple/rpc/handlers/LedgerEntry.cpp | 40 ++++++++- src/ripple/rpc/impl/RPCHelpers.cpp | 7 +- src/test/app/Import_test.cpp | 24 +----- src/test/app/XahauGenesis_test.cpp | 24 +----- src/test/jtx/impl/unl.cpp | 22 +++++ src/test/jtx/unl.h | 11 +++ src/test/rpc/AccountOffers_test.cpp | 2 +- src/test/rpc/LedgerData_test.cpp | 103 +++++++++++++++++++++++- src/test/rpc/LedgerRPC_test.cpp | 36 ++++++++- 10 files changed, 214 insertions(+), 57 deletions(-) diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index 18f486595..b841f76d2 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -354,6 +354,7 @@ JSS(id); // websocket. JSS(ident); // in: AccountCurrencies, AccountInfo, // OwnerInfo JSS(ignore_default); // in: AccountLines +JSS(import_vlseq); // in: LedgerEntry JSS(inLedger); // out: tx/Transaction JSS(in_queue); JSS(inbound); // out: PeerImp @@ -698,6 +699,7 @@ JSS(TYPES); // out: RPC server_definitions JSS(type_hex); // out: STPathSet JSS(unl); // out: UnlList JSS(unlimited); // out: Connection.h +JSS(unl_report); // in: LedgerEntry JSS(uptime); // out: GetCounts JSS(uri); // out: ValidatorSites JSS(uri_token); // in: LedgerEntry diff --git a/src/ripple/rpc/handlers/LedgerEntry.cpp b/src/ripple/rpc/handlers/LedgerEntry.cpp index a6e718e39..d8d784cd4 100644 --- a/src/ripple/rpc/handlers/LedgerEntry.cpp +++ b/src/ripple/rpc/handlers/LedgerEntry.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -231,6 +232,21 @@ doLedgerEntry(RPC::JsonContext& context) uNodeIndex = keylet::emittedTxn(uNodeIndex).key; } } + else if (context.params.isMember(jss::import_vlseq)) + { + expectedType = ltIMPORT_VLSEQ; + if (!context.params[jss::public_key].isString()) + { + uNodeIndex = beast::zero; + jvResult[jss::error] = "malformedRequest"; + } + else + { + auto const pkHex = strUnHex(context.params[jss::public_key].asString()); + auto const pk = PublicKey(makeSlice(*pkHex)); + uNodeIndex = keylet::import_vlseq(pk).key; + } + } else if (context.params.isMember(jss::offer)) { expectedType = ltOFFER; @@ -277,11 +293,31 @@ doLedgerEntry(RPC::JsonContext& context) { expectedType = ltURI_TOKEN; - if (!uNodeIndex.parseHex(context.params[jss::uri_token].asString())) + if (!context.params[jss::uri_token].isObject()) + { + if (!uNodeIndex.parseHex(context.params[jss::uri_token].asString())) + { + uNodeIndex = beast::zero; + jvResult[jss::error] = "malformedRequest"; + } + } + else if ( + !context.params[jss::uri_token].isMember(jss::account) || + !context.params[jss::uri_token].isMember(jss::uri)) { - uNodeIndex = beast::zero; jvResult[jss::error] = "malformedRequest"; } + else + { + auto const id = parseBase58( + context.params[jss::uri_token][jss::account].asString()); + auto const strUri = context.params[jss::uri_token][jss::uri].asString(); + Blob raw = Blob(strUri.begin(), strUri.end()); + if (!id) + jvResult[jss::error] = "malformedAddress"; + else + uNodeIndex = keylet::uritoken(*id, raw).key; + } } else if (context.params.isMember(jss::ripple_state)) { diff --git a/src/ripple/rpc/impl/RPCHelpers.cpp b/src/ripple/rpc/impl/RPCHelpers.cpp index 8a3195571..26d279dbd 100644 --- a/src/ripple/rpc/impl/RPCHelpers.cpp +++ b/src/ripple/rpc/impl/RPCHelpers.cpp @@ -1067,7 +1067,7 @@ chooseLedgerEntryType(Json::Value const& params) std::pair result{RPC::Status::OK, ltANY}; if (params.isMember(jss::type)) { - static constexpr std::array, 19> + static constexpr std::array, 22> types{ {{jss::account, ltACCOUNT_ROOT}, {jss::amendments, ltAMENDMENTS}, @@ -1075,11 +1075,13 @@ chooseLedgerEntryType(Json::Value const& params) {jss::deposit_preauth, ltDEPOSIT_PREAUTH}, {jss::directory, ltDIR_NODE}, {jss::escrow, ltESCROW}, + {jss::emitted_txn, ltEMITTED_TXN}, {jss::hook, ltHOOK}, {jss::hook_definition, ltHOOK_DEFINITION}, {jss::hook_state, ltHOOK_STATE}, {jss::fee, ltFEE_SETTINGS}, {jss::hashes, ltLEDGER_HASHES}, + {jss::import_vlseq, ltIMPORT_VLSEQ}, {jss::offer, ltOFFER}, {jss::payment_channel, ltPAYCHAN}, {jss::uri_token, ltURI_TOKEN}, @@ -1087,7 +1089,8 @@ chooseLedgerEntryType(Json::Value const& params) {jss::state, ltRIPPLE_STATE}, {jss::ticket, ltTICKET}, {jss::nft_offer, ltNFTOKEN_OFFER}, - {jss::nft_page, ltNFTOKEN_PAGE}}}; + {jss::nft_page, ltNFTOKEN_PAGE}, + {jss::unl_report, ltUNL_REPORT}}}; auto const& p = params[jss::type]; if (!p.isString()) diff --git a/src/test/app/Import_test.cpp b/src/test/app/Import_test.cpp index d85a0420b..c115bcc4d 100644 --- a/src/test/app/Import_test.cpp +++ b/src/test/app/Import_test.cpp @@ -84,28 +84,6 @@ class Import_test : public beast::unit_test::suite return 0; } - STTx - createUNLReportTx( - LedgerIndex seq, - PublicKey const& importKey, - PublicKey const& valKey) - { - auto fill = [&](auto& obj) { - obj.setFieldU32(sfLedgerSequence, seq); - obj.set(([&]() { - auto inner = std::make_unique(sfActiveValidator); - inner->setFieldVL(sfPublicKey, valKey); - return inner; - })()); - obj.set(([&]() { - auto inner = std::make_unique(sfImportVLKey); - inner->setFieldVL(sfPublicKey, importKey); - return inner; - })()); - }; - return STTx(ttUNL_REPORT, fill); - } - bool hasUNLReport(jtx::Env const& env) { @@ -5320,7 +5298,7 @@ class Import_test : public beast::unit_test::suite // insert a ttUNL_REPORT pseudo into the open ledger env.app().openLedger().modify( [&](OpenView& view, beast::Journal j) -> bool { - STTx tx = createUNLReportTx( + STTx tx = unl::createUNLReportTx( env.current()->seq() + 1, ivlKeys[0], vlKeys[0]); uint256 txID = tx.getTransactionID(); auto s = std::make_shared(); diff --git a/src/test/app/XahauGenesis_test.cpp b/src/test/app/XahauGenesis_test.cpp index 23ec46a60..3c409a36a 100644 --- a/src/test/app/XahauGenesis_test.cpp +++ b/src/test/app/XahauGenesis_test.cpp @@ -3598,28 +3598,6 @@ struct XahauGenesis_test : public beast::unit_test::suite return slep != nullptr; } - STTx - createUNLReportTx( - LedgerIndex seq, - PublicKey const& importKey, - PublicKey const& valKey) - { - auto fill = [&](auto& obj) { - obj.setFieldU32(sfLedgerSequence, seq); - obj.set(([&]() { - auto inner = std::make_unique(sfActiveValidator); - inner->setFieldVL(sfPublicKey, valKey); - return inner; - })()); - obj.set(([&]() { - auto inner = std::make_unique(sfImportVLKey); - inner->setFieldVL(sfPublicKey, importKey); - return inner; - })()); - }; - return STTx(ttUNL_REPORT, fill); - } - void activateUNLReport( jtx::Env& env, @@ -3631,7 +3609,7 @@ struct XahauGenesis_test : public beast::unit_test::suite { env.app().openLedger().modify( [&](OpenView& view, beast::Journal j) -> bool { - STTx tx = createUNLReportTx( + STTx tx = unl::createUNLReportTx( env.current()->seq() + 1, ivlKeys[0], vlKey); uint256 txID = tx.getTransactionID(); auto s = std::make_shared(); diff --git a/src/test/jtx/impl/unl.cpp b/src/test/jtx/impl/unl.cpp index 41cbd50b0..54d628cff 100644 --- a/src/test/jtx/impl/unl.cpp +++ b/src/test/jtx/impl/unl.cpp @@ -90,6 +90,28 @@ createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey) return STTx(ttUNL_MODIFY, fill); } +STTx +createUNLReportTx( + LedgerIndex seq, + PublicKey const& importKey, + PublicKey const& valKey) +{ + auto fill = [&](auto& obj) { + obj.setFieldU32(sfLedgerSequence, seq); + obj.set(([&]() { + auto inner = std::make_unique(sfActiveValidator); + inner->setFieldVL(sfPublicKey, valKey); + return inner; + })()); + obj.set(([&]() { + auto inner = std::make_unique(sfImportVLKey); + inner->setFieldVL(sfPublicKey, importKey); + return inner; + })()); + }; + return STTx(ttUNL_REPORT, fill); +} + } // namespace unl } // namespace test } // namespace ripple diff --git a/src/test/jtx/unl.h b/src/test/jtx/unl.h index 68a30cc6b..5fb993061 100644 --- a/src/test/jtx/unl.h +++ b/src/test/jtx/unl.h @@ -78,6 +78,17 @@ countTx(std::shared_ptr const& txSet); STTx createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey); +/** + * Create ttUNL_REPORT Tx + * + * @param seq current ledger seq + * @param importKey the public key of the import network + * @param txKey the public key of the validator + * @return the ttUNL_REPORT Tx + */ +STTx +createUNLReportTx(LedgerIndex seq, PublicKey const& importKey, PublicKey const& valKey); + } // namespace unl } // namespace test diff --git a/src/test/rpc/AccountOffers_test.cpp b/src/test/rpc/AccountOffers_test.cpp index 58b908f73..5a7c3e513 100644 --- a/src/test/rpc/AccountOffers_test.cpp +++ b/src/test/rpc/AccountOffers_test.cpp @@ -327,7 +327,7 @@ class AccountOffers_test : public beast::unit_test::suite run() override { using namespace jtx; - FeatureBitset const all{supported_amendments() - featureXahauGenesis}; + FeatureBitset const all{supported_amendments()}; testSequential(all, true); testSequential(all, false); testBadInput(all); diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index 5e354c881..498eb8947 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -17,8 +17,11 @@ */ //============================================================================== +#include #include +#include #include +#include #include namespace ripple { @@ -308,11 +311,14 @@ class LedgerData_test : public beast::unit_test::suite // Put a bunch of different LedgerEntryTypes into a ledger using namespace test::jtx; using namespace std::chrono; - Env env{*this, envconfig(validator, "")}; + std::vector const keys = {"ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1"}; + Env env{*this, network::makeNetworkVLConfig(21337, keys)}; + + Account const alice{"alice"}; Account const gw{"gateway"}; auto const USD = gw["USD"]; - env.fund(XRP(100000), gw); + env.fund(XRP(100000), gw, alice); auto makeRequest = [&env](Json::StaticString const& type) { Json::Value jvParams; @@ -335,6 +341,10 @@ class LedgerData_test : public beast::unit_test::suite jss::ticket, jss::escrow, jss::payment_channel, + jss::hook, + jss::hook_definition, + jss::hook_state, + jss::uri_token, jss::deposit_preauth}) { auto const jrr = makeRequest(type); @@ -398,6 +408,12 @@ class LedgerData_test : public beast::unit_test::suite env(pay(Account{"bob2"}, Account{"bob3"}, XRP(1)), fee(XRP(1))); env.close(); } + + { + std::string const uri(maxTokenURILength, '?'); + env(uritoken::mint(Account{"bob2"}, uri)); + env.close(); + } { Json::Value jv; @@ -414,6 +430,63 @@ class LedgerData_test : public beast::unit_test::suite env(jv); } + { + auto const master = Account("masterpassphrase"); + env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); + env.close(); + env(import::import( + alice, import::loadXpop(test::ImportTCAccountSet::w_seed)), + fee(10 * 10), + ter(tesSUCCESS)); + env.close(); + } + + { + // ADD UNL REPORT + std::vector const _ivlKeys = { + "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" + "CDC1", + "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" + "CDC2", + }; + + std::vector ivlKeys; + for (auto const& strPk : _ivlKeys) + { + auto pkHex = strUnHex(strPk); + ivlKeys.emplace_back(makeSlice(*pkHex)); + } + + std::vector const _vlKeys = { + "ED8E43A943A174190BA2FAE91F44AC6E2D1D8202EFDCC2EA3DBB39814576D6" + "90F7", + "ED45D1840EE724BE327ABE9146503D5848EFD5F38B6D5FEDE71E80ACCE5E6E" + "738B"}; + + std::vector vlKeys; + for (auto const& strPk : _vlKeys) + { + auto pkHex = strUnHex(strPk); + vlKeys.emplace_back(makeSlice(*pkHex)); + } + + // insert a ttUNL_REPORT pseudo into the open ledger + env.app().openLedger().modify( + [&](OpenView& view, beast::Journal j) -> bool { + STTx tx = test::unl::createUNLReportTx( + env.current()->seq() + 1, ivlKeys[0], vlKeys[0]); + uint256 txID = tx.getTransactionID(); + auto s = std::make_shared(); + tx.add(*s); + env.app().getHashRouter().setFlags(txID, SF_PRIVATE2); + view.rawTxInsert(txID, std::move(s), nullptr); + return true; + }); + + // close the ledger + env.close(); + } + env(check::create("bob6", "bob7", XRP(100))); // bob9 DepositPreauths bob4 and bob8. @@ -425,18 +498,26 @@ class LedgerData_test : public beast::unit_test::suite { // jvParams[jss::type] = "account"; auto const jrr = makeRequest(jss::account); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 12)); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 13)); for (auto const& j : jrr[jss::state]) BEAST_EXPECT(j["LedgerEntryType"] == jss::AccountRoot); } { // jvParams[jss::type] = "amendments"; auto const jrr = makeRequest(jss::amendments); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 0)); for (auto const& j : jrr[jss::state]) BEAST_EXPECT(j["LedgerEntryType"] == jss::Amendments); } + { // jvParams[jss::type] = "unl_report"; + auto const jrr = makeRequest(jss::unl_report); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::UNLReport); + } + { // jvParams[jss::type] = "check"; auto const jrr = makeRequest(jss::check); BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); @@ -465,6 +546,13 @@ class LedgerData_test : public beast::unit_test::suite BEAST_EXPECT(j["LedgerEntryType"] == jss::LedgerHashes); } + { // jvParams[jss::type] = "import_vlseq"; + auto const jrr = makeRequest(jss::import_vlseq); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::ImportVLSequence); + } + { // jvParams[jss::type] = "offer"; auto const jrr = makeRequest(jss::offer); BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); @@ -521,6 +609,13 @@ class LedgerData_test : public beast::unit_test::suite BEAST_EXPECT(j["LedgerEntryType"] == jss::HookState); } + { // jvParams[jss::type] = "uri_token"; + auto const jrr = makeRequest(jss::uri_token); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::URIToken); + } + { // jvParams[jss::type] = "payment_channel"; auto const jrr = makeRequest(jss::payment_channel); BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 7eb4e4484..f6bea6286 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -1694,8 +1694,7 @@ class LedgerRPC_test : public beast::unit_test::suite std::string const ledgerHash{to_string(env.closed()->info().hash)}; - uint256 const uritokenIndex{ - keylet::uritoken(alice, Blob(uri.begin(), uri.end())).key}; + uint256 const uritokenIndex{keylet::uritoken(alice, Blob(uri.begin(), uri.end())).key}; { // Request the uritoken using its index. Json::Value jvParams; @@ -1707,6 +1706,39 @@ class LedgerRPC_test : public beast::unit_test::suite BEAST_EXPECT(jrr[jss::node][sfURI.jsonName] == strHex(uri)); BEAST_EXPECT(jrr[jss::node][sfFlags.jsonName] == lsfBurnable); } + { + // Request the uritoken using its account and uri. + Json::Value jvParams; + jvParams[jss::uri_token] = Json::objectValue; + jvParams[jss::uri_token][jss::account] = alice.human(); + jvParams[jss::uri_token][jss::uri] = uri; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == alice.human()); + BEAST_EXPECT(jrr[jss::node][sfURI.jsonName] == strHex(uri)); + BEAST_EXPECT(jrr[jss::node][sfFlags.jsonName] == lsfBurnable); + } + { + // Malformed ticket object. Missing account member. + Json::Value jvParams; + jvParams[jss::uri_token] = Json::objectValue; + jvParams[jss::uri_token][jss::uri] = uri; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // Malformed ticket object. Missing seq member. + Json::Value jvParams; + jvParams[jss::uri_token] = Json::objectValue; + jvParams[jss::uri_token][jss::account] = env.master.human(); + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } { // Request an index that is not a uritoken. Json::Value jvParams; From 1f6fd098312c090e5cea3365159ec6c80f5a1516 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Thu, 21 Mar 2024 13:50:05 +0100 Subject: [PATCH 06/12] clang-format --- src/ripple/rpc/handlers/LedgerEntry.cpp | 6 ++++-- src/test/jtx/unl.h | 5 ++++- src/test/rpc/LedgerData_test.cpp | 8 +++++--- src/test/rpc/LedgerRPC_test.cpp | 3 ++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/ripple/rpc/handlers/LedgerEntry.cpp b/src/ripple/rpc/handlers/LedgerEntry.cpp index d8d784cd4..7c14de603 100644 --- a/src/ripple/rpc/handlers/LedgerEntry.cpp +++ b/src/ripple/rpc/handlers/LedgerEntry.cpp @@ -242,7 +242,8 @@ doLedgerEntry(RPC::JsonContext& context) } else { - auto const pkHex = strUnHex(context.params[jss::public_key].asString()); + auto const pkHex = + strUnHex(context.params[jss::public_key].asString()); auto const pk = PublicKey(makeSlice(*pkHex)); uNodeIndex = keylet::import_vlseq(pk).key; } @@ -311,7 +312,8 @@ doLedgerEntry(RPC::JsonContext& context) { auto const id = parseBase58( context.params[jss::uri_token][jss::account].asString()); - auto const strUri = context.params[jss::uri_token][jss::uri].asString(); + auto const strUri = + context.params[jss::uri_token][jss::uri].asString(); Blob raw = Blob(strUri.begin(), strUri.end()); if (!id) jvResult[jss::error] = "malformedAddress"; diff --git a/src/test/jtx/unl.h b/src/test/jtx/unl.h index 5fb993061..2e0bae354 100644 --- a/src/test/jtx/unl.h +++ b/src/test/jtx/unl.h @@ -87,7 +87,10 @@ createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey); * @return the ttUNL_REPORT Tx */ STTx -createUNLReportTx(LedgerIndex seq, PublicKey const& importKey, PublicKey const& valKey); +createUNLReportTx( + LedgerIndex seq, + PublicKey const& importKey, + PublicKey const& valKey); } // namespace unl diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index 498eb8947..1c5366891 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -312,7 +312,9 @@ class LedgerData_test : public beast::unit_test::suite using namespace test::jtx; using namespace std::chrono; - std::vector const keys = {"ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1"}; + std::vector const keys = { + "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC" + "1"}; Env env{*this, network::makeNetworkVLConfig(21337, keys)}; Account const alice{"alice"}; @@ -408,7 +410,7 @@ class LedgerData_test : public beast::unit_test::suite env(pay(Account{"bob2"}, Account{"bob3"}, XRP(1)), fee(XRP(1))); env.close(); } - + { std::string const uri(maxTokenURILength, '?'); env(uritoken::mint(Account{"bob2"}, uri)); @@ -513,7 +515,7 @@ class LedgerData_test : public beast::unit_test::suite { // jvParams[jss::type] = "unl_report"; auto const jrr = makeRequest(jss::unl_report); BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - + for (auto const& j : jrr[jss::state]) BEAST_EXPECT(j["LedgerEntryType"] == jss::UNLReport); } diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index f6bea6286..1bd351f77 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -1694,7 +1694,8 @@ class LedgerRPC_test : public beast::unit_test::suite std::string const ledgerHash{to_string(env.closed()->info().hash)}; - uint256 const uritokenIndex{keylet::uritoken(alice, Blob(uri.begin(), uri.end())).key}; + uint256 const uritokenIndex{ + keylet::uritoken(alice, Blob(uri.begin(), uri.end())).key}; { // Request the uritoken using its index. Json::Value jvParams; From ec58e82328bb350a091c640bdf50b26944fef71b Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Thu, 21 Mar 2024 14:28:31 +0100 Subject: [PATCH 07/12] fix account offers test --- src/test/rpc/AccountOffers_test.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/rpc/AccountOffers_test.cpp b/src/test/rpc/AccountOffers_test.cpp index 5a7c3e513..79e0ddd72 100644 --- a/src/test/rpc/AccountOffers_test.cpp +++ b/src/test/rpc/AccountOffers_test.cpp @@ -119,23 +119,23 @@ class AccountOffers_test : public beast::unit_test::suite BEAST_EXPECT(jroOuter[0u][jss::quality] == "100000000"); BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::currency] == "USD"); BEAST_EXPECT( - jroOuter[0u][jss::taker_gets][jss::issuer] == gw.human()); - BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::value] == "2"); - BEAST_EXPECT(jroOuter[0u][jss::taker_pays] == "200000000"); + jroOuter[0u][jss::taker_gets][jss::issuer] == bob.human()); + BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::value] == "1"); + BEAST_EXPECT(jroOuter[0u][jss::taker_pays] == "100000000"); - BEAST_EXPECT(jroOuter[1u][jss::quality] == "100000000"); + BEAST_EXPECT(jroOuter[1u][jss::quality] == "5000000"); BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::currency] == "USD"); BEAST_EXPECT( - jroOuter[1u][jss::taker_gets][jss::issuer] == bob.human()); - BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::value] == "1"); - BEAST_EXPECT(jroOuter[1u][jss::taker_pays] == "100000000"); + jroOuter[1u][jss::taker_gets][jss::issuer] == gw.human()); + BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::value] == "6"); + BEAST_EXPECT(jroOuter[1u][jss::taker_pays] == "30000000"); - BEAST_EXPECT(jroOuter[2u][jss::quality] == "5000000"); + BEAST_EXPECT(jroOuter[2u][jss::quality] == "100000000"); BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::currency] == "USD"); BEAST_EXPECT( jroOuter[2u][jss::taker_gets][jss::issuer] == gw.human()); - BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::value] == "6"); - BEAST_EXPECT(jroOuter[2u][jss::taker_pays] == "30000000"); + BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::value] == "2"); + BEAST_EXPECT(jroOuter[2u][jss::taker_pays] == "200000000"); } { From e232b6ed1f7ec1ebd95564d30de1424990cba30e Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Thu, 21 Mar 2024 14:33:51 +0100 Subject: [PATCH 08/12] Update LedgerData_test.cpp --- src/test/rpc/LedgerData_test.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index 1c5366891..7bd38f19a 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -305,6 +305,28 @@ class LedgerData_test : public beast::unit_test::suite } } + STTx + createUNLReportTx( + LedgerIndex seq, + PublicKey const& importKey, + PublicKey const& valKey) + { + auto fill = [&](auto& obj) { + obj.setFieldU32(sfLedgerSequence, seq); + obj.set(([&]() { + auto inner = std::make_unique(sfActiveValidator); + inner->setFieldVL(sfPublicKey, valKey); + return inner; + })()); + obj.set(([&]() { + auto inner = std::make_unique(sfImportVLKey); + inner->setFieldVL(sfPublicKey, importKey); + return inner; + })()); + }; + return STTx(ttUNL_REPORT, fill); + } + void testLedgerType() { @@ -475,7 +497,7 @@ class LedgerData_test : public beast::unit_test::suite // insert a ttUNL_REPORT pseudo into the open ledger env.app().openLedger().modify( [&](OpenView& view, beast::Journal j) -> bool { - STTx tx = test::unl::createUNLReportTx( + STTx tx = createUNLReportTx( env.current()->seq() + 1, ivlKeys[0], vlKeys[0]); uint256 txID = tx.getTransactionID(); auto s = std::make_shared(); From 20a0f3a0965980d6b9a7200605b7f945c221f195 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Thu, 21 Mar 2024 14:36:05 +0100 Subject: [PATCH 09/12] Update LedgerData_test.cpp --- src/test/rpc/LedgerData_test.cpp | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index 7bd38f19a..1c5366891 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -305,28 +305,6 @@ class LedgerData_test : public beast::unit_test::suite } } - STTx - createUNLReportTx( - LedgerIndex seq, - PublicKey const& importKey, - PublicKey const& valKey) - { - auto fill = [&](auto& obj) { - obj.setFieldU32(sfLedgerSequence, seq); - obj.set(([&]() { - auto inner = std::make_unique(sfActiveValidator); - inner->setFieldVL(sfPublicKey, valKey); - return inner; - })()); - obj.set(([&]() { - auto inner = std::make_unique(sfImportVLKey); - inner->setFieldVL(sfPublicKey, importKey); - return inner; - })()); - }; - return STTx(ttUNL_REPORT, fill); - } - void testLedgerType() { @@ -497,7 +475,7 @@ class LedgerData_test : public beast::unit_test::suite // insert a ttUNL_REPORT pseudo into the open ledger env.app().openLedger().modify( [&](OpenView& view, beast::Journal j) -> bool { - STTx tx = createUNLReportTx( + STTx tx = test::unl::createUNLReportTx( env.current()->seq() + 1, ivlKeys[0], vlKeys[0]); uint256 txID = tx.getTransactionID(); auto s = std::make_shared(); From b23ec6ec6b32e77f76ac461a8b977ddb1d10d48c Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Thu, 21 Mar 2024 14:37:45 +0100 Subject: [PATCH 10/12] levelization --- Builds/levelization/results/loops.txt | 3 +++ Builds/levelization/results/ordering.txt | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Builds/levelization/results/loops.txt b/Builds/levelization/results/loops.txt index 917cd45b4..209e0e1fa 100644 --- a/Builds/levelization/results/loops.txt +++ b/Builds/levelization/results/loops.txt @@ -52,6 +52,9 @@ Loop: ripple.overlay ripple.rpc Loop: test.app test.jtx test.app > test.jtx +Loop: test.app test.rpc + test.rpc == test.app + Loop: test.jtx test.toplevel test.toplevel > test.jtx diff --git a/Builds/levelization/results/ordering.txt b/Builds/levelization/results/ordering.txt index ddb0f6083..12df1a86e 100644 --- a/Builds/levelization/results/ordering.txt +++ b/Builds/levelization/results/ordering.txt @@ -90,7 +90,6 @@ test.app > ripple.overlay test.app > ripple.protocol test.app > ripple.resource test.app > ripple.rpc -test.app > test.rpc test.app > test.toplevel test.app > test.unit_test test.basics > ripple.basics From 6bc99432182c055659fe030ff455879683a59cec Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Tue, 26 Mar 2024 16:20:21 +0100 Subject: [PATCH 11/12] update import_vlseq --- src/ripple/rpc/handlers/LedgerEntry.cpp | 31 +++++++-- src/test/rpc/LedgerRPC_test.cpp | 92 ++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 8 deletions(-) diff --git a/src/ripple/rpc/handlers/LedgerEntry.cpp b/src/ripple/rpc/handlers/LedgerEntry.cpp index 7c14de603..aa5ffb02a 100644 --- a/src/ripple/rpc/handlers/LedgerEntry.cpp +++ b/src/ripple/rpc/handlers/LedgerEntry.cpp @@ -235,17 +235,36 @@ doLedgerEntry(RPC::JsonContext& context) else if (context.params.isMember(jss::import_vlseq)) { expectedType = ltIMPORT_VLSEQ; - if (!context.params[jss::public_key].isString()) + if (!context.params[jss::import_vlseq].isObject()) + { + if (!uNodeIndex.parseHex( + context.params[jss::import_vlseq].asString())) + { + uNodeIndex = beast::zero; + jvResult[jss::error] = "malformedRequest"; + } + } + else if ( + !context.params[jss::import_vlseq].isMember(jss::public_key) || + !context.params[jss::import_vlseq][jss::public_key].isString()) { - uNodeIndex = beast::zero; jvResult[jss::error] = "malformedRequest"; } else { - auto const pkHex = - strUnHex(context.params[jss::public_key].asString()); - auto const pk = PublicKey(makeSlice(*pkHex)); - uNodeIndex = keylet::import_vlseq(pk).key; + auto const pkHex = strUnHex( + context.params[jss::import_vlseq][jss::public_key].asString()); + auto const pkSlice = makeSlice(*pkHex); + if (!publicKeyType(pkSlice)) + { + uNodeIndex = beast::zero; + jvResult[jss::error] = "malformedRequest"; + } + else + { + auto const pk = PublicKey(pkSlice); + uNodeIndex = keylet::import_vlseq(pk).key; + } } } else if (context.params.isMember(jss::offer)) diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 1bd351f77..39a80ad20 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -1721,7 +1721,7 @@ class LedgerRPC_test : public beast::unit_test::suite BEAST_EXPECT(jrr[jss::node][sfFlags.jsonName] == lsfBurnable); } { - // Malformed ticket object. Missing account member. + // Malformed uritoken object. Missing account member. Json::Value jvParams; jvParams[jss::uri_token] = Json::objectValue; jvParams[jss::uri_token][jss::uri] = uri; @@ -1731,7 +1731,7 @@ class LedgerRPC_test : public beast::unit_test::suite checkErrorValue(jrr, "malformedRequest", ""); } { - // Malformed ticket object. Missing seq member. + // Malformed uritoken object. Missing seq member. Json::Value jvParams; jvParams[jss::uri_token] = Json::objectValue; jvParams[jss::uri_token][jss::account] = env.master.human(); @@ -1751,6 +1751,93 @@ class LedgerRPC_test : public beast::unit_test::suite } } + void + testLedgerEntryImportVLSeq() + { + testcase("ledger_entry Request ImportVLSeq"); + using namespace test::jtx; + + std::vector const keys = { + "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC" + "1"}; + Env env{*this, network::makeNetworkVLConfig(21337, keys)}; + + Account const alice{"alice"}; + env.fund(XRP(10000), alice); + env.close(); + + auto const master = Account("masterpassphrase"); + env(noop(master), fee(10'000'000'000), ter(tesSUCCESS)); + env.close(); + env(import::import( + alice, import::loadXpop(test::ImportTCAccountSet::w_seed)), + fee(10 * 10), + ter(tesSUCCESS)); + env.close(); + + std::string const ledgerHash{to_string(env.closed()->info().hash)}; + + auto const pk = PublicKey(makeSlice(*strUnHex(keys[0u]))); + uint256 const importvlIndex{keylet::import_vlseq(pk).key}; + { + // Request the import vl using its index. + Json::Value jvParams; + jvParams[jss::import_vlseq] = to_string(importvlIndex); + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfPublicKey.jsonName] == keys[0u]); + } + { + // Request the import vl using its public key. + Json::Value jvParams; + jvParams[jss::import_vlseq] = Json::objectValue; + jvParams[jss::import_vlseq][jss::public_key] = keys[0u]; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfPublicKey.jsonName] == keys[0u]); + } + { + // Malformed import vl object. Missing public key. + Json::Value jvParams; + jvParams[jss::import_vlseq] = Json::objectValue; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // Malformed import vl object. Bad public key. + Json::Value jvParams; + jvParams[jss::import_vlseq] = Json::objectValue; + jvParams[jss::import_vlseq][jss::public_key] = 1; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // Malformed import vl object. Bad public key. + Json::Value jvParams; + jvParams[jss::import_vlseq] = Json::objectValue; + jvParams[jss::import_vlseq][jss::public_key] = "DEADBEEF"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // Request an index that is not a uritoken. + Json::Value jvParams; + jvParams[jss::import_vlseq] = ledgerHash; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "entryNotFound", ""); + } + } + void testLedgerEntryUnknownOption() { @@ -2275,6 +2362,7 @@ class LedgerRPC_test : public beast::unit_test::suite testLedgerEntryRippleState(); testLedgerEntryTicket(); testLedgerEntryURIToken(); + testLedgerEntryImportVLSeq(); testLedgerEntryUnknownOption(); testLookupLedger(); testNoQueue(); From df7a00343ddbc0eb5a54c844a10bf155bce6a68d Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Tue, 26 Mar 2024 16:25:40 +0100 Subject: [PATCH 12/12] Update LedgerRPC_test.cpp --- src/test/rpc/LedgerRPC_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 39a80ad20..de141311b 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -1756,7 +1756,7 @@ class LedgerRPC_test : public beast::unit_test::suite { testcase("ledger_entry Request ImportVLSeq"); using namespace test::jtx; - + std::vector const keys = { "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC" "1"};