xrpld
Loading...
Searching...
No Matches
Handler.cpp
1#include <xrpld/rpc/detail/Handler.h>
2
3#include <xrpld/rpc/Context.h>
4#include <xrpld/rpc/Role.h>
5#include <xrpld/rpc/handlers/Handlers.h>
6#include <xrpld/rpc/handlers/ledger/Ledger.h>
7#include <xrpld/rpc/handlers/server_info/Version.h>
8
9#include <xrpl/basics/contract.h>
10#include <xrpl/beast/utility/instrumentation.h>
11#include <xrpl/json/json_value.h>
12#include <xrpl/protocol/ApiVersion.h>
13
14#include <algorithm>
15#include <cstddef>
16#include <map>
17#include <set>
18#include <string>
19#include <utility>
20
21namespace xrpl::RPC {
22namespace {
23
25template <typename Function>
27byRef(Function const& f)
28{
29 return [f](JsonContext& context, json::Value& result) {
30 result = f(context);
31 if (result.type() != json::ValueType::Object)
32 {
33 // LCOV_EXCL_START
34 UNREACHABLE("xrpl::RPC::byRef : result is object");
35 result = RPC::makeObjectValue(result);
36 // LCOV_EXCL_STOP
37 }
38
39 return Status();
40 };
41}
42
43template <class Object, class HandlerImpl>
45handle(JsonContext& context, Object& object)
46{
47 XRPL_ASSERT(
48 context.apiVersion >= HandlerImpl::minApiVer &&
49 context.apiVersion <= HandlerImpl::maxApiVer,
50 "xrpl::RPC::handle : valid API version");
51 HandlerImpl handler(context);
52
53 auto status = handler.check();
54 if (status)
55 {
56 status.inject(object);
57 }
58 else
59 {
60 handler.writeResult(object);
61 }
62 return status;
63}
64
65template <typename HandlerImpl>
67handlerFrom()
68{
69 return {
70 HandlerImpl::name,
71 &handle<json::Value, HandlerImpl>,
72 HandlerImpl::role,
73 HandlerImpl::condition,
74 HandlerImpl::minApiVer,
75 HandlerImpl::maxApiVer};
76}
77
78Handler const kHandlerArray[]{
79 // Some handlers not specified here are added to the table via addHandler()
80 // Request-response methods
81 {.name = "account_info",
82 .valueMethod = byRef(&doAccountInfo),
83 .role = Role::USER,
84 .condition = Condition::NoCondition},
85 {.name = "account_currencies",
86 .valueMethod = byRef(&doAccountCurrencies),
87 .role = Role::USER,
88 .condition = Condition::NoCondition},
89 {.name = "account_lines",
90 .valueMethod = byRef(&doAccountLines),
91 .role = Role::USER,
92 .condition = Condition::NoCondition},
93 {.name = "account_channels",
94 .valueMethod = byRef(&doAccountChannels),
95 .role = Role::USER,
96 .condition = Condition::NoCondition},
97 {.name = "account_nfts",
98 .valueMethod = byRef(&doAccountNFTs),
99 .role = Role::USER,
100 .condition = Condition::NoCondition},
101 {.name = "account_objects",
102 .valueMethod = byRef(&doAccountObjects),
103 .role = Role::USER,
104 .condition = Condition::NoCondition},
105 {.name = "account_offers",
106 .valueMethod = byRef(&doAccountOffers),
107 .role = Role::USER,
108 .condition = Condition::NoCondition},
109 {.name = "account_tx",
110 .valueMethod = byRef(&doAccountTx),
111 .role = Role::USER,
112 .condition = Condition::NoCondition},
113 {.name = "amm_info",
114 .valueMethod = byRef(&doAMMInfo),
115 .role = Role::USER,
116 .condition = Condition::NoCondition},
117 {.name = "blacklist",
118 .valueMethod = byRef(&doBlackList),
119 .role = Role::ADMIN,
120 .condition = Condition::NoCondition},
121 {.name = "book_changes",
122 .valueMethod = byRef(&doBookChanges),
123 .role = Role::USER,
124 .condition = Condition::NoCondition},
125 {.name = "book_offers",
126 .valueMethod = byRef(&doBookOffers),
127 .role = Role::USER,
128 .condition = Condition::NoCondition},
129 {.name = "can_delete",
130 .valueMethod = byRef(&doCanDelete),
131 .role = Role::ADMIN,
132 .condition = Condition::NoCondition},
133 {.name = "channel_authorize",
134 .valueMethod = byRef(&doChannelAuthorize),
135 .role = Role::USER,
136 .condition = Condition::NoCondition},
137 {.name = "channel_verify",
138 .valueMethod = byRef(&doChannelVerify),
139 .role = Role::USER,
140 .condition = Condition::NoCondition},
141 {.name = "connect",
142 .valueMethod = byRef(&doConnect),
143 .role = Role::ADMIN,
144 .condition = Condition::NoCondition},
145 {.name = "consensus_info",
146 .valueMethod = byRef(&doConsensusInfo),
147 .role = Role::ADMIN,
148 .condition = Condition::NoCondition},
149 {.name = "deposit_authorized",
150 .valueMethod = byRef(&doDepositAuthorized),
151 .role = Role::USER,
152 .condition = Condition::NoCondition},
153 {.name = "feature",
154 .valueMethod = byRef(&doFeature),
155 .role = Role::USER,
156 .condition = Condition::NoCondition},
157 {.name = "fee",
158 .valueMethod = byRef(&doFee),
159 .role = Role::USER,
160 .condition = Condition::NeedsCurrentLedger},
161 {.name = "fetch_info",
162 .valueMethod = byRef(&doFetchInfo),
163 .role = Role::ADMIN,
164 .condition = Condition::NoCondition},
165 {.name = "gateway_balances",
166 .valueMethod = byRef(&doGatewayBalances),
167 .role = Role::USER,
168 .condition = Condition::NoCondition},
169 {.name = "get_counts",
170 .valueMethod = byRef(&doGetCounts),
171 .role = Role::ADMIN,
172 .condition = Condition::NoCondition},
173 {.name = "get_aggregate_price",
174 .valueMethod = byRef(&doGetAggregatePrice),
175 .role = Role::USER,
176 .condition = Condition::NoCondition},
177 {.name = "ledger_accept",
178 .valueMethod = byRef(&doLedgerAccept),
179 .role = Role::ADMIN,
180 .condition = Condition::NeedsCurrentLedger},
181 {.name = "ledger_cleaner",
182 .valueMethod = byRef(&doLedgerCleaner),
183 .role = Role::ADMIN,
185 {.name = "ledger_closed",
186 .valueMethod = byRef(&doLedgerClosed),
187 .role = Role::USER,
188 .condition = Condition::NeedsClosedLedger},
189 {.name = "ledger_current",
190 .valueMethod = byRef(&doLedgerCurrent),
191 .role = Role::USER,
192 .condition = Condition::NeedsCurrentLedger},
193 {.name = "ledger_data",
194 .valueMethod = byRef(&doLedgerData),
195 .role = Role::USER,
196 .condition = Condition::NoCondition},
197 {.name = "ledger_entry",
198 .valueMethod = byRef(&doLedgerEntry),
199 .role = Role::USER,
200 .condition = Condition::NoCondition},
201 {.name = "ledger_header",
202 .valueMethod = byRef(&doLedgerHeader),
203 .role = Role::USER,
204 .condition = Condition::NoCondition,
205 .minApiVer = 1,
206 .maxApiVer = 1},
207 {.name = "ledger_request",
208 .valueMethod = byRef(&doLedgerRequest),
209 .role = Role::ADMIN,
210 .condition = Condition::NoCondition},
211 {.name = "log_level",
212 .valueMethod = byRef(&doLogLevel),
213 .role = Role::ADMIN,
214 .condition = Condition::NoCondition},
215 {.name = "logrotate",
216 .valueMethod = byRef(&doLogRotate),
217 .role = Role::ADMIN,
218 .condition = Condition::NoCondition},
219 {.name = "manifest",
220 .valueMethod = byRef(&doManifest),
221 .role = Role::USER,
222 .condition = Condition::NoCondition},
223 {.name = "nft_buy_offers",
224 .valueMethod = byRef(&doNFTBuyOffers),
225 .role = Role::USER,
226 .condition = Condition::NoCondition},
227 {.name = "nft_sell_offers",
228 .valueMethod = byRef(&doNFTSellOffers),
229 .role = Role::USER,
230 .condition = Condition::NoCondition},
231 {.name = "noripple_check",
232 .valueMethod = byRef(&doNoRippleCheck),
233 .role = Role::USER,
234 .condition = Condition::NoCondition},
235 {.name = "owner_info",
236 .valueMethod = byRef(&doOwnerInfo),
237 .role = Role::USER,
238 .condition = Condition::NeedsCurrentLedger},
239 {.name = "peers",
240 .valueMethod = byRef(&doPeers),
241 .role = Role::ADMIN,
242 .condition = Condition::NoCondition},
243 {.name = "path_find",
244 .valueMethod = byRef(&doPathFind),
245 .role = Role::USER,
246 .condition = Condition::NeedsCurrentLedger},
247 {.name = "ping",
248 .valueMethod = byRef(&doPing),
249 .role = Role::USER,
250 .condition = Condition::NoCondition},
251 {.name = "print",
252 .valueMethod = byRef(&doPrint),
253 .role = Role::ADMIN,
254 .condition = Condition::NoCondition},
255 // { "profile", byRef (&doProfile), Role::USER,
256 // NEEDS_CURRENT_LEDGER },
257 {.name = "random",
258 .valueMethod = byRef(&doRandom),
259 .role = Role::USER,
260 .condition = Condition::NoCondition},
261 {.name = "peer_reservations_add",
262 .valueMethod = byRef(&doPeerReservationsAdd),
263 .role = Role::ADMIN,
264 .condition = Condition::NoCondition},
265 {.name = "peer_reservations_del",
266 .valueMethod = byRef(&doPeerReservationsDel),
267 .role = Role::ADMIN,
268 .condition = Condition::NoCondition},
269 {.name = "peer_reservations_list",
270 .valueMethod = byRef(&doPeerReservationsList),
271 .role = Role::ADMIN,
272 .condition = Condition::NoCondition},
273 {.name = "ripple_path_find",
274 .valueMethod = byRef(&doRipplePathFind),
275 .role = Role::USER,
276 .condition = Condition::NoCondition},
277 {.name = "server_definitions",
278 .valueMethod = byRef(&doServerDefinitions),
279 .role = Role::USER,
280 .condition = Condition::NoCondition},
281 {.name = "server_info",
282 .valueMethod = byRef(&doServerInfo),
283 .role = Role::USER,
284 .condition = Condition::NoCondition},
285 {.name = "server_state",
286 .valueMethod = byRef(&doServerState),
287 .role = Role::USER,
288 .condition = Condition::NoCondition},
289 {.name = "sign",
290 .valueMethod = byRef(&doSign),
291 .role = Role::USER,
292 .condition = Condition::NoCondition},
293 {.name = "sign_for",
294 .valueMethod = byRef(&doSignFor),
295 .role = Role::USER,
296 .condition = Condition::NoCondition},
297 {.name = "simulate",
298 .valueMethod = byRef(&doSimulate),
299 .role = Role::USER,
300 .condition = Condition::NeedsCurrentLedger},
301 {.name = "stop",
302 .valueMethod = byRef(&doStop),
303 .role = Role::ADMIN,
304 .condition = Condition::NoCondition},
305 {.name = "submit",
306 .valueMethod = byRef(&doSubmit),
307 .role = Role::USER,
308 .condition = Condition::NeedsCurrentLedger},
309 {.name = "submit_multisigned",
310 .valueMethod = byRef(&doSubmitMultiSigned),
311 .role = Role::USER,
312 .condition = Condition::NeedsCurrentLedger},
313 {.name = "transaction_entry",
314 .valueMethod = byRef(&doTransactionEntry),
315 .role = Role::USER,
316 .condition = Condition::NoCondition},
317 {.name = "tx",
318 .valueMethod = byRef(&doTxJson),
319 .role = Role::USER,
321 {.name = "tx_history",
322 .valueMethod = byRef(&doTxHistory),
323 .role = Role::USER,
324 .condition = Condition::NoCondition,
325 .minApiVer = 1,
326 .maxApiVer = 1},
327 {.name = "tx_reduce_relay",
328 .valueMethod = byRef(&doTxReduceRelay),
329 .role = Role::USER,
330 .condition = Condition::NoCondition},
331 {.name = "unl_list",
332 .valueMethod = byRef(&doUnlList),
333 .role = Role::ADMIN,
334 .condition = Condition::NoCondition},
335 {.name = "validation_create",
336 .valueMethod = byRef(&doValidationCreate),
337 .role = Role::ADMIN,
338 .condition = Condition::NoCondition},
339 {.name = "validators",
340 .valueMethod = byRef(&doValidators),
341 .role = Role::ADMIN,
342 .condition = Condition::NoCondition},
343 {.name = "validator_list_sites",
344 .valueMethod = byRef(&doValidatorListSites),
345 .role = Role::ADMIN,
346 .condition = Condition::NoCondition},
347 {.name = "validator_info",
348 .valueMethod = byRef(&doValidatorInfo),
349 .role = Role::ADMIN,
350 .condition = Condition::NoCondition},
351 {.name = "vault_info",
352 .valueMethod = byRef(&doVaultInfo),
353 .role = Role::USER,
354 .condition = Condition::NoCondition},
355 {.name = "wallet_propose",
356 .valueMethod = byRef(&doWalletPropose),
357 .role = Role::ADMIN,
358 .condition = Condition::NoCondition},
359 // Event methods
360 {.name = "subscribe",
361 .valueMethod = byRef(&doSubscribe),
362 .role = Role::USER,
363 .condition = Condition::NoCondition},
364 {.name = "unsubscribe",
365 .valueMethod = byRef(&doUnsubscribe),
366 .role = Role::USER,
367 .condition = Condition::NoCondition},
368};
369
370class HandlerTable
371{
372private:
373 using handler_table_t = std::multimap<std::string, Handler>;
374
375 // Use with equal_range to enforce that API range of a newly added handler
376 // does not overlap with API range of an existing handler with same name
377 [[nodiscard]] static bool
378 overlappingApiVersion(
379 std::pair<handler_table_t::iterator, handler_table_t::iterator> range,
380 unsigned minVer,
381 unsigned maxVer)
382 {
383 XRPL_ASSERT(minVer <= maxVer, "xrpl::RPC::HandlerTable : valid API version range");
384 XRPL_ASSERT(
386 "xrpl::RPC::HandlerTable : valid max API version");
387
388 return std::any_of(
389 range.first,
390 range.second, //
391 [minVer, maxVer](auto const& item) {
392 return item.second.minApiVer <= maxVer && item.second.maxApiVer >= minVer;
393 });
394 }
395
396 template <std::size_t N>
397 explicit HandlerTable(Handler const (&entries)[N])
398 {
399 for (auto const& entry : entries)
400 {
401 if (overlappingApiVersion(
402 table_.equal_range(entry.name), entry.minApiVer, entry.maxApiVer))
403 {
405 std::string("Handler for ") + entry.name +
406 " overlaps with an existing handler");
407 }
408
409 table_.insert({entry.name, entry});
410 }
411
412 // This is where the new-style handlers are added.
413 addHandler<LedgerHandler>();
414 addHandler<VersionHandler>();
415 }
416
417public:
418 static HandlerTable const&
419 instance()
420 {
421 static HandlerTable const kHandlerTable(kHandlerArray);
422 return kHandlerTable;
423 }
424
425 [[nodiscard]] Handler const*
426 getHandler(unsigned version, bool betaEnabled, std::string const& name) const
427 {
428 if (version < RPC::kApiMinimumSupportedVersion ||
429 version > (betaEnabled ? RPC::kApiBetaVersion : RPC::kApiMaximumSupportedVersion))
430 return nullptr;
431
432 auto const range = table_.equal_range(name);
433 auto const i = std::find_if(range.first, range.second, [version](auto const& entry) {
434 return entry.second.minApiVer <= version && version <= entry.second.maxApiVer;
435 });
436
437 return i == range.second ? nullptr : &i->second;
438 }
439
440 [[nodiscard]] std::set<char const*>
441 getHandlerNames() const
442 {
443 std::set<char const*> ret;
444 for (auto const& i : table_)
445 ret.insert(i.second.name);
446
447 return ret;
448 }
449
450private:
451 handler_table_t table_;
452
453 template <class HandlerImpl>
454 void
455 addHandler()
456 {
457 static_assert(HandlerImpl::minApiVer <= HandlerImpl::maxApiVer);
458 static_assert(HandlerImpl::maxApiVer <= RPC::kApiMaximumValidVersion);
459 static_assert(RPC::kApiMinimumSupportedVersion <= HandlerImpl::minApiVer);
460
461 if (overlappingApiVersion(
462 table_.equal_range(HandlerImpl::name),
463 HandlerImpl::minApiVer,
464 HandlerImpl::maxApiVer))
465 {
467 std::string("Handler for ") + HandlerImpl::name +
468 " overlaps with an existing handler");
469 }
470
471 table_.insert({HandlerImpl::name, handlerFrom<HandlerImpl>()});
472 }
473};
474
475} // namespace
476
477Handler const*
478getHandler(unsigned version, bool betaEnabled, std::string const& name)
479{
480 return HandlerTable::instance().getHandler(version, betaEnabled, name);
481}
482
485{
486 return HandlerTable::instance().getHandlerNames();
487}
488
489} // namespace xrpl::RPC
T any_of(T... args)
T find_if(T... args)
T insert(T... args)
@ Object
object value (collection of name/value pairs).
Definition json_value.h:26
API version numbers used in later API versions.
Definition ApiVersion.h:35
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition Handler.cpp:484
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition Handler.cpp:478
static constexpr auto kApiMinimumSupportedVersion
Definition ApiVersion.h:41
json::Value makeObjectValue(Value const &value, json::StaticString const &field=jss::message)
Return a json::ValueType::Object with a single entry.
Definition Handler.h:45
static constexpr auto kApiMaximumValidVersion
Definition ApiVersion.h:46
static constexpr auto kApiBetaVersion
Definition ApiVersion.h:45
static constexpr auto kApiMaximumSupportedVersion
Definition ApiVersion.h:42
json::Value entry(jtx::Env &env, jtx::Account const &account, jtx::Account const &authorize)
Definition delegate.cpp:41
json::Value doPing(RPC::JsonContext &)
Definition Ping.cpp:14
json::Value doSubmitMultiSigned(RPC::JsonContext &)
json::Value doPeers(RPC::JsonContext &context)
Definition Peers.cpp:20
json::Value doLedgerCurrent(RPC::JsonContext &)
json::Value doValidators(RPC::JsonContext &context)
json::Value doValidationCreate(RPC::JsonContext &context)
json::Value doManifest(RPC::JsonContext &)
json::Value doGetAggregatePrice(RPC::JsonContext &)
oracles: array of {account, oracle_document_id} base_asset: is the asset to be priced quote_asset: is...
json::Value doStop(RPC::JsonContext &context)
Definition Stop.cpp:14
json::Value doAccountChannels(RPC::JsonContext &context)
json::Value doLedgerRequest(RPC::JsonContext &context)
json::Value doServerInfo(RPC::JsonContext &)
json::Value doWalletPropose(RPC::JsonContext &context)
json::Value doTransactionEntry(RPC::JsonContext &)
json::Value doServerState(RPC::JsonContext &)
json::Value doLogLevel(RPC::JsonContext &context)
Definition LogLevel.cpp:19
json::Value doNoRippleCheck(RPC::JsonContext &context)
json::Value doAccountTx(RPC::JsonContext &context)
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:34
json::Value doFeature(RPC::JsonContext &)
json::Value doConnect(RPC::JsonContext &context)
Definition Connect.cpp:24
json::Value doSign(RPC::JsonContext &context)
json::Value doGatewayBalances(RPC::JsonContext &context)
json::Value doAccountNFTs(RPC::JsonContext &context)
General RPC command that can retrieve objects in the account root.
json::Value doPrint(RPC::JsonContext &context)
Definition Print.cpp:11
json::Value doChannelAuthorize(RPC::JsonContext &context)
json::Value doAccountInfo(RPC::JsonContext &context)
void logicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
json::Value doTxReduceRelay(RPC::JsonContext &)
json::Value doLedgerEntry(RPC::JsonContext &)
json::Value doGetCounts(RPC::JsonContext &context)
@ USER
Definition Role.h:24
@ ADMIN
Definition Role.h:24
json::Value doPeerReservationsDel(RPC::JsonContext &context)
json::Value doPathFind(RPC::JsonContext &)
Definition PathFind.cpp:16
json::Value doVaultInfo(RPC::JsonContext &)
Definition VaultInfo.cpp:64
json::Value doLedgerData(RPC::JsonContext &)
json::Value doBookChanges(RPC::JsonContext &)
json::Value doRipplePathFind(RPC::JsonContext &)
json::Value doTxHistory(RPC::JsonContext &)
Definition TxHistory.cpp:19
json::Value doAccountCurrencies(RPC::JsonContext &context)
json::Value doLedgerHeader(RPC::JsonContext &)
json::Value doSubscribe(RPC::JsonContext &)
Definition Subscribe.cpp:30
json::Value doOwnerInfo(RPC::JsonContext &context)
Definition OwnerInfo.cpp:20
json::Value doChannelVerify(RPC::JsonContext &context)
json::Value doValidatorInfo(RPC::JsonContext &context)
json::Value doDepositAuthorized(RPC::JsonContext &)
json::Value doLedgerClosed(RPC::JsonContext &)
json::Value doAMMInfo(RPC::JsonContext &)
Definition AMMInfo.cpp:64
json::Value doAccountOffers(RPC::JsonContext &context)
json::Value doFetchInfo(RPC::JsonContext &context)
Definition FetchInfo.cpp:10
json::Value doPeerReservationsList(RPC::JsonContext &context)
json::Value doCanDelete(RPC::JsonContext &context)
Definition CanDelete.cpp:22
json::Value doAccountObjects(RPC::JsonContext &context)
json::Value doSimulate(RPC::JsonContext &)
Definition Simulate.cpp:307
json::Value doFee(RPC::JsonContext &)
Definition Fee.cpp:11
json::Value doNFTSellOffers(RPC::JsonContext &)
json::Value doUnsubscribe(RPC::JsonContext &)
json::Value doUnlList(RPC::JsonContext &context)
Definition UnlList.cpp:15
json::Value doAccountLines(RPC::JsonContext &context)
json::Value doBlackList(RPC::JsonContext &context)
Definition BlackList.cpp:11
json::Value doSubmit(RPC::JsonContext &)
Definition Submit.cpp:45
json::Value doServerDefinitions(RPC::JsonContext &)
json::Value doBookOffers(RPC::JsonContext &)
json::Value doPeerReservationsAdd(RPC::JsonContext &context)
json::Value doRandom(RPC::JsonContext &)
Definition Random.cpp:22
json::Value doConsensusInfo(RPC::JsonContext &context)
json::Value doLogRotate(RPC::JsonContext &context)
Definition LogRotate.cpp:12
json::Value doLedgerCleaner(RPC::JsonContext &context)
json::Value doSignFor(RPC::JsonContext &context)
Definition SignFor.cpp:19
json::Value doLedgerAccept(RPC::JsonContext &context)
json::Value doTxJson(RPC::JsonContext &)
Definition Tx.cpp:270
json::Value doNFTBuyOffers(RPC::JsonContext &)
json::Value doValidatorListSites(RPC::JsonContext &context)
std::function< Status(JsonContext &, JsonValue &)> Method
Definition Handler.h:28
Status represents the results of an operation that might fail.
Definition Status.h:19