From 30ce0e393744a3ba239c1b7502b1d685d4008f04 Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Mon, 30 Jan 2023 11:29:21 +0000 Subject: [PATCH] Add rpc call `server_definitions` to rippled. --- src/ripple/protocol/SField.h | 1 + src/ripple/protocol/jss.h | 162 +++++++++++------------ src/ripple/rpc/handlers/ServerInfo.cpp | 170 ++++++++++++++----------- src/ripple/rpc/impl/Handler.cpp | 4 +- 4 files changed, 183 insertions(+), 154 deletions(-) diff --git a/src/ripple/protocol/SField.h b/src/ripple/protocol/SField.h index b85eef7c0..ba136bf0a 100644 --- a/src/ripple/protocol/SField.h +++ b/src/ripple/protocol/SField.h @@ -263,6 +263,7 @@ public: compare(const SField& f1, const SField& f2); static std::map knownCodeToField; + private: static int num; }; diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index ace224133..a471c7765 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -41,87 +41,87 @@ namespace jss { error: Common properties of RPC error responses. */ -JSS(AL_size); // out: GetCounts -JSS(AL_hit_rate); // out: GetCounts -JSS(Account); // in: TransactionSign; field. -JSS(AccountDelete); // transaction type. -JSS(AccountRoot); // ledger type. -JSS(AccountSet); // transaction type. -JSS(Amendments); // ledger type. -JSS(Amount); // in: TransactionSign; field. -JSS(Authorize); // field -JSS(Check); // ledger type. -JSS(CheckCancel); // transaction type. -JSS(CheckCash); // transaction type. -JSS(CheckCreate); // transaction type. -JSS(ClaimReward); // transaction type. -JSS(ClearFlag); // field. -JSS(CreateCode); // field. -JSS(DeliverMin); // in: TransactionSign -JSS(DepositPreauth); // transaction and ledger type. -JSS(Destination); // in: TransactionSign; field. -JSS(DirectoryNode); // ledger type. -JSS(EnableAmendment); // transaction type. -JSS(EmitFailure); // transaction type. (cleanup emit) -JSS(Escrow); // ledger type. -JSS(EscrowCancel); // transaction type. -JSS(EscrowCreate); // transaction type. -JSS(EscrowFinish); // transaction type. -JSS(Fee); // in/out: TransactionSign; field. -JSS(FeeSettings); // ledger type. -JSS(FIELDS); // out: RPC server_definitions -JSS(Flags); // in/out: TransactionSign; field. -JSS(incomplete_shards); // out: OverlayImpl, PeerImp -JSS(HookApiVersion); // field -JSS(HookHash); // field -JSS(HookNamespace); // field -JSS(HookOn); // field -JSS(Hooks); // field -JSS(HookGrants); // field -JSS(HookParameters); // field -JSS(HookParameterName); // field -JSS(HookParameterValue); // field -JSS(HookParameter); // field -JSS(HookGrant); // field -JSS(isSerialized); // out: RPC server_definitions -JSS(isSigningField); // out: RPC server_definitions -JSS(isVLEncoded); // out: RPC server_definitions -JSS(Invalid); // -JSS(Invoke); // transaction type -JSS(InvoiceID); // field -JSS(LastLedgerSequence); // in: TransactionSign; field -JSS(LedgerHashes); // ledger type. -JSS(LimitAmount); // field. -JSS(NetworkID); // field. -JSS(NFTokenBurn); // transaction type. -JSS(NFTokenMint); // transaction type. -JSS(NFTokenOffer); // ledger type. -JSS(NFTokenAcceptOffer); // transaction type. -JSS(NFTokenCancelOffer); // transaction type. -JSS(NFTokenCreateOffer); // transaction type. -JSS(NFTokenPage); // ledger type. -JSS(Offer); // ledger type. -JSS(OfferCancel); // transaction type. -JSS(OfferCreate); // transaction type. -JSS(OfferSequence); // field. -JSS(Paths); // in/out: TransactionSign -JSS(PayChannel); // ledger type. -JSS(Payment); // transaction type. -JSS(PaymentChannelClaim); // transaction type. -JSS(PaymentChannelCreate); // transaction type. -JSS(PaymentChannelFund); // transaction type. -JSS(RippleState); // ledger type. -JSS(SLE_hit_rate); // out: GetCounts. -JSS(SetFee); // transaction type. -JSS(UNLModify); // transaction type. -JSS(SettleDelay); // in: TransactionSign -JSS(SendMax); // in: TransactionSign -JSS(Sequence); // in/out: TransactionSign; field. -JSS(SetFlag); // field. -JSS(SetRegularKey); // transaction type. -JSS(SetHook); // transaction type. -JSS(Hook); // ledger type. -JSS(HookState); // ledger type. +JSS(AL_size); // out: GetCounts +JSS(AL_hit_rate); // out: GetCounts +JSS(Account); // in: TransactionSign; field. +JSS(AccountDelete); // transaction type. +JSS(AccountRoot); // ledger type. +JSS(AccountSet); // transaction type. +JSS(Amendments); // ledger type. +JSS(Amount); // in: TransactionSign; field. +JSS(Authorize); // field +JSS(Check); // ledger type. +JSS(CheckCancel); // transaction type. +JSS(CheckCash); // transaction type. +JSS(CheckCreate); // transaction type. +JSS(ClaimReward); // transaction type. +JSS(ClearFlag); // field. +JSS(CreateCode); // field. +JSS(DeliverMin); // in: TransactionSign +JSS(DepositPreauth); // transaction and ledger type. +JSS(Destination); // in: TransactionSign; field. +JSS(DirectoryNode); // ledger type. +JSS(EnableAmendment); // transaction type. +JSS(EmitFailure); // transaction type. (cleanup emit) +JSS(Escrow); // ledger type. +JSS(EscrowCancel); // transaction type. +JSS(EscrowCreate); // transaction type. +JSS(EscrowFinish); // transaction type. +JSS(Fee); // in/out: TransactionSign; field. +JSS(FeeSettings); // ledger type. +JSS(FIELDS); // out: RPC server_definitions +JSS(Flags); // in/out: TransactionSign; field. +JSS(incomplete_shards); // out: OverlayImpl, PeerImp +JSS(HookApiVersion); // field +JSS(HookHash); // field +JSS(HookNamespace); // field +JSS(HookOn); // field +JSS(Hooks); // field +JSS(HookGrants); // field +JSS(HookParameters); // field +JSS(HookParameterName); // field +JSS(HookParameterValue); // field +JSS(HookParameter); // field +JSS(HookGrant); // field +JSS(isSerialized); // out: RPC server_definitions +JSS(isSigningField); // out: RPC server_definitions +JSS(isVLEncoded); // out: RPC server_definitions +JSS(Invalid); // +JSS(Invoke); // transaction type +JSS(InvoiceID); // field +JSS(LastLedgerSequence); // in: TransactionSign; field +JSS(LedgerHashes); // ledger type. +JSS(LimitAmount); // field. +JSS(NetworkID); // field. +JSS(NFTokenBurn); // transaction type. +JSS(NFTokenMint); // transaction type. +JSS(NFTokenOffer); // ledger type. +JSS(NFTokenAcceptOffer); // transaction type. +JSS(NFTokenCancelOffer); // transaction type. +JSS(NFTokenCreateOffer); // transaction type. +JSS(NFTokenPage); // ledger type. +JSS(Offer); // ledger type. +JSS(OfferCancel); // transaction type. +JSS(OfferCreate); // transaction type. +JSS(OfferSequence); // field. +JSS(Paths); // in/out: TransactionSign +JSS(PayChannel); // ledger type. +JSS(Payment); // transaction type. +JSS(PaymentChannelClaim); // transaction type. +JSS(PaymentChannelCreate); // transaction type. +JSS(PaymentChannelFund); // transaction type. +JSS(RippleState); // ledger type. +JSS(SLE_hit_rate); // out: GetCounts. +JSS(SetFee); // transaction type. +JSS(UNLModify); // transaction type. +JSS(SettleDelay); // in: TransactionSign +JSS(SendMax); // in: TransactionSign +JSS(Sequence); // in/out: TransactionSign; field. +JSS(SetFlag); // field. +JSS(SetRegularKey); // transaction type. +JSS(SetHook); // transaction type. +JSS(Hook); // ledger type. +JSS(HookState); // ledger type. JSS(HookDefinition); JSS(EmittedTxn); // ledger type. JSS(SignerList); // ledger type. diff --git a/src/ripple/rpc/handlers/ServerInfo.cpp b/src/ripple/rpc/handlers/ServerInfo.cpp index cd03c04d1..d44ff0475 100644 --- a/src/ripple/rpc/handlers/ServerInfo.cpp +++ b/src/ripple/rpc/handlers/ServerInfo.cpp @@ -21,24 +21,26 @@ #include #include #include +#include #include +#include +#include +#include #include #include #include #include -#include +#include #include #include -#include -#include -#define MAGIC_ENUM(x)\ -template <>\ -struct magic_enum::customize::enum_range< x >\ -{\ - static constexpr int min = -20000;\ - static constexpr int max = 20000;\ -}; +#define MAGIC_ENUM(x) \ + template <> \ + struct magic_enum::customize::enum_range \ + { \ + static constexpr int min = -20000; \ + static constexpr int max = 20000; \ + }; MAGIC_ENUM(ripple::SerializedTypeID); MAGIC_ENUM(ripple::LedgerEntryType); @@ -49,7 +51,6 @@ MAGIC_ENUM(ripple::TERcodes); MAGIC_ENUM(ripple::TEScodes); MAGIC_ENUM(ripple::TECcodes); - namespace ripple { class Definitions @@ -59,29 +60,26 @@ private: generate() { // RH TODO: probably a better way to do this? -#define STR(x)\ - ([&]{ std::ostringstream ss; return ss << (x), ss.str(); }()) - - +#define STR(x) \ + ([&] { \ + std::ostringstream ss; \ + return ss << (x), ss.str(); \ + }()) Json::Value ret{Json::objectValue}; ret[jss::TYPES] = Json::objectValue; - auto const translate = [](std::string inp) -> std::string - { - auto replace = [&](const char* f, const char* r) -> std::string - { + auto const translate = [](std::string inp) -> std::string { + auto replace = [&](const char* f, const char* r) -> std::string { std::string out = inp; boost::replace_all(out, f, r); return out; }; - auto find = [&](const char* s) -> bool - { + auto find = [&](const char* s) -> bool { return inp.find(s) != std::string::npos; }; - if (find("UINT")) { if (find("256") || find("160") || find("128")) @@ -111,25 +109,24 @@ private: if (inp == "PAYCHAN") return "PayChannel"; - static const std::map capitalization_exceptions = - { - {"NFTOKEN", "NFToken"}, - {"UNL", "UNL"}, - {"XCHAIN", "XChain"}, - {"ID", "ID"}, - {"AMM", "AMM"} - }; - + static const std::map + capitalization_exceptions = { + {"NFTOKEN", "NFToken"}, + {"UNL", "UNL"}, + {"XCHAIN", "XChain"}, + {"ID", "ID"}, + {"AMM", "AMM"}}; std::string out; size_t pos = 0; - for(;;) + for (;;) { pos = inp.find("_"); if (pos == std::string::npos) pos = inp.size(); std::string token = inp.substr(0, pos); - if (auto const e = capitalization_exceptions.find(token); e != capitalization_exceptions.end()) + if (auto const e = capitalization_exceptions.find(token); + e != capitalization_exceptions.end()) out += e->second; else if (token.size() > 1) { @@ -141,16 +138,17 @@ private: out += token; if (pos == inp.size()) break; - inp = inp.substr(pos+1); + inp = inp.substr(pos + 1); } return out; }; ret[jss::TYPES]["Done"] = -1; - std::map type_map {{ -1, "Done" }}; + std::map type_map{{-1, "Done"}}; for (auto [value, name] : magic_enum::enum_entries()) { - std::string type_name = translate(STR(name).substr(4) /* remove STI_ */); + std::string type_name = + translate(STR(name).substr(4) /* remove STI_ */); int32_t type_value = std::stoi(STR(value)); ret[jss::TYPES][type_name] = type_value; type_map[type_value] = type_name; @@ -159,11 +157,11 @@ private: ret[jss::LEDGER_ENTRY_TYPES] = Json::objectValue; ret[jss::LEDGER_ENTRY_TYPES][jss::Invalid] = -1; - for (auto [value, name] : magic_enum::enum_entries()) - ret[jss::LEDGER_ENTRY_TYPES][translate(STR(name).substr(2) /* remove lt_ */)] = - std::stoi(STR(value)); - + ret[jss::LEDGER_ENTRY_TYPES] + [translate(STR(name).substr(2) /* remove lt_ */)] = + std::stoi(STR(value)); + ret[jss::FIELDS] = Json::arrayValue; uint32_t i = 0; @@ -176,10 +174,10 @@ private: v[jss::isSerialized] = false; v[jss::isSigningField] = false; v[jss::type] = "Unknown"; - a[1U] = v; + a[1U] = v; ret[jss::FIELDS][i++] = a; } - + { Json::Value a = Json::arrayValue; a[0U] = "Invalid"; @@ -189,10 +187,10 @@ private: v[jss::isSerialized] = false; v[jss::isSigningField] = false; v[jss::type] = "Unknown"; - a[1U] = v; + a[1U] = v; ret[jss::FIELDS][i++] = a; } - + { Json::Value a = Json::arrayValue; a[0U] = "ObjectEndMarker"; @@ -202,10 +200,10 @@ private: v[jss::isSerialized] = false; v[jss::isSigningField] = true; v[jss::type] = "STObject"; - a[1U] = v; + a[1U] = v; ret[jss::FIELDS][i++] = a; } - + { Json::Value a = Json::arrayValue; a[0U] = "ArrayEndMarker"; @@ -215,10 +213,10 @@ private: v[jss::isSerialized] = false; v[jss::isSigningField] = true; v[jss::type] = "STArray"; - a[1U] = v; + a[1U] = v; ret[jss::FIELDS][i++] = a; } - + { Json::Value a = Json::arrayValue; a[0U] = "hash"; @@ -228,10 +226,10 @@ private: v[jss::isSerialized] = false; v[jss::isSigningField] = false; v[jss::type] = "Hash256"; - a[1U] = v; + a[1U] = v; ret[jss::FIELDS][i++] = a; } - + { Json::Value a = Json::arrayValue; a[0U] = "index"; @@ -241,10 +239,10 @@ private: v[jss::isSerialized] = false; v[jss::isSigningField] = false; v[jss::type] = "Hash256"; - a[1U] = v; + a[1U] = v; ret[jss::FIELDS][i++] = a; } - + { Json::Value a = Json::arrayValue; a[0U] = "taker_gets_funded"; @@ -254,10 +252,10 @@ private: v[jss::isSerialized] = false; v[jss::isSigningField] = false; v[jss::type] = "Amount"; - a[1U] = v; + a[1U] = v; ret[jss::FIELDS][i++] = a; } - + { Json::Value a = Json::arrayValue; a[0U] = "taker_pays_funded"; @@ -267,13 +265,12 @@ private: v[jss::isSerialized] = false; v[jss::isSigningField] = false; v[jss::type] = "Amount"; - a[1U] = v; + a[1U] = v; ret[jss::FIELDS][i++] = a; } for (auto const& [code, f] : ripple::SField::knownCodeToField) { - if (f->fieldName == "") continue; @@ -284,19 +281,17 @@ private: innerObj[jss::nth] = fc; - innerObj[jss::isVLEncoded] = - (tc == 7U /* Blob */ || - tc == 8U /* AccountID */ || + innerObj[jss::isVLEncoded] = + (tc == 7U /* Blob */ || tc == 8U /* AccountID */ || tc == 19U /* Vector256 */); - innerObj[jss::isSerialized] = - (tc >= 10000); /* TRANSACTION, LEDGER_ENTRY, VALIDATION, METADATA */ - - innerObj[jss::isSigningField] = - f->shouldInclude(false); + innerObj[jss::isSerialized] = + (tc >= + 10000); /* TRANSACTION, LEDGER_ENTRY, VALIDATION, METADATA */ - innerObj[jss::type] = - type_map[tc]; + innerObj[jss::isSigningField] = f->shouldInclude(false); + + innerObj[jss::type] = type_map[tc]; Json::Value innerArray = Json::arrayValue; innerArray[0U] = f->fieldName; @@ -304,7 +299,7 @@ private: ret[jss::FIELDS][i++] = innerArray; } - + ret[jss::TRANSACTION_RESULTS] = Json::objectValue; for (auto [value, name] : magic_enum::enum_entries()) ret[jss::TRANSACTION_RESULTS][STR(name)] = std::stoi(STR(value)); @@ -318,19 +313,35 @@ private: ret[jss::TRANSACTION_RESULTS][STR(name)] = std::stoi(STR(value)); for (auto [value, name] : magic_enum::enum_entries()) ret[jss::TRANSACTION_RESULTS][STR(name)] = std::stoi(STR(value)); - + ret[jss::TRANSACTION_TYPES] = Json::objectValue; ret[jss::TRANSACTION_TYPES][jss::Invalid] = -1; for (auto [value, name] : magic_enum::enum_entries()) - ret[jss::TRANSACTION_TYPES][translate(STR(name).substr(2))] = std::stoi(STR(value)); + ret[jss::TRANSACTION_TYPES][translate(STR(name).substr(2))] = + std::stoi(STR(value)); + + // generate hash + { + const std::string out = Json::FastWriter().write(ret); + defsHash = + ripple::sha512Half(ripple::Slice{out.data(), out.size()}); + ret[jss::hash] = to_string(*defsHash); + } return ret; } + std::optional defsHash; Json::Value defs; public: - Definitions() : defs(generate()) {}; + Definitions() : defs(generate()){}; + + bool + hashMatches(uint256 hash) const + { + return defsHash && *defsHash == hash; + } Json::Value const& operator()(void) const @@ -339,12 +350,27 @@ public: } }; - - Json::Value doServerDefinitions(RPC::JsonContext& context) { + auto& params = context.params; + + uint256 hash; + if (params.isMember(jss::hash)) + { + if (!params[jss::hash].isString() || + !hash.parseHex(params[jss::hash].asString())) + return RPC::invalid_field_error(jss::hash); + } + static const Definitions defs{}; + if (defs.hashMatches(hash)) + { + Json::Value jv = Json::objectValue; + jv[jss::hash] = to_string(hash); + return jv; + } + return defs(); } diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/ripple/rpc/impl/Handler.cpp index f5dbd0b85..14226abf2 100644 --- a/src/ripple/rpc/impl/Handler.cpp +++ b/src/ripple/rpc/impl/Handler.cpp @@ -146,7 +146,9 @@ Handler const handlerArray[]{ byRef(&doSubmitMultiSigned), Role::USER, NEEDS_CURRENT_LEDGER}, - {"server_definitions", byRef(&doServerDefinitions), Role::USER, NO_CONDITION}, + byRef(&doServerDefinitions), + Role::USER, + NO_CONDITION}, {"server_info", byRef(&doServerInfo), Role::USER, NO_CONDITION}, {"server_state", byRef(&doServerState), Role::USER, NO_CONDITION}, {"crawl_shards", byRef(&doCrawlShards), Role::ADMIN, NO_CONDITION},