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