mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
267 lines
10 KiB
C++
267 lines
10 KiB
C++
#include <xrpld/rpc/detail/Handler.h>
|
|
#include <xrpld/rpc/handlers/Handlers.h>
|
|
#include <xrpld/rpc/handlers/server_info/Version.h>
|
|
|
|
#include <xrpl/basics/contract.h>
|
|
#include <xrpl/protocol/ApiVersion.h>
|
|
|
|
#include <map>
|
|
|
|
namespace xrpl {
|
|
namespace RPC {
|
|
namespace {
|
|
|
|
/** Adjust an old-style handler to be call-by-reference. */
|
|
template <typename Function>
|
|
Handler::Method<Json::Value>
|
|
byRef(Function const& f)
|
|
{
|
|
return [f](JsonContext& context, Json::Value& result) {
|
|
result = f(context);
|
|
if (result.type() != Json::objectValue)
|
|
{
|
|
// LCOV_EXCL_START
|
|
UNREACHABLE("xrpl::RPC::byRef : result is object");
|
|
result = RPC::makeObjectValue(result);
|
|
// LCOV_EXCL_STOP
|
|
}
|
|
|
|
return Status();
|
|
};
|
|
}
|
|
|
|
template <class Object, class HandlerImpl>
|
|
Status
|
|
handle(JsonContext& context, Object& object)
|
|
{
|
|
XRPL_ASSERT(
|
|
context.apiVersion >= HandlerImpl::minApiVer &&
|
|
context.apiVersion <= HandlerImpl::maxApiVer,
|
|
"xrpl::RPC::handle : valid API version");
|
|
HandlerImpl handler(context);
|
|
|
|
auto status = handler.check();
|
|
if (status)
|
|
{
|
|
status.inject(object);
|
|
}
|
|
else
|
|
{
|
|
handler.writeResult(object);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
template <typename HandlerImpl>
|
|
Handler
|
|
handlerFrom()
|
|
{
|
|
return {
|
|
HandlerImpl::name,
|
|
&handle<Json::Value, HandlerImpl>,
|
|
HandlerImpl::role,
|
|
HandlerImpl::condition,
|
|
HandlerImpl::minApiVer,
|
|
HandlerImpl::maxApiVer};
|
|
}
|
|
|
|
Handler const handlerArray[]{
|
|
// Some handlers not specified here are added to the table via addHandler()
|
|
// Request-response methods
|
|
{"account_info", byRef(&doAccountInfo), Role::USER, NO_CONDITION},
|
|
{"account_currencies", byRef(&doAccountCurrencies), Role::USER, NO_CONDITION},
|
|
{"account_lines", byRef(&doAccountLines), Role::USER, NO_CONDITION},
|
|
{"account_channels", byRef(&doAccountChannels), Role::USER, NO_CONDITION},
|
|
{"account_nfts", byRef(&doAccountNFTs), Role::USER, NO_CONDITION},
|
|
{"account_objects", byRef(&doAccountObjects), Role::USER, NO_CONDITION},
|
|
{"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
|
|
{"account_tx", byRef(&doAccountTx), Role::USER, NO_CONDITION},
|
|
{"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
|
|
{"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
|
|
{"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},
|
|
{"book_offers", byRef(&doBookOffers), Role::USER, NO_CONDITION},
|
|
{"can_delete", byRef(&doCanDelete), Role::ADMIN, NO_CONDITION},
|
|
{"channel_authorize", byRef(&doChannelAuthorize), Role::USER, NO_CONDITION},
|
|
{"channel_verify", byRef(&doChannelVerify), Role::USER, NO_CONDITION},
|
|
{"connect", byRef(&doConnect), Role::ADMIN, NO_CONDITION},
|
|
{"consensus_info", byRef(&doConsensusInfo), Role::ADMIN, NO_CONDITION},
|
|
{"deposit_authorized", byRef(&doDepositAuthorized), Role::USER, NO_CONDITION},
|
|
{"feature", byRef(&doFeature), Role::USER, NO_CONDITION},
|
|
{"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER},
|
|
{"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION},
|
|
{"gateway_balances", byRef(&doGatewayBalances), Role::USER, NO_CONDITION},
|
|
{"get_counts", byRef(&doGetCounts), Role::ADMIN, NO_CONDITION},
|
|
{"get_aggregate_price", byRef(&doGetAggregatePrice), Role::USER, NO_CONDITION},
|
|
{"ledger_accept", byRef(&doLedgerAccept), Role::ADMIN, NEEDS_CURRENT_LEDGER},
|
|
{"ledger_cleaner", byRef(&doLedgerCleaner), Role::ADMIN, NEEDS_NETWORK_CONNECTION},
|
|
{"ledger_closed", byRef(&doLedgerClosed), Role::USER, NEEDS_CLOSED_LEDGER},
|
|
{"ledger_current", byRef(&doLedgerCurrent), Role::USER, NEEDS_CURRENT_LEDGER},
|
|
{"ledger_data", byRef(&doLedgerData), Role::USER, NO_CONDITION},
|
|
{"ledger_entry", byRef(&doLedgerEntry), Role::USER, NO_CONDITION},
|
|
{"ledger_header", byRef(&doLedgerHeader), Role::USER, NO_CONDITION, 1, 1},
|
|
{"ledger_request", byRef(&doLedgerRequest), Role::ADMIN, NO_CONDITION},
|
|
{"log_level", byRef(&doLogLevel), Role::ADMIN, NO_CONDITION},
|
|
{"logrotate", byRef(&doLogRotate), Role::ADMIN, NO_CONDITION},
|
|
{"manifest", byRef(&doManifest), Role::USER, NO_CONDITION},
|
|
{"nft_buy_offers", byRef(&doNFTBuyOffers), Role::USER, NO_CONDITION},
|
|
{"nft_sell_offers", byRef(&doNFTSellOffers), Role::USER, NO_CONDITION},
|
|
{"noripple_check", byRef(&doNoRippleCheck), Role::USER, NO_CONDITION},
|
|
{"owner_info", byRef(&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER},
|
|
{"peers", byRef(&doPeers), Role::ADMIN, NO_CONDITION},
|
|
{"path_find", byRef(&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER},
|
|
{"ping", byRef(&doPing), Role::USER, NO_CONDITION},
|
|
{"print", byRef(&doPrint), Role::ADMIN, NO_CONDITION},
|
|
// { "profile", byRef (&doProfile), Role::USER,
|
|
// NEEDS_CURRENT_LEDGER },
|
|
{"random", byRef(&doRandom), Role::USER, NO_CONDITION},
|
|
{"peer_reservations_add", byRef(&doPeerReservationsAdd), Role::ADMIN, NO_CONDITION},
|
|
{"peer_reservations_del", byRef(&doPeerReservationsDel), Role::ADMIN, NO_CONDITION},
|
|
{"peer_reservations_list", byRef(&doPeerReservationsList), Role::ADMIN, NO_CONDITION},
|
|
{"ripple_path_find", byRef(&doRipplePathFind), Role::USER, NO_CONDITION},
|
|
{"server_definitions", byRef(&doServerDefinitions), Role::USER, NO_CONDITION},
|
|
{"server_info", byRef(&doServerInfo), Role::USER, NO_CONDITION},
|
|
{"server_state", byRef(&doServerState), Role::USER, NO_CONDITION},
|
|
{"sign", byRef(&doSign), Role::USER, NO_CONDITION},
|
|
{"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION},
|
|
{"simulate", byRef(&doSimulate), Role::USER, NEEDS_CURRENT_LEDGER},
|
|
{"stop", byRef(&doStop), Role::ADMIN, NO_CONDITION},
|
|
{"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER},
|
|
{"submit_multisigned", byRef(&doSubmitMultiSigned), Role::USER, NEEDS_CURRENT_LEDGER},
|
|
{"transaction_entry", byRef(&doTransactionEntry), Role::USER, NO_CONDITION},
|
|
{"tx", byRef(&doTxJson), Role::USER, NEEDS_NETWORK_CONNECTION},
|
|
{"tx_history", byRef(&doTxHistory), Role::USER, NO_CONDITION, 1, 1},
|
|
{"tx_reduce_relay", byRef(&doTxReduceRelay), Role::USER, NO_CONDITION},
|
|
{"unl_list", byRef(&doUnlList), Role::ADMIN, NO_CONDITION},
|
|
{"validation_create", byRef(&doValidationCreate), Role::ADMIN, NO_CONDITION},
|
|
{"validators", byRef(&doValidators), Role::ADMIN, NO_CONDITION},
|
|
{"validator_list_sites", byRef(&doValidatorListSites), Role::ADMIN, NO_CONDITION},
|
|
{"validator_info", byRef(&doValidatorInfo), Role::ADMIN, NO_CONDITION},
|
|
{"vault_info", byRef(&doVaultInfo), Role::USER, NO_CONDITION},
|
|
{"wallet_propose", byRef(&doWalletPropose), Role::ADMIN, NO_CONDITION},
|
|
// Event methods
|
|
{"subscribe", byRef(&doSubscribe), Role::USER, NO_CONDITION},
|
|
{"unsubscribe", byRef(&doUnsubscribe), Role::USER, NO_CONDITION},
|
|
};
|
|
|
|
class HandlerTable
|
|
{
|
|
private:
|
|
using handler_table_t = std::multimap<std::string, Handler>;
|
|
|
|
// Use with equal_range to enforce that API range of a newly added handler
|
|
// does not overlap with API range of an existing handler with same name
|
|
[[nodiscard]] static bool
|
|
overlappingApiVersion(
|
|
std::pair<handler_table_t::iterator, handler_table_t::iterator> range,
|
|
unsigned minVer,
|
|
unsigned maxVer)
|
|
{
|
|
XRPL_ASSERT(minVer <= maxVer, "xrpl::RPC::HandlerTable : valid API version range");
|
|
XRPL_ASSERT(
|
|
maxVer <= RPC::apiMaximumValidVersion,
|
|
"xrpl::RPC::HandlerTable : valid max API version");
|
|
|
|
return std::any_of(
|
|
range.first,
|
|
range.second, //
|
|
[minVer, maxVer](auto const& item) {
|
|
return item.second.minApiVer_ <= maxVer && item.second.maxApiVer_ >= minVer;
|
|
});
|
|
}
|
|
|
|
template <std::size_t N>
|
|
explicit HandlerTable(Handler const (&entries)[N])
|
|
{
|
|
for (auto const& entry : entries)
|
|
{
|
|
if (overlappingApiVersion(
|
|
table_.equal_range(entry.name_), entry.minApiVer_, entry.maxApiVer_))
|
|
{
|
|
LogicError(
|
|
std::string("Handler for ") + entry.name_ +
|
|
" overlaps with an existing handler");
|
|
}
|
|
|
|
table_.insert({entry.name_, entry});
|
|
}
|
|
|
|
// This is where the new-style handlers are added.
|
|
addHandler<LedgerHandler>();
|
|
addHandler<VersionHandler>();
|
|
}
|
|
|
|
public:
|
|
static HandlerTable const&
|
|
instance()
|
|
{
|
|
static HandlerTable const handlerTable(handlerArray);
|
|
return handlerTable;
|
|
}
|
|
|
|
[[nodiscard]] Handler const*
|
|
getHandler(unsigned version, bool betaEnabled, std::string const& name) const
|
|
{
|
|
if (version < RPC::apiMinimumSupportedVersion ||
|
|
version > (betaEnabled ? RPC::apiBetaVersion : RPC::apiMaximumSupportedVersion))
|
|
return nullptr;
|
|
|
|
auto const range = table_.equal_range(name);
|
|
auto const i = std::find_if(range.first, range.second, [version](auto const& entry) {
|
|
return entry.second.minApiVer_ <= version && version <= entry.second.maxApiVer_;
|
|
});
|
|
|
|
return i == range.second ? nullptr : &i->second;
|
|
}
|
|
|
|
[[nodiscard]] std::set<char const*>
|
|
getHandlerNames() const
|
|
{
|
|
std::set<char const*> ret;
|
|
for (auto const& i : table_)
|
|
ret.insert(i.second.name_);
|
|
|
|
return ret;
|
|
}
|
|
|
|
private:
|
|
handler_table_t table_;
|
|
|
|
template <class HandlerImpl>
|
|
void
|
|
addHandler()
|
|
{
|
|
static_assert(HandlerImpl::minApiVer <= HandlerImpl::maxApiVer);
|
|
static_assert(HandlerImpl::maxApiVer <= RPC::apiMaximumValidVersion);
|
|
static_assert(RPC::apiMinimumSupportedVersion <= HandlerImpl::minApiVer);
|
|
|
|
if (overlappingApiVersion(
|
|
table_.equal_range(HandlerImpl::name),
|
|
HandlerImpl::minApiVer,
|
|
HandlerImpl::maxApiVer))
|
|
{
|
|
LogicError(
|
|
std::string("Handler for ") + HandlerImpl::name +
|
|
" overlaps with an existing handler");
|
|
}
|
|
|
|
table_.insert({HandlerImpl::name, handlerFrom<HandlerImpl>()});
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
Handler const*
|
|
getHandler(unsigned version, bool betaEnabled, std::string const& name)
|
|
{
|
|
return HandlerTable::instance().getHandler(version, betaEnabled, name);
|
|
}
|
|
|
|
std::set<char const*>
|
|
getHandlerNames()
|
|
{
|
|
return HandlerTable::instance().getHandlerNames();
|
|
}
|
|
|
|
} // namespace RPC
|
|
} // namespace xrpl
|