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