rippled
Loading...
Searching...
No Matches
Handler.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/rpc/detail/Handler.h>
21#include <xrpld/rpc/handlers/Handlers.h>
22#include <xrpld/rpc/handlers/Version.h>
23
24#include <xrpl/basics/contract.h>
25
26#include <map>
27
28namespace ripple {
29namespace RPC {
30namespace {
31
33template <typename Function>
34Handler::Method<Json::Value>
35byRef(Function const& f)
36{
37 return [f](JsonContext& context, Json::Value& result) {
38 result = f(context);
39 if (result.type() != Json::objectValue)
40 {
41 // LCOV_EXCL_START
42 UNREACHABLE("ripple::RPC::byRef : result is object");
43 result = RPC::makeObjectValue(result);
44 // LCOV_EXCL_STOP
45 }
46
47 return Status();
48 };
49}
50
51template <class Object, class HandlerImpl>
53handle(JsonContext& context, Object& object)
54{
55 XRPL_ASSERT(
56 context.apiVersion >= HandlerImpl::minApiVer &&
57 context.apiVersion <= HandlerImpl::maxApiVer,
58 "ripple::RPC::handle : valid API version");
59 HandlerImpl handler(context);
60
61 auto status = handler.check();
62 if (status)
63 status.inject(object);
64 else
65 handler.writeResult(object);
66 return status;
67}
68
69template <typename HandlerImpl>
70Handler
71handlerFrom()
72{
73 return {
74 HandlerImpl::name,
75 &handle<Json::Value, HandlerImpl>,
76 HandlerImpl::role,
77 HandlerImpl::condition,
78 HandlerImpl::minApiVer,
79 HandlerImpl::maxApiVer};
80}
81
82Handler const handlerArray[]{
83 // Some handlers not specified here are added to the table via addHandler()
84 // Request-response methods
85 {"account_info", byRef(&doAccountInfo), Role::USER, NO_CONDITION},
86 {"account_currencies",
87 byRef(&doAccountCurrencies),
90 {"account_lines", byRef(&doAccountLines), Role::USER, NO_CONDITION},
91 {"account_channels", byRef(&doAccountChannels), Role::USER, NO_CONDITION},
92 {"account_nfts", byRef(&doAccountNFTs), Role::USER, NO_CONDITION},
93 {"account_objects", byRef(&doAccountObjects), Role::USER, NO_CONDITION},
94 {"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
95 {"account_tx", byRef(&doAccountTxJson), Role::USER, NO_CONDITION},
96 {"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
97 {"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
98 {"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},
99 {"book_offers", byRef(&doBookOffers), Role::USER, NO_CONDITION},
100 {"can_delete", byRef(&doCanDelete), Role::ADMIN, NO_CONDITION},
101 {"channel_authorize", byRef(&doChannelAuthorize), Role::USER, NO_CONDITION},
102 {"channel_verify", byRef(&doChannelVerify), Role::USER, NO_CONDITION},
103 {"connect", byRef(&doConnect), Role::ADMIN, NO_CONDITION},
104 {"consensus_info", byRef(&doConsensusInfo), Role::ADMIN, NO_CONDITION},
105 {"deposit_authorized",
106 byRef(&doDepositAuthorized),
109 {"feature", byRef(&doFeature), Role::USER, NO_CONDITION},
110 {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER},
111 {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION},
112 {"gateway_balances", byRef(&doGatewayBalances), Role::USER, NO_CONDITION},
113 {"get_counts", byRef(&doGetCounts), Role::ADMIN, NO_CONDITION},
114 {"get_aggregate_price",
115 byRef(&doGetAggregatePrice),
118 {"ledger_accept",
119 byRef(&doLedgerAccept),
122 {"ledger_cleaner",
123 byRef(&doLedgerCleaner),
126 {"ledger_closed", byRef(&doLedgerClosed), Role::USER, NEEDS_CLOSED_LEDGER},
127 {"ledger_current",
128 byRef(&doLedgerCurrent),
131 {"ledger_data", byRef(&doLedgerData), Role::USER, NO_CONDITION},
132 {"ledger_entry", byRef(&doLedgerEntry), Role::USER, NO_CONDITION},
133 {"ledger_header", byRef(&doLedgerHeader), Role::USER, NO_CONDITION, 1, 1},
134 {"ledger_request", byRef(&doLedgerRequest), Role::ADMIN, NO_CONDITION},
135 {"log_level", byRef(&doLogLevel), Role::ADMIN, NO_CONDITION},
136 {"logrotate", byRef(&doLogRotate), Role::ADMIN, NO_CONDITION},
137 {"manifest", byRef(&doManifest), Role::USER, NO_CONDITION},
138 {"nft_buy_offers", byRef(&doNFTBuyOffers), Role::USER, NO_CONDITION},
139 {"nft_sell_offers", byRef(&doNFTSellOffers), Role::USER, NO_CONDITION},
140 {"noripple_check", byRef(&doNoRippleCheck), Role::USER, NO_CONDITION},
141 {"owner_info", byRef(&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER},
142 {"peers", byRef(&doPeers), Role::ADMIN, NO_CONDITION},
143 {"path_find", byRef(&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER},
144 {"ping", byRef(&doPing), Role::USER, NO_CONDITION},
145 {"print", byRef(&doPrint), Role::ADMIN, NO_CONDITION},
146 // { "profile", byRef (&doProfile), Role::USER,
147 // NEEDS_CURRENT_LEDGER },
148 {"random", byRef(&doRandom), Role::USER, NO_CONDITION},
149 {"peer_reservations_add",
150 byRef(&doPeerReservationsAdd),
153 {"peer_reservations_del",
154 byRef(&doPeerReservationsDel),
157 {"peer_reservations_list",
161 {"ripple_path_find", byRef(&doRipplePathFind), Role::USER, NO_CONDITION},
162 {"server_definitions",
163 byRef(&doServerDefinitions),
166 {"server_info", byRef(&doServerInfo), Role::USER, NO_CONDITION},
167 {"server_state", byRef(&doServerState), Role::USER, NO_CONDITION},
168 {"sign", byRef(&doSign), Role::USER, NO_CONDITION},
169 {"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION},
170 {"simulate", byRef(&doSimulate), Role::USER, NEEDS_CURRENT_LEDGER},
171 {"stop", byRef(&doStop), Role::ADMIN, NO_CONDITION},
172 {"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER},
173 {"submit_multisigned",
174 byRef(&doSubmitMultiSigned),
177 {"transaction_entry", byRef(&doTransactionEntry), Role::USER, NO_CONDITION},
179 {"tx_history", byRef(&doTxHistory), Role::USER, NO_CONDITION, 1, 1},
180 {"tx_reduce_relay", byRef(&doTxReduceRelay), Role::USER, NO_CONDITION},
181 {"unl_list", byRef(&doUnlList), Role::ADMIN, NO_CONDITION},
182 {"validation_create",
183 byRef(&doValidationCreate),
186 {"validators", byRef(&doValidators), Role::ADMIN, NO_CONDITION},
187 {"validator_list_sites",
188 byRef(&doValidatorListSites),
191 {"validator_info", byRef(&doValidatorInfo), Role::ADMIN, NO_CONDITION},
192 {"vault_info", byRef(&doVaultInfo), Role::USER, NO_CONDITION},
193 {"wallet_propose", byRef(&doWalletPropose), Role::ADMIN, NO_CONDITION},
194 // Evented methods
195 {"subscribe", byRef(&doSubscribe), Role::USER, NO_CONDITION},
196 {"unsubscribe", byRef(&doUnsubscribe), Role::USER, NO_CONDITION},
197};
198
199class HandlerTable
200{
201private:
202 using handler_table_t = std::multimap<std::string, Handler>;
203
204 // Use with equal_range to enforce that API range of a newly added handler
205 // does not overlap with API range of an existing handler with same name
206 [[nodiscard]] bool
207 overlappingApiVersion(
209 unsigned minVer,
210 unsigned maxVer)
211 {
212 XRPL_ASSERT(
213 minVer <= maxVer,
214 "ripple::RPC::HandlerTable : valid API version range");
215 XRPL_ASSERT(
217 "ripple::RPC::HandlerTable : valid max API version");
218
219 return std::any_of(
220 range.first,
221 range.second, //
222 [minVer, maxVer](auto const& item) {
223 return item.second.minApiVer_ <= maxVer &&
224 item.second.maxApiVer_ >= minVer;
225 });
226 }
227
228 template <std::size_t N>
229 explicit HandlerTable(Handler const (&entries)[N])
230 {
231 for (auto const& entry : entries)
232 {
233 if (overlappingApiVersion(
234 table_.equal_range(entry.name_),
235 entry.minApiVer_,
236 entry.maxApiVer_))
238 std::string("Handler for ") + entry.name_ +
239 " overlaps with an existing handler");
240
241 table_.insert({entry.name_, entry});
242 }
243
244 // This is where the new-style handlers are added.
245 addHandler<LedgerHandler>();
246 addHandler<VersionHandler>();
247 }
248
249public:
250 static HandlerTable const&
251 instance()
252 {
253 static HandlerTable const handlerTable(handlerArray);
254 return handlerTable;
255 }
256
257 [[nodiscard]] Handler const*
258 getHandler(unsigned version, bool betaEnabled, std::string const& name)
259 const
260 {
261 if (version < RPC::apiMinimumSupportedVersion ||
262 version > (betaEnabled ? RPC::apiBetaVersion
264 return nullptr;
265
266 auto const range = table_.equal_range(name);
267 auto const i = std::find_if(
268 range.first, range.second, [version](auto const& entry) {
269 return entry.second.minApiVer_ <= version &&
270 version <= entry.second.maxApiVer_;
271 });
272
273 return i == range.second ? nullptr : &i->second;
274 }
275
276 [[nodiscard]] std::set<char const*>
277 getHandlerNames() const
278 {
280 for (auto const& i : table_)
281 ret.insert(i.second.name_);
282
283 return ret;
284 }
285
286private:
287 handler_table_t table_;
288
289 template <class HandlerImpl>
290 void
291 addHandler()
292 {
293 static_assert(HandlerImpl::minApiVer <= HandlerImpl::maxApiVer);
294 static_assert(HandlerImpl::maxApiVer <= RPC::apiMaximumValidVersion);
295 static_assert(
296 RPC::apiMinimumSupportedVersion <= HandlerImpl::minApiVer);
297
298 if (overlappingApiVersion(
299 table_.equal_range(HandlerImpl::name),
300 HandlerImpl::minApiVer,
301 HandlerImpl::maxApiVer))
303 std::string("Handler for ") + HandlerImpl::name +
304 " overlaps with an existing handler");
305
306 table_.insert({HandlerImpl::name, handlerFrom<HandlerImpl>()});
307 }
308};
309
310} // namespace
311
312Handler const*
313getHandler(unsigned version, bool betaEnabled, std::string const& name)
314{
315 return HandlerTable::instance().getHandler(version, betaEnabled, name);
316}
317
320{
321 return HandlerTable::instance().getHandlerNames();
322}
323
324} // namespace RPC
325} // namespace ripple
T any_of(T... args)
Represents a JSON value.
Definition json_value.h:149
T equal_range(T... args)
T find_if(T... args)
T insert(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:45
Status
Return codes from Backend operations.
@ NEEDS_CURRENT_LEDGER
Definition Handler.h:42
@ NEEDS_NETWORK_CONNECTION
Definition Handler.h:41
@ NO_CONDITION
Definition Handler.h:40
@ NEEDS_CLOSED_LEDGER
Definition Handler.h:43
static constexpr auto apiMaximumSupportedVersion
Definition ApiVersion.h:62
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition Handler.cpp:319
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition Handler.h:66
static constexpr auto apiMaximumValidVersion
Definition ApiVersion.h:67
static constexpr auto apiBetaVersion
Definition ApiVersion.h:66
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition Handler.cpp:313
static constexpr auto apiMinimumSupportedVersion
Definition ApiVersion.h:61
Json::Value entry(jtx::Env &env, jtx::Account const &account, jtx::Account const &authorize)
Definition delegate.cpp:55
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
Json::Value doPeers(RPC::JsonContext &)
Definition Peers.cpp:33
Json::Value doTxHistory(RPC::JsonContext &)
Definition TxHistory.cpp:39
Json::Value doLedgerAccept(RPC::JsonContext &)
Json::Value doUnsubscribe(RPC::JsonContext &)
Json::Value doTxReduceRelay(RPC::JsonContext &)
Json::Value doServerState(RPC::JsonContext &)
Json::Value doChannelVerify(RPC::JsonContext &)
Json::Value doValidationCreate(RPC::JsonContext &)
Json::Value doGetAggregatePrice(RPC::JsonContext &context)
oracles: array of {account, oracle_document_id} base_asset: is the asset to be priced quote_asset: is...
Json::Value doSubmitMultiSigned(RPC::JsonContext &)
Json::Value doLedgerEntry(RPC::JsonContext &)
Json::Value doNFTBuyOffers(RPC::JsonContext &)
Json::Value doChannelAuthorize(RPC::JsonContext &)
Json::Value doNoRippleCheck(RPC::JsonContext &)
Json::Value doTransactionEntry(RPC::JsonContext &)
Json::Value doConsensusInfo(RPC::JsonContext &context)
Json::Value doBookChanges(RPC::JsonContext &context)
Json::Value doLedgerRequest(RPC::JsonContext &)
Json::Value doSimulate(RPC::JsonContext &)
Definition Simulate.cpp:320
Json::Value doPeerReservationsAdd(RPC::JsonContext &)
Json::Value doLedgerCleaner(RPC::JsonContext &)
Json::Value doSign(RPC::JsonContext &)
Json::Value doAccountTxJson(RPC::JsonContext &context)
Json::Value doAccountLines(RPC::JsonContext &context)
Json::Value doTxJson(RPC::JsonContext &)
Definition Tx.cpp:285
Json::Value doAMMInfo(RPC::JsonContext &context)
Definition AMMInfo.cpp:76
Json::Value doPeerReservationsList(RPC::JsonContext &)
Json::Value doServerInfo(RPC::JsonContext &)
Json::Value doFee(RPC::JsonContext &context)
Definition Fee1.cpp:30
Json::Value doConnect(RPC::JsonContext &context)
Definition Connect.cpp:39
Json::Value doNFTSellOffers(RPC::JsonContext &)
Json::Value doDepositAuthorized(RPC::JsonContext &context)
Json::Value doStop(RPC::JsonContext &)
Definition Stop.cpp:32
Json::Value doLedgerClosed(RPC::JsonContext &)
Json::Value doLogLevel(RPC::JsonContext &)
Definition LogLevel.cpp:34
Json::Value doSubmit(RPC::JsonContext &)
Definition Submit.cpp:45
Json::Value doServerDefinitions(RPC::JsonContext &)
Json::Value doSubscribe(RPC::JsonContext &)
Definition Subscribe.cpp:38
Json::Value doAccountObjects(RPC::JsonContext &context)
Json::Value doFeature(RPC::JsonContext &context)
Definition Feature1.cpp:36
Json::Value doAccountNFTs(RPC::JsonContext &context)
General RPC command that can retrieve objects in the account root.
Json::Value doFetchInfo(RPC::JsonContext &context)
Definition FetchInfo.cpp:30
Json::Value doLedgerHeader(RPC::JsonContext &)
Json::Value doRandom(RPC::JsonContext &)
Definition Random.cpp:39
Json::Value doGetCounts(RPC::JsonContext &context)
Json::Value doManifest(RPC::JsonContext &context)
Json::Value doPing(RPC::JsonContext &)
Definition Ping.cpp:33
Json::Value doBlackList(RPC::JsonContext &context)
Definition BlackList.cpp:29
Json::Value doLedgerData(RPC::JsonContext &)
Json::Value doValidatorListSites(RPC::JsonContext &)
Json::Value doSignFor(RPC::JsonContext &)
Definition SignFor.cpp:35
Json::Value doLedgerCurrent(RPC::JsonContext &)
Json::Value doAccountOffers(RPC::JsonContext &context)
Json::Value doValidatorInfo(RPC::JsonContext &)
Json::Value doGatewayBalances(RPC::JsonContext &context)
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:54
Json::Value doRipplePathFind(RPC::JsonContext &)
Json::Value doBookOffers(RPC::JsonContext &context)
Json::Value doAccountCurrencies(RPC::JsonContext &context)
Json::Value doAccountInfo(RPC::JsonContext &context)
Json::Value doLogRotate(RPC::JsonContext &)
Definition LogRotate.cpp:29
Json::Value doCanDelete(RPC::JsonContext &context)
Definition CanDelete.cpp:35
Json::Value doWalletPropose(RPC::JsonContext &)
Json::Value doVaultInfo(RPC::JsonContext &)
Definition VaultInfo.cpp:79
Json::Value doAccountChannels(RPC::JsonContext &context)
Json::Value doPeerReservationsDel(RPC::JsonContext &)
Json::Value doValidators(RPC::JsonContext &)
Json::Value doOwnerInfo(RPC::JsonContext &)
Definition OwnerInfo.cpp:35
Json::Value doPrint(RPC::JsonContext &)
Definition Print.cpp:30
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Json::Value doUnlList(RPC::JsonContext &)
Definition UnlList.cpp:30
Json::Value doPathFind(RPC::JsonContext &)
Definition PathFind.cpp:33