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/detail/RPCHelpers.h>
22#include <xrpld/rpc/handlers/Handlers.h>
23#include <xrpld/rpc/handlers/Version.h>
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 UNREACHABLE("ripple::RPC::byRef : result is object");
42 result = RPC::makeObjectValue(result);
43 }
44
45 return Status();
46 };
47}
48
49template <class Object, class HandlerImpl>
51handle(JsonContext& context, Object& object)
52{
53 XRPL_ASSERT(
54 context.apiVersion >= HandlerImpl::minApiVer &&
55 context.apiVersion <= HandlerImpl::maxApiVer,
56 "ripple::RPC::handle : valid API version");
57 HandlerImpl handler(context);
58
59 auto status = handler.check();
60 if (status)
61 status.inject(object);
62 else
63 handler.writeResult(object);
64 return status;
65}
66
67template <typename HandlerImpl>
68Handler
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 handlerArray[]{
81 // Some handlers not specified here are added to the table via addHandler()
82 // Request-response methods
83 {"account_info", byRef(&doAccountInfo), Role::USER, NO_CONDITION},
84 {"account_currencies",
85 byRef(&doAccountCurrencies),
88 {"account_lines", byRef(&doAccountLines), Role::USER, NO_CONDITION},
89 {"account_channels", byRef(&doAccountChannels), Role::USER, NO_CONDITION},
90 {"account_nfts", byRef(&doAccountNFTs), Role::USER, NO_CONDITION},
91 {"account_objects", byRef(&doAccountObjects), Role::USER, NO_CONDITION},
92 {"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
93 {"account_tx", byRef(&doAccountTxJson), Role::USER, NO_CONDITION},
94 {"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
95 {"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
96 {"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},
97 {"book_offers", byRef(&doBookOffers), Role::USER, NO_CONDITION},
98 {"can_delete", byRef(&doCanDelete), Role::ADMIN, NO_CONDITION},
99 {"channel_authorize", byRef(&doChannelAuthorize), Role::USER, NO_CONDITION},
100 {"channel_verify", byRef(&doChannelVerify), Role::USER, NO_CONDITION},
101 {"connect", byRef(&doConnect), Role::ADMIN, NO_CONDITION},
102 {"consensus_info", byRef(&doConsensusInfo), Role::ADMIN, NO_CONDITION},
103 {"deposit_authorized",
104 byRef(&doDepositAuthorized),
107 {"feature", byRef(&doFeature), Role::USER, NO_CONDITION},
108 {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER},
109 {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION},
110 {"gateway_balances", byRef(&doGatewayBalances), Role::USER, NO_CONDITION},
111 {"get_counts", byRef(&doGetCounts), Role::ADMIN, NO_CONDITION},
112 {"get_aggregate_price",
113 byRef(&doGetAggregatePrice),
116 {"ledger_accept",
117 byRef(&doLedgerAccept),
120 {"ledger_cleaner",
121 byRef(&doLedgerCleaner),
124 {"ledger_closed", byRef(&doLedgerClosed), Role::USER, NEEDS_CLOSED_LEDGER},
125 {"ledger_current",
126 byRef(&doLedgerCurrent),
129 {"ledger_data", byRef(&doLedgerData), Role::USER, NO_CONDITION},
130 {"ledger_entry", byRef(&doLedgerEntry), Role::USER, NO_CONDITION},
131 {"ledger_header", byRef(&doLedgerHeader), Role::USER, NO_CONDITION, 1, 1},
132 {"ledger_request", byRef(&doLedgerRequest), Role::ADMIN, NO_CONDITION},
133 {"log_level", byRef(&doLogLevel), Role::ADMIN, NO_CONDITION},
134 {"logrotate", byRef(&doLogRotate), Role::ADMIN, NO_CONDITION},
135 {"manifest", byRef(&doManifest), Role::USER, NO_CONDITION},
136 {"nft_buy_offers", byRef(&doNFTBuyOffers), Role::USER, NO_CONDITION},
137 {"nft_sell_offers", byRef(&doNFTSellOffers), Role::USER, NO_CONDITION},
138 {"noripple_check", byRef(&doNoRippleCheck), Role::USER, NO_CONDITION},
139 {"owner_info", byRef(&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER},
140 {"peers", byRef(&doPeers), Role::ADMIN, NO_CONDITION},
141 {"path_find", byRef(&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER},
142 {"ping", byRef(&doPing), Role::USER, NO_CONDITION},
143 {"print", byRef(&doPrint), Role::ADMIN, NO_CONDITION},
144 // { "profile", byRef (&doProfile), Role::USER,
145 // NEEDS_CURRENT_LEDGER },
146 {"random", byRef(&doRandom), Role::USER, NO_CONDITION},
147 {"peer_reservations_add",
148 byRef(&doPeerReservationsAdd),
151 {"peer_reservations_del",
152 byRef(&doPeerReservationsDel),
155 {"peer_reservations_list",
159 {"ripple_path_find", byRef(&doRipplePathFind), Role::USER, NO_CONDITION},
160 {"server_definitions",
161 byRef(&doServerDefinitions),
164 {"server_info", byRef(&doServerInfo), Role::USER, NO_CONDITION},
165 {"server_state", byRef(&doServerState), Role::USER, NO_CONDITION},
166 {"sign", byRef(&doSign), Role::USER, NO_CONDITION},
167 {"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION},
168 {"stop", byRef(&doStop), Role::ADMIN, NO_CONDITION},
169 {"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER},
170 {"submit_multisigned",
171 byRef(&doSubmitMultiSigned),
174 {"transaction_entry", byRef(&doTransactionEntry), Role::USER, NO_CONDITION},
176 {"tx_history", byRef(&doTxHistory), Role::USER, NO_CONDITION, 1, 1},
177 {"tx_reduce_relay", byRef(&doTxReduceRelay), Role::USER, NO_CONDITION},
178 {"unl_list", byRef(&doUnlList), Role::ADMIN, NO_CONDITION},
179 {"validation_create",
180 byRef(&doValidationCreate),
183 {"validators", byRef(&doValidators), Role::ADMIN, NO_CONDITION},
184 {"validator_list_sites",
185 byRef(&doValidatorListSites),
188 {"validator_info", byRef(&doValidatorInfo), Role::ADMIN, NO_CONDITION},
189 {"wallet_propose", byRef(&doWalletPropose), Role::ADMIN, NO_CONDITION},
190 // Evented methods
191 {"subscribe", byRef(&doSubscribe), Role::USER, NO_CONDITION},
192 {"unsubscribe", byRef(&doUnsubscribe), Role::USER, NO_CONDITION},
193};
194
195class HandlerTable
196{
197private:
198 using handler_table_t = std::multimap<std::string, Handler>;
199
200 // Use with equal_range to enforce that API range of a newly added handler
201 // does not overlap with API range of an existing handler with same name
202 [[nodiscard]] bool
203 overlappingApiVersion(
205 unsigned minVer,
206 unsigned maxVer)
207 {
208 XRPL_ASSERT(
209 minVer <= maxVer,
210 "ripple::RPC::HandlerTable : valid API version range");
211 XRPL_ASSERT(
213 "ripple::RPC::HandlerTable : valid max API version");
214
215 return std::any_of(
216 range.first,
217 range.second, //
218 [minVer, maxVer](auto const& item) {
219 return item.second.minApiVer_ <= maxVer &&
220 item.second.maxApiVer_ >= minVer;
221 });
222 }
223
224 template <std::size_t N>
225 explicit HandlerTable(const Handler (&entries)[N])
226 {
227 for (auto const& entry : entries)
228 {
229 if (overlappingApiVersion(
230 table_.equal_range(entry.name_),
231 entry.minApiVer_,
232 entry.maxApiVer_))
234 std::string("Handler for ") + entry.name_ +
235 " overlaps with an existing handler");
236
237 table_.insert({entry.name_, entry});
238 }
239
240 // This is where the new-style handlers are added.
241 addHandler<LedgerHandler>();
242 addHandler<VersionHandler>();
243 }
244
245public:
246 static HandlerTable const&
247 instance()
248 {
249 static HandlerTable const handlerTable(handlerArray);
250 return handlerTable;
251 }
252
253 [[nodiscard]] Handler const*
254 getHandler(unsigned version, bool betaEnabled, std::string const& name)
255 const
256 {
257 if (version < RPC::apiMinimumSupportedVersion ||
258 version > (betaEnabled ? RPC::apiBetaVersion
260 return nullptr;
261
262 auto const range = table_.equal_range(name);
263 auto const i = std::find_if(
264 range.first, range.second, [version](auto const& entry) {
265 return entry.second.minApiVer_ <= version &&
266 version <= entry.second.maxApiVer_;
267 });
268
269 return i == range.second ? nullptr : &i->second;
270 }
271
272 [[nodiscard]] std::set<char const*>
273 getHandlerNames() const
274 {
276 for (auto const& i : table_)
277 ret.insert(i.second.name_);
278
279 return ret;
280 }
281
282private:
283 handler_table_t table_;
284
285 template <class HandlerImpl>
286 void
287 addHandler()
288 {
289 static_assert(HandlerImpl::minApiVer <= HandlerImpl::maxApiVer);
290 static_assert(HandlerImpl::maxApiVer <= RPC::apiMaximumValidVersion);
291 static_assert(
292 RPC::apiMinimumSupportedVersion <= HandlerImpl::minApiVer);
293
294 if (overlappingApiVersion(
295 table_.equal_range(HandlerImpl::name),
296 HandlerImpl::minApiVer,
297 HandlerImpl::maxApiVer))
299 std::string("Handler for ") + HandlerImpl::name +
300 " overlaps with an existing handler");
301
302 table_.insert({HandlerImpl::name, handlerFrom<HandlerImpl>()});
303 }
304};
305
306} // namespace
307
308Handler const*
309getHandler(unsigned version, bool betaEnabled, std::string const& name)
310{
311 return HandlerTable::instance().getHandler(version, betaEnabled, name);
312}
313
316{
317 return HandlerTable::instance().getHandlerNames();
318}
319
320} // namespace RPC
321} // namespace ripple
T any_of(T... args)
Represents a JSON value.
Definition: json_value.h:147
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:43
Status
Return codes from Backend operations.
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:43
@ NEEDS_NETWORK_CONNECTION
Definition: Handler.h:42
@ NO_CONDITION
Definition: Handler.h:41
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:44
static constexpr auto apiMaximumSupportedVersion
Definition: ApiVersion.h:58
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:315
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:67
static constexpr auto apiMaximumValidVersion
Definition: ApiVersion.h:63
static constexpr auto apiBetaVersion
Definition: ApiVersion.h:62
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:309
static constexpr auto apiMinimumSupportedVersion
Definition: ApiVersion.h:57
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
Json::Value doPeers(RPC::JsonContext &)
Definition: Peers.cpp:32
Json::Value doTxHistory(RPC::JsonContext &)
Definition: TxHistory.cpp:42
Json::Value doLedgerAccept(RPC::JsonContext &)
Json::Value doUnsubscribe(RPC::JsonContext &)
Definition: Unsubscribe.cpp:32
Json::Value doTxReduceRelay(RPC::JsonContext &)
Json::Value doServerState(RPC::JsonContext &)
Definition: ServerState.cpp:31
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 &)
Definition: NFTOffers.cpp:165
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)
Definition: BookOffers.cpp:205
Json::Value doLedgerRequest(RPC::JsonContext &)
Json::Value doPeerReservationsAdd(RPC::JsonContext &)
Json::Value doLedgerCleaner(RPC::JsonContext &)
Json::Value doSign(RPC::JsonContext &)
Definition: SignHandler.cpp:33
Json::Value doAccountTxJson(RPC::JsonContext &context)
Definition: AccountTx.cpp:407
Json::Value doAccountLines(RPC::JsonContext &context)
Json::Value doTxJson(RPC::JsonContext &)
Definition: Tx.cpp:282
Json::Value doAMMInfo(RPC::JsonContext &context)
Definition: AMMInfo.cpp:74
Json::Value doPeerReservationsList(RPC::JsonContext &)
Json::Value doServerInfo(RPC::JsonContext &)
Definition: ServerInfo.cpp:323
Json::Value doFee(RPC::JsonContext &context)
Definition: Fee1.cpp:30
Json::Value doConnect(RPC::JsonContext &context)
Definition: Connect.cpp:38
Json::Value doNFTSellOffers(RPC::JsonContext &)
Definition: NFTOffers.cpp:151
Json::Value doDepositAuthorized(RPC::JsonContext &context)
Json::Value doStop(RPC::JsonContext &)
Definition: Stop.cpp:33
Json::Value doLedgerClosed(RPC::JsonContext &)
Json::Value doLogLevel(RPC::JsonContext &)
Definition: LogLevel.cpp:32
Json::Value doSubmit(RPC::JsonContext &)
Definition: Submit.cpp:47
Json::Value doServerDefinitions(RPC::JsonContext &)
Definition: ServerInfo.cpp:300
Json::Value doSubscribe(RPC::JsonContext &)
Definition: Subscribe.cpp:37
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:31
Json::Value doLedgerHeader(RPC::JsonContext &)
Json::Value doRandom(RPC::JsonContext &)
Definition: Random.cpp:39
Json::Value doManifest(RPC::JsonContext &)
Json::Value doGetCounts(RPC::JsonContext &context)
Definition: GetCounts.cpp:139
Json::Value doPing(RPC::JsonContext &)
Definition: Ping.cpp:32
Json::Value doBlackList(RPC::JsonContext &context)
Definition: BlackList.cpp:28
Json::Value doLedgerData(RPC::JsonContext &)
Definition: LedgerData.cpp:45
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)
Definition: BookOffers.cpp:36
Json::Value doAccountCurrencies(RPC::JsonContext &context)
Json::Value doAccountInfo(RPC::JsonContext &context)
Definition: AccountInfo.cpp:51
Json::Value doLogRotate(RPC::JsonContext &)
Definition: LogRotate.cpp:28
Json::Value doCanDelete(RPC::JsonContext &context)
Definition: CanDelete.cpp:35
Json::Value doWalletPropose(RPC::JsonContext &)
Json::Value doAccountChannels(RPC::JsonContext &context)
Json::Value doPeerReservationsDel(RPC::JsonContext &)
Json::Value doValidators(RPC::JsonContext &)
Definition: Validators.cpp:29
Json::Value doOwnerInfo(RPC::JsonContext &)
Definition: OwnerInfo.cpp:35
Json::Value doPrint(RPC::JsonContext &)
Definition: Print.cpp:29
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:48
Json::Value doUnlList(RPC::JsonContext &)
Definition: UnlList.cpp:30
Json::Value doPathFind(RPC::JsonContext &)
Definition: PathFind.cpp:33