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