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