From 442795bfeb2756bdf8b5170f10e46f97822a21a7 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 7 Apr 2025 11:29:04 +0100 Subject: [PATCH] Change vault_info to take vault_id or owner&seq --- include/xrpl/protocol/jss.h | 1 + src/test/app/Vault_test.cpp | 125 +++++++++++++++++++++++-- src/xrpld/net/detail/RPCCall.cpp | 4 +- src/xrpld/rpc/detail/RPCHelpers.cpp | 31 ------ src/xrpld/rpc/detail/RPCHelpers.h | 4 - src/xrpld/rpc/handlers/LedgerEntry.cpp | 27 +++++- src/xrpld/rpc/handlers/VaultInfo.cpp | 52 +++++++++- 7 files changed, 194 insertions(+), 50 deletions(-) diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index d6822026a7..ae780cae67 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -687,6 +687,7 @@ JSS(validations); // out: AmendmentTableImpl JSS(validator_list_threshold); // out: ValidatorList JSS(validator_sites); // out: ValidatorSites JSS(value); // out: STAmount +JSS(vault_id); // in: VaultInfo JSS(version); // out: RPCVersion JSS(vetoed); // out: AmendmentTableImpl JSS(volume_a); // out: BookChanges diff --git a/src/test/app/Vault_test.cpp b/src/test/app/Vault_test.cpp index c786b558a7..b7b0447fc8 100644 --- a/src/test/app/Vault_test.cpp +++ b/src/test/app/Vault_test.cpp @@ -1575,11 +1575,10 @@ class Vault_test : public beast::unit_test::suite } { - testcase("RPC vault_info json by owner and sequence"); + testcase("RPC vault_info json"); Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; - jvParams[jss::vault][jss::owner] = owner.human(); - jvParams[jss::vault][jss::seq] = sequence; + jvParams[jss::vault_id] = strHex(keylet.key); auto jv = env.rpc("json", "vault_info", to_string(jvParams)); BEAST_EXPECT(!jv[jss::result].isMember(jss::error)); @@ -1589,18 +1588,126 @@ class Vault_test : public beast::unit_test::suite jv[jss::result][jss::vault][jss::shares]); } + { + testcase("RPC vault_info json invalid index"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::vault_id] = 0; + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + + { + testcase("RPC vault_info json by owner and sequence"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::owner] = owner.human(); + jvParams[jss::seq] = sequence; + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + + BEAST_EXPECT(!jv[jss::result].isMember(jss::error)); + BEAST_EXPECT(jv[jss::result].isMember(jss::vault)); + check( + jv[jss::result][jss::vault], + jv[jss::result][jss::vault][jss::shares]); + } + + { + testcase("RPC vault_info json malformed sequence"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::owner] = owner.human(); + jvParams[jss::seq] = "foobar"; + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + + { + testcase("RPC vault_info json malformed owner"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::owner] = "foobar"; + jvParams[jss::seq] = sequence; + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + + { + testcase("RPC vault_info json invalid combination only owner"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::owner] = owner.human(); + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + + { + testcase("RPC vault_info json invalid combination only seq"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::seq] = sequence; + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + + { + testcase("RPC vault_info json invalid combination seq vault_id"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::vault_id] = strHex(keylet.key); + jvParams[jss::seq] = sequence; + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + + { + testcase("RPC vault_info json invalid combination owner vault_id"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::vault_id] = strHex(keylet.key); + jvParams[jss::owner] = owner.human(); + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + + { + testcase( + "RPC vault_info json invalid combination owner seq vault_id"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::vault_id] = strHex(keylet.key); + jvParams[jss::seq] = sequence; + jvParams[jss::owner] = owner.human(); + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + + { + testcase("RPC vault_info json no input"); + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + BEAST_EXPECT( + jv[jss::result][jss::error].asString() == "malformedRequest"); + } + { testcase("RPC vault_info command line invalid index"); - Json::Value jv = env.rpc("vault_info", "0", "validated"); + Json::Value jv = env.rpc("vault_info", "foobar", "validated"); BEAST_EXPECT(jv[jss::error].asString() == "invalidParams"); } { - testcase("RPC vault_info json invalid index"); - Json::Value jvParams; - jvParams[jss::ledger_index] = jss::validated; - jvParams[jss::vault] = 0; - auto jv = env.rpc("json", "vault_info", to_string(jvParams)); + testcase("RPC vault_info command line invalid index"); + Json::Value jv = env.rpc("vault_info", "0", "validated"); BEAST_EXPECT( jv[jss::result][jss::error].asString() == "malformedRequest"); } diff --git a/src/xrpld/net/detail/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp index 1d6c904ab1..aaabee8462 100644 --- a/src/xrpld/net/detail/RPCCall.cpp +++ b/src/xrpld/net/detail/RPCCall.cpp @@ -870,11 +870,9 @@ private: uint256 id = beast::zero; if (!id.parseHex(strVaultID)) return rpcError(rpcINVALID_PARAMS); - if (id == beast::zero) - return rpcError(rpcINVALID_PARAMS); Json::Value jvRequest(Json::objectValue); - jvRequest[jss::vault] = strVaultID; + jvRequest[jss::vault_id] = strVaultID; if (jvParams.size() > 1) jvParseLedger(jvRequest, jvParams[1u].asString()); diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index ee246e0e19..b84b9dc27c 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -1141,36 +1141,5 @@ getLedgerByContext(RPC::JsonContext& context) rpcNOT_READY, "findCreate failed to return an inbound ledger"); } -std::optional -parseVault(Json::Value const& params, Json::Value& jvResult) -{ - if (!params.isObject()) - { - uint256 uNodeIndex; - if (!uNodeIndex.parseHex(params.asString())) - { - jvResult[jss::error] = "malformedRequest"; - return std::nullopt; - } - return uNodeIndex; - } - - if (!params.isMember(jss::owner) || !params.isMember(jss::seq) || - !params[jss::seq].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - return std::nullopt; - } - - auto const id = parseBase58(params[jss::owner].asString()); - if (!id) - { - jvResult[jss::error] = "malformedOwner"; - return std::nullopt; - } - - return keylet::vault(*id, params[jss::seq].asUInt()).key; -} - } // namespace RPC } // namespace ripple diff --git a/src/xrpld/rpc/detail/RPCHelpers.h b/src/xrpld/rpc/detail/RPCHelpers.h index da12304177..0bbea6c2f1 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.h +++ b/src/xrpld/rpc/detail/RPCHelpers.h @@ -270,10 +270,6 @@ keypairForSignature( Json::Value& error, unsigned int apiVersion = apiVersionIfUnspecified); -// Used by both VaultInfo and LedgerEntry -std::optional -parseVault(Json::Value const& params, Json::Value& jvResult); - } // namespace RPC } // namespace ripple diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index bd43209124..64e54be6a9 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -856,7 +856,32 @@ parsePermissionedDomains(Json::Value const& pd, Json::Value& jvResult) static std::optional parseVault(Json::Value const& params, Json::Value& jvResult) { - return RPC::parseVault(params, jvResult); + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + return uNodeIndex; + } + + if (!params.isMember(jss::owner) || !params.isMember(jss::seq) || + !params[jss::seq].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id = parseBase58(params[jss::owner].asString()); + if (!id) + { + jvResult[jss::error] = "malformedOwner"; + return std::nullopt; + } + + return keylet::vault(*id, params[jss::seq].asUInt()).key; } using FunctionType = diff --git a/src/xrpld/rpc/handlers/VaultInfo.cpp b/src/xrpld/rpc/handlers/VaultInfo.cpp index 6d11d93ec2..aee29b8993 100644 --- a/src/xrpld/rpc/handlers/VaultInfo.cpp +++ b/src/xrpld/rpc/handlers/VaultInfo.cpp @@ -29,6 +29,55 @@ namespace ripple { +static std::optional +parseVault(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const hasVaultId = params.isMember(jss::vault_id); + auto const hasOwner = params.isMember(jss::owner); + auto const hasSeq = params.isMember(jss::seq); + + uint256 uNodeIndex = beast::zero; + if (hasVaultId && !hasOwner && !hasSeq) + { + if (!uNodeIndex.parseHex(params[jss::vault_id].asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + // else uNodeIndex holds the value we need + } + else if (!hasVaultId && hasOwner && hasSeq) + { + auto const id = parseBase58(params[jss::owner].asString()); + if (!id) + { + jvResult[jss::error] = "malformedOwner"; + return std::nullopt; + } + else if (!params[jss::seq].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + uNodeIndex = keylet::vault(*id, params[jss::seq].asUInt()).key; + } + else + { + // Invalid combination of fields vault_id/owner/seq + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + return uNodeIndex; +} + Json::Value doVaultInfo(RPC::JsonContext& context) { @@ -39,8 +88,7 @@ doVaultInfo(RPC::JsonContext& context) return jvResult; auto const uNodeIndex = - RPC::parseVault(context.params[jss::vault], jvResult) - .value_or(beast::zero); + parseVault(context.params, jvResult).value_or(beast::zero); if (uNodeIndex == beast::zero) { jvResult[jss::error] = "malformedRequest";