mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
Add RPC vault_info, remove RPC::supplementJson<ltVAULT>
This commit is contained in:
@@ -450,6 +450,7 @@ JSS(node_reads_hit); // out: GetCounts
|
|||||||
JSS(node_reads_total); // out: GetCounts
|
JSS(node_reads_total); // out: GetCounts
|
||||||
JSS(node_reads_duration_us); // out: GetCounts
|
JSS(node_reads_duration_us); // out: GetCounts
|
||||||
JSS(node_size); // out: server_info
|
JSS(node_size); // out: server_info
|
||||||
|
JSS(nodes); // out: VaultInfo
|
||||||
JSS(nodestore); // out: GetCounts
|
JSS(nodestore); // out: GetCounts
|
||||||
JSS(node_writes); // out: GetCounts
|
JSS(node_writes); // out: GetCounts
|
||||||
JSS(node_written_bytes); // out: GetCounts
|
JSS(node_written_bytes); // out: GetCounts
|
||||||
|
|||||||
@@ -802,19 +802,17 @@ class Vault_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
auto const vaultAccount = //
|
auto const vaultAccount = //
|
||||||
[&env, key = keylet.key, this]() -> AccountID {
|
[&env, key = keylet.key, this]() -> AccountID {
|
||||||
Json::Value jvParams;
|
auto jvVault = env.rpc("vault_info", strHex(key));
|
||||||
jvParams[jss::ledger_index] = jss::validated;
|
|
||||||
jvParams[jss::vault] = strHex(key);
|
|
||||||
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
|
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
jvVault[jss::result][jss::node][jss::SharesTotal] == "100");
|
jvVault[jss::result][jss::nodes][0u][sfAssetsTotal] == "100");
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
jvVault[jss::result][jss::node][sfAssetsTotal.fieldName] ==
|
jvVault[jss::result][jss::nodes][1u][sfOutstandingAmount] ==
|
||||||
"100");
|
"100");
|
||||||
|
|
||||||
// Vault pseudo-account
|
// Vault pseudo-account
|
||||||
return parseBase58<AccountID>(
|
return parseBase58<AccountID>(
|
||||||
jvVault[jss::result][jss::node][jss::Account].asString())
|
jvVault[jss::result][jss::nodes][0u][jss::Account]
|
||||||
|
.asString())
|
||||||
.value();
|
.value();
|
||||||
}();
|
}();
|
||||||
|
|
||||||
@@ -843,15 +841,11 @@ class Vault_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
{
|
{
|
||||||
testcase("nontransferable shares balance check");
|
testcase("nontransferable shares balance check");
|
||||||
Json::Value jvParams;
|
auto jvVault = env.rpc("vault_info", strHex(keylet.key));
|
||||||
jvParams[jss::ledger_index] = jss::validated;
|
|
||||||
jvParams[jss::vault] = strHex(keylet.key);
|
|
||||||
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
|
|
||||||
|
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
jvVault[jss::result][jss::node][jss::SharesTotal] == "50");
|
jvVault[jss::result][jss::nodes][0u][sfAssetsTotal] == "50");
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
jvVault[jss::result][jss::node][sfAssetsTotal.fieldName] ==
|
jvVault[jss::result][jss::nodes][1u][sfOutstandingAmount] ==
|
||||||
"50");
|
"50");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1383,52 +1377,66 @@ class Vault_test : public beast::unit_test::suite
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
auto const check = [&, keylet = keylet, sle = sleVault, this](
|
auto const check = [&, keylet = keylet, sle = sleVault, this](
|
||||||
Json::Value const& node) {
|
Json::Value const& vault,
|
||||||
BEAST_EXPECT(node.isObject());
|
Json::Value const& issuance = Json::nullValue) {
|
||||||
|
BEAST_EXPECT(vault.isObject());
|
||||||
|
|
||||||
auto checkString =
|
constexpr auto checkString =
|
||||||
[&node](SField const& field, std::string expected) -> bool {
|
[](auto& node, SField const& field, std::string v) -> bool {
|
||||||
return node.isMember(field.fieldName) &&
|
return node.isMember(field.fieldName) &&
|
||||||
node[field.fieldName].isString() &&
|
node[field.fieldName].isString() &&
|
||||||
node[field.fieldName] == expected;
|
node[field.fieldName] == v;
|
||||||
};
|
};
|
||||||
auto checkObject =
|
constexpr auto checkObject =
|
||||||
[&node](SField const& field, Json::Value expected) -> bool {
|
[](auto& node, SField const& field, Json::Value v) -> bool {
|
||||||
return node.isMember(field.fieldName) &&
|
return node.isMember(field.fieldName) &&
|
||||||
node[field.fieldName].isObject() &&
|
node[field.fieldName].isObject() &&
|
||||||
node[field.fieldName] == expected;
|
node[field.fieldName] == v;
|
||||||
};
|
};
|
||||||
auto checkInt = [&node](SField const& field, int expected) -> bool {
|
constexpr auto checkInt =
|
||||||
|
[](auto& node, SField const& field, int v) -> bool {
|
||||||
return node.isMember(field.fieldName) &&
|
return node.isMember(field.fieldName) &&
|
||||||
((node[field.fieldName].isInt() &&
|
((node[field.fieldName].isInt() &&
|
||||||
node[field.fieldName] == Json::Int(expected)) ||
|
node[field.fieldName] == Json::Int(v)) ||
|
||||||
(node[field.fieldName].isUInt() &&
|
(node[field.fieldName].isUInt() &&
|
||||||
node[field.fieldName] == Json::UInt(expected)));
|
node[field.fieldName] == Json::UInt(v)));
|
||||||
};
|
};
|
||||||
|
|
||||||
BEAST_EXPECT(node["LedgerEntryType"].asString() == "Vault");
|
BEAST_EXPECT(vault["LedgerEntryType"].asString() == "Vault");
|
||||||
BEAST_EXPECT(node[jss::index].asString() == strHex(keylet.key));
|
BEAST_EXPECT(vault[jss::index].asString() == strHex(keylet.key));
|
||||||
BEAST_EXPECT(checkInt(sfFlags, 0));
|
BEAST_EXPECT(checkInt(vault, sfFlags, 0));
|
||||||
// Ignore all other standard fields, this test doesn't care
|
// Ignore all other standard fields, this test doesn't care
|
||||||
|
|
||||||
BEAST_EXPECT(checkString(sfAccount, toBase58(sle->at(sfAccount))));
|
|
||||||
BEAST_EXPECT(checkObject(sfAsset, to_json(sle->at(sfAsset))));
|
|
||||||
BEAST_EXPECT(checkString(sfAssetsAvailable, "50"));
|
|
||||||
BEAST_EXPECT(checkString(sfAssetsMaximum, "1000"));
|
|
||||||
BEAST_EXPECT(checkString(sfAssetsTotal, "50"));
|
|
||||||
BEAST_EXPECT(checkString(sfLossUnrealized, "0"));
|
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
checkString(sfShareMPTID, strHex(sle->at(sfShareMPTID))));
|
checkString(vault, sfAccount, toBase58(sle->at(sfAccount))));
|
||||||
BEAST_EXPECT(checkString(sfOwner, toBase58(owner.id())));
|
|
||||||
BEAST_EXPECT(checkInt(sfSequence, sequence));
|
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
checkInt(sfWithdrawalPolicy, vaultStrategyFirstComeFirstServe));
|
checkObject(vault, sfAsset, to_json(sle->at(sfAsset))));
|
||||||
|
BEAST_EXPECT(checkString(vault, sfAssetsAvailable, "50"));
|
||||||
|
BEAST_EXPECT(checkString(vault, sfAssetsMaximum, "1000"));
|
||||||
|
BEAST_EXPECT(checkString(vault, sfAssetsTotal, "50"));
|
||||||
|
BEAST_EXPECT(checkString(vault, sfLossUnrealized, "0"));
|
||||||
|
|
||||||
// This field is injected in RPC::supplementJson<ltVAULT>
|
auto const strShareID = strHex(sle->at(sfShareMPTID));
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(checkString(vault, sfShareMPTID, strShareID));
|
||||||
node.isMember(jss::SharesTotal) &&
|
BEAST_EXPECT(checkString(vault, sfOwner, toBase58(owner.id())));
|
||||||
node[jss::SharesTotal].isString() &&
|
BEAST_EXPECT(checkInt(vault, sfSequence, sequence));
|
||||||
node[jss::SharesTotal] == "50");
|
BEAST_EXPECT(checkInt(
|
||||||
|
vault, sfWithdrawalPolicy, vaultStrategyFirstComeFirstServe));
|
||||||
|
|
||||||
|
if (issuance.isObject())
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(
|
||||||
|
issuance["LedgerEntryType"].asString() ==
|
||||||
|
"MPTokenIssuance");
|
||||||
|
BEAST_EXPECT(
|
||||||
|
issuance[jss::mpt_issuance_id].asString() == strShareID);
|
||||||
|
BEAST_EXPECT(checkInt(issuance, sfSequence, 1));
|
||||||
|
BEAST_EXPECT(checkInt(
|
||||||
|
issuance,
|
||||||
|
sfFlags,
|
||||||
|
int(lsfMPTCanEscrow | lsfMPTCanTrade | lsfMPTCanTransfer)));
|
||||||
|
BEAST_EXPECT(checkString(issuance, sfOutstandingAmount, "50"));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1537,6 +1545,74 @@ class Vault_test : public beast::unit_test::suite
|
|||||||
BEAST_EXPECT(jv[jss::result][jss::state].size() == 1);
|
BEAST_EXPECT(jv[jss::result][jss::state].size() == 1);
|
||||||
check(jv[jss::result][jss::state][0u]);
|
check(jv[jss::result][jss::state][0u]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
testcase("RPC vault_info command line");
|
||||||
|
Json::Value jv =
|
||||||
|
env.rpc("vault_info", strHex(keylet.key), "validated");
|
||||||
|
|
||||||
|
BEAST_EXPECT(!jv[jss::result].isMember(jss::error));
|
||||||
|
BEAST_EXPECT(jv[jss::result].isMember(jss::nodes));
|
||||||
|
BEAST_EXPECT(jv[jss::result][jss::nodes].isArray());
|
||||||
|
BEAST_EXPECT(jv[jss::result].isMember(jss::directory));
|
||||||
|
BEAST_EXPECT(jv[jss::result][jss::directory][jss::vault] == 0);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
jv[jss::result][jss::directory][jss::mpt_issuance] == 1);
|
||||||
|
check(
|
||||||
|
jv[jss::result][jss::nodes][0u],
|
||||||
|
jv[jss::result][jss::nodes][1u]);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
testcase("RPC vault_info json by owner and sequence");
|
||||||
|
Json::Value jvParams;
|
||||||
|
jvParams[jss::ledger_index] = jss::validated;
|
||||||
|
jvParams[jss::vault][jss::owner] = owner.human();
|
||||||
|
jvParams[jss::vault][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::nodes));
|
||||||
|
BEAST_EXPECT(jv[jss::result][jss::nodes].isArray());
|
||||||
|
BEAST_EXPECT(jv[jss::result].isMember(jss::directory));
|
||||||
|
BEAST_EXPECT(jv[jss::result][jss::directory][jss::vault] == 0);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
jv[jss::result][jss::directory][jss::mpt_issuance] == 1);
|
||||||
|
check(
|
||||||
|
jv[jss::result][jss::nodes][0u],
|
||||||
|
jv[jss::result][jss::nodes][1u]);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
testcase("RPC vault_info command line invalid index");
|
||||||
|
Json::Value jv = env.rpc("vault_info", "0", "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));
|
||||||
|
BEAST_EXPECT(
|
||||||
|
jv[jss::result][jss::error].asString() == "malformedRequest");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
testcase("RPC vault_info command line invalid index");
|
||||||
|
Json::Value jv =
|
||||||
|
env.rpc("vault_info", strHex(uint256(42)), "validated");
|
||||||
|
BEAST_EXPECT(
|
||||||
|
jv[jss::result][jss::error].asString() == "entryNotFound");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
testcase("RPC vault_info command line invalid ledger");
|
||||||
|
Json::Value jv = env.rpc("vault_info", strHex(keylet.key), "0");
|
||||||
|
BEAST_EXPECT(
|
||||||
|
jv[jss::result][jss::error].asString() == "lgrNotFound");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <xrpl/basics/base64.h>
|
#include <xrpl/basics/base64.h>
|
||||||
#include <xrpl/basics/contract.h>
|
#include <xrpl/basics/contract.h>
|
||||||
#include <xrpl/beast/core/LexicalCast.h>
|
#include <xrpl/beast/core/LexicalCast.h>
|
||||||
|
#include <xrpl/json/json_forwards.h>
|
||||||
#include <xrpl/json/json_reader.h>
|
#include <xrpl/json/json_reader.h>
|
||||||
#include <xrpl/json/to_string.h>
|
#include <xrpl/json/to_string.h>
|
||||||
#include <xrpl/protocol/ErrorCodes.h>
|
#include <xrpl/protocol/ErrorCodes.h>
|
||||||
@@ -862,6 +863,25 @@ private:
|
|||||||
return jvRequest;
|
return jvRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Json::Value
|
||||||
|
parseVault(Json::Value const& jvParams)
|
||||||
|
{
|
||||||
|
std::string strVaultID = jvParams[0u].asString();
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (jvParams.size() > 1)
|
||||||
|
jvParseLedger(jvRequest, jvParams[1u].asString());
|
||||||
|
|
||||||
|
return jvRequest;
|
||||||
|
}
|
||||||
|
|
||||||
// peer_reservations_add <public_key> [<name>]
|
// peer_reservations_add <public_key> [<name>]
|
||||||
Json::Value
|
Json::Value
|
||||||
parsePeerReservationsAdd(Json::Value const& jvParams)
|
parsePeerReservationsAdd(Json::Value const& jvParams)
|
||||||
@@ -1208,6 +1228,7 @@ public:
|
|||||||
{"account_offers", &RPCParser::parseAccountItems, 1, 4},
|
{"account_offers", &RPCParser::parseAccountItems, 1, 4},
|
||||||
{"account_tx", &RPCParser::parseAccountTransactions, 1, 8},
|
{"account_tx", &RPCParser::parseAccountTransactions, 1, 8},
|
||||||
{"amm_info", &RPCParser::parseAsIs, 1, 2},
|
{"amm_info", &RPCParser::parseAsIs, 1, 2},
|
||||||
|
{"vault_info", &RPCParser::parseVault, 1, 2},
|
||||||
{"book_changes", &RPCParser::parseLedgerId, 1, 1},
|
{"book_changes", &RPCParser::parseLedgerId, 1, 1},
|
||||||
{"book_offers", &RPCParser::parseBookOffers, 2, 7},
|
{"book_offers", &RPCParser::parseBookOffers, 2, 7},
|
||||||
{"can_delete", &RPCParser::parseCanDelete, 0, 1},
|
{"can_delete", &RPCParser::parseCanDelete, 0, 1},
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ Handler const handlerArray[]{
|
|||||||
{"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
|
{"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
|
||||||
{"account_tx", byRef(&doAccountTxJson), Role::USER, NO_CONDITION},
|
{"account_tx", byRef(&doAccountTxJson), Role::USER, NO_CONDITION},
|
||||||
{"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
|
{"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
|
||||||
|
{"vault_info", byRef(&doVaultInfo), Role::USER, NO_CONDITION},
|
||||||
{"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
|
{"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
|
||||||
{"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},
|
{"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},
|
||||||
{"book_offers", byRef(&doBookOffers), Role::USER, NO_CONDITION},
|
{"book_offers", byRef(&doBookOffers), Role::USER, NO_CONDITION},
|
||||||
|
|||||||
@@ -149,26 +149,6 @@ isRelatedToAccount(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
|
||||||
void
|
|
||||||
supplementJson<ltVAULT>(
|
|
||||||
ReadView const& view,
|
|
||||||
std::shared_ptr<SLE const> const& vault,
|
|
||||||
Json::Value& node)
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(
|
|
||||||
vault->getType() == ltVAULT,
|
|
||||||
"ripple::RPC::supplementJson<ltVAULT> : matching type");
|
|
||||||
|
|
||||||
auto const share = vault->at(sfShareMPTID);
|
|
||||||
auto const sleIssuance = view.read(keylet::mptIssuance(share));
|
|
||||||
if (!sleIssuance)
|
|
||||||
return;
|
|
||||||
|
|
||||||
node[jss::SharesTotal] =
|
|
||||||
Number(sleIssuance->getFieldU64(sfOutstandingAmount));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
getAccountObjects(
|
getAccountObjects(
|
||||||
ReadView const& ledger,
|
ReadView const& ledger,
|
||||||
@@ -320,10 +300,7 @@ getAccountObjects(
|
|||||||
if (!typeFilter.has_value() ||
|
if (!typeFilter.has_value() ||
|
||||||
typeMatchesFilter(typeFilter.value(), sleNode->getType()))
|
typeMatchesFilter(typeFilter.value(), sleNode->getType()))
|
||||||
{
|
{
|
||||||
auto& entry =
|
jvObjects.append(sleNode->getJson(JsonOptions::none));
|
||||||
jvObjects.append(sleNode->getJson(JsonOptions::none));
|
|
||||||
if (sleNode->getType() == ltVAULT)
|
|
||||||
RPC::supplementJson<ltVAULT>(ledger, sleNode, entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++i == mlimit)
|
if (++i == mlimit)
|
||||||
@@ -1163,5 +1140,37 @@ getLedgerByContext(RPC::JsonContext& context)
|
|||||||
return RPC::make_error(
|
return RPC::make_error(
|
||||||
rpcNOT_READY, "findCreate failed to return an inbound ledger");
|
rpcNOT_READY, "findCreate failed to return an inbound ledger");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<uint256>
|
||||||
|
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<AccountID>(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 RPC
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|||||||
@@ -270,29 +270,12 @@ keypairForSignature(
|
|||||||
Json::Value& error,
|
Json::Value& error,
|
||||||
unsigned int apiVersion = apiVersionIfUnspecified);
|
unsigned int apiVersion = apiVersionIfUnspecified);
|
||||||
|
|
||||||
/**
|
// Used by both VaultInfo and LedgerEntry
|
||||||
* Supplement JSON of a ledger object with additional data read from a view
|
std::optional<uint256>
|
||||||
*
|
parseVault(Json::Value const& params, Json::Value& jvResult);
|
||||||
* To be specialized per ledger object type as needed; any specialization of
|
|
||||||
* this function must be declared below and defined in RPCHelpers.cpp
|
|
||||||
*
|
|
||||||
* The general template is never used, hence it is only declared but not defined
|
|
||||||
*/
|
|
||||||
template <LedgerEntryType Type>
|
|
||||||
inline void
|
|
||||||
supplementJson(
|
|
||||||
ReadView const&,
|
|
||||||
std::shared_ptr<SLE const> const& sle,
|
|
||||||
Json::Value&);
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void
|
|
||||||
supplementJson<ltVAULT>(
|
|
||||||
ReadView const& view,
|
|
||||||
std::shared_ptr<SLE const> const& vault,
|
|
||||||
Json::Value& node);
|
|
||||||
|
|
||||||
} // namespace RPC
|
} // namespace RPC
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -166,6 +166,8 @@ Json::Value
|
|||||||
doValidatorListSites(RPC::JsonContext&);
|
doValidatorListSites(RPC::JsonContext&);
|
||||||
Json::Value
|
Json::Value
|
||||||
doValidatorInfo(RPC::JsonContext&);
|
doValidatorInfo(RPC::JsonContext&);
|
||||||
|
Json::Value
|
||||||
|
doVaultInfo(RPC::JsonContext&);
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -124,8 +124,6 @@ doLedgerData(RPC::JsonContext& context)
|
|||||||
{
|
{
|
||||||
Json::Value& entry =
|
Json::Value& entry =
|
||||||
nodes.append(sle->getJson(JsonOptions::none));
|
nodes.append(sle->getJson(JsonOptions::none));
|
||||||
if (sle->getType() == ltVAULT)
|
|
||||||
RPC::supplementJson<ltVAULT>(*lpLedger, sle, entry);
|
|
||||||
entry[jss::index] = to_string(sle->key());
|
entry[jss::index] = to_string(sle->key());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -856,32 +856,7 @@ parsePermissionedDomains(Json::Value const& pd, Json::Value& jvResult)
|
|||||||
static std::optional<uint256>
|
static std::optional<uint256>
|
||||||
parseVault(Json::Value const& params, Json::Value& jvResult)
|
parseVault(Json::Value const& params, Json::Value& jvResult)
|
||||||
{
|
{
|
||||||
if (!params.isObject())
|
return RPC::parseVault(params, jvResult);
|
||||||
{
|
|
||||||
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<AccountID>(params[jss::owner].asString());
|
|
||||||
if (!id)
|
|
||||||
{
|
|
||||||
jvResult[jss::error] = "malformedOwner";
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return keylet::vault(*id, params[jss::seq].asUInt()).key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using FunctionType =
|
using FunctionType =
|
||||||
@@ -1033,9 +1008,6 @@ doLedgerEntry(RPC::JsonContext& context)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
jvResult[jss::node] = sleNode->getJson(JsonOptions::none);
|
jvResult[jss::node] = sleNode->getJson(JsonOptions::none);
|
||||||
if (sleNode->getType() == ltVAULT)
|
|
||||||
RPC::supplementJson<ltVAULT>(
|
|
||||||
*lpLedger, sleNode, jvResult[jss::node]);
|
|
||||||
jvResult[jss::index] = to_string(uNodeIndex);
|
jvResult[jss::index] = to_string(uNodeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
95
src/xrpld/rpc/handlers/VaultInfo.cpp
Normal file
95
src/xrpld/rpc/handlers/VaultInfo.cpp
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2025 Ripple Labs Inc.
|
||||||
|
|
||||||
|
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 <xrpld/rpc/Context.h>
|
||||||
|
#include <xrpld/rpc/detail/RPCHelpers.h>
|
||||||
|
|
||||||
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
|
#include <xrpl/json/json_value.h>
|
||||||
|
#include <xrpl/protocol/ErrorCodes.h>
|
||||||
|
#include <xrpl/protocol/Indexes.h>
|
||||||
|
#include <xrpl/protocol/jss.h>
|
||||||
|
#include <xrpl/protocol/serialize.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
Json::Value
|
||||||
|
doVaultInfo(RPC::JsonContext& context)
|
||||||
|
{
|
||||||
|
std::shared_ptr<ReadView const> lpLedger;
|
||||||
|
auto jvResult = RPC::lookupLedger(lpLedger, context);
|
||||||
|
|
||||||
|
if (!lpLedger)
|
||||||
|
return jvResult;
|
||||||
|
|
||||||
|
auto const uNodeIndex =
|
||||||
|
RPC::parseVault(context.params[jss::vault], jvResult)
|
||||||
|
.value_or(beast::zero);
|
||||||
|
if (uNodeIndex == beast::zero)
|
||||||
|
{
|
||||||
|
jvResult[jss::error] = "malformedRequest";
|
||||||
|
return jvResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool const isBinary = context.params[jss::binary].asBool();
|
||||||
|
|
||||||
|
auto const sleVault = lpLedger->read(keylet::vault(uNodeIndex));
|
||||||
|
auto const sleIssuance = sleVault == nullptr //
|
||||||
|
? nullptr
|
||||||
|
: lpLedger->read(keylet::mptIssuance(sleVault->at(sfShareMPTID)));
|
||||||
|
if (!sleVault || !sleIssuance)
|
||||||
|
{
|
||||||
|
jvResult[jss::error] = "entryNotFound";
|
||||||
|
return jvResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value directory = Json::objectValue;
|
||||||
|
// Some directory positions in nodes are hardcoded below, because the
|
||||||
|
// order of writing these is hardcoded, but it may not stay like this
|
||||||
|
// forever. If a given type can have any number of nodes, use an array
|
||||||
|
// rather than a number
|
||||||
|
directory[jss::vault] = 0;
|
||||||
|
directory[jss::mpt_issuance] = 1;
|
||||||
|
|
||||||
|
Json::Value nodes = Json::arrayValue;
|
||||||
|
if (!isBinary)
|
||||||
|
{
|
||||||
|
auto& vault = nodes.append(Json::objectValue);
|
||||||
|
vault = sleVault->getJson(JsonOptions::none);
|
||||||
|
|
||||||
|
auto& issuance = nodes.append(Json::objectValue);
|
||||||
|
issuance = sleIssuance->getJson(JsonOptions::none);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto& vault = nodes.append(Json::objectValue);
|
||||||
|
vault[jss::data] = serializeHex(*sleVault);
|
||||||
|
vault[jss::index] = to_string(sleVault->key());
|
||||||
|
|
||||||
|
auto& issuance = nodes.append(Json::objectValue);
|
||||||
|
issuance[jss::data] = serializeHex(*sleIssuance);
|
||||||
|
issuance[jss::index] = to_string(sleIssuance->key());
|
||||||
|
}
|
||||||
|
|
||||||
|
jvResult[jss::directory] = directory;
|
||||||
|
jvResult[jss::nodes] = nodes;
|
||||||
|
return jvResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
Reference in New Issue
Block a user