rippled
Loading...
Searching...
No Matches
RPCCall.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/app/main/Application.h>
21#include <xrpld/core/Config.h>
22#include <xrpld/net/HTTPClient.h>
23#include <xrpld/net/RPCCall.h>
24#include <xrpld/rpc/ServerHandler.h>
25#include <xrpld/rpc/detail/RPCHelpers.h>
26
27#include <xrpl/basics/ByteUtilities.h>
28#include <xrpl/basics/Log.h>
29#include <xrpl/basics/StringUtilities.h>
30#include <xrpl/basics/base64.h>
31#include <xrpl/basics/contract.h>
32#include <xrpl/beast/core/LexicalCast.h>
33#include <xrpl/json/json_forwards.h>
34#include <xrpl/json/json_reader.h>
35#include <xrpl/json/to_string.h>
36#include <xrpl/protocol/ErrorCodes.h>
37#include <xrpl/protocol/RPCErr.h>
38#include <xrpl/protocol/SystemParameters.h>
39#include <xrpl/protocol/UintTypes.h>
40#include <xrpl/protocol/jss.h>
41
42#include <boost/algorithm/string/predicate.hpp>
43#include <boost/asio/streambuf.hpp>
44#include <boost/regex.hpp>
45
46#include <array>
47#include <iostream>
48#include <type_traits>
49#include <unordered_map>
50
51namespace ripple {
52
53class RPCParser;
54
55//
56// HTTP protocol
57//
58// This ain't Apache. We're just using HTTP header for the length field
59// and to be compatible with other JSON-RPC implementations.
60//
61
64 std::string const& strHost,
65 std::string const& strPath,
66 std::string const& strMsg,
67 std::unordered_map<std::string, std::string> const& mapRequestHeaders)
68{
70
71 // CHECKME this uses a different version than the replies below use. Is
72 // this by design or an accident or should it be using
73 // BuildInfo::getFullVersionString () as well?
74
75 s << "POST " << (strPath.empty() ? "/" : strPath) << " HTTP/1.0\r\n"
76 << "User-Agent: " << systemName() << "-json-rpc/v1\r\n"
77 << "Host: " << strHost << "\r\n"
78 << "Content-Type: application/json\r\n"
79 << "Content-Length: " << strMsg.size() << "\r\n"
80 << "Accept: application/json\r\n";
81
82 for (auto const& [k, v] : mapRequestHeaders)
83 s << k << ": " << v << "\r\n";
84
85 s << "\r\n" << strMsg;
86
87 return s.str();
88}
89
91{
92private:
93 unsigned const apiVersion_;
95
96 // TODO New routine for parsing ledger parameters, other routines should
97 // standardize on this.
98 static bool
99 jvParseLedger(Json::Value& jvRequest, std::string const& strLedger)
100 {
101 if (strLedger == "current" || strLedger == "closed" ||
102 strLedger == "validated")
103 {
104 jvRequest[jss::ledger_index] = strLedger;
105 }
106 else if (strLedger.length() == 64)
107 {
108 // YYY Could confirm this is a uint256.
109 jvRequest[jss::ledger_hash] = strLedger;
110 }
111 else
112 {
113 jvRequest[jss::ledger_index] =
114 beast::lexicalCast<std::uint32_t>(strLedger);
115 }
116
117 return true;
118 }
119
120 // Build a object { "currency" : "XYZ", "issuer" : "rXYX" }
121 static Json::Value
122 jvParseCurrencyIssuer(std::string const& strCurrencyIssuer)
123 {
124 // Matches a sequence of 3 characters from
125 // `ripple::detail::isoCharSet` (the currency),
126 // optionally followed by a forward slash and some other characters
127 // (the issuer).
128 // https://www.boost.org/doc/libs/1_82_0/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html
129 static boost::regex reCurIss(
130 "\\`([][:alnum:]<>(){}[|?!@#$%^&*]{3})(?:/(.+))?\\'");
131
132 boost::smatch smMatch;
133
134 if (boost::regex_match(strCurrencyIssuer, smMatch, reCurIss))
135 {
137 std::string strCurrency = smMatch[1];
138 std::string strIssuer = smMatch[2];
139
140 jvResult[jss::currency] = strCurrency;
141
142 if (strIssuer.length())
143 {
144 // Could confirm issuer is a valid Ripple address.
145 jvResult[jss::issuer] = strIssuer;
146 }
147
148 return jvResult;
149 }
150 else
151 {
153 std::string("Invalid currency/issuer '") + strCurrencyIssuer +
154 "'");
155 }
156 }
157
158 static bool
160 std::string const& strPk,
162 {
163 if (parseBase58<PublicKey>(type, strPk))
164 return true;
165
166 auto pkHex = strUnHex(strPk);
167 if (!pkHex)
168 return false;
169
170 if (!publicKeyType(makeSlice(*pkHex)))
171 return false;
172
173 return true;
174 }
175
176private:
178 Json::Value (RPCParser::*)(Json::Value const& jvParams);
179
181 parseAsIs(Json::Value const& jvParams)
182 {
184
185 if (jvParams.isArray() && (jvParams.size() > 0))
186 v[jss::params] = jvParams;
187
188 return v;
189 }
190
192 parseInternal(Json::Value const& jvParams)
193 {
195 v[jss::internal_command] = jvParams[0u];
196
198
199 for (unsigned i = 1; i < jvParams.size(); ++i)
200 params.append(jvParams[i]);
201
202 v[jss::params] = params;
203
204 return v;
205 }
206
208 parseManifest(Json::Value const& jvParams)
209 {
210 if (jvParams.size() == 1)
211 {
213
214 std::string const strPk = jvParams[0u].asString();
217
218 jvRequest[jss::public_key] = strPk;
219
220 return jvRequest;
221 }
222
224 }
225
226 // fetch_info [clear]
229 {
231 unsigned int iParams = jvParams.size();
232
233 if (iParams != 0)
234 jvRequest[jvParams[0u].asString()] = true;
235
236 return jvRequest;
237 }
238
239 // account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary]
240 // [count] [descending]
243 {
245 unsigned int iParams = jvParams.size();
246
247 auto const account = parseBase58<AccountID>(jvParams[0u].asString());
248 if (!account)
250
251 jvRequest[jss::account] = toBase58(*account);
252
253 bool bDone = false;
254
255 while (!bDone && iParams >= 2)
256 {
257 // VFALCO Why is Json::StaticString appearing on the right side?
258 if (jvParams[iParams - 1].asString() == jss::binary)
259 {
260 jvRequest[jss::binary] = true;
261 --iParams;
262 }
263 else if (jvParams[iParams - 1].asString() == jss::count)
264 {
265 jvRequest[jss::count] = true;
266 --iParams;
267 }
268 else if (jvParams[iParams - 1].asString() == jss::descending)
269 {
270 jvRequest[jss::descending] = true;
271 --iParams;
272 }
273 else
274 {
275 bDone = true;
276 }
277 }
278
279 if (1 == iParams)
280 {
281 }
282 else if (2 == iParams)
283 {
284 if (!jvParseLedger(jvRequest, jvParams[1u].asString()))
285 return jvRequest;
286 }
287 else
288 {
289 std::int64_t uLedgerMin = jvParams[1u].asInt();
290 std::int64_t uLedgerMax = jvParams[2u].asInt();
291
292 if (uLedgerMax != -1 && uLedgerMax < uLedgerMin)
293 {
294 if (apiVersion_ == 1)
296 return rpcError(rpcNOT_SYNCED);
297 }
298
299 jvRequest[jss::ledger_index_min] = jvParams[1u].asInt();
300 jvRequest[jss::ledger_index_max] = jvParams[2u].asInt();
301
302 if (iParams >= 4)
303 jvRequest[jss::limit] = jvParams[3u].asInt();
304
305 if (iParams >= 5)
306 jvRequest[jss::offset] = jvParams[4u].asInt();
307 }
308
309 return jvRequest;
310 }
311
312 // book_offers <taker_pays> <taker_gets> [<taker> [<ledger> [<limit>
313 // [<proof> [<marker>]]]]] limit: 0 = no limit proof: 0 or 1
314 //
315 // Mnemonic: taker pays --> offer --> taker gets
318 {
320
321 Json::Value jvTakerPays =
322 jvParseCurrencyIssuer(jvParams[0u].asString());
323 Json::Value jvTakerGets =
324 jvParseCurrencyIssuer(jvParams[1u].asString());
325
326 if (isRpcError(jvTakerPays))
327 {
328 return jvTakerPays;
329 }
330 else
331 {
332 jvRequest[jss::taker_pays] = jvTakerPays;
333 }
334
335 if (isRpcError(jvTakerGets))
336 {
337 return jvTakerGets;
338 }
339 else
340 {
341 jvRequest[jss::taker_gets] = jvTakerGets;
342 }
343
344 if (jvParams.size() >= 3)
345 {
346 jvRequest[jss::issuer] = jvParams[2u].asString();
347 }
348
349 if (jvParams.size() >= 4 &&
350 !jvParseLedger(jvRequest, jvParams[3u].asString()))
351 return jvRequest;
352
353 if (jvParams.size() >= 5)
354 {
355 int iLimit = jvParams[5u].asInt();
356
357 if (iLimit > 0)
358 jvRequest[jss::limit] = iLimit;
359 }
360
361 if (jvParams.size() >= 6 && jvParams[5u].asInt())
362 {
363 jvRequest[jss::proof] = true;
364 }
365
366 if (jvParams.size() == 7)
367 jvRequest[jss::marker] = jvParams[6u];
368
369 return jvRequest;
370 }
371
372 // can_delete [<ledgerid>|<ledgerhash>|now|always|never]
375 {
377
378 if (!jvParams.size())
379 return jvRequest;
380
381 std::string input = jvParams[0u].asString();
382 if (input.find_first_not_of("0123456789") == std::string::npos)
383 jvRequest["can_delete"] = jvParams[0u].asUInt();
384 else
385 jvRequest["can_delete"] = input;
386
387 return jvRequest;
388 }
389
390 // connect <ip[:port]> [port]
392 parseConnect(Json::Value const& jvParams)
393 {
395 std::string ip = jvParams[0u].asString();
396 if (jvParams.size() == 2)
397 {
398 jvRequest[jss::ip] = ip;
399 jvRequest[jss::port] = jvParams[1u].asUInt();
400 return jvRequest;
401 }
402
403 // handle case where there is one argument of the form ip:port
404 if (std::count(ip.begin(), ip.end(), ':') == 1)
405 {
406 std::size_t colon = ip.find_last_of(":");
407 jvRequest[jss::ip] = std::string{ip, 0, colon};
408 jvRequest[jss::port] =
409 Json::Value{std::string{ip, colon + 1}}.asUInt();
410 return jvRequest;
411 }
412
413 // default case, no port
414 jvRequest[jss::ip] = ip;
415 return jvRequest;
416 }
417
418 // deposit_authorized <source_account> <destination_account>
419 // [<ledger> [<credentials>, ...]]
422 {
424 jvRequest[jss::source_account] = jvParams[0u].asString();
425 jvRequest[jss::destination_account] = jvParams[1u].asString();
426
427 if (jvParams.size() >= 3)
428 jvParseLedger(jvRequest, jvParams[2u].asString());
429
430 // 8 credentials max
431 if ((jvParams.size() >= 4) && (jvParams.size() <= 11))
432 {
433 jvRequest[jss::credentials] = Json::Value(Json::arrayValue);
434 for (uint32_t i = 3; i < jvParams.size(); ++i)
435 jvRequest[jss::credentials].append(jvParams[i].asString());
436 }
437
438 return jvRequest;
439 }
440
441 // Return an error for attemping to subscribe/unsubscribe via RPC.
443 parseEvented(Json::Value const& jvParams)
444 {
445 return rpcError(rpcNO_EVENTS);
446 }
447
448 // feature [<feature>] [accept|reject]
450 parseFeature(Json::Value const& jvParams)
451 {
453
454 if (jvParams.size() > 0)
455 jvRequest[jss::feature] = jvParams[0u].asString();
456
457 if (jvParams.size() > 1)
458 {
459 auto const action = jvParams[1u].asString();
460
461 // This may look reversed, but it's intentional: jss::vetoed
462 // determines whether an amendment is vetoed - so "reject" means
463 // that jss::vetoed is true.
464 if (boost::iequals(action, "reject"))
465 jvRequest[jss::vetoed] = Json::Value(true);
466 else if (boost::iequals(action, "accept"))
467 jvRequest[jss::vetoed] = Json::Value(false);
468 else
470 }
471
472 return jvRequest;
473 }
474
475 // get_counts [<min_count>]
478 {
480
481 if (jvParams.size())
482 jvRequest[jss::min_count] = jvParams[0u].asUInt();
483
484 return jvRequest;
485 }
486
487 // sign_for <account> <secret> <json> offline
488 // sign_for <account> <secret> <json>
490 parseSignFor(Json::Value const& jvParams)
491 {
492 bool const bOffline =
493 4 == jvParams.size() && jvParams[3u].asString() == "offline";
494
495 if (3 == jvParams.size() || bOffline)
496 {
497 Json::Value txJSON;
498 Json::Reader reader;
499 if (reader.parse(jvParams[2u].asString(), txJSON))
500 {
501 // sign_for txJSON.
503
504 jvRequest[jss::account] = jvParams[0u].asString();
505 jvRequest[jss::secret] = jvParams[1u].asString();
506 jvRequest[jss::tx_json] = txJSON;
507
508 if (bOffline)
509 jvRequest[jss::offline] = true;
510
511 return jvRequest;
512 }
513 }
515 }
516
517 // json <command> <json>
519 parseJson(Json::Value const& jvParams)
520 {
521 Json::Reader reader;
522 Json::Value jvRequest;
523
524 JLOG(j_.trace()) << "RPC method: " << jvParams[0u];
525 JLOG(j_.trace()) << "RPC json: " << jvParams[1u];
526
527 if (reader.parse(jvParams[1u].asString(), jvRequest))
528 {
529 if (!jvRequest.isObjectOrNull())
531
532 jvRequest[jss::method] = jvParams[0u];
533
534 return jvRequest;
535 }
536
538 }
539
540 bool
542 {
543 if (jv.isArray())
544 {
545 if (jv.size() == 0)
546 return false;
547 for (auto const& j : jv)
548 {
549 if (!isValidJson2(j))
550 return false;
551 }
552 return true;
553 }
554 if (jv.isObject())
555 {
556 if (jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0" &&
557 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0" &&
558 jv.isMember(jss::id) && jv.isMember(jss::method))
559 {
560 if (jv.isMember(jss::params) &&
561 !(jv[jss::params].isNull() || jv[jss::params].isArray() ||
562 jv[jss::params].isObject()))
563 return false;
564 return true;
565 }
566 }
567 return false;
568 }
569
571 parseJson2(Json::Value const& jvParams)
572 {
573 Json::Reader reader;
574 Json::Value jv;
575 bool valid_parse = reader.parse(jvParams[0u].asString(), jv);
576 if (valid_parse && isValidJson2(jv))
577 {
578 if (jv.isObject())
579 {
581 if (jv.isMember(jss::params))
582 {
583 auto const& params = jv[jss::params];
584 for (auto i = params.begin(); i != params.end(); ++i)
585 jv1[i.key().asString()] = *i;
586 }
587 jv1[jss::jsonrpc] = jv[jss::jsonrpc];
588 jv1[jss::ripplerpc] = jv[jss::ripplerpc];
589 jv1[jss::id] = jv[jss::id];
590 jv1[jss::method] = jv[jss::method];
591 return jv1;
592 }
593 // else jv.isArray()
595 for (Json::UInt j = 0; j < jv.size(); ++j)
596 {
597 if (jv[j].isMember(jss::params))
598 {
599 auto const& params = jv[j][jss::params];
600 for (auto i = params.begin(); i != params.end(); ++i)
601 jv1[j][i.key().asString()] = *i;
602 }
603 jv1[j][jss::jsonrpc] = jv[j][jss::jsonrpc];
604 jv1[j][jss::ripplerpc] = jv[j][jss::ripplerpc];
605 jv1[j][jss::id] = jv[j][jss::id];
606 jv1[j][jss::method] = jv[j][jss::method];
607 }
608 return jv1;
609 }
610 auto jv_error = rpcError(rpcINVALID_PARAMS);
611 if (jv.isMember(jss::jsonrpc))
612 jv_error[jss::jsonrpc] = jv[jss::jsonrpc];
613 if (jv.isMember(jss::ripplerpc))
614 jv_error[jss::ripplerpc] = jv[jss::ripplerpc];
615 if (jv.isMember(jss::id))
616 jv_error[jss::id] = jv[jss::id];
617 return jv_error;
618 }
619
620 // ledger [id|index|current|closed|validated] [full|tx]
622 parseLedger(Json::Value const& jvParams)
623 {
625
626 if (!jvParams.size())
627 {
628 return jvRequest;
629 }
630
631 jvParseLedger(jvRequest, jvParams[0u].asString());
632
633 if (2 == jvParams.size())
634 {
635 if (jvParams[1u].asString() == "full")
636 {
637 jvRequest[jss::full] = true;
638 }
639 else if (jvParams[1u].asString() == "tx")
640 {
641 jvRequest[jss::transactions] = true;
642 jvRequest[jss::expand] = true;
643 }
644 }
645
646 return jvRequest;
647 }
648
649 // ledger_header <id>|<index>
651 parseLedgerId(Json::Value const& jvParams)
652 {
654
655 std::string strLedger = jvParams[0u].asString();
656
657 if (strLedger.length() == 64)
658 {
659 jvRequest[jss::ledger_hash] = strLedger;
660 }
661 else
662 {
663 jvRequest[jss::ledger_index] =
664 beast::lexicalCast<std::uint32_t>(strLedger);
665 }
666
667 return jvRequest;
668 }
669
670 // ledger_entry [id] [<index>]
673 {
675
676 jvRequest[jss::index] = jvParams[0u].asString();
677
678 if (jvParams.size() == 2 &&
679 !jvParseLedger(jvRequest, jvParams[1u].asString()))
681
682 return jvRequest;
683 }
684
685 // log_level: Get log levels
686 // log_level <severity>: Set master log level to the
687 // specified severity log_level <partition> <severity>: Set specified
688 // partition to specified severity
690 parseLogLevel(Json::Value const& jvParams)
691 {
693
694 if (jvParams.size() == 1)
695 {
696 jvRequest[jss::severity] = jvParams[0u].asString();
697 }
698 else if (jvParams.size() == 2)
699 {
700 jvRequest[jss::partition] = jvParams[0u].asString();
701 jvRequest[jss::severity] = jvParams[1u].asString();
702 }
703
704 return jvRequest;
705 }
706
707 // owner_info <account>
708 // account_info <account> [<ledger>]
709 // account_offers <account> [<ledger>]
712 {
713 return parseAccountRaw1(jvParams);
714 }
715
718 {
719 return parseAccountRaw1(jvParams);
720 }
721
722 // account_lines <account> <account>|"" [<ledger>]
725 {
726 return parseAccountRaw2(jvParams, jss::peer);
727 }
728
729 // account_channels <account> <account>|"" [<ledger>]
732 {
733 return parseAccountRaw2(jvParams, jss::destination_account);
734 }
735
736 // channel_authorize: <private_key> [<key_type>] <channel_id> <drops>
739 {
741
742 unsigned int index = 0;
743
744 if (jvParams.size() == 4)
745 {
746 jvRequest[jss::passphrase] = jvParams[index];
747 index++;
748
749 if (!keyTypeFromString(jvParams[index].asString()))
751 jvRequest[jss::key_type] = jvParams[index];
752 index++;
753 }
754 else
755 {
756 jvRequest[jss::secret] = jvParams[index];
757 index++;
758 }
759
760 {
761 // verify the channel id is a valid 256 bit number
762 uint256 channelId;
763 if (!channelId.parseHex(jvParams[index].asString()))
765 jvRequest[jss::channel_id] = to_string(channelId);
766 index++;
767 }
768
769 if (!jvParams[index].isString() ||
770 !to_uint64(jvParams[index].asString()))
772 jvRequest[jss::amount] = jvParams[index];
773
774 // If additional parameters are appended, be sure to increment index
775 // here
776
777 return jvRequest;
778 }
779
780 // channel_verify <public_key> <channel_id> <drops> <signature>
783 {
784 std::string const strPk = jvParams[0u].asString();
785
786 if (!validPublicKey(strPk))
788
790
791 jvRequest[jss::public_key] = strPk;
792 {
793 // verify the channel id is a valid 256 bit number
794 uint256 channelId;
795 if (!channelId.parseHex(jvParams[1u].asString()))
797 }
798 jvRequest[jss::channel_id] = jvParams[1u].asString();
799
800 if (!jvParams[2u].isString() || !to_uint64(jvParams[2u].asString()))
802 jvRequest[jss::amount] = jvParams[2u];
803
804 jvRequest[jss::signature] = jvParams[3u].asString();
805
806 return jvRequest;
807 }
808
810 parseAccountRaw2(Json::Value const& jvParams, char const* const acc2Field)
811 {
812 std::array<char const* const, 2> accFields{{jss::account, acc2Field}};
813 auto const nParams = jvParams.size();
815 for (auto i = 0; i < nParams; ++i)
816 {
817 std::string strParam = jvParams[i].asString();
818
819 if (i == 1 && strParam.empty())
820 continue;
821
822 // Parameters 0 and 1 are accounts
823 if (i < 2)
824 {
825 if (parseBase58<AccountID>(strParam))
826 {
827 jvRequest[accFields[i]] = std::move(strParam);
828 }
829 else
830 {
832 }
833 }
834 else
835 {
836 if (jvParseLedger(jvRequest, strParam))
837 return jvRequest;
839 }
840 }
841
842 return jvRequest;
843 }
844
845 // TODO: Get index from an alternate syntax: rXYZ:<index>
848 {
849 std::string strIdent = jvParams[0u].asString();
850 unsigned int iCursor = jvParams.size();
851
852 if (!parseBase58<AccountID>(strIdent))
854
855 // Get info on account.
857
858 jvRequest[jss::account] = strIdent;
859
860 if (iCursor == 2 && !jvParseLedger(jvRequest, jvParams[1u].asString()))
862
863 return jvRequest;
864 }
865
867 parseVault(Json::Value const& jvParams)
868 {
869 std::string strVaultID = jvParams[0u].asString();
870 uint256 id = beast::zero;
871 if (!id.parseHex(strVaultID))
873
875 jvRequest[jss::vault_id] = strVaultID;
876
877 if (jvParams.size() > 1)
878 jvParseLedger(jvRequest, jvParams[1u].asString());
879
880 return jvRequest;
881 }
882
883 // peer_reservations_add <public_key> [<name>]
886 {
887 Json::Value jvRequest;
888 jvRequest[jss::public_key] = jvParams[0u].asString();
889 if (jvParams.size() > 1)
890 {
891 jvRequest[jss::description] = jvParams[1u].asString();
892 }
893 return jvRequest;
894 }
895
896 // peer_reservations_del <public_key>
899 {
900 Json::Value jvRequest;
901 jvRequest[jss::public_key] = jvParams[0u].asString();
902 return jvRequest;
903 }
904
905 // ripple_path_find <json> [<ledger>]
908 {
909 Json::Reader reader;
911 bool bLedger = 2 == jvParams.size();
912
913 JLOG(j_.trace()) << "RPC json: " << jvParams[0u];
914
915 if (reader.parse(jvParams[0u].asString(), jvRequest))
916 {
917 if (bLedger)
918 {
919 jvParseLedger(jvRequest, jvParams[1u].asString());
920 }
921
922 return jvRequest;
923 }
924
926 }
927
928 // simulate any transaction on the network
929 //
930 // simulate <tx_blob> [binary]
931 // simulate <tx_json> [binary]
933 parseSimulate(Json::Value const& jvParams)
934 {
935 Json::Value txJSON;
936 Json::Reader reader;
938
939 if (reader.parse(jvParams[0u].asString(), txJSON))
940 {
941 jvRequest[jss::tx_json] = txJSON;
942 }
943 else
944 {
945 jvRequest[jss::tx_blob] = jvParams[0u].asString();
946 }
947
948 if (jvParams.size() == 2)
949 {
950 if (!jvParams[1u].isString() || jvParams[1u].asString() != "binary")
952 jvRequest[jss::binary] = true;
953 }
954
955 return jvRequest;
956 }
957
958 // sign/submit any transaction to the network
959 //
960 // sign <private_key> <json> offline
961 // submit <private_key> <json>
962 // submit <tx_blob>
965 {
966 Json::Value txJSON;
967 Json::Reader reader;
968 bool const bOffline =
969 3 == jvParams.size() && jvParams[2u].asString() == "offline";
970
971 if (1 == jvParams.size())
972 {
973 // Submitting tx_blob
974
976
977 jvRequest[jss::tx_blob] = jvParams[0u].asString();
978
979 return jvRequest;
980 }
981 else if (
982 (2 == jvParams.size() || bOffline) &&
983 reader.parse(jvParams[1u].asString(), txJSON))
984 {
985 // Signing or submitting tx_json.
987
988 jvRequest[jss::secret] = jvParams[0u].asString();
989 jvRequest[jss::tx_json] = txJSON;
990
991 if (bOffline)
992 jvRequest[jss::offline] = true;
993
994 return jvRequest;
995 }
996
998 }
999
1000 // submit any multisigned transaction to the network
1001 //
1002 // submit_multisigned <json>
1005 {
1006 if (1 == jvParams.size())
1007 {
1008 Json::Value txJSON;
1009 Json::Reader reader;
1010 if (reader.parse(jvParams[0u].asString(), txJSON))
1011 {
1012 Json::Value jvRequest{Json::objectValue};
1013 jvRequest[jss::tx_json] = txJSON;
1014 return jvRequest;
1015 }
1016 }
1017
1019 }
1020
1021 // transaction_entry <tx_hash> <ledger_hash/ledger_index>
1024 {
1025 // Parameter count should have already been verified.
1026 XRPL_ASSERT(
1027 jvParams.size() == 2,
1028 "ripple::RPCParser::parseTransactionEntry : valid parameter count");
1029
1030 std::string const txHash = jvParams[0u].asString();
1031 if (txHash.length() != 64)
1033
1034 Json::Value jvRequest{Json::objectValue};
1035 jvRequest[jss::tx_hash] = txHash;
1036
1037 jvParseLedger(jvRequest, jvParams[1u].asString());
1038
1039 // jvParseLedger inserts a "ledger_index" of 0 if it doesn't
1040 // find a match.
1041 if (jvRequest.isMember(jss::ledger_index) &&
1042 jvRequest[jss::ledger_index] == 0)
1044
1045 return jvRequest;
1046 }
1047
1048 // tx <transaction_id>
1050 parseTx(Json::Value const& jvParams)
1051 {
1052 Json::Value jvRequest{Json::objectValue};
1053
1054 if (jvParams.size() == 2 || jvParams.size() == 4)
1055 {
1056 if (jvParams[1u].asString() == jss::binary)
1057 jvRequest[jss::binary] = true;
1058 }
1059
1060 if (jvParams.size() >= 3)
1061 {
1062 auto const offset = jvParams.size() == 3 ? 0 : 1;
1063
1064 jvRequest[jss::min_ledger] = jvParams[1u + offset].asString();
1065 jvRequest[jss::max_ledger] = jvParams[2u + offset].asString();
1066 }
1067
1068 if (jvParams[0u].asString().length() == 16)
1069 jvRequest[jss::ctid] = jvParams[0u].asString();
1070 else
1071 jvRequest[jss::transaction] = jvParams[0u].asString();
1072
1073 return jvRequest;
1074 }
1075
1076 // tx_history <index>
1079 {
1080 Json::Value jvRequest{Json::objectValue};
1081
1082 jvRequest[jss::start] = jvParams[0u].asUInt();
1083
1084 return jvRequest;
1085 }
1086
1087 // validation_create [<pass_phrase>|<seed>|<seed_key>]
1088 //
1089 // NOTE: It is poor security to specify secret information on the command
1090 // line. This information might be saved in the command shell history file
1091 // (e.g. .bash_history) and it may be leaked via the process status command
1092 // (i.e. ps).
1095 {
1096 Json::Value jvRequest{Json::objectValue};
1097
1098 if (jvParams.size())
1099 jvRequest[jss::secret] = jvParams[0u].asString();
1100
1101 return jvRequest;
1102 }
1103
1104 // wallet_propose [<passphrase>]
1105 // <passphrase> is only for testing. Master seeds should only be generated
1106 // randomly.
1109 {
1110 Json::Value jvRequest{Json::objectValue};
1111
1112 if (jvParams.size())
1113 jvRequest[jss::passphrase] = jvParams[0u].asString();
1114
1115 return jvRequest;
1116 }
1117
1118 // parse gateway balances
1119 // gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ <hotwallet>
1120 // ]]
1121
1124 {
1125 unsigned int index = 0;
1126 unsigned int const size = jvParams.size();
1127
1128 Json::Value jvRequest{Json::objectValue};
1129
1130 std::string param = jvParams[index++].asString();
1131 if (param.empty())
1132 return RPC::make_param_error("Invalid first parameter");
1133
1134 if (param[0] != 'r')
1135 {
1136 if (param.size() == 64)
1137 jvRequest[jss::ledger_hash] = param;
1138 else
1139 jvRequest[jss::ledger_index] = param;
1140
1141 if (size <= index)
1142 return RPC::make_param_error("Invalid hotwallet");
1143
1144 param = jvParams[index++].asString();
1145 }
1146
1147 jvRequest[jss::account] = param;
1148
1149 if (index < size)
1150 {
1151 Json::Value& hotWallets =
1152 (jvRequest["hotwallet"] = Json::arrayValue);
1153 while (index < size)
1154 hotWallets.append(jvParams[index++].asString());
1155 }
1156
1157 return jvRequest;
1158 }
1159
1160 // server_definitions [hash]
1163 {
1164 Json::Value jvRequest{Json::objectValue};
1165
1166 if (jvParams.size() == 1)
1167 {
1168 jvRequest[jss::hash] = jvParams[0u].asString();
1169 }
1170
1171 return jvRequest;
1172 }
1173
1174 // server_info [counters]
1177 {
1178 Json::Value jvRequest(Json::objectValue);
1179 if (jvParams.size() == 1 && jvParams[0u].asString() == "counters")
1180 jvRequest[jss::counters] = true;
1181 return jvRequest;
1182 }
1183
1184public:
1185 //--------------------------------------------------------------------------
1186
1187 explicit RPCParser(unsigned apiVersion, beast::Journal j)
1188 : apiVersion_(apiVersion), j_(j)
1189 {
1190 }
1191
1192 //--------------------------------------------------------------------------
1193
1194 // Convert a rpc method and params to a request.
1195 // <-- { method: xyz, params: [... ] } or { error: ..., ... }
1198 std::string strMethod,
1199 Json::Value jvParams,
1200 bool allowAnyCommand)
1201 {
1202 if (auto stream = j_.trace())
1203 {
1204 stream << "Method: '" << strMethod << "'";
1205 stream << "Params: " << jvParams;
1206 }
1207
1208 struct Command
1209 {
1210 char const* name;
1211 parseFuncPtr parse;
1212 int minParams;
1213 int maxParams;
1214 };
1215
1216 static constexpr Command commands[] = {
1217 // Request-response methods
1218 // - Returns an error, or the request.
1219 // - To modify the method, provide a new method in the request.
1220 {"account_currencies", &RPCParser::parseAccountCurrencies, 1, 3},
1221 {"account_info", &RPCParser::parseAccountItems, 1, 3},
1222 {"account_lines", &RPCParser::parseAccountLines, 1, 5},
1223 {"account_channels", &RPCParser::parseAccountChannels, 1, 3},
1224 {"account_nfts", &RPCParser::parseAccountItems, 1, 5},
1225 {"account_objects", &RPCParser::parseAccountItems, 1, 5},
1226 {"account_offers", &RPCParser::parseAccountItems, 1, 4},
1227 {"account_tx", &RPCParser::parseAccountTransactions, 1, 8},
1228 {"amm_info", &RPCParser::parseAsIs, 1, 2},
1229 {"vault_info", &RPCParser::parseVault, 1, 2},
1230 {"book_changes", &RPCParser::parseLedgerId, 1, 1},
1231 {"book_offers", &RPCParser::parseBookOffers, 2, 7},
1232 {"can_delete", &RPCParser::parseCanDelete, 0, 1},
1233 {"channel_authorize", &RPCParser::parseChannelAuthorize, 3, 4},
1234 {"channel_verify", &RPCParser::parseChannelVerify, 4, 4},
1235 {"connect", &RPCParser::parseConnect, 1, 2},
1236 {"consensus_info", &RPCParser::parseAsIs, 0, 0},
1237 {"deposit_authorized", &RPCParser::parseDepositAuthorized, 2, 11},
1238 {"feature", &RPCParser::parseFeature, 0, 2},
1239 {"fetch_info", &RPCParser::parseFetchInfo, 0, 1},
1240 {"gateway_balances", &RPCParser::parseGatewayBalances, 1, -1},
1241 {"get_counts", &RPCParser::parseGetCounts, 0, 1},
1242 {"json", &RPCParser::parseJson, 2, 2},
1243 {"json2", &RPCParser::parseJson2, 1, 1},
1244 {"ledger", &RPCParser::parseLedger, 0, 2},
1245 {"ledger_accept", &RPCParser::parseAsIs, 0, 0},
1246 {"ledger_closed", &RPCParser::parseAsIs, 0, 0},
1247 {"ledger_current", &RPCParser::parseAsIs, 0, 0},
1248 {"ledger_entry", &RPCParser::parseLedgerEntry, 1, 2},
1249 {"ledger_header", &RPCParser::parseLedgerId, 1, 1},
1250 {"ledger_request", &RPCParser::parseLedgerId, 1, 1},
1251 {"log_level", &RPCParser::parseLogLevel, 0, 2},
1252 {"logrotate", &RPCParser::parseAsIs, 0, 0},
1253 {"manifest", &RPCParser::parseManifest, 1, 1},
1254 {"owner_info", &RPCParser::parseAccountItems, 1, 3},
1255 {"peers", &RPCParser::parseAsIs, 0, 0},
1256 {"ping", &RPCParser::parseAsIs, 0, 0},
1257 {"print", &RPCParser::parseAsIs, 0, 1},
1258 // { "profile", &RPCParser::parseProfile, 1, 9
1259 // },
1260 {"random", &RPCParser::parseAsIs, 0, 0},
1261 {"peer_reservations_add",
1263 1,
1264 2},
1265 {"peer_reservations_del",
1267 1,
1268 1},
1269 {"peer_reservations_list", &RPCParser::parseAsIs, 0, 0},
1270 {"ripple_path_find", &RPCParser::parseRipplePathFind, 1, 2},
1271 {"server_definitions", &RPCParser::parseServerDefinitions, 0, 1},
1272 {"server_info", &RPCParser::parseServerInfo, 0, 1},
1273 {"server_state", &RPCParser::parseServerInfo, 0, 1},
1274 {"sign", &RPCParser::parseSignSubmit, 2, 3},
1275 {"sign_for", &RPCParser::parseSignFor, 3, 4},
1276 {"stop", &RPCParser::parseAsIs, 0, 0},
1277 {"simulate", &RPCParser::parseSimulate, 1, 2},
1278 {"submit", &RPCParser::parseSignSubmit, 1, 3},
1279 {"submit_multisigned", &RPCParser::parseSubmitMultiSigned, 1, 1},
1280 {"transaction_entry", &RPCParser::parseTransactionEntry, 2, 2},
1281 {"tx", &RPCParser::parseTx, 1, 4},
1282 {"tx_history", &RPCParser::parseTxHistory, 1, 1},
1283 {"unl_list", &RPCParser::parseAsIs, 0, 0},
1284 {"validation_create", &RPCParser::parseValidationCreate, 0, 1},
1285 {"validator_info", &RPCParser::parseAsIs, 0, 0},
1286 {"version", &RPCParser::parseAsIs, 0, 0},
1287 {"wallet_propose", &RPCParser::parseWalletPropose, 0, 1},
1288 {"internal", &RPCParser::parseInternal, 1, -1},
1289
1290 // Evented methods
1291 {"path_find", &RPCParser::parseEvented, -1, -1},
1292 {"subscribe", &RPCParser::parseEvented, -1, -1},
1293 {"unsubscribe", &RPCParser::parseEvented, -1, -1},
1294 };
1295
1296 auto const count = jvParams.size();
1297
1298 for (auto const& command : commands)
1299 {
1300 if (strMethod == command.name)
1301 {
1302 if ((command.minParams >= 0 && count < command.minParams) ||
1303 (command.maxParams >= 0 && count > command.maxParams))
1304 {
1305 JLOG(j_.debug())
1306 << "Wrong number of parameters for " << command.name
1307 << " minimum=" << command.minParams
1308 << " maximum=" << command.maxParams
1309 << " actual=" << count;
1310
1311 return rpcError(rpcBAD_SYNTAX);
1312 }
1313
1314 return (this->*(command.parse))(jvParams);
1315 }
1316 }
1317
1318 // The command could not be found
1319 if (!allowAnyCommand)
1321
1322 return parseAsIs(jvParams);
1323 }
1324};
1325
1326//------------------------------------------------------------------------------
1327
1328//
1329// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1330// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1331// unspecified (HTTP errors and contents of 'error').
1332//
1333// 1.0 spec: http://json-rpc.org/wiki/specification
1334// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1335//
1336
1339 std::string const& strMethod,
1340 Json::Value const& params,
1341 Json::Value const& id)
1342{
1343 Json::Value request;
1344 request[jss::method] = strMethod;
1345 request[jss::params] = params;
1346 request[jss::id] = id;
1347 return to_string(request) + "\n";
1348}
1349
1350namespace {
1351// Special local exception type thrown when request can't be parsed.
1352class RequestNotParseable : public std::runtime_error
1353{
1354 using std::runtime_error::runtime_error; // Inherit constructors
1355};
1356}; // namespace
1357
1359{
1360 explicit RPCCallImp() = default;
1361
1362 // VFALCO NOTE Is this a to-do comment or a doc comment?
1363 // Place the async result somewhere useful.
1364 static void
1365 callRPCHandler(Json::Value* jvOutput, Json::Value const& jvInput)
1366 {
1367 (*jvOutput) = jvInput;
1368 }
1369
1370 static bool
1372 std::function<void(Json::Value const& jvInput)> callbackFuncP,
1373 boost::system::error_code const& ecResult,
1374 int iStatus,
1375 std::string const& strData,
1377 {
1378 if (callbackFuncP)
1379 {
1380 // Only care about the result, if we care to deliver it
1381 // callbackFuncP.
1382
1383 // Receive reply
1384 if (strData.empty())
1385 Throw<std::runtime_error>(
1386 "no response from server. Please "
1387 "ensure that the rippled server is running in another "
1388 "process.");
1389
1390 // Parse reply
1391 JLOG(j.debug()) << "RPC reply: " << strData << std::endl;
1392 if (strData.find("Unable to parse request") == 0 ||
1393 strData.find(jss::invalid_API_version.c_str()) == 0)
1394 Throw<RequestNotParseable>(strData);
1395 Json::Reader reader;
1396 Json::Value jvReply;
1397 if (!reader.parse(strData, jvReply))
1398 Throw<std::runtime_error>("couldn't parse reply from server");
1399
1400 if (!jvReply)
1401 Throw<std::runtime_error>(
1402 "expected reply to have result, error and id properties");
1403
1405
1406 jvResult["result"] = jvReply;
1407
1408 (callbackFuncP)(jvResult);
1409 }
1410
1411 return false;
1412 }
1413
1414 // Build the request.
1415 static void
1417 std::string const& strMethod,
1418 Json::Value const& jvParams,
1420 std::string const& strPath,
1421 boost::asio::streambuf& sb,
1422 std::string const& strHost,
1424 {
1425 JLOG(j.debug()) << "requestRPC: strPath='" << strPath << "'";
1426
1427 std::ostream osRequest(&sb);
1428 osRequest << createHTTPPost(
1429 strHost,
1430 strPath,
1431 JSONRPCRequest(strMethod, jvParams, Json::Value(1)),
1432 headers);
1433 }
1434};
1435
1436//------------------------------------------------------------------------------
1437
1438// Used internally by rpcClient.
1441 std::vector<std::string> const& args,
1442 Json::Value& retParams,
1443 unsigned int apiVersion,
1445{
1446 Json::Value jvRequest(Json::objectValue);
1447
1448 RPCParser rpParser(apiVersion, j);
1449 Json::Value jvRpcParams(Json::arrayValue);
1450
1451 for (int i = 1; i != args.size(); i++)
1452 jvRpcParams.append(args[i]);
1453
1454 retParams = Json::Value(Json::objectValue);
1455
1456 retParams[jss::method] = args[0];
1457 retParams[jss::params] = jvRpcParams;
1458
1459 jvRequest = rpParser.parseCommand(args[0], jvRpcParams, true);
1460
1461 auto insert_api_version = [apiVersion](Json::Value& jr) {
1462 if (jr.isObject() && !jr.isMember(jss::error) &&
1463 !jr.isMember(jss::api_version))
1464 {
1465 jr[jss::api_version] = apiVersion;
1466 }
1467 };
1468
1469 if (jvRequest.isObject())
1470 insert_api_version(jvRequest);
1471 else if (jvRequest.isArray())
1472 std::for_each(jvRequest.begin(), jvRequest.end(), insert_api_version);
1473
1474 JLOG(j.trace()) << "RPC Request: " << jvRequest << std::endl;
1475 return jvRequest;
1476}
1477
1478//------------------------------------------------------------------------------
1479
1482 std::vector<std::string> const& args,
1483 Config const& config,
1484 Logs& logs,
1485 unsigned int apiVersion,
1487{
1488 static_assert(
1489 rpcBAD_SYNTAX == 1 && rpcSUCCESS == 0,
1490 "Expect specific rpc enum values.");
1491 if (args.empty())
1492 return {rpcBAD_SYNTAX, {}}; // rpcBAD_SYNTAX = print usage
1493
1494 int nRet = rpcSUCCESS;
1495 Json::Value jvOutput;
1496 Json::Value jvRequest(Json::objectValue);
1497
1498 try
1499 {
1501 jvRequest =
1502 rpcCmdToJson(args, jvRpc, apiVersion, logs.journal("RPCParser"));
1503
1504 if (jvRequest.isMember(jss::error))
1505 {
1506 jvOutput = jvRequest;
1507 jvOutput["rpc"] = jvRpc;
1508 }
1509 else
1510 {
1512 try
1513 {
1514 setup = setup_ServerHandler(
1515 config,
1516 beast::logstream{logs.journal("HTTPClient").warn()});
1517 }
1518 catch (std::exception const&)
1519 {
1520 // ignore any exceptions, so the command
1521 // line client works without a config file
1522 }
1523
1524 if (config.rpc_ip)
1525 {
1526 setup.client.ip = config.rpc_ip->address().to_string();
1527 setup.client.port = config.rpc_ip->port();
1528 }
1529
1530 Json::Value jvParams(Json::arrayValue);
1531
1532 if (!setup.client.admin_user.empty())
1533 jvRequest["admin_user"] = setup.client.admin_user;
1534
1535 if (!setup.client.admin_password.empty())
1536 jvRequest["admin_password"] = setup.client.admin_password;
1537
1538 if (jvRequest.isObject())
1539 jvParams.append(jvRequest);
1540 else if (jvRequest.isArray())
1541 {
1542 for (Json::UInt i = 0; i < jvRequest.size(); ++i)
1543 jvParams.append(jvRequest[i]);
1544 }
1545
1546 {
1547 boost::asio::io_service isService;
1549 isService,
1550 setup.client.ip,
1551 setup.client.port,
1552 setup.client.user,
1553 setup.client.password,
1554 "",
1555 jvRequest.isMember(
1556 jss::method) // Allow parser to rewrite method.
1557 ? jvRequest[jss::method].asString()
1558 : jvRequest.isArray() ? "batch" : args[0],
1559 jvParams, // Parsed, execute.
1560 setup.client.secure != 0, // Use SSL
1561 config.quiet(),
1562 logs,
1563 std::bind(
1565 &jvOutput,
1566 std::placeholders::_1),
1567 headers);
1568 isService.run(); // This blocks until there are no more
1569 // outstanding async calls.
1570 }
1571 if (jvOutput.isMember("result"))
1572 {
1573 // Had a successful JSON-RPC 2.0 call.
1574 jvOutput = jvOutput["result"];
1575
1576 // jvOutput may report a server side error.
1577 // It should report "status".
1578 }
1579 else
1580 {
1581 // Transport error.
1582 Json::Value jvRpcError = jvOutput;
1583
1584 jvOutput = rpcError(rpcJSON_RPC);
1585 jvOutput["result"] = jvRpcError;
1586 }
1587
1588 // If had an error, supply invocation in result.
1589 if (jvOutput.isMember(jss::error))
1590 {
1591 jvOutput["rpc"] =
1592 jvRpc; // How the command was seen as method + params.
1593 jvOutput["request_sent"] =
1594 jvRequest; // How the command was translated.
1595 }
1596 }
1597
1598 if (jvOutput.isMember(jss::error))
1599 {
1600 jvOutput[jss::status] = "error";
1601 if (jvOutput.isMember(jss::error_code))
1602 nRet = std::stoi(jvOutput[jss::error_code].asString());
1603 else if (jvOutput[jss::error].isMember(jss::error_code))
1604 nRet =
1605 std::stoi(jvOutput[jss::error][jss::error_code].asString());
1606 else
1607 nRet = rpcBAD_SYNTAX;
1608 }
1609
1610 // YYY We could have a command line flag for single line output for
1611 // scripts. YYY We would intercept output here and simplify it.
1612 }
1613 catch (RequestNotParseable& e)
1614 {
1615 jvOutput = rpcError(rpcINVALID_PARAMS);
1616 jvOutput["error_what"] = e.what();
1617 nRet = rpcINVALID_PARAMS;
1618 }
1619 catch (std::exception& e)
1620 {
1621 jvOutput = rpcError(rpcINTERNAL);
1622 jvOutput["error_what"] = e.what();
1623 nRet = rpcINTERNAL;
1624 }
1625
1626 return {nRet, std::move(jvOutput)};
1627}
1628
1629//------------------------------------------------------------------------------
1630
1631namespace RPCCall {
1632
1633int
1635 Config const& config,
1636 std::vector<std::string> const& vCmd,
1637 Logs& logs)
1638{
1639 auto const result =
1640 rpcClient(vCmd, config, logs, RPC::apiCommandLineVersion);
1641
1642 std::cout << result.second.toStyledString();
1643
1644 return result.first;
1645}
1646
1647//------------------------------------------------------------------------------
1648
1649void
1651 boost::asio::io_service& io_service,
1652 std::string const& strIp,
1653 std::uint16_t const iPort,
1654 std::string const& strUsername,
1655 std::string const& strPassword,
1656 std::string const& strPath,
1657 std::string const& strMethod,
1658 Json::Value const& jvParams,
1659 bool const bSSL,
1660 bool const quiet,
1661 Logs& logs,
1662 std::function<void(Json::Value const& jvInput)> callbackFuncP,
1664{
1665 auto j = logs.journal("HTTPClient");
1666
1667 // Connect to localhost
1668 if (!quiet)
1669 {
1670 JLOG(j.info()) << (bSSL ? "Securely connecting to " : "Connecting to ")
1671 << strIp << ":" << iPort << std::endl;
1672 }
1673
1674 // HTTP basic authentication
1675 headers["Authorization"] =
1676 std::string("Basic ") + base64_encode(strUsername + ":" + strPassword);
1677
1678 // Send request
1679
1680 // Number of bytes to try to receive if no
1681 // Content-Length header received
1682 constexpr auto RPC_REPLY_MAX_BYTES = megabytes(256);
1683
1684 using namespace std::chrono_literals;
1685 auto constexpr RPC_WEBHOOK_TIMEOUT = 30s;
1686
1688 bSSL,
1689 io_service,
1690 strIp,
1691 iPort,
1692 std::bind(
1694 strMethod,
1695 jvParams,
1696 headers,
1697 strPath,
1698 std::placeholders::_1,
1699 std::placeholders::_2,
1700 j),
1701 RPC_REPLY_MAX_BYTES,
1702 RPC_WEBHOOK_TIMEOUT,
1703 std::bind(
1705 callbackFuncP,
1706 std::placeholders::_1,
1707 std::placeholders::_2,
1708 std::placeholders::_3,
1709 j),
1710 j);
1711}
1712
1713} // namespace RPCCall
1714
1715} // namespace ripple
T begin(T... args)
T bind(T... args)
Unserialize a JSON document into a Value.
Definition: json_reader.h:39
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:78
Represents a JSON value.
Definition: json_value.h:150
const_iterator begin() const
bool isArray() const
Value & append(Value const &value)
Append value to array at the end.
Definition: json_value.cpp:910
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:719
const_iterator end() const
bool isObjectOrNull() const
Int asInt() const
Definition: json_value.cpp:516
UInt asUInt() const
Definition: json_value.cpp:558
bool isObject() const
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:482
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:999
bool isMember(char const *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:962
A generic endpoint for log messages.
Definition: Journal.h:60
Stream debug() const
Definition: Journal.h:328
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
std::optional< beast::IP::Endpoint > rpc_ip
Definition: Config.h:274
bool quiet() const
Definition: Config.h:326
static void request(bool bSSL, boost::asio::io_service &io_service, std::string strSite, unsigned short const port, std::function< void(boost::asio::streambuf &sb, std::string const &strHost)> build, std::size_t responseMax, std::chrono::seconds timeout, std::function< bool(boost::system::error_code const &ecResult, int iStatus, std::string const &strData)> complete, beast::Journal &j)
Definition: HTTPClient.cpp:586
Manages partitions for logging.
Definition: Log.h:51
beast::Journal journal(std::string const &name)
Definition: Log.cpp:160
Json::Value parseLedger(Json::Value const &jvParams)
Definition: RPCCall.cpp:622
Json::Value parseValidationCreate(Json::Value const &jvParams)
Definition: RPCCall.cpp:1094
Json::Value parseBookOffers(Json::Value const &jvParams)
Definition: RPCCall.cpp:317
Json::Value parseTxHistory(Json::Value const &jvParams)
Definition: RPCCall.cpp:1078
Json::Value parseLedgerId(Json::Value const &jvParams)
Definition: RPCCall.cpp:651
Json::Value parseCommand(std::string strMethod, Json::Value jvParams, bool allowAnyCommand)
Definition: RPCCall.cpp:1197
Json::Value parseGatewayBalances(Json::Value const &jvParams)
Definition: RPCCall.cpp:1123
RPCParser(unsigned apiVersion, beast::Journal j)
Definition: RPCCall.cpp:1187
Json::Value parseAccountItems(Json::Value const &jvParams)
Definition: RPCCall.cpp:711
unsigned const apiVersion_
Definition: RPCCall.cpp:93
Json::Value parseJson(Json::Value const &jvParams)
Definition: RPCCall.cpp:519
Json::Value parseAccountRaw1(Json::Value const &jvParams)
Definition: RPCCall.cpp:847
Json::Value parseFetchInfo(Json::Value const &jvParams)
Definition: RPCCall.cpp:228
Json::Value parseSubmitMultiSigned(Json::Value const &jvParams)
Definition: RPCCall.cpp:1004
Json::Value parseAccountChannels(Json::Value const &jvParams)
Definition: RPCCall.cpp:731
Json::Value parseInternal(Json::Value const &jvParams)
Definition: RPCCall.cpp:192
static Json::Value jvParseCurrencyIssuer(std::string const &strCurrencyIssuer)
Definition: RPCCall.cpp:122
Json::Value parseSimulate(Json::Value const &jvParams)
Definition: RPCCall.cpp:933
Json::Value parseEvented(Json::Value const &jvParams)
Definition: RPCCall.cpp:443
Json::Value parseDepositAuthorized(Json::Value const &jvParams)
Definition: RPCCall.cpp:421
Json::Value parseAccountTransactions(Json::Value const &jvParams)
Definition: RPCCall.cpp:242
Json::Value parseChannelVerify(Json::Value const &jvParams)
Definition: RPCCall.cpp:782
Json::Value parseGetCounts(Json::Value const &jvParams)
Definition: RPCCall.cpp:477
Json::Value parseLogLevel(Json::Value const &jvParams)
Definition: RPCCall.cpp:690
bool isValidJson2(Json::Value const &jv)
Definition: RPCCall.cpp:541
Json::Value parseConnect(Json::Value const &jvParams)
Definition: RPCCall.cpp:392
static bool validPublicKey(std::string const &strPk, TokenType type=TokenType::AccountPublic)
Definition: RPCCall.cpp:159
Json::Value(RPCParser::*)(Json::Value const &jvParams) parseFuncPtr
Definition: RPCCall.cpp:178
beast::Journal const j_
Definition: RPCCall.cpp:94
Json::Value parseCanDelete(Json::Value const &jvParams)
Definition: RPCCall.cpp:374
Json::Value parseWalletPropose(Json::Value const &jvParams)
Definition: RPCCall.cpp:1108
Json::Value parseJson2(Json::Value const &jvParams)
Definition: RPCCall.cpp:571
Json::Value parseChannelAuthorize(Json::Value const &jvParams)
Definition: RPCCall.cpp:738
Json::Value parseAccountCurrencies(Json::Value const &jvParams)
Definition: RPCCall.cpp:717
Json::Value parsePeerReservationsDel(Json::Value const &jvParams)
Definition: RPCCall.cpp:898
Json::Value parseVault(Json::Value const &jvParams)
Definition: RPCCall.cpp:867
Json::Value parseLedgerEntry(Json::Value const &jvParams)
Definition: RPCCall.cpp:672
Json::Value parseTx(Json::Value const &jvParams)
Definition: RPCCall.cpp:1050
Json::Value parseServerInfo(Json::Value const &jvParams)
Definition: RPCCall.cpp:1176
Json::Value parseAsIs(Json::Value const &jvParams)
Definition: RPCCall.cpp:181
Json::Value parsePeerReservationsAdd(Json::Value const &jvParams)
Definition: RPCCall.cpp:885
Json::Value parseRipplePathFind(Json::Value const &jvParams)
Definition: RPCCall.cpp:907
Json::Value parseServerDefinitions(Json::Value const &jvParams)
Definition: RPCCall.cpp:1162
Json::Value parseTransactionEntry(Json::Value const &jvParams)
Definition: RPCCall.cpp:1023
Json::Value parseFeature(Json::Value const &jvParams)
Definition: RPCCall.cpp:450
Json::Value parseManifest(Json::Value const &jvParams)
Definition: RPCCall.cpp:208
Json::Value parseAccountRaw2(Json::Value const &jvParams, char const *const acc2Field)
Definition: RPCCall.cpp:810
static bool jvParseLedger(Json::Value &jvRequest, std::string const &strLedger)
Definition: RPCCall.cpp:99
Json::Value parseSignSubmit(Json::Value const &jvParams)
Definition: RPCCall.cpp:964
Json::Value parseAccountLines(Json::Value const &jvParams)
Definition: RPCCall.cpp:724
Json::Value parseSignFor(Json::Value const &jvParams)
Definition: RPCCall.cpp:490
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:503
T count(T... args)
T empty(T... args)
T end(T... args)
T endl(T... args)
T find_first_not_of(T... args)
T find(T... args)
T find_last_of(T... args)
T for_each(T... args)
@ arrayValue
array value (ordered list)
Definition: json_value.h:45
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
unsigned int UInt
Definition: json_forwards.h:27
int fromCommandLine(Config const &config, std::vector< std::string > const &vCmd, Logs &logs)
Definition: RPCCall.cpp:1634
void fromNetwork(boost::asio::io_service &io_service, std::string const &strIp, std::uint16_t const iPort, std::string const &strUsername, std::string const &strPassword, std::string const &strPath, std::string const &strMethod, Json::Value const &jvParams, bool const bSSL, bool const quiet, Logs &logs, std::function< void(Json::Value const &jvInput)> callbackFuncP, std::unordered_map< std::string, std::string > headers)
Definition: RPCCall.cpp:1650
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
Definition: ErrorCodes.h:264
static constexpr auto apiCommandLineVersion
Definition: ApiVersion.h:60
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::optional< KeyType > keyTypeFromString(std::string const &s)
Definition: KeyType.h:34
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
constexpr auto megabytes(T value) noexcept
Definition: ByteUtilities.h:34
std::pair< int, Json::Value > rpcClient(std::vector< std::string > const &args, Config const &config, Logs &logs, unsigned int apiVersion, std::unordered_map< std::string, std::string > const &headers)
Internal invocation of RPC client.
Definition: RPCCall.cpp:1481
static std::string const & systemName()
TokenType
Definition: tokens.h:38
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
std::string createHTTPPost(std::string const &strHost, std::string const &strPath, std::string const &strMsg, std::unordered_map< std::string, std::string > const &mapRequestHeaders)
Definition: RPCCall.cpp:63
@ rpcNO_EVENTS
Definition: ErrorCodes.h:54
@ rpcUNKNOWN_COMMAND
Definition: ErrorCodes.h:85
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
@ rpcBAD_KEY_TYPE
Definition: ErrorCodes.h:133
@ rpcCHANNEL_AMT_MALFORMED
Definition: ErrorCodes.h:101
@ rpcSUCCESS
Definition: ErrorCodes.h:44
@ rpcPUBLIC_MALFORMED
Definition: ErrorCodes.h:117
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
@ rpcINTERNAL
Definition: ErrorCodes.h:130
@ rpcBAD_SYNTAX
Definition: ErrorCodes.h:46
@ rpcLGR_IDXS_INVALID
Definition: ErrorCodes.h:112
@ rpcCHANNEL_MALFORMED
Definition: ErrorCodes.h:100
@ rpcLGR_IDX_MALFORMED
Definition: ErrorCodes.h:113
@ rpcJSON_RPC
Definition: ErrorCodes.h:47
@ rpcNOT_SYNCED
Definition: ErrorCodes.h:67
std::optional< std::uint64_t > to_uint64(std::string const &s)
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:31
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:223
bool isRpcError(Json::Value jvResult)
Definition: RPCErr.cpp:40
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:244
ServerHandler::Setup setup_ServerHandler(Config const &config, std::ostream &&log)
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:239
std::string JSONRPCRequest(std::string const &strMethod, Json::Value const &params, Json::Value const &id)
Definition: RPCCall.cpp:1338
Json::Value rpcCmdToJson(std::vector< std::string > const &args, Json::Value &retParams, unsigned int apiVersion, beast::Journal j)
Definition: RPCCall.cpp:1440
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
T size(T... args)
T stoi(T... args)
T str(T... args)
static void callRPCHandler(Json::Value *jvOutput, Json::Value const &jvInput)
Definition: RPCCall.cpp:1365
static bool onResponse(std::function< void(Json::Value const &jvInput)> callbackFuncP, boost::system::error_code const &ecResult, int iStatus, std::string const &strData, beast::Journal j)
Definition: RPCCall.cpp:1371
RPCCallImp()=default
static void onRequest(std::string const &strMethod, Json::Value const &jvParams, std::unordered_map< std::string, std::string > const &headers, std::string const &strPath, boost::asio::streambuf &sb, std::string const &strHost, beast::Journal j)
Definition: RPCCall.cpp:1416