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]
487  parseConnect(Json::Value const& jvParams)
488  {
489  Json::Value jvRequest(Json::objectValue);
490 
491  jvRequest[jss::ip] = jvParams[0u].asString();
492 
493  if (jvParams.size() == 2)
494  jvRequest[jss::port] = jvParams[1u].asUInt();
495 
496  return jvRequest;
497  }
498 
499  // deposit_authorized <source_account> <destination_account> [<ledger>]
502  {
503  Json::Value jvRequest(Json::objectValue);
504  jvRequest[jss::source_account] = jvParams[0u].asString();
505  jvRequest[jss::destination_account] = jvParams[1u].asString();
506 
507  if (jvParams.size() == 3)
508  jvParseLedger(jvRequest, jvParams[2u].asString());
509 
510  return jvRequest;
511  }
512 
513  // Return an error for attemping to subscribe/unsubscribe via RPC.
515  parseEvented(Json::Value const& jvParams)
516  {
517  return rpcError(rpcNO_EVENTS);
518  }
519 
520  // feature [<feature>] [accept|reject]
522  parseFeature(Json::Value const& jvParams)
523  {
524  Json::Value jvRequest(Json::objectValue);
525 
526  if (jvParams.size() > 0)
527  jvRequest[jss::feature] = jvParams[0u].asString();
528 
529  if (jvParams.size() > 1)
530  {
531  auto const action = jvParams[1u].asString();
532 
533  // This may look reversed, but it's intentional: jss::vetoed
534  // determines whether an amendment is vetoed - so "reject" means
535  // that jss::vetoed is true.
536  if (boost::iequals(action, "reject"))
537  jvRequest[jss::vetoed] = Json::Value(true);
538  else if (boost::iequals(action, "accept"))
539  jvRequest[jss::vetoed] = Json::Value(false);
540  else
541  return rpcError(rpcINVALID_PARAMS);
542  }
543 
544  return jvRequest;
545  }
546 
547  // get_counts [<min_count>]
549  parseGetCounts(Json::Value const& jvParams)
550  {
551  Json::Value jvRequest(Json::objectValue);
552 
553  if (jvParams.size())
554  jvRequest[jss::min_count] = jvParams[0u].asUInt();
555 
556  return jvRequest;
557  }
558 
559  // sign_for <account> <secret> <json> offline
560  // sign_for <account> <secret> <json>
562  parseSignFor(Json::Value const& jvParams)
563  {
564  bool const bOffline =
565  4 == jvParams.size() && jvParams[3u].asString() == "offline";
566 
567  if (3 == jvParams.size() || bOffline)
568  {
569  Json::Value txJSON;
570  Json::Reader reader;
571  if (reader.parse(jvParams[2u].asString(), txJSON))
572  {
573  // sign_for txJSON.
574  Json::Value jvRequest{Json::objectValue};
575 
576  jvRequest[jss::account] = jvParams[0u].asString();
577  jvRequest[jss::secret] = jvParams[1u].asString();
578  jvRequest[jss::tx_json] = txJSON;
579 
580  if (bOffline)
581  jvRequest[jss::offline] = true;
582 
583  return jvRequest;
584  }
585  }
586  return rpcError(rpcINVALID_PARAMS);
587  }
588 
589  // json <command> <json>
591  parseJson(Json::Value const& jvParams)
592  {
593  Json::Reader reader;
594  Json::Value jvRequest;
595 
596  JLOG(j_.trace()) << "RPC method: " << jvParams[0u];
597  JLOG(j_.trace()) << "RPC json: " << jvParams[1u];
598 
599  if (reader.parse(jvParams[1u].asString(), jvRequest))
600  {
601  if (!jvRequest.isObjectOrNull())
602  return rpcError(rpcINVALID_PARAMS);
603 
604  jvRequest[jss::method] = jvParams[0u];
605 
606  return jvRequest;
607  }
608 
609  return rpcError(rpcINVALID_PARAMS);
610  }
611 
612  bool
614  {
615  if (jv.isArray())
616  {
617  if (jv.size() == 0)
618  return false;
619  for (auto const& j : jv)
620  {
621  if (!isValidJson2(j))
622  return false;
623  }
624  return true;
625  }
626  if (jv.isObject())
627  {
628  if (jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0" &&
629  jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0" &&
630  jv.isMember(jss::id) && jv.isMember(jss::method))
631  {
632  if (jv.isMember(jss::params) &&
633  !(jv[jss::params].isNull() || jv[jss::params].isArray() ||
634  jv[jss::params].isObject()))
635  return false;
636  return true;
637  }
638  }
639  return false;
640  }
641 
643  parseJson2(Json::Value const& jvParams)
644  {
645  Json::Reader reader;
646  Json::Value jv;
647  bool valid_parse = reader.parse(jvParams[0u].asString(), jv);
648  if (valid_parse && isValidJson2(jv))
649  {
650  if (jv.isObject())
651  {
653  if (jv.isMember(jss::params))
654  {
655  auto const& params = jv[jss::params];
656  for (auto i = params.begin(); i != params.end(); ++i)
657  jv1[i.key().asString()] = *i;
658  }
659  jv1[jss::jsonrpc] = jv[jss::jsonrpc];
660  jv1[jss::ripplerpc] = jv[jss::ripplerpc];
661  jv1[jss::id] = jv[jss::id];
662  jv1[jss::method] = jv[jss::method];
663  return jv1;
664  }
665  // else jv.isArray()
667  for (Json::UInt j = 0; j < jv.size(); ++j)
668  {
669  if (jv[j].isMember(jss::params))
670  {
671  auto const& params = jv[j][jss::params];
672  for (auto i = params.begin(); i != params.end(); ++i)
673  jv1[j][i.key().asString()] = *i;
674  }
675  jv1[j][jss::jsonrpc] = jv[j][jss::jsonrpc];
676  jv1[j][jss::ripplerpc] = jv[j][jss::ripplerpc];
677  jv1[j][jss::id] = jv[j][jss::id];
678  jv1[j][jss::method] = jv[j][jss::method];
679  }
680  return jv1;
681  }
682  auto jv_error = rpcError(rpcINVALID_PARAMS);
683  if (jv.isMember(jss::jsonrpc))
684  jv_error[jss::jsonrpc] = jv[jss::jsonrpc];
685  if (jv.isMember(jss::ripplerpc))
686  jv_error[jss::ripplerpc] = jv[jss::ripplerpc];
687  if (jv.isMember(jss::id))
688  jv_error[jss::id] = jv[jss::id];
689  return jv_error;
690  }
691 
692  // ledger [id|index|current|closed|validated] [full|tx]
694  parseLedger(Json::Value const& jvParams)
695  {
696  Json::Value jvRequest(Json::objectValue);
697 
698  if (!jvParams.size())
699  {
700  return jvRequest;
701  }
702 
703  jvParseLedger(jvRequest, jvParams[0u].asString());
704 
705  if (2 == jvParams.size())
706  {
707  if (jvParams[1u].asString() == "full")
708  {
709  jvRequest[jss::full] = true;
710  }
711  else if (jvParams[1u].asString() == "tx")
712  {
713  jvRequest[jss::transactions] = true;
714  jvRequest[jss::expand] = true;
715  }
716  }
717 
718  return jvRequest;
719  }
720 
721  // ledger_header <id>|<index>
723  parseLedgerId(Json::Value const& jvParams)
724  {
725  Json::Value jvRequest(Json::objectValue);
726 
727  std::string strLedger = jvParams[0u].asString();
728 
729  if (strLedger.length() == 64)
730  {
731  jvRequest[jss::ledger_hash] = strLedger;
732  }
733  else
734  {
735  jvRequest[jss::ledger_index] =
736  beast::lexicalCast<std::uint32_t>(strLedger);
737  }
738 
739  return jvRequest;
740  }
741 
742  // log_level: Get log levels
743  // log_level <severity>: Set master log level to the
744  // specified severity log_level <partition> <severity>: Set specified
745  // partition to specified severity
747  parseLogLevel(Json::Value const& jvParams)
748  {
749  Json::Value jvRequest(Json::objectValue);
750 
751  if (jvParams.size() == 1)
752  {
753  jvRequest[jss::severity] = jvParams[0u].asString();
754  }
755  else if (jvParams.size() == 2)
756  {
757  jvRequest[jss::partition] = jvParams[0u].asString();
758  jvRequest[jss::severity] = jvParams[1u].asString();
759  }
760 
761  return jvRequest;
762  }
763 
764  // owner_info <account>|<account_public_key> [strict]
765  // owner_info <seed>|<pass_phrase>|<key> [<ledger>] [strict]
766  // account_info <account>|<account_public_key> [strict]
767  // account_info <seed>|<pass_phrase>|<key> [<ledger>] [strict]
768  // account_offers <account>|<account_public_key> [<ledger>] [strict]
771  {
772  return parseAccountRaw1(jvParams);
773  }
774 
777  {
778  return parseAccountRaw1(jvParams);
779  }
780 
781  // account_lines <account> <account>|"" [<ledger>]
784  {
785  return parseAccountRaw2(jvParams, jss::peer);
786  }
787 
788  // account_channels <account> <account>|"" [<ledger>]
791  {
792  return parseAccountRaw2(jvParams, jss::destination_account);
793  }
794 
795  // channel_authorize: <private_key> [<key_type>] <channel_id> <drops>
798  {
799  Json::Value jvRequest(Json::objectValue);
800 
801  unsigned int index = 0;
802 
803  if (jvParams.size() == 4)
804  {
805  jvRequest[jss::passphrase] = jvParams[index];
806  index++;
807 
808  if (!keyTypeFromString(jvParams[index].asString()))
809  return rpcError(rpcBAD_KEY_TYPE);
810  jvRequest[jss::key_type] = jvParams[index];
811  index++;
812  }
813  else
814  {
815  jvRequest[jss::secret] = jvParams[index];
816  index++;
817  }
818 
819  {
820  // verify the channel id is a valid 256 bit number
821  uint256 channelId;
822  if (!channelId.parseHex(jvParams[index].asString()))
824  jvRequest[jss::channel_id] = to_string(channelId);
825  index++;
826  }
827 
828  if (!jvParams[index].isString() ||
829  !to_uint64(jvParams[index].asString()))
831  jvRequest[jss::amount] = jvParams[index];
832 
833  // If additional parameters are appended, be sure to increment index
834  // here
835 
836  return jvRequest;
837  }
838 
839  // channel_verify <public_key> <channel_id> <drops> <signature>
842  {
843  std::string const strPk = jvParams[0u].asString();
844 
845  if (!validPublicKey(strPk))
847 
848  Json::Value jvRequest(Json::objectValue);
849 
850  jvRequest[jss::public_key] = strPk;
851  {
852  // verify the channel id is a valid 256 bit number
853  uint256 channelId;
854  if (!channelId.parseHex(jvParams[1u].asString()))
856  }
857  jvRequest[jss::channel_id] = jvParams[1u].asString();
858 
859  if (!jvParams[2u].isString() || !to_uint64(jvParams[2u].asString()))
861  jvRequest[jss::amount] = jvParams[2u];
862 
863  jvRequest[jss::signature] = jvParams[3u].asString();
864 
865  return jvRequest;
866  }
867 
869  parseAccountRaw2(Json::Value const& jvParams, char const* const acc2Field)
870  {
871  std::array<char const* const, 2> accFields{{jss::account, acc2Field}};
872  auto const nParams = jvParams.size();
873  Json::Value jvRequest(Json::objectValue);
874  for (auto i = 0; i < nParams; ++i)
875  {
876  std::string strParam = jvParams[i].asString();
877 
878  if (i == 1 && strParam.empty())
879  continue;
880 
881  // Parameters 0 and 1 are accounts
882  if (i < 2)
883  {
884  if (parseBase58<PublicKey>(
885  TokenType::AccountPublic, strParam) ||
886  parseBase58<AccountID>(strParam) ||
887  parseGenericSeed(strParam))
888  {
889  jvRequest[accFields[i]] = std::move(strParam);
890  }
891  else
892  {
893  return rpcError(rpcACT_MALFORMED);
894  }
895  }
896  else
897  {
898  if (jvParseLedger(jvRequest, strParam))
899  return jvRequest;
901  }
902  }
903 
904  return jvRequest;
905  }
906 
907  // TODO: Get index from an alternate syntax: rXYZ:<index>
909  parseAccountRaw1(Json::Value const& jvParams)
910  {
911  std::string strIdent = jvParams[0u].asString();
912  unsigned int iCursor = jvParams.size();
913  bool bStrict = false;
914 
915  if (iCursor >= 2 && jvParams[iCursor - 1] == jss::strict)
916  {
917  bStrict = true;
918  --iCursor;
919  }
920 
921  if (!parseBase58<PublicKey>(TokenType::AccountPublic, strIdent) &&
922  !parseBase58<AccountID>(strIdent) && !parseGenericSeed(strIdent))
923  return rpcError(rpcACT_MALFORMED);
924 
925  // Get info on account.
926  Json::Value jvRequest(Json::objectValue);
927 
928  jvRequest[jss::account] = strIdent;
929 
930  if (bStrict)
931  jvRequest[jss::strict] = 1;
932 
933  if (iCursor == 2 && !jvParseLedger(jvRequest, jvParams[1u].asString()))
935 
936  return jvRequest;
937  }
938 
940  parseNodeToShard(Json::Value const& jvParams)
941  {
942  Json::Value jvRequest;
943  jvRequest[jss::action] = jvParams[0u].asString();
944 
945  return jvRequest;
946  }
947 
948  // peer_reservations_add <public_key> [<name>]
951  {
952  Json::Value jvRequest;
953  jvRequest[jss::public_key] = jvParams[0u].asString();
954  if (jvParams.size() > 1)
955  {
956  jvRequest[jss::description] = jvParams[1u].asString();
957  }
958  return jvRequest;
959  }
960 
961  // peer_reservations_del <public_key>
964  {
965  Json::Value jvRequest;
966  jvRequest[jss::public_key] = jvParams[0u].asString();
967  return jvRequest;
968  }
969 
970  // ripple_path_find <json> [<ledger>]
973  {
974  Json::Reader reader;
975  Json::Value jvRequest{Json::objectValue};
976  bool bLedger = 2 == jvParams.size();
977 
978  JLOG(j_.trace()) << "RPC json: " << jvParams[0u];
979 
980  if (reader.parse(jvParams[0u].asString(), jvRequest))
981  {
982  if (bLedger)
983  {
984  jvParseLedger(jvRequest, jvParams[1u].asString());
985  }
986 
987  return jvRequest;
988  }
989 
990  return rpcError(rpcINVALID_PARAMS);
991  }
992 
993  // sign/submit any transaction to the network
994  //
995  // sign <private_key> <json> offline
996  // submit <private_key> <json>
997  // submit <tx_blob>
999  parseSignSubmit(Json::Value const& jvParams)
1000  {
1001  Json::Value txJSON;
1002  Json::Reader reader;
1003  bool const bOffline =
1004  3 == jvParams.size() && jvParams[2u].asString() == "offline";
1005 
1006  if (1 == jvParams.size())
1007  {
1008  // Submitting tx_blob
1009 
1010  Json::Value jvRequest{Json::objectValue};
1011 
1012  jvRequest[jss::tx_blob] = jvParams[0u].asString();
1013 
1014  return jvRequest;
1015  }
1016  else if (
1017  (2 == jvParams.size() || bOffline) &&
1018  reader.parse(jvParams[1u].asString(), txJSON))
1019  {
1020  // Signing or submitting tx_json.
1021  Json::Value jvRequest{Json::objectValue};
1022 
1023  jvRequest[jss::secret] = jvParams[0u].asString();
1024  jvRequest[jss::tx_json] = txJSON;
1025 
1026  if (bOffline)
1027  jvRequest[jss::offline] = true;
1028 
1029  return jvRequest;
1030  }
1031 
1032  return rpcError(rpcINVALID_PARAMS);
1033  }
1034 
1035  // submit any multisigned transaction to the network
1036  //
1037  // submit_multisigned <json>
1038  Json::Value
1040  {
1041  if (1 == jvParams.size())
1042  {
1043  Json::Value txJSON;
1044  Json::Reader reader;
1045  if (reader.parse(jvParams[0u].asString(), txJSON))
1046  {
1047  Json::Value jvRequest{Json::objectValue};
1048  jvRequest[jss::tx_json] = txJSON;
1049  return jvRequest;
1050  }
1051  }
1052 
1053  return rpcError(rpcINVALID_PARAMS);
1054  }
1055 
1056  // transaction_entry <tx_hash> <ledger_hash/ledger_index>
1057  Json::Value
1059  {
1060  // Parameter count should have already been verified.
1061  assert(jvParams.size() == 2);
1062 
1063  std::string const txHash = jvParams[0u].asString();
1064  if (txHash.length() != 64)
1065  return rpcError(rpcINVALID_PARAMS);
1066 
1067  Json::Value jvRequest{Json::objectValue};
1068  jvRequest[jss::tx_hash] = txHash;
1069 
1070  jvParseLedger(jvRequest, jvParams[1u].asString());
1071 
1072  // jvParseLedger inserts a "ledger_index" of 0 if it doesn't
1073  // find a match.
1074  if (jvRequest.isMember(jss::ledger_index) &&
1075  jvRequest[jss::ledger_index] == 0)
1076  return rpcError(rpcINVALID_PARAMS);
1077 
1078  return jvRequest;
1079  }
1080 
1081  // tx <transaction_id>
1082  Json::Value
1083  parseTx(Json::Value const& jvParams)
1084  {
1085  Json::Value jvRequest{Json::objectValue};
1086 
1087  if (jvParams.size() == 2 || jvParams.size() == 4)
1088  {
1089  if (jvParams[1u].asString() == jss::binary)
1090  jvRequest[jss::binary] = true;
1091  }
1092 
1093  if (jvParams.size() >= 3)
1094  {
1095  const auto offset = jvParams.size() == 3 ? 0 : 1;
1096 
1097  jvRequest[jss::min_ledger] = jvParams[1u + offset].asString();
1098  jvRequest[jss::max_ledger] = jvParams[2u + offset].asString();
1099  }
1100 
1101  jvRequest[jss::transaction] = jvParams[0u].asString();
1102  return jvRequest;
1103  }
1104 
1105  // tx_history <index>
1106  Json::Value
1107  parseTxHistory(Json::Value const& jvParams)
1108  {
1109  Json::Value jvRequest{Json::objectValue};
1110 
1111  jvRequest[jss::start] = jvParams[0u].asUInt();
1112 
1113  return jvRequest;
1114  }
1115 
1116  // validation_create [<pass_phrase>|<seed>|<seed_key>]
1117  //
1118  // NOTE: It is poor security to specify secret information on the command
1119  // line. This information might be saved in the command shell history file
1120  // (e.g. .bash_history) and it may be leaked via the process status command
1121  // (i.e. ps).
1122  Json::Value
1124  {
1125  Json::Value jvRequest{Json::objectValue};
1126 
1127  if (jvParams.size())
1128  jvRequest[jss::secret] = jvParams[0u].asString();
1129 
1130  return jvRequest;
1131  }
1132 
1133  // wallet_propose [<passphrase>]
1134  // <passphrase> is only for testing. Master seeds should only be generated
1135  // randomly.
1136  Json::Value
1138  {
1139  Json::Value jvRequest{Json::objectValue};
1140 
1141  if (jvParams.size())
1142  jvRequest[jss::passphrase] = jvParams[0u].asString();
1143 
1144  return jvRequest;
1145  }
1146 
1147  // parse gateway balances
1148  // gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ <hotwallet>
1149  // ]]
1150 
1151  Json::Value
1153  {
1154  unsigned int index = 0;
1155  const unsigned int size = jvParams.size();
1156 
1157  Json::Value jvRequest{Json::objectValue};
1158 
1159  std::string param = jvParams[index++].asString();
1160  if (param.empty())
1161  return RPC::make_param_error("Invalid first parameter");
1162 
1163  if (param[0] != 'r')
1164  {
1165  if (param.size() == 64)
1166  jvRequest[jss::ledger_hash] = param;
1167  else
1168  jvRequest[jss::ledger_index] = param;
1169 
1170  if (size <= index)
1171  return RPC::make_param_error("Invalid hotwallet");
1172 
1173  param = jvParams[index++].asString();
1174  }
1175 
1176  jvRequest[jss::account] = param;
1177 
1178  if (index < size)
1179  {
1180  Json::Value& hotWallets =
1181  (jvRequest["hotwallet"] = Json::arrayValue);
1182  while (index < size)
1183  hotWallets.append(jvParams[index++].asString());
1184  }
1185 
1186  return jvRequest;
1187  }
1188 
1189  // server_info [counters]
1190  Json::Value
1191  parseServerInfo(Json::Value const& jvParams)
1192  {
1193  Json::Value jvRequest(Json::objectValue);
1194  if (jvParams.size() == 1 && jvParams[0u].asString() == "counters")
1195  jvRequest[jss::counters] = true;
1196  return jvRequest;
1197  }
1198 
1199 public:
1200  //--------------------------------------------------------------------------
1201 
1202  explicit RPCParser(beast::Journal j) : j_(j)
1203  {
1204  }
1205 
1206  //--------------------------------------------------------------------------
1207 
1208  // Convert a rpc method and params to a request.
1209  // <-- { method: xyz, params: [... ] } or { error: ..., ... }
1210  Json::Value
1212  std::string strMethod,
1213  Json::Value jvParams,
1214  bool allowAnyCommand)
1215  {
1216  if (auto stream = j_.trace())
1217  {
1218  stream << "Method: '" << strMethod << "'";
1219  stream << "Params: " << jvParams;
1220  }
1221 
1222  struct Command
1223  {
1224  const char* name;
1225  parseFuncPtr parse;
1226  int minParams;
1227  int maxParams;
1228  };
1229 
1230  static constexpr Command commands[] = {
1231  // Request-response methods
1232  // - Returns an error, or the request.
1233  // - To modify the method, provide a new method in the request.
1234  {"account_currencies", &RPCParser::parseAccountCurrencies, 1, 3},
1235  {"account_info", &RPCParser::parseAccountItems, 1, 3},
1236  {"account_lines", &RPCParser::parseAccountLines, 1, 5},
1237  {"account_channels", &RPCParser::parseAccountChannels, 1, 3},
1238  {"account_nfts", &RPCParser::parseAccountItems, 1, 5},
1239  {"account_objects", &RPCParser::parseAccountItems, 1, 5},
1240  {"account_offers", &RPCParser::parseAccountItems, 1, 4},
1241  {"account_tx", &RPCParser::parseAccountTransactions, 1, 8},
1242  {"book_changes", &RPCParser::parseLedgerId, 1, 1},
1243  {"book_offers", &RPCParser::parseBookOffers, 2, 7},
1244  {"can_delete", &RPCParser::parseCanDelete, 0, 1},
1245  {"channel_authorize", &RPCParser::parseChannelAuthorize, 3, 4},
1246  {"channel_verify", &RPCParser::parseChannelVerify, 4, 4},
1247  {"connect", &RPCParser::parseConnect, 1, 2},
1248  {"consensus_info", &RPCParser::parseAsIs, 0, 0},
1249  {"deposit_authorized", &RPCParser::parseDepositAuthorized, 2, 3},
1250  {"download_shard", &RPCParser::parseDownloadShard, 2, -1},
1251  {"feature", &RPCParser::parseFeature, 0, 2},
1252  {"fetch_info", &RPCParser::parseFetchInfo, 0, 1},
1253  {"gateway_balances", &RPCParser::parseGatewayBalances, 1, -1},
1254  {"get_counts", &RPCParser::parseGetCounts, 0, 1},
1255  {"json", &RPCParser::parseJson, 2, 2},
1256  {"json2", &RPCParser::parseJson2, 1, 1},
1257  {"ledger", &RPCParser::parseLedger, 0, 2},
1258  {"ledger_accept", &RPCParser::parseAsIs, 0, 0},
1259  {"ledger_closed", &RPCParser::parseAsIs, 0, 0},
1260  {"ledger_current", &RPCParser::parseAsIs, 0, 0},
1261  // { "ledger_entry", &RPCParser::parseLedgerEntry,
1262  // -1, -1 },
1263  {"ledger_header", &RPCParser::parseLedgerId, 1, 1},
1264  {"ledger_request", &RPCParser::parseLedgerId, 1, 1},
1265  {"log_level", &RPCParser::parseLogLevel, 0, 2},
1266  {"logrotate", &RPCParser::parseAsIs, 0, 0},
1267  {"manifest", &RPCParser::parseManifest, 1, 1},
1268  {"node_to_shard", &RPCParser::parseNodeToShard, 1, 1},
1269  {"owner_info", &RPCParser::parseAccountItems, 1, 3},
1270  {"peers", &RPCParser::parseAsIs, 0, 0},
1271  {"ping", &RPCParser::parseAsIs, 0, 0},
1272  {"print", &RPCParser::parseAsIs, 0, 1},
1273  // { "profile", &RPCParser::parseProfile, 1, 9
1274  // },
1275  {"random", &RPCParser::parseAsIs, 0, 0},
1276  {"peer_reservations_add",
1278  1,
1279  2},
1280  {"peer_reservations_del",
1282  1,
1283  1},
1284  {"peer_reservations_list", &RPCParser::parseAsIs, 0, 0},
1285  {"ripple_path_find", &RPCParser::parseRipplePathFind, 1, 2},
1286  {"sign", &RPCParser::parseSignSubmit, 2, 3},
1287  {"sign_for", &RPCParser::parseSignFor, 3, 4},
1288  {"submit", &RPCParser::parseSignSubmit, 1, 3},
1289  {"submit_multisigned", &RPCParser::parseSubmitMultiSigned, 1, 1},
1290  {"server_info", &RPCParser::parseServerInfo, 0, 1},
1291  {"server_state", &RPCParser::parseServerInfo, 0, 1},
1292  {"crawl_shards", &RPCParser::parseAsIs, 0, 2},
1293  {"stop", &RPCParser::parseAsIs, 0, 0},
1294  {"transaction_entry", &RPCParser::parseTransactionEntry, 2, 2},
1295  {"tx", &RPCParser::parseTx, 1, 4},
1296  {"tx_account", &RPCParser::parseTxAccount, 1, 7},
1297  {"tx_history", &RPCParser::parseTxHistory, 1, 1},
1298  {"unl_list", &RPCParser::parseAsIs, 0, 0},
1299  {"validation_create", &RPCParser::parseValidationCreate, 0, 1},
1300  {"validator_info", &RPCParser::parseAsIs, 0, 0},
1301  {"version", &RPCParser::parseAsIs, 0, 0},
1302  {"wallet_propose", &RPCParser::parseWalletPropose, 0, 1},
1303  {"internal", &RPCParser::parseInternal, 1, -1},
1304 
1305  // Evented methods
1306  {"path_find", &RPCParser::parseEvented, -1, -1},
1307  {"subscribe", &RPCParser::parseEvented, -1, -1},
1308  {"unsubscribe", &RPCParser::parseEvented, -1, -1},
1309  };
1310 
1311  auto const count = jvParams.size();
1312 
1313  for (auto const& command : commands)
1314  {
1315  if (strMethod == command.name)
1316  {
1317  if ((command.minParams >= 0 && count < command.minParams) ||
1318  (command.maxParams >= 0 && count > command.maxParams))
1319  {
1320  JLOG(j_.debug())
1321  << "Wrong number of parameters for " << command.name
1322  << " minimum=" << command.minParams
1323  << " maximum=" << command.maxParams
1324  << " actual=" << count;
1325 
1326  return rpcError(rpcBAD_SYNTAX);
1327  }
1328 
1329  return (this->*(command.parse))(jvParams);
1330  }
1331  }
1332 
1333  // The command could not be found
1334  if (!allowAnyCommand)
1335  return rpcError(rpcUNKNOWN_COMMAND);
1336 
1337  return parseAsIs(jvParams);
1338  }
1339 };
1340 
1341 //------------------------------------------------------------------------------
1342 
1343 //
1344 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1345 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1346 // unspecified (HTTP errors and contents of 'error').
1347 //
1348 // 1.0 spec: http://json-rpc.org/wiki/specification
1349 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1350 //
1351 
1354  std::string const& strMethod,
1355  Json::Value const& params,
1356  Json::Value const& id)
1357 {
1358  Json::Value request;
1359  request[jss::method] = strMethod;
1360  request[jss::params] = params;
1361  request[jss::id] = id;
1362  return to_string(request) + "\n";
1363 }
1364 
1365 namespace {
1366 // Special local exception type thrown when request can't be parsed.
1367 class RequestNotParseable : public std::runtime_error
1368 {
1369  using std::runtime_error::runtime_error; // Inherit constructors
1370 };
1371 }; // namespace
1372 
1374 {
1375  explicit RPCCallImp() = default;
1376 
1377  // VFALCO NOTE Is this a to-do comment or a doc comment?
1378  // Place the async result somewhere useful.
1379  static void
1380  callRPCHandler(Json::Value* jvOutput, Json::Value const& jvInput)
1381  {
1382  (*jvOutput) = jvInput;
1383  }
1384 
1385  static bool
1387  std::function<void(Json::Value const& jvInput)> callbackFuncP,
1388  const boost::system::error_code& ecResult,
1389  int iStatus,
1390  std::string const& strData,
1391  beast::Journal j)
1392  {
1393  if (callbackFuncP)
1394  {
1395  // Only care about the result, if we care to deliver it
1396  // callbackFuncP.
1397 
1398  // Receive reply
1399  if (iStatus == 401)
1400  Throw<std::runtime_error>(
1401  "incorrect rpcuser or rpcpassword (authorization failed)");
1402  else if (
1403  (iStatus >= 400) && (iStatus != 400) && (iStatus != 404) &&
1404  (iStatus != 500)) // ?
1405  Throw<std::runtime_error>(
1406  std::string("server returned HTTP error ") +
1407  std::to_string(iStatus));
1408  else if (strData.empty())
1409  Throw<std::runtime_error>("no response from server");
1410 
1411  // Parse reply
1412  JLOG(j.debug()) << "RPC reply: " << strData << std::endl;
1413  if (strData.find("Unable to parse request") == 0 ||
1414  strData.find(jss::invalid_API_version.c_str()) == 0)
1415  Throw<RequestNotParseable>(strData);
1416  Json::Reader reader;
1417  Json::Value jvReply;
1418  if (!reader.parse(strData, jvReply))
1419  Throw<std::runtime_error>("couldn't parse reply from server");
1420 
1421  if (!jvReply)
1422  Throw<std::runtime_error>(
1423  "expected reply to have result, error and id properties");
1424 
1425  Json::Value jvResult(Json::objectValue);
1426 
1427  jvResult["result"] = jvReply;
1428 
1429  (callbackFuncP)(jvResult);
1430  }
1431 
1432  return false;
1433  }
1434 
1435  // Build the request.
1436  static void
1438  std::string const& strMethod,
1439  Json::Value const& jvParams,
1441  std::string const& strPath,
1442  boost::asio::streambuf& sb,
1443  std::string const& strHost,
1444  beast::Journal j)
1445  {
1446  JLOG(j.debug()) << "requestRPC: strPath='" << strPath << "'";
1447 
1448  std::ostream osRequest(&sb);
1449  osRequest << createHTTPPost(
1450  strHost,
1451  strPath,
1452  JSONRPCRequest(strMethod, jvParams, Json::Value(1)),
1453  headers);
1454  }
1455 };
1456 
1457 //------------------------------------------------------------------------------
1458 
1459 // Used internally by rpcClient.
1460 static Json::Value
1462  std::vector<std::string> const& args,
1463  Json::Value& retParams,
1464  beast::Journal j)
1465 {
1466  Json::Value jvRequest(Json::objectValue);
1467 
1468  RPCParser rpParser(j);
1469  Json::Value jvRpcParams(Json::arrayValue);
1470 
1471  for (int i = 1; i != args.size(); i++)
1472  jvRpcParams.append(args[i]);
1473 
1474  retParams = Json::Value(Json::objectValue);
1475 
1476  retParams[jss::method] = args[0];
1477  retParams[jss::params] = jvRpcParams;
1478 
1479  jvRequest = rpParser.parseCommand(args[0], jvRpcParams, true);
1480 
1481  auto insert_api_version = [](Json::Value& jr) {
1482  if (jr.isObject() && !jr.isMember(jss::error) &&
1483  !jr.isMember(jss::api_version))
1484  {
1485  jr[jss::api_version] = RPC::apiMaximumSupportedVersion;
1486  }
1487  };
1488 
1489  if (jvRequest.isObject())
1490  insert_api_version(jvRequest);
1491  else if (jvRequest.isArray())
1492  std::for_each(jvRequest.begin(), jvRequest.end(), insert_api_version);
1493 
1494  JLOG(j.trace()) << "RPC Request: " << jvRequest << std::endl;
1495  return jvRequest;
1496 }
1497 
1500 {
1502  auto const paramsObj = rpcCmdLineToJson(args, jv, j);
1503 
1504  // Re-use jv to return our formatted result.
1505  jv.clear();
1506 
1507  // Allow parser to rewrite method.
1508  jv[jss::method] = paramsObj.isMember(jss::method)
1509  ? paramsObj[jss::method].asString()
1510  : args[0];
1511 
1512  // If paramsObj is not empty, put it in a [params] array.
1513  if (paramsObj.begin() != paramsObj.end())
1514  {
1515  auto& paramsArray = Json::setArray(jv, jss::params);
1516  paramsArray.append(paramsObj);
1517  }
1518  if (paramsObj.isMember(jss::jsonrpc))
1519  jv[jss::jsonrpc] = paramsObj[jss::jsonrpc];
1520  if (paramsObj.isMember(jss::ripplerpc))
1521  jv[jss::ripplerpc] = paramsObj[jss::ripplerpc];
1522  if (paramsObj.isMember(jss::id))
1523  jv[jss::id] = paramsObj[jss::id];
1524  return jv;
1525 }
1526 
1527 //------------------------------------------------------------------------------
1528 
1531  std::vector<std::string> const& args,
1532  Config const& config,
1533  Logs& logs,
1535 {
1536  static_assert(
1537  rpcBAD_SYNTAX == 1 && rpcSUCCESS == 0,
1538  "Expect specific rpc enum values.");
1539  if (args.empty())
1540  return {rpcBAD_SYNTAX, {}}; // rpcBAD_SYNTAX = print usage
1541 
1542  int nRet = rpcSUCCESS;
1543  Json::Value jvOutput;
1544  Json::Value jvRequest(Json::objectValue);
1545 
1546  try
1547  {
1549  jvRequest = rpcCmdLineToJson(args, jvRpc, logs.journal("RPCParser"));
1550 
1551  if (jvRequest.isMember(jss::error))
1552  {
1553  jvOutput = jvRequest;
1554  jvOutput["rpc"] = jvRpc;
1555  }
1556  else
1557  {
1558  ServerHandler::Setup setup;
1559  try
1560  {
1561  setup = setup_ServerHandler(
1562  config,
1563  beast::logstream{logs.journal("HTTPClient").warn()});
1564  }
1565  catch (std::exception const&)
1566  {
1567  // ignore any exceptions, so the command
1568  // line client works without a config file
1569  }
1570 
1571  if (config.rpc_ip)
1572  {
1573  setup.client.ip = config.rpc_ip->address().to_string();
1574  setup.client.port = config.rpc_ip->port();
1575  }
1576 
1577  Json::Value jvParams(Json::arrayValue);
1578 
1579  if (!setup.client.admin_user.empty())
1580  jvRequest["admin_user"] = setup.client.admin_user;
1581 
1582  if (!setup.client.admin_password.empty())
1583  jvRequest["admin_password"] = setup.client.admin_password;
1584 
1585  if (jvRequest.isObject())
1586  jvParams.append(jvRequest);
1587  else if (jvRequest.isArray())
1588  {
1589  for (Json::UInt i = 0; i < jvRequest.size(); ++i)
1590  jvParams.append(jvRequest[i]);
1591  }
1592 
1593  {
1594  boost::asio::io_service isService;
1596  isService,
1597  setup.client.ip,
1598  setup.client.port,
1599  setup.client.user,
1600  setup.client.password,
1601  "",
1602  jvRequest.isMember(
1603  jss::method) // Allow parser to rewrite method.
1604  ? jvRequest[jss::method].asString()
1605  : jvRequest.isArray() ? "batch" : args[0],
1606  jvParams, // Parsed, execute.
1607  setup.client.secure != 0, // Use SSL
1608  config.quiet(),
1609  logs,
1610  std::bind(
1612  &jvOutput,
1613  std::placeholders::_1),
1614  headers);
1615  isService.run(); // This blocks until there are no more
1616  // outstanding async calls.
1617  }
1618  if (jvOutput.isMember("result"))
1619  {
1620  // Had a successful JSON-RPC 2.0 call.
1621  jvOutput = jvOutput["result"];
1622 
1623  // jvOutput may report a server side error.
1624  // It should report "status".
1625  }
1626  else
1627  {
1628  // Transport error.
1629  Json::Value jvRpcError = jvOutput;
1630 
1631  jvOutput = rpcError(rpcJSON_RPC);
1632  jvOutput["result"] = jvRpcError;
1633  }
1634 
1635  // If had an error, supply invocation in result.
1636  if (jvOutput.isMember(jss::error))
1637  {
1638  jvOutput["rpc"] =
1639  jvRpc; // How the command was seen as method + params.
1640  jvOutput["request_sent"] =
1641  jvRequest; // How the command was translated.
1642  }
1643  }
1644 
1645  if (jvOutput.isMember(jss::error))
1646  {
1647  jvOutput[jss::status] = "error";
1648  if (jvOutput.isMember(jss::error_code))
1649  nRet = std::stoi(jvOutput[jss::error_code].asString());
1650  else if (jvOutput[jss::error].isMember(jss::error_code))
1651  nRet =
1652  std::stoi(jvOutput[jss::error][jss::error_code].asString());
1653  else
1654  nRet = rpcBAD_SYNTAX;
1655  }
1656 
1657  // YYY We could have a command line flag for single line output for
1658  // scripts. YYY We would intercept output here and simplify it.
1659  }
1660  catch (RequestNotParseable& e)
1661  {
1662  jvOutput = rpcError(rpcINVALID_PARAMS);
1663  jvOutput["error_what"] = e.what();
1664  nRet = rpcINVALID_PARAMS;
1665  }
1666  catch (std::exception& e)
1667  {
1668  jvOutput = rpcError(rpcINTERNAL);
1669  jvOutput["error_what"] = e.what();
1670  nRet = rpcINTERNAL;
1671  }
1672 
1673  return {nRet, std::move(jvOutput)};
1674 }
1675 
1676 //------------------------------------------------------------------------------
1677 
1678 namespace RPCCall {
1679 
1680 int
1682  Config const& config,
1683  const std::vector<std::string>& vCmd,
1684  Logs& logs)
1685 {
1686  auto const result = rpcClient(vCmd, config, logs);
1687 
1688  std::cout << result.second.toStyledString();
1689 
1690  return result.first;
1691 }
1692 
1693 //------------------------------------------------------------------------------
1694 
1695 void
1697  boost::asio::io_service& io_service,
1698  std::string const& strIp,
1699  const std::uint16_t iPort,
1700  std::string const& strUsername,
1701  std::string const& strPassword,
1702  std::string const& strPath,
1703  std::string const& strMethod,
1704  Json::Value const& jvParams,
1705  const bool bSSL,
1706  const bool quiet,
1707  Logs& logs,
1708  std::function<void(Json::Value const& jvInput)> callbackFuncP,
1710 {
1711  auto j = logs.journal("HTTPClient");
1712 
1713  // Connect to localhost
1714  if (!quiet)
1715  {
1716  JLOG(j.info()) << (bSSL ? "Securely connecting to " : "Connecting to ")
1717  << strIp << ":" << iPort << std::endl;
1718  }
1719 
1720  // HTTP basic authentication
1721  headers["Authorization"] =
1722  std::string("Basic ") + base64_encode(strUsername + ":" + strPassword);
1723 
1724  // Send request
1725 
1726  // Number of bytes to try to receive if no
1727  // Content-Length header received
1728  constexpr auto RPC_REPLY_MAX_BYTES = megabytes(256);
1729 
1730  using namespace std::chrono_literals;
1731  auto constexpr RPC_NOTIFY = 10min;
1732 
1734  bSSL,
1735  io_service,
1736  strIp,
1737  iPort,
1738  std::bind(
1740  strMethod,
1741  jvParams,
1742  headers,
1743  strPath,
1744  std::placeholders::_1,
1745  std::placeholders::_2,
1746  j),
1747  RPC_REPLY_MAX_BYTES,
1748  RPC_NOTIFY,
1749  std::bind(
1751  callbackFuncP,
1752  std::placeholders::_1,
1753  std::placeholders::_2,
1754  std::placeholders::_3,
1755  j),
1756  j);
1757 }
1758 
1759 } // namespace RPCCall
1760 
1761 } // 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:1107
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:841
ripple::RPCParser::parseFeature
Json::Value parseFeature(Json::Value const &jvParams)
Definition: RPCCall.cpp:522
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:783
ripple::RPCParser::parseAccountRaw2
Json::Value parseAccountRaw2(Json::Value const &jvParams, char const *const acc2Field)
Definition: RPCCall.cpp:869
ripple::RPCParser::parseCanDelete
Json::Value parseCanDelete(Json::Value const &jvParams)
Definition: RPCCall.cpp:469
ripple::RPCCallImp
Definition: RPCCall.cpp:1373
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:643
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:1202
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:1380
iostream
ripple::RPCParser::parseChannelAuthorize
Json::Value parseChannelAuthorize(Json::Value const &jvParams)
Definition: RPCCall.cpp:797
ripple::RPCParser::parseAccountItems
Json::Value parseAccountItems(Json::Value const &jvParams)
Definition: RPCCall.cpp:770
ripple::RPCParser::jvParseCurrencyIssuer
static Json::Value jvParseCurrencyIssuer(std::string const &strCurrencyIssuer)
Definition: RPCCall.cpp:122
ripple::Config::quiet
bool quiet() const
Definition: Config.h:302
ripple::RPCParser::parseSubmitMultiSigned
Json::Value parseSubmitMultiSigned(Json::Value const &jvParams)
Definition: RPCCall.cpp:1039
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:950
ripple::setup_ServerHandler
ServerHandler::Setup setup_ServerHandler(Config const &config, std::ostream &&log)
Definition: ServerHandlerImp.cpp:1211
std::cout
ripple::publicKeyType
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:206
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:1437
ripple::base_uint< 256 >
ripple::RPCParser::parseGatewayBalances
Json::Value parseGatewayBalances(Json::Value const &jvParams)
Definition: RPCCall.cpp:1152
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:909
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:1191
ripple::Config
Definition: Config.h:69
ripple::RPCParser::parseAccountCurrencies
Json::Value parseAccountCurrencies(Json::Value const &jvParams)
Definition: RPCCall.cpp:776
std::ostream
STL class.
ripple::RPCParser::parseLogLevel
Json::Value parseLogLevel(Json::Value const &jvParams)
Definition: RPCCall.cpp:747
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:1083
std::to_string
T to_string(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:1211
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:1137
std::int64_t
ripple::RPCParser::parseLedger
Json::Value parseLedger(Json::Value const &jvParams)
Definition: RPCCall.cpp:694
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:972
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:1123
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:1681
ripple::RPCParser::parseEvented
Json::Value parseEvented(Json::Value const &jvParams)
Definition: RPCCall.cpp:515
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:1353
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:1499
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:501
ripple::rpcCmdLineToJson
static Json::Value rpcCmdLineToJson(std::vector< std::string > const &args, Json::Value &retParams, beast::Journal j)
Definition: RPCCall.cpp:1461
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:1386
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:1530
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:723
ripple::rpcLGR_IDX_MALFORMED
@ rpcLGR_IDX_MALFORMED
Definition: ErrorCodes.h:113
ripple::rpcCHANNEL_MALFORMED
@ rpcCHANNEL_MALFORMED
Definition: ErrorCodes.h:100
std::string::empty
T empty(T... args)
ripple::RPCParser::parseGetCounts
Json::Value parseGetCounts(Json::Value const &jvParams)
Definition: RPCCall.cpp:549
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
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:613
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:1696
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:495
ripple::RPCParser::parseJson
Json::Value parseJson(Json::Value const &jvParams)
Definition: RPCCall.cpp:591
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:234
ripple::RPCParser::parseSignFor
Json::Value parseSignFor(Json::Value const &jvParams)
Definition: RPCCall.cpp:562
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:940
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:963
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:790
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:1058
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::RPCParser::parseSignSubmit
Json::Value parseSignSubmit(Json::Value const &jvParams)
Definition: RPCCall.cpp:999
ripple::Config::rpc_ip
std::optional< beast::IP::Endpoint > rpc_ip
Definition: Config.h:260
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