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