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
25#include <xrpl/basics/contract.h>
26
27#include <map>
28
29namespace ripple {
30namespace RPC {
31namespace {
32
34template <typename Function>
35Handler::Method<Json::Value>
36byRef(Function const& f)
37{
38 return [f](JsonContext& context, Json::Value& result) {
39 result = f(context);
40 if (result.type() != Json::objectValue)
41 {
42 UNREACHABLE("ripple::RPC::byRef : result is object");
43 result = RPC::makeObjectValue(result);
44 }
45
46 return Status();
47 };
48}
49
50template <class Object, class HandlerImpl>
52handle(JsonContext& context, Object& object)
53{
54 XRPL_ASSERT(
55 context.apiVersion >= HandlerImpl::minApiVer &&
56 context.apiVersion <= HandlerImpl::maxApiVer,
57 "ripple::RPC::handle : valid API version");
58 HandlerImpl handler(context);
59
60 auto status = handler.check();
61 if (status)
62 status.inject(object);
63 else
64 handler.writeResult(object);
65 return status;
66}
67
68template <typename HandlerImpl>
69Handler
70handlerFrom()
71{
72 return {
73 HandlerImpl::name,
74 &handle<Json::Value, HandlerImpl>,
75 HandlerImpl::role,
76 HandlerImpl::condition,
77 HandlerImpl::minApiVer,
78 HandlerImpl::maxApiVer};
79}
80
81Handler const handlerArray[]{
82 // Some handlers not specified here are added to the table via addHandler()
83 // Request-response methods
84 {"account_info", byRef(&doAccountInfo), Role::USER, NO_CONDITION},
85 {"account_currencies",
86 byRef(&doAccountCurrencies),
89 {"account_lines", byRef(&doAccountLines), Role::USER, NO_CONDITION},
90 {"account_channels", byRef(&doAccountChannels), Role::USER, NO_CONDITION},
91 {"account_nfts", byRef(&doAccountNFTs), Role::USER, NO_CONDITION},
92 {"account_objects", byRef(&doAccountObjects), Role::USER, NO_CONDITION},
93 {"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
94 {"account_tx", byRef(&doAccountTxJson), Role::USER, NO_CONDITION},
95 {"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
96 {"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
97 {"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},
98 {"book_offers", byRef(&doBookOffers), Role::USER, NO_CONDITION},
99 {"can_delete", byRef(&doCanDelete), Role::ADMIN, NO_CONDITION},
100 {"channel_authorize", byRef(&doChannelAuthorize), Role::USER, NO_CONDITION},
101 {"channel_verify", byRef(&doChannelVerify), Role::USER, NO_CONDITION},
102 {"connect", byRef(&doConnect), Role::ADMIN, NO_CONDITION},
103 {"consensus_info", byRef(&doConsensusInfo), Role::ADMIN, NO_CONDITION},
104 {"deposit_authorized",
105 byRef(&doDepositAuthorized),
108 {"feature", byRef(&doFeature), Role::USER, NO_CONDITION},
109 {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER},
110 {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION},
111 {"gateway_balances", byRef(&doGatewayBalances), Role::USER, NO_CONDITION},
112 {"get_counts", byRef(&doGetCounts), Role::ADMIN, NO_CONDITION},
113 {"get_aggregate_price",
114 byRef(&doGetAggregatePrice),
117 {"ledger_accept",
118 byRef(&doLedgerAccept),
121 {"ledger_cleaner",
122 byRef(&doLedgerCleaner),
125 {"ledger_closed", byRef(&doLedgerClosed), Role::USER, NEEDS_CLOSED_LEDGER},
126 {"ledger_current",
127 byRef(&doLedgerCurrent),
130 {"ledger_data", byRef(&doLedgerData), Role::USER, NO_CONDITION},
131 {"ledger_entry", byRef(&doLedgerEntry), Role::USER, NO_CONDITION},
132 {"ledger_header", byRef(&doLedgerHeader), Role::USER, NO_CONDITION, 1, 1},
133 {"ledger_request", byRef(&doLedgerRequest), Role::ADMIN, NO_CONDITION},
134 {"log_level", byRef(&doLogLevel), Role::ADMIN, NO_CONDITION},
135 {"logrotate", byRef(&doLogRotate), Role::ADMIN, NO_CONDITION},
136 {"manifest", byRef(&doManifest), Role::USER, NO_CONDITION},
137 {"nft_buy_offers", byRef(&doNFTBuyOffers), Role::USER, NO_CONDITION},
138 {"nft_sell_offers", byRef(&doNFTSellOffers), Role::USER, NO_CONDITION},
139 {"noripple_check", byRef(&doNoRippleCheck), Role::USER, NO_CONDITION},
140 {"owner_info", byRef(&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER},
141 {"peers", byRef(&doPeers), Role::ADMIN, NO_CONDITION},
142 {"path_find", byRef(&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER},
143 {"ping", byRef(&doPing), Role::USER, NO_CONDITION},
144 {"print", byRef(&doPrint), Role::ADMIN, NO_CONDITION},
145 // { "profile", byRef (&doProfile), Role::USER,
146 // NEEDS_CURRENT_LEDGER },
147 {"random", byRef(&doRandom), Role::USER, NO_CONDITION},
148 {"peer_reservations_add",
149 byRef(&doPeerReservationsAdd),
152 {"peer_reservations_del",
153 byRef(&doPeerReservationsDel),
156 {"peer_reservations_list",
160 {"ripple_path_find", byRef(&doRipplePathFind), Role::USER, NO_CONDITION},
161 {"server_definitions",
162 byRef(&doServerDefinitions),
165 {"server_info", byRef(&doServerInfo), Role::USER, NO_CONDITION},
166 {"server_state", byRef(&doServerState), Role::USER, NO_CONDITION},
167 {"sign", byRef(&doSign), Role::USER, NO_CONDITION},
168 {"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION},
169 {"simulate", byRef(&doSimulate), Role::USER, NEEDS_CURRENT_LEDGER},
170 {"stop", byRef(&doStop), Role::ADMIN, NO_CONDITION},
171 {"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER},
172 {"submit_multisigned",
173 byRef(&doSubmitMultiSigned),
176 {"transaction_entry", byRef(&doTransactionEntry), Role::USER, NO_CONDITION},
178 {"tx_history", byRef(&doTxHistory), Role::USER, NO_CONDITION, 1, 1},
179 {"tx_reduce_relay", byRef(&doTxReduceRelay), Role::USER, NO_CONDITION},
180 {"unl_list", byRef(&doUnlList), Role::ADMIN, NO_CONDITION},
181 {"validation_create",
182 byRef(&doValidationCreate),
185 {"validators", byRef(&doValidators), Role::ADMIN, NO_CONDITION},
186 {"validator_list_sites",
187 byRef(&doValidatorListSites),
190 {"validator_info", byRef(&doValidatorInfo), Role::ADMIN, NO_CONDITION},
191 {"vault_info", byRef(&doVaultInfo), Role::USER, NO_CONDITION},
192 {"wallet_propose", byRef(&doWalletPropose), Role::ADMIN, NO_CONDITION},
193 // Evented methods
194 {"subscribe", byRef(&doSubscribe), Role::USER, NO_CONDITION},
195 {"unsubscribe", byRef(&doUnsubscribe), Role::USER, NO_CONDITION},
196};
197
198class HandlerTable
199{
200private:
201 using handler_table_t = std::multimap<std::string, Handler>;
202
203 // Use with equal_range to enforce that API range of a newly added handler
204 // does not overlap with API range of an existing handler with same name
205 [[nodiscard]] bool
206 overlappingApiVersion(
208 unsigned minVer,
209 unsigned maxVer)
210 {
211 XRPL_ASSERT(
212 minVer <= maxVer,
213 "ripple::RPC::HandlerTable : valid API version range");
214 XRPL_ASSERT(
216 "ripple::RPC::HandlerTable : valid max API version");
217
218 return std::any_of(
219 range.first,
220 range.second, //
221 [minVer, maxVer](auto const& item) {
222 return item.second.minApiVer_ <= maxVer &&
223 item.second.maxApiVer_ >= minVer;
224 });
225 }
226
227 template <std::size_t N>
228 explicit HandlerTable(Handler const (&entries)[N])
229 {
230 for (auto const& entry : entries)
231 {
232 if (overlappingApiVersion(
233 table_.equal_range(entry.name_),
234 entry.minApiVer_,
235 entry.maxApiVer_))
237 std::string("Handler for ") + entry.name_ +
238 " overlaps with an existing handler");
239
240 table_.insert({entry.name_, entry});
241 }
242
243 // This is where the new-style handlers are added.
244 addHandler<LedgerHandler>();
245 addHandler<VersionHandler>();
246 }
247
248public:
249 static HandlerTable const&
250 instance()
251 {
252 static HandlerTable const handlerTable(handlerArray);
253 return handlerTable;
254 }
255
256 [[nodiscard]] Handler const*
257 getHandler(unsigned version, bool betaEnabled, std::string const& name)
258 const
259 {
260 if (version < RPC::apiMinimumSupportedVersion ||
261 version > (betaEnabled ? RPC::apiBetaVersion
263 return nullptr;
264
265 auto const range = table_.equal_range(name);
266 auto const i = std::find_if(
267 range.first, range.second, [version](auto const& entry) {
268 return entry.second.minApiVer_ <= version &&
269 version <= entry.second.maxApiVer_;
270 });
271
272 return i == range.second ? nullptr : &i->second;
273 }
274
275 [[nodiscard]] std::set<char const*>
276 getHandlerNames() const
277 {
279 for (auto const& i : table_)
280 ret.insert(i.second.name_);
281
282 return ret;
283 }
284
285private:
286 handler_table_t table_;
287
288 template <class HandlerImpl>
289 void
290 addHandler()
291 {
292 static_assert(HandlerImpl::minApiVer <= HandlerImpl::maxApiVer);
293 static_assert(HandlerImpl::maxApiVer <= RPC::apiMaximumValidVersion);
294 static_assert(
295 RPC::apiMinimumSupportedVersion <= HandlerImpl::minApiVer);
296
297 if (overlappingApiVersion(
298 table_.equal_range(HandlerImpl::name),
299 HandlerImpl::minApiVer,
300 HandlerImpl::maxApiVer))
302 std::string("Handler for ") + HandlerImpl::name +
303 " overlaps with an existing handler");
304
305 table_.insert({HandlerImpl::name, handlerFrom<HandlerImpl>()});
306 }
307};
308
309} // namespace
310
311Handler const*
312getHandler(unsigned version, bool betaEnabled, std::string const& name)
313{
314 return HandlerTable::instance().getHandler(version, betaEnabled, name);
315}
316
319{
320 return HandlerTable::instance().getHandlerNames();
321}
322
323} // namespace RPC
324} // 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:41
@ NEEDS_NETWORK_CONNECTION
Definition Handler.h:40
@ NO_CONDITION
Definition Handler.h:39
@ NEEDS_CLOSED_LEDGER
Definition Handler.h:42
static constexpr auto apiMaximumSupportedVersion
Definition ApiVersion.h:57
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition Handler.cpp:318
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition Handler.h:65
static constexpr auto apiMaximumValidVersion
Definition ApiVersion.h:62
static constexpr auto apiBetaVersion
Definition ApiVersion.h:61
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition Handler.cpp:312
static constexpr auto apiMinimumSupportedVersion
Definition ApiVersion.h:56
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:311
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:286
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