From 2ebd745a1b46a8a82d3e8680a5b17315b4cec75f Mon Sep 17 00:00:00 2001 From: Alex Kremer Date: Tue, 6 Oct 2026 13:19:20 +0000 Subject: [PATCH] refactor: Migrate handlers to rpc-spec (A) (#8345) --- cmake/XrplCore.cmake | 8 ++ conan.lock | 2 +- conanfile.py | 2 +- include/xrpl/protocol/LedgerShortcut.h | 28 ---- include/xrpl/rdb/RelationalDatabase.h | 16 --- src/test/rpc/AccountTx_test.cpp | 16 +++ src/test/rpc/LedgerRPC_test.cpp | 13 ++ src/tests/xrpld/rpc/SpecBridge.cpp | 14 ++ src/xrpld/rpc/detail/Handler.cpp | 56 +++++++- src/xrpld/rpc/detail/RPCLedgerHelpers.cpp | 57 ++++++-- src/xrpld/rpc/detail/RPCLedgerHelpers.h | 19 ++- src/xrpld/rpc/detail/SpecBridge.hpp | 20 +++ src/xrpld/rpc/handlers/account/AccountTx.cpp | 28 +++- src/xrpld/rpc/handlers/ledger/Ledger.cpp | 134 +++++++------------ src/xrpld/rpc/handlers/ledger/Ledger.h | 28 ++-- src/xrpld/rpc/handlers/server_info/Version.h | 33 +++-- 16 files changed, 291 insertions(+), 183 deletions(-) delete mode 100644 include/xrpl/protocol/LedgerShortcut.h diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake index 228a55e57e..f3713b3b00 100644 --- a/cmake/XrplCore.cmake +++ b/cmake/XrplCore.cmake @@ -292,6 +292,14 @@ if(xrpld) ) target_sources(xrpld PRIVATE ${sources}) + rpcspec_generate_instantiations( + OUT_VAR rpcspec_instantiations + VALUE_TYPE "::json::Value" + VIEW_HEADER "xrpld/rpc/detail/JsonObjectView.hpp" + HANDLERS ledger + ) + target_sources(xrpld PRIVATE ${rpcspec_instantiations}) + if(tests) file( GLOB_RECURSE sources diff --git a/conan.lock b/conan.lock index 01d4079c36..1a4a0e7817 100644 --- a/conan.lock +++ b/conan.lock @@ -3,7 +3,7 @@ "requires": [ "zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708", "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688", - "xrpl-rpc-spec/0.1.19#870b2d3abcfbbf13b61c2d3c69495060%1790348286.187549", + "xrpl-rpc-spec/0.1.20#6daa13eeb4e6c92b82ea6d78866e1da8%1790720024.368048", "sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447", "soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521", "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168", diff --git a/conanfile.py b/conanfile.py index ccab522b95..a1aa248c93 100644 --- a/conanfile.py +++ b/conanfile.py @@ -40,7 +40,7 @@ class Xrpl(ConanFile): "nudb/2.0.9", "openssl/3.6.3", "soci/4.0.3", - "xrpl-rpc-spec/0.1.19", + "xrpl-rpc-spec/0.1.20", "zlib/1.3.2", ] diff --git a/include/xrpl/protocol/LedgerShortcut.h b/include/xrpl/protocol/LedgerShortcut.h deleted file mode 100644 index 037621121d..0000000000 --- a/include/xrpl/protocol/LedgerShortcut.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -namespace xrpl { - -/** - * @brief Enumeration of ledger shortcuts for specifying which ledger to use. - * - * These shortcuts provide a convenient way to reference commonly used ledgers - * without needing to specify their exact hash or sequence number. - */ -enum class LedgerShortcut { - /** - * The current working ledger (open, not yet closed) - */ - Current, - - /** - * The most recently closed ledger (may not be validated) - */ - Closed, - - /** - * The most recently validated ledger - */ - Validated -}; - -} // namespace xrpl diff --git a/include/xrpl/rdb/RelationalDatabase.h b/include/xrpl/rdb/RelationalDatabase.h index 3e96c36356..e59b7a5ed7 100644 --- a/include/xrpl/rdb/RelationalDatabase.h +++ b/include/xrpl/rdb/RelationalDatabase.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -105,21 +104,6 @@ public: using TxnMetaLedgerType = std::tuple; using MetaTxsList = std::vector; - using LedgerSequence = uint32_t; - using LedgerHash = UInt256; - using LedgerSpecifier = std::variant; - - struct AccountTxArgs - { - AccountID account; - std::optional ledger; - bool binary = false; - bool forward = false; - uint32_t limit = 0; - std::optional marker; - std::optional delegate; - }; - struct AccountTxResult { std::variant transactions; diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index 735c318b21..7e61ce6577 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -319,6 +319,22 @@ class AccountTx_test : public beast::unit_test::Suite BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrNotFound)); } + { + json::Value p{jParams}; + + p[jss::ledger_index] = "validated"; + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + + p[jss::ledger_index] = "closed"; + BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p)))); + + p[jss::ledger_index] = "current"; + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrNotValidated)); + + p[jss::ledger_index] = ""; + BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrNotValidated)); + } + // Ledger Hash { json::Value p{jParams}; diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 82918a39c0..2ee8d58cf3 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -103,6 +103,19 @@ class LedgerRPC_test : public beast::unit_test::Suite jrr[jss::ledger][jss::ledger_index] == std::to_string(env.current()->header().seq)); BEAST_EXPECT(jrr[jss::ledger_current_index] == env.current()->header().seq); } + + { + auto const jrr = env.rpc("json", "ledger", "{}")[jss::result]; + BEAST_EXPECT(!jrr.isMember(jss::ledger)); + BEAST_EXPECT(jrr[jss::closed][jss::ledger][jss::closed] == true); + BEAST_EXPECT( + jrr[jss::closed][jss::ledger][jss::ledger_index] == + std::to_string(env.closed()->header().seq)); + BEAST_EXPECT(jrr[jss::open][jss::ledger][jss::closed] == false); + BEAST_EXPECT( + jrr[jss::open][jss::ledger][jss::ledger_index] == + std::to_string(env.current()->header().seq)); + } } void diff --git a/src/tests/xrpld/rpc/SpecBridge.cpp b/src/tests/xrpld/rpc/SpecBridge.cpp index 149b95122f..d7cacba665 100644 --- a/src/tests/xrpld/rpc/SpecBridge.cpp +++ b/src/tests/xrpld/rpc/SpecBridge.cpp @@ -311,6 +311,20 @@ TEST(SpecBridge, shared_spec_warns_on_a_deprecated_field) EXPECT_EQ(warnings[0].code, ::rpc::WarningCode::WarnRpcDeprecated); } +TEST(SpecBridge, inject_spec_error_uses_default_message) +{ + json::Value out{json::ValueType::Object}; + rpc::injectSpecError(out, ::rpc::Status{RpcLgrNotFound}); + EXPECT_EQ(out, rpc::makeError(RpcLgrNotFound)); +} + +TEST(SpecBridge, inject_spec_error_uses_custom_message) +{ + json::Value out{json::ValueType::Object}; + rpc::injectSpecError(out, ::rpc::Status{RpcInvalidParams, "Invalid field 'ledger'."}); + EXPECT_EQ(out, rpc::makeError(RpcInvalidParams, "Invalid field 'ledger'.")); +} + TEST(SpecBridge, inject_spec_warnings) { std::string const kDeprecatedBase{ diff --git a/src/xrpld/rpc/detail/Handler.cpp b/src/xrpld/rpc/detail/Handler.cpp index 3c0b41a149..ca4fbe762e 100644 --- a/src/xrpld/rpc/detail/Handler.cpp +++ b/src/xrpld/rpc/detail/Handler.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -12,10 +13,16 @@ #include #include #include +#include + +#include +#include #include #include +#include #include +#include #include #include #include @@ -49,7 +56,34 @@ byRef(JsonContext& context, json::Value& result) return Status(); } +template +concept SpecBasedHandler = std::derived_from>; + +template +concept InputlessHandler = requires(HandlerImpl& handler) { handler.process(); }; + +template +Status +respond( + HandlerImpl const& handler, + json::Value& object, + std::expected const& output, + ::rpc::spec::Warnings const& warnings) +{ + if (not output.has_value()) + { + injectSpecError(object, output.error()); + return std::get(output.error().code); + } + + handler.writeResult(object, *output); + injectSpecWarnings(object, warnings); + + return Status::kOK; +} + template + requires SpecBasedHandler or InputlessHandler Status handle(JsonContext& context, json::Value& object) { @@ -57,18 +91,28 @@ handle(JsonContext& context, json::Value& object) context.apiVersion >= HandlerImpl::minApiVer && context.apiVersion <= HandlerImpl::maxApiVer, "xrpl::rpc::handle : valid API version"); - HandlerImpl handler(context); - auto status = handler.check(); - if (status) + if constexpr (SpecBasedHandler) { - status.inject(object); + auto const input = HandlerImpl::parseInput(context.params, context.apiVersion); + if (not input.has_value()) + { + injectSpecError(object, input.error()); + return std::get(input.error().code); + } + + HandlerImpl handler(context); + auto const output = handler.process(*input); + auto const warnings = output.has_value() + ? HandlerImpl::spec(context.apiVersion).check(context.params) + : ::rpc::spec::Warnings{}; + return respond(handler, object, output, warnings); } else { - handler.writeResult(object); + HandlerImpl handler(context); + return respond(handler, object, handler.process(), /* warnings= */ {}); } - return status; } template diff --git a/src/xrpld/rpc/detail/RPCLedgerHelpers.cpp b/src/xrpld/rpc/detail/RPCLedgerHelpers.cpp index 837bc61610..cf7ab843cb 100644 --- a/src/xrpld/rpc/detail/RPCLedgerHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCLedgerHelpers.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -25,15 +24,28 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep #include +#include #include #include #include +#include +#include namespace xrpl::rpc { namespace { +template +struct Overload : Ts... +{ + using Ts::operator()...; + + constexpr Overload(Ts&&... ts) : Ts(std::forward(ts))... + { + } +}; + bool isValidatedOld(LedgerMaster& ledgerMaster, bool standalone) { @@ -68,13 +80,13 @@ ledgerFromIndex( auto const index = indexValue.asString(); if (index == "current" || index.empty()) - return getLedger(ledger, LedgerShortcut::Current, context); + return getLedger(ledger, ::rpc::spec::LedgerShortcut::Current, context); if (index == "validated") - return getLedger(ledger, LedgerShortcut::Validated, context); + return getLedger(ledger, ::rpc::spec::LedgerShortcut::Validated, context); if (index == "closed") - return getLedger(ledger, LedgerShortcut::Closed, context); + return getLedger(ledger, ::rpc::spec::LedgerShortcut::Closed, context); std::uint32_t iVal = 0; if (!beast::lexicalCastChecked(iVal, index)) @@ -146,7 +158,7 @@ ledgerFromRequest(T& ledger, JsonContext const& context) } // nothing specified, `index` has a default setting - return getLedger(ledger, LedgerShortcut::Current, context); + return getLedger(ledger, ::rpc::spec::LedgerShortcut::Current, context); } } // namespace @@ -204,17 +216,17 @@ ledgerFromSpecifier( auto const shortcut = specifier.shortcut(); if (shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED) { - return getLedger(ledger, LedgerShortcut::Validated, context); + return getLedger(ledger, ::rpc::spec::LedgerShortcut::Validated, context); } if (shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT || shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED) { - return getLedger(ledger, LedgerShortcut::Current, context); + return getLedger(ledger, ::rpc::spec::LedgerShortcut::Current, context); } if (shortcut == org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED) { - return getLedger(ledger, LedgerShortcut::Closed, context); + return getLedger(ledger, ::rpc::spec::LedgerShortcut::Closed, context); } } } @@ -263,7 +275,7 @@ getLedger(T& ledger, uint32_t ledgerIndex, Context const& context) template Status -getLedger(T& ledger, LedgerShortcut shortcut, Context const& context) +getLedger(T& ledger, ::rpc::spec::LedgerShortcut shortcut, Context const& context) { if (isValidatedOld(context.ledgerMaster, context.app.config().standalone())) { @@ -272,7 +284,7 @@ getLedger(T& ledger, LedgerShortcut shortcut, Context const& context) return {RpcNotSynced, "notSynced"}; } - if (shortcut == LedgerShortcut::Validated) + if (shortcut == ::rpc::spec::LedgerShortcut::Validated) { ledger = context.ledgerMaster.getValidatedLedger(); if (ledger == nullptr) @@ -286,12 +298,12 @@ getLedger(T& ledger, LedgerShortcut shortcut, Context const& context) } else { - if (shortcut == LedgerShortcut::Current) + if (shortcut == ::rpc::spec::LedgerShortcut::Current) { ledger = context.ledgerMaster.getCurrentLedger(); XRPL_ASSERT(ledger->open(), "xrpl::rpc::getLedger : current is open"); } - else if (shortcut == LedgerShortcut::Closed) + else if (shortcut == ::rpc::spec::LedgerShortcut::Closed) { ledger = context.ledgerMaster.getClosedLedger(); XRPL_ASSERT(!ledger->open(), "xrpl::rpc::getLedger : closed is not open"); @@ -321,16 +333,33 @@ getLedger(T& ledger, LedgerShortcut shortcut, Context const& context) return Status::kOK; } -// Explicit instantiation of above three functions +template +Status +getLedger(T& ledger, ::rpc::spec::LedgerSpecifier const& specifier, Context const& context) +{ + return std::visit( + Overload{ + [&](std::monostate) { + return getLedger(ledger, ::rpc::spec::kDefaultLedgerShortcut, context); + }, + [&](auto const& value) { return getLedger(ledger, value, context); }, + }, + specifier.value); +} + +// Explicit instantiation of above four functions template Status getLedger<>(std::shared_ptr&, uint32_t, Context const&); template Status -getLedger<>(std::shared_ptr&, LedgerShortcut shortcut, Context const&); +getLedger<>(std::shared_ptr&, ::rpc::spec::LedgerShortcut shortcut, Context const&); template Status getLedger<>(std::shared_ptr&, UInt256 const&, Context const&); +template Status +getLedger<>(std::shared_ptr&, ::rpc::spec::LedgerSpecifier const&, Context const&); + // explicit instantiation of ledgerFromSpecifier template Status ledgerFromSpecifier<>( diff --git a/src/xrpld/rpc/detail/RPCLedgerHelpers.h b/src/xrpld/rpc/detail/RPCLedgerHelpers.h index 8249a5913d..15a35dee91 100644 --- a/src/xrpld/rpc/detail/RPCLedgerHelpers.h +++ b/src/xrpld/rpc/detail/RPCLedgerHelpers.h @@ -7,10 +7,10 @@ #include #include #include -#include #include #include +#include #include #include @@ -76,7 +76,22 @@ getLedger(T& ledger, uint32_t ledgerIndex, Context const& context); */ template Status -getLedger(T& ledger, LedgerShortcut shortcut, Context const& context); +getLedger(T& ledger, ::rpc::spec::LedgerShortcut shortcut, Context const& context); + +/** + * @brief Retrieves the ledger a spec-parsed request selects. + * + * An unspecified selection means the current ledger. + * + * @tparam T Type of the ledger pointer to be filled. + * @param ledger Reference to the ledger pointer to be filled. + * @param specifier The ledger the request selects. + * @param context The RPC context. + * @return Status indicating success or failure of the operation. + */ +template +Status +getLedger(T& ledger, ::rpc::spec::LedgerSpecifier const& specifier, Context const& context); /** * @brief Looks up a ledger from a request and returns a json::Value with either diff --git a/src/xrpld/rpc/detail/SpecBridge.hpp b/src/xrpld/rpc/detail/SpecBridge.hpp index d89fe9e358..d99d3f777b 100644 --- a/src/xrpld/rpc/detail/SpecBridge.hpp +++ b/src/xrpld/rpc/detail/SpecBridge.hpp @@ -1,9 +1,13 @@ #pragma once +#include + #include +#include #include #include +#include #include #include @@ -12,6 +16,22 @@ namespace xrpl::rpc { +template +using HandlerFor = ::rpc::spec::HandlerFor; + +inline void +injectSpecError(json::Value& object, ::rpc::Status const& status) +{ + if (auto const code = std::get(status.code); status.message.empty()) + { + injectError(code, object); + } + else + { + injectError(code, status.message, object); + } +} + // Warnings are grouped by code into one entry each: the code's standard message followed by // every per-field detail, space separated. // diff --git a/src/xrpld/rpc/handlers/account/AccountTx.cpp b/src/xrpld/rpc/handlers/account/AccountTx.cpp index b1e6542e57..a688223170 100644 --- a/src/xrpld/rpc/handlers/account/AccountTx.cpp +++ b/src/xrpld/rpc/handlers/account/AccountTx.cpp @@ -20,13 +20,14 @@ #include #include #include -#include #include #include #include #include #include +#include + #include #include #include @@ -82,9 +83,24 @@ parseDelegateFilter(json::Value const& delegateNode) using TxnsData = RelationalDatabase::AccountTxs; using TxnsDataBinary = RelationalDatabase::MetaTxsList; using TxnDataBinary = RelationalDatabase::TxnMetaLedgerType; -using AccountTxArgs = RelationalDatabase::AccountTxArgs; using AccountTxResult = RelationalDatabase::AccountTxResult; -using LedgerSpecifier = RelationalDatabase::LedgerSpecifier; + +// Moved here from RelationalDatabase, where nothing but this handler used them, so that +// libxrpl does not depend on the spec for LedgerShortcut. Temporary: the spec's +// account_tx Input replaces both once account_tx is migrated to the spec. +using LedgerSpecifier = + std::variant; + +struct AccountTxArgs +{ + AccountID account; + std::optional ledger; + bool binary = false; + bool forward = false; + uint32_t limit = 0; + std::optional marker; + std::optional delegate; +}; // parses args into a ledger specifier, or returns a Json object on error std::variant, json::Value> @@ -148,15 +164,15 @@ parseLedgerArgs(rpc::Context& context, json::Value const& params) if (ledgerStr == "current" || ledgerStr.empty()) { - ledger = LedgerShortcut::Current; + ledger = ::rpc::spec::LedgerShortcut::Current; } else if (ledgerStr == "closed") { - ledger = LedgerShortcut::Closed; + ledger = ::rpc::spec::LedgerShortcut::Closed; } else if (ledgerStr == "validated") { - ledger = LedgerShortcut::Validated; + ledger = ::rpc::spec::LedgerShortcut::Validated; } else { diff --git a/src/xrpld/rpc/handlers/ledger/Ledger.cpp b/src/xrpld/rpc/handlers/ledger/Ledger.cpp index 51f5bdf348..e6d207ddf4 100644 --- a/src/xrpld/rpc/handlers/ledger/Ledger.cpp +++ b/src/xrpld/rpc/handlers/ledger/Ledger.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -19,11 +20,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -40,126 +41,83 @@ LedgerHandler::LedgerHandler(JsonContext& context) : context_(context) { } -Status -LedgerHandler::check() +std::expected +LedgerHandler::process(Input const& input) { - auto const& params = context_.params; + Output output; + output.options = (input.full ? static_cast(LedgerFill::Options::Full) : 0) | + (input.expand ? static_cast(LedgerFill::Options::Expand) : 0) | + (input.transactions ? static_cast(LedgerFill::Options::DumpTxrp) : 0) | + (input.accounts ? static_cast(LedgerFill::Options::DumpState) : 0) | + (input.binary ? static_cast(LedgerFill::Options::Binary) : 0) | + (input.ownerFunds ? static_cast(LedgerFill::Options::OwnerFunds) : 0) | + (input.queue ? static_cast(LedgerFill::Options::DumpQueue) : 0); - auto getBool = [&](json::StaticString const& field) -> std::expected { - if (!params.isMember(field)) - { - return false; - } - if (!params[field].isBool()) - { - return std::unexpected(RpcInvalidParams); - } + if (input.ledger.isUnspecified()) + return output; - return params[field].asBool(); - }; + if (auto const status = getLedger(output.ledger, input.ledger, context_.get())) + return std::unexpected{::rpc::Status{status.toErrorCode(), status.message()}}; - auto const full = getBool(jss::full); - auto const transactions = getBool(jss::transactions); - auto const accounts = getBool(jss::accounts); - auto const expand = getBool(jss::expand); - auto const binary = getBool(jss::binary); - auto const ownerFunds = getBool(jss::owner_funds); - auto const queue = getBool(jss::queue); - - if (!full.has_value()) - return full.error(); - if (!transactions.has_value()) - return transactions.error(); - if (!accounts.has_value()) - return accounts.error(); - if (!expand.has_value()) - return expand.error(); - if (!binary.has_value()) - return binary.error(); - if (!ownerFunds.has_value()) - return ownerFunds.error(); - if (!queue.has_value()) - return queue.error(); - - options_ = (*full ? static_cast(LedgerFill::Options::Full) : 0) | - (*expand ? static_cast(LedgerFill::Options::Expand) : 0) | - (*transactions ? static_cast(LedgerFill::Options::DumpTxrp) : 0) | - (*accounts ? static_cast(LedgerFill::Options::DumpState) : 0) | - (*binary ? static_cast(LedgerFill::Options::Binary) : 0) | - (*ownerFunds ? static_cast(LedgerFill::Options::OwnerFunds) : 0) | - (*queue ? static_cast(LedgerFill::Options::DumpQueue) : 0); - - bool const needsLedger = params.isMember(jss::ledger) || params.isMember(jss::ledger_hash) || - params.isMember(jss::ledger_index); - if (!needsLedger) - return Status::kOK; - if (auto s = lookupLedger(ledger_, context_, result_)) - return s; - - if (*full || *accounts) + if (input.full || input.accounts) { // Until some sane way to get full ledgers has been implemented, // disallow retrieving all state nodes. - if (!isUnlimited(context_.role)) - return RpcNoPermission; + if (!isUnlimited(context_.get().role)) + return std::unexpected{::rpc::Status{RpcNoPermission}}; - if (context_.app.getFeeTrack().isLoadedLocal() && !isUnlimited(context_.role)) - { - return RpcTooBusy; - } - context_.loadType = binary ? resource::kFeeMediumBurdenRpc : resource::kFeeHeavyBurdenRpc; + context_.get().loadType = + input.binary ? resource::kFeeMediumBurdenRpc : resource::kFeeHeavyBurdenRpc; } - if (*queue) + if (input.queue) { - if (!ledger_ || !ledger_->open()) + if (!output.ledger || !output.ledger->open()) { // It doesn't make sense to request the queue // with a non-existent or closed/validated ledger. - return RpcInvalidParams; + return std::unexpected{::rpc::Status{RpcInvalidParams}}; } - queueTxs_ = context_.app.getTxQ().getTxs(); + output.queueTxs = context_.get().app.getTxQ().getTxs(); } - return Status::kOK; + return output; } void -LedgerHandler::writeResult(json::Value& value) +LedgerHandler::writeResult(json::Value& value, Output const& output) const { - if (ledger_) + if (output.ledger) { - copyFrom(value, result_); - addJson(value, {*ledger_, &context_, options_, queueTxs_}); + auto const& header = output.ledger->header(); + + if (output.ledger->open()) + { + value[jss::ledger_current_index] = header.seq; + } + else + { + value[jss::ledger_hash] = to_string(header.hash); + value[jss::ledger_index] = header.seq; + } + + value[jss::validated] = context_.get().ledgerMaster.isValidated(*output.ledger); + + addJson(value, {*output.ledger, &context_.get(), output.options, output.queueTxs}); } else { - auto& master = context_.app.getLedgerMaster(); + auto& master = context_.get().app.getLedgerMaster(); { auto& closed = value[jss::closed] = json::ValueType::Object; - addJson(closed, {*master.getClosedLedger(), &context_, 0}); + addJson(closed, {*master.getClosedLedger(), &context_.get(), 0}); } { auto& open = value[jss::open] = json::ValueType::Object; - addJson(open, {*master.getCurrentLedger(), &context_, 0}); + addJson(open, {*master.getCurrentLedger(), &context_.get(), 0}); } } - - json::Value warnings{json::ValueType::Array}; - if (context_.params.isMember(jss::type)) - { - json::Value& w = warnings.append(json::ValueType::Object); - w[jss::id] = WarnRpcFieldsDeprecated; - w[jss::message] = - "Some fields from your request are deprecated. Please check the " - "documentation at " - "https://xrpl.org/docs/references/http-websocket-apis/ " - "and update your request. Field `type` is deprecated."; - } - - if (warnings.size() != 0u) - value[jss::warnings] = std::move(warnings); } } // namespace rpc diff --git a/src/xrpld/rpc/handlers/ledger/Ledger.h b/src/xrpld/rpc/handlers/ledger/Ledger.h index b63faa5efa..f79f9aed82 100644 --- a/src/xrpld/rpc/handlers/ledger/Ledger.h +++ b/src/xrpld/rpc/handlers/ledger/Ledger.h @@ -5,13 +5,18 @@ #include #include #include -#include #include +#include #include #include #include +#include +#include + +#include +#include #include #include #include @@ -26,16 +31,23 @@ struct JsonContext; // full: true | false // optional, defaults to false. // } -class LedgerHandler +class LedgerHandler : public HandlerFor<::rpc::spec::handlers::ledger::Input> { public: + struct Output + { + std::shared_ptr ledger; + std::vector queueTxs; + int options = 0; + }; + explicit LedgerHandler(JsonContext&); - Status - check(); + [[nodiscard]] std::expected + process(Input const& input); void - writeResult(json::Value&); + writeResult(json::Value& value, Output const& output) const; // NOLINTBEGIN(readability-identifier-naming) static constexpr std::string_view name = method::kLedger; @@ -50,11 +62,7 @@ public: // NOLINTEND(readability-identifier-naming) private: - JsonContext& context_; - std::shared_ptr ledger_; - std::vector queueTxs_; - json::Value result_; - int options_ = 0; + std::reference_wrapper context_; }; } // namespace xrpl::rpc diff --git a/src/xrpld/rpc/handlers/server_info/Version.h b/src/xrpld/rpc/handlers/server_info/Version.h index 98c9fa987c..fe134af266 100644 --- a/src/xrpld/rpc/handlers/server_info/Version.h +++ b/src/xrpld/rpc/handlers/server_info/Version.h @@ -4,12 +4,16 @@ #include #include #include -#include #include #include #include +#include + +#include +#include +#include #include namespace xrpl::rpc { @@ -17,21 +21,29 @@ namespace xrpl::rpc { class VersionHandler { public: - explicit VersionHandler(JsonContext& c) - : apiVersion_(c.apiVersion), betaEnabled_(c.app.config().betaRpcApi) + struct Output + { + std::uint32_t apiVersion; + bool betaEnabled; + }; + + explicit VersionHandler(JsonContext& context) : context_(context) { } - static Status - check() + [[nodiscard]] std::expected + process() const { - return Status::kOK; + return Output{ + .apiVersion = context_.get().apiVersion, + .betaEnabled = context_.get().app.config().betaRpcApi, + }; } - void - writeResult(json::Value& obj) const + static void + writeResult(json::Value& obj, Output const& output) { - setVersion(obj, apiVersion_, betaEnabled_); + setVersion(obj, output.apiVersion, output.betaEnabled); } // NOLINTBEGIN(readability-identifier-naming) @@ -47,8 +59,7 @@ public: // NOLINTEND(readability-identifier-naming) private: - unsigned int apiVersion_; - bool betaEnabled_; + std::reference_wrapper context_; }; } // namespace xrpl::rpc