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