mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-09 13:18:09 +00:00
refactor: Migrate handlers to rpc-spec (A) (#8345)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/LedgerHeader.h>
|
||||
#include <xrpl/protocol/LedgerShortcut.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/TxMeta.h>
|
||||
#include <xrpl/protocol/TxSearched.h>
|
||||
@@ -105,21 +104,6 @@ public:
|
||||
using TxnMetaLedgerType = std::tuple<Blob, Blob, std::uint32_t>;
|
||||
using MetaTxsList = std::vector<TxnMetaLedgerType>;
|
||||
|
||||
using LedgerSequence = uint32_t;
|
||||
using LedgerHash = UInt256;
|
||||
using LedgerSpecifier = std::variant<LedgerRange, LedgerShortcut, LedgerSequence, LedgerHash>;
|
||||
|
||||
struct AccountTxArgs
|
||||
{
|
||||
AccountID account;
|
||||
std::optional<LedgerSpecifier> ledger;
|
||||
bool binary = false;
|
||||
bool forward = false;
|
||||
uint32_t limit = 0;
|
||||
std::optional<AccountTxMarker> marker;
|
||||
std::optional<DelegateFilter> delegate;
|
||||
};
|
||||
|
||||
struct AccountTxResult
|
||||
{
|
||||
std::variant<AccountTxs, MetaTxsList> transactions;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <xrpld/rpc/MethodNames.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
#include <xrpld/rpc/Status.h>
|
||||
#include <xrpld/rpc/detail/SpecBridge.hpp>
|
||||
#include <xrpld/rpc/handlers/Handlers.h>
|
||||
#include <xrpld/rpc/handlers/ledger/Ledger.h>
|
||||
#include <xrpld/rpc/handlers/server_info/Version.h>
|
||||
@@ -12,10 +13,16 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
|
||||
#include <rpcspec/Errors.hpp>
|
||||
#include <rpcspec/Types.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <expected>
|
||||
#include <iterator>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
@@ -49,7 +56,34 @@ byRef(JsonContext& context, json::Value& result)
|
||||
return Status();
|
||||
}
|
||||
|
||||
template <typename HandlerImpl>
|
||||
concept SpecBasedHandler = std::derived_from<HandlerImpl, HandlerFor<typename HandlerImpl::Input>>;
|
||||
|
||||
template <typename HandlerImpl>
|
||||
concept InputlessHandler = requires(HandlerImpl& handler) { handler.process(); };
|
||||
|
||||
template <class HandlerImpl, class Output>
|
||||
Status
|
||||
respond(
|
||||
HandlerImpl const& handler,
|
||||
json::Value& object,
|
||||
std::expected<Output, ::rpc::Status> const& output,
|
||||
::rpc::spec::Warnings const& warnings)
|
||||
{
|
||||
if (not output.has_value())
|
||||
{
|
||||
injectSpecError(object, output.error());
|
||||
return std::get<ErrorCodeI>(output.error().code);
|
||||
}
|
||||
|
||||
handler.writeResult(object, *output);
|
||||
injectSpecWarnings(object, warnings);
|
||||
|
||||
return Status::kOK;
|
||||
}
|
||||
|
||||
template <class HandlerImpl>
|
||||
requires SpecBasedHandler<HandlerImpl> or InputlessHandler<HandlerImpl>
|
||||
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<HandlerImpl>)
|
||||
{
|
||||
status.inject(object);
|
||||
auto const input = HandlerImpl::parseInput(context.params, context.apiVersion);
|
||||
if (not input.has_value())
|
||||
{
|
||||
injectSpecError(object, input.error());
|
||||
return std::get<ErrorCodeI>(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 <typename HandlerImpl>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/LedgerShortcut.h>
|
||||
#include <xrpl/protocol/RPCErr.h>
|
||||
#include <xrpl/protocol/RippleLedgerHash.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
@@ -25,15 +24,28 @@
|
||||
#include <org/xrpl/rpc/v1/get_ledger_data.pb.h> // IWYU pragma: keep
|
||||
#include <org/xrpl/rpc/v1/get_ledger_entry.pb.h> // IWYU pragma: keep
|
||||
#include <org/xrpl/rpc/v1/ledger.pb.h>
|
||||
#include <rpcspec/Ledger.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace xrpl::rpc {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename... Ts>
|
||||
struct Overload : Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
|
||||
constexpr Overload(Ts&&... ts) : Ts(std::forward<Ts>(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 <class T>
|
||||
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 <class T>
|
||||
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<ReadView const>&, uint32_t, Context const&);
|
||||
|
||||
template Status
|
||||
getLedger<>(std::shared_ptr<ReadView const>&, LedgerShortcut shortcut, Context const&);
|
||||
getLedger<>(std::shared_ptr<ReadView const>&, ::rpc::spec::LedgerShortcut shortcut, Context const&);
|
||||
|
||||
template Status
|
||||
getLedger<>(std::shared_ptr<ReadView const>&, UInt256 const&, Context const&);
|
||||
|
||||
template Status
|
||||
getLedger<>(std::shared_ptr<ReadView const>&, ::rpc::spec::LedgerSpecifier const&, Context const&);
|
||||
|
||||
// explicit instantiation of ledgerFromSpecifier
|
||||
template Status
|
||||
ledgerFromSpecifier<>(
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/ledger/Ledger.h>
|
||||
#include <xrpl/protocol/LedgerShortcut.h>
|
||||
#include <xrpl/server/NetworkOPs.h>
|
||||
|
||||
#include <org/xrpl/rpc/v1/ledger.pb.h>
|
||||
#include <rpcspec/Ledger.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
@@ -76,7 +76,22 @@ getLedger(T& ledger, uint32_t ledgerIndex, Context const& context);
|
||||
*/
|
||||
template <class T>
|
||||
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 <class T>
|
||||
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
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpld/rpc/detail/JsonObjectView.hpp>
|
||||
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <rpcspec/Errors.hpp>
|
||||
#include <rpcspec/HandlerFor.hpp>
|
||||
#include <rpcspec/Types.hpp>
|
||||
|
||||
#include <map>
|
||||
@@ -12,6 +16,22 @@
|
||||
|
||||
namespace xrpl::rpc {
|
||||
|
||||
template <typename InputT>
|
||||
using HandlerFor = ::rpc::spec::HandlerFor<InputT, json::Value>;
|
||||
|
||||
inline void
|
||||
injectSpecError(json::Value& object, ::rpc::Status const& status)
|
||||
{
|
||||
if (auto const code = std::get<ErrorCodeI>(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.
|
||||
//
|
||||
|
||||
@@ -20,13 +20,14 @@
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/LedgerShortcut.h>
|
||||
#include <xrpl/protocol/RPCErr.h>
|
||||
#include <xrpl/protocol/RippleLedgerHash.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/rdb/RelationalDatabase.h>
|
||||
#include <xrpl/resource/Fees.h>
|
||||
|
||||
#include <rpcspec/Ledger.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
@@ -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<LedgerRange, ::rpc::spec::LedgerShortcut, std::uint32_t, uint256>;
|
||||
|
||||
struct AccountTxArgs
|
||||
{
|
||||
AccountID account;
|
||||
std::optional<LedgerSpecifier> ledger;
|
||||
bool binary = false;
|
||||
bool forward = false;
|
||||
uint32_t limit = 0;
|
||||
std::optional<RelationalDatabase::AccountTxMarker> marker;
|
||||
std::optional<DelegateFilter> delegate;
|
||||
};
|
||||
|
||||
// parses args into a ledger specifier, or returns a Json object on error
|
||||
std::variant<std::optional<LedgerSpecifier>, 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
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
@@ -19,11 +20,11 @@
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/resource/Fees.h>
|
||||
#include <xrpl/server/LoadFeeTrack.h>
|
||||
#include <xrpl/shamap/SHAMap.h>
|
||||
|
||||
#include <grpcpp/support/status.h>
|
||||
#include <org/xrpl/rpc/v1/get_ledger.pb.h>
|
||||
#include <rpcspec/Errors.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
@@ -40,126 +41,83 @@ LedgerHandler::LedgerHandler(JsonContext& context) : context_(context)
|
||||
{
|
||||
}
|
||||
|
||||
Status
|
||||
LedgerHandler::check()
|
||||
std::expected<LedgerHandler::Output, ::rpc::Status>
|
||||
LedgerHandler::process(Input const& input)
|
||||
{
|
||||
auto const& params = context_.params;
|
||||
Output output;
|
||||
output.options = (input.full ? static_cast<int>(LedgerFill::Options::Full) : 0) |
|
||||
(input.expand ? static_cast<int>(LedgerFill::Options::Expand) : 0) |
|
||||
(input.transactions ? static_cast<int>(LedgerFill::Options::DumpTxrp) : 0) |
|
||||
(input.accounts ? static_cast<int>(LedgerFill::Options::DumpState) : 0) |
|
||||
(input.binary ? static_cast<int>(LedgerFill::Options::Binary) : 0) |
|
||||
(input.ownerFunds ? static_cast<int>(LedgerFill::Options::OwnerFunds) : 0) |
|
||||
(input.queue ? static_cast<int>(LedgerFill::Options::DumpQueue) : 0);
|
||||
|
||||
auto getBool = [&](json::StaticString const& field) -> std::expected<bool, Status> {
|
||||
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<int>(LedgerFill::Options::Full) : 0) |
|
||||
(*expand ? static_cast<int>(LedgerFill::Options::Expand) : 0) |
|
||||
(*transactions ? static_cast<int>(LedgerFill::Options::DumpTxrp) : 0) |
|
||||
(*accounts ? static_cast<int>(LedgerFill::Options::DumpState) : 0) |
|
||||
(*binary ? static_cast<int>(LedgerFill::Options::Binary) : 0) |
|
||||
(*ownerFunds ? static_cast<int>(LedgerFill::Options::OwnerFunds) : 0) |
|
||||
(*queue ? static_cast<int>(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
|
||||
|
||||
@@ -5,13 +5,18 @@
|
||||
#include <xrpld/rpc/Context.h>
|
||||
#include <xrpld/rpc/MethodNames.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
#include <xrpld/rpc/Status.h>
|
||||
#include <xrpld/rpc/detail/Handler.h>
|
||||
#include <xrpld/rpc/detail/SpecBridge.hpp>
|
||||
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
|
||||
#include <rpcspec/Errors.hpp>
|
||||
#include <rpcspec/handlers/ledger/Types.hpp>
|
||||
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -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<ReadView const> ledger;
|
||||
std::vector<TxQ::TxDetails> queueTxs;
|
||||
int options = 0;
|
||||
};
|
||||
|
||||
explicit LedgerHandler(JsonContext&);
|
||||
|
||||
Status
|
||||
check();
|
||||
[[nodiscard]] std::expected<Output, ::rpc::Status>
|
||||
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<ReadView const> ledger_;
|
||||
std::vector<TxQ::TxDetails> queueTxs_;
|
||||
json::Value result_;
|
||||
int options_ = 0;
|
||||
std::reference_wrapper<JsonContext> context_;
|
||||
};
|
||||
|
||||
} // namespace xrpl::rpc
|
||||
|
||||
@@ -4,12 +4,16 @@
|
||||
#include <xrpld/rpc/Context.h>
|
||||
#include <xrpld/rpc/MethodNames.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
#include <xrpld/rpc/Status.h>
|
||||
#include <xrpld/rpc/detail/Handler.h>
|
||||
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
|
||||
#include <rpcspec/Errors.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
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<Output, ::rpc::Status>
|
||||
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<JsonContext> context_;
|
||||
};
|
||||
|
||||
} // namespace xrpl::rpc
|
||||
|
||||
Reference in New Issue
Block a user