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