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