rippled
RPCHelpers.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 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/ledger/LedgerMaster.h>
21 #include <ripple/app/ledger/OpenLedger.h>
22 #include <ripple/app/misc/Transaction.h>
23 #include <ripple/ledger/View.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/protocol/AccountID.h>
26 #include <ripple/protocol/Feature.h>
27 #include <ripple/rpc/Context.h>
28 #include <ripple/rpc/DeliveredAmount.h>
29 #include <ripple/rpc/impl/RPCHelpers.h>
30 #include <boost/algorithm/string/case_conv.hpp>
31 
32 #include <ripple/rpc/impl/GRPCHelpers.h>
33 
34 namespace ripple {
35 namespace RPC {
36 
37 boost::optional<AccountID>
39 {
40  boost::optional<AccountID> result;
41 
42  auto const publicKey =
43  parseBase58<PublicKey>(TokenType::AccountPublic, account);
44 
45  if (publicKey)
46  result = calcAccountID(*publicKey);
47  else
48  result = parseBase58<AccountID>(account);
49 
50  return result;
51 }
52 
55  AccountID& result,
56  std::string const& strIdent,
57  bool bStrict)
58 {
59  if (auto accountID = accountFromStringStrict(strIdent))
60  {
61  result = *accountID;
62  return rpcSUCCESS;
63  }
64 
65  if (bStrict)
66  {
67  auto id = deprecatedParseBitcoinAccountID(strIdent);
68  return id ? rpcACT_BITCOIN : rpcACT_MALFORMED;
69  }
70 
71  // We allow the use of the seeds which is poor practice
72  // and merely for debugging convenience.
73  auto const seed = parseGenericSeed(strIdent);
74 
75  if (!seed)
76  return rpcBAD_SEED;
77 
78  auto const keypair = generateKeyPair(KeyType::secp256k1, *seed);
79 
80  result = calcAccountID(keypair.first);
81  return rpcSUCCESS;
82 }
83 
85 accountFromString(AccountID& result, std::string const& strIdent, bool bStrict)
86 {
87  error_code_i code = accountFromStringWithCode(result, strIdent, bStrict);
88  if (code != rpcSUCCESS)
89  return rpcError(code);
90  else
91  return Json::objectValue;
92 }
93 
94 bool
96  ReadView const& ledger,
97  AccountID const& account,
98  boost::optional<std::vector<LedgerEntryType>> const& typeFilter,
99  uint256 dirIndex,
100  uint256 const& entryIndex,
101  std::uint32_t const limit,
102  Json::Value& jvResult)
103 {
104  auto const root = keylet::ownerDir(account);
105  auto found = false;
106 
107  if (dirIndex.isZero())
108  {
109  dirIndex = root.key;
110  found = true;
111  }
112 
113  auto dir = ledger.read({ltDIR_NODE, dirIndex});
114  if (!dir)
115  return false;
116 
117  std::uint32_t i = 0;
118  auto& jvObjects = (jvResult[jss::account_objects] = Json::arrayValue);
119  for (;;)
120  {
121  auto const& entries = dir->getFieldV256(sfIndexes);
122  auto iter = entries.begin();
123 
124  if (!found)
125  {
126  iter = std::find(iter, entries.end(), entryIndex);
127  if (iter == entries.end())
128  return false;
129 
130  found = true;
131  }
132 
133  for (; iter != entries.end(); ++iter)
134  {
135  auto const sleNode = ledger.read(keylet::child(*iter));
136 
137  auto typeMatchesFilter =
138  [](std::vector<LedgerEntryType> const& typeFilter,
139  LedgerEntryType ledgerType) {
140  auto it = std::find(
141  typeFilter.begin(), typeFilter.end(), ledgerType);
142  return it != typeFilter.end();
143  };
144 
145  if (!typeFilter.has_value() ||
146  typeMatchesFilter(typeFilter.value(), sleNode->getType()))
147  {
148  jvObjects.append(sleNode->getJson(JsonOptions::none));
149 
150  if (++i == limit)
151  {
152  if (++iter != entries.end())
153  {
154  jvResult[jss::limit] = limit;
155  jvResult[jss::marker] =
156  to_string(dirIndex) + ',' + to_string(*iter);
157  return true;
158  }
159 
160  break;
161  }
162  }
163  }
164 
165  auto const nodeIndex = dir->getFieldU64(sfIndexNext);
166  if (nodeIndex == 0)
167  return true;
168 
169  dirIndex = keylet::page(root, nodeIndex).key;
170  dir = ledger.read({ltDIR_NODE, dirIndex});
171  if (!dir)
172  return true;
173 
174  if (i == limit)
175  {
176  auto const& e = dir->getFieldV256(sfIndexes);
177  if (!e.empty())
178  {
179  jvResult[jss::limit] = limit;
180  jvResult[jss::marker] =
181  to_string(dirIndex) + ',' + to_string(*e.begin());
182  }
183 
184  return true;
185  }
186  }
187 }
188 
189 namespace {
190 
191 bool
192 isValidatedOld(LedgerMaster& ledgerMaster, bool standalone)
193 {
194  if (standalone)
195  return false;
196 
197  return ledgerMaster.getValidatedLedgerAge() > Tuning::maxValidatedLedgerAge;
198 }
199 
200 template <class T>
201 Status
202 ledgerFromRequest(T& ledger, JsonContext& context)
203 {
204  ledger.reset();
205 
206  auto& params = context.params;
207 
208  auto indexValue = params[jss::ledger_index];
209  auto hashValue = params[jss::ledger_hash];
210 
211  // We need to support the legacy "ledger" field.
212  auto& legacyLedger = params[jss::ledger];
213  if (legacyLedger)
214  {
215  if (legacyLedger.asString().size() > 12)
216  hashValue = legacyLedger;
217  else
218  indexValue = legacyLedger;
219  }
220 
221  if (hashValue)
222  {
223  if (!hashValue.isString())
224  return {rpcINVALID_PARAMS, "ledgerHashNotString"};
225 
226  uint256 ledgerHash;
227  if (!ledgerHash.SetHex(hashValue.asString()))
228  return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
229  return getLedger(ledger, ledgerHash, context);
230  }
231  else if (indexValue.isNumeric())
232  {
233  return getLedger(ledger, indexValue.asInt(), context);
234  }
235  else
236  {
237  auto const index = indexValue.asString();
238  if (index == "validated")
239  {
240  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
241  }
242  else
243  {
244  if (index.empty() || index == "current")
245  return getLedger(ledger, LedgerShortcut::CURRENT, context);
246  else if (index == "closed")
247  return getLedger(ledger, LedgerShortcut::CLOSED, context);
248  else
249  {
250  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
251  }
252  }
253  }
254 
255  return Status::OK;
256 }
257 } // namespace
258 
259 template <class T>
260 Status
262  T& ledger,
264 {
265  ledger.reset();
266 
267  org::xrpl::rpc::v1::GetAccountInfoRequest& request = context.params;
268 
269  using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
270  LedgerCase ledgerCase = request.ledger().ledger_case();
271  switch (ledgerCase)
272  {
273  case LedgerCase::kHash: {
274  uint256 ledgerHash =
275  uint256::fromVoid(request.ledger().hash().data());
276  return getLedger(ledger, ledgerHash, context);
277  }
278  case LedgerCase::kSequence:
279  return getLedger(ledger, request.ledger().sequence(), context);
280  case LedgerCase::kShortcut:
281  [[fallthrough]];
282  case LedgerCase::LEDGER_NOT_SET: {
283  auto const shortcut = request.ledger().shortcut();
284  if (shortcut ==
285  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED)
286  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
287  else
288  {
289  // note, if unspecified, defaults to current ledger
290  if (shortcut ==
291  org::xrpl::rpc::v1::LedgerSpecifier::
292  SHORTCUT_UNSPECIFIED ||
293  shortcut ==
294  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT)
295  {
296  return getLedger(ledger, LedgerShortcut::CURRENT, context);
297  }
298  else if (
299  shortcut ==
300  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
301  {
302  return getLedger(ledger, LedgerShortcut::CLOSED, context);
303  }
304  }
305  }
306  }
307 
308  return Status::OK;
309 }
310 
311 // explicit instantiation of above function
312 template Status
313 ledgerFromRequest<>(
315  GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>&);
316 
317 Status
320  uint256 const& ledgerHash,
321  Context& context)
322 {
323  ledger = context.ledgerMaster.getLedgerByHash(ledgerHash);
324  if (ledger == nullptr)
325  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
326  return Status::OK;
327 }
328 
329 template <class T>
330 Status
331 getLedger(T& ledger, uint32_t ledgerIndex, Context& context)
332 {
333  ledger = context.ledgerMaster.getLedgerBySeq(ledgerIndex);
334  if (ledger == nullptr)
335  {
336  auto cur = context.ledgerMaster.getCurrentLedger();
337  if (cur->info().seq == ledgerIndex)
338  {
339  ledger = cur;
340  }
341  }
342 
343  if (ledger == nullptr)
344  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
345 
346  if (ledger->info().seq > context.ledgerMaster.getValidLedgerIndex() &&
347  isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
348  {
349  ledger.reset();
350  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
351  }
352 
353  return Status::OK;
354 }
355 
356 template <class T>
357 Status
358 getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
359 {
360  if (isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
361  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
362 
363  if (shortcut == LedgerShortcut::VALIDATED)
364  {
365  ledger = context.ledgerMaster.getValidatedLedger();
366  if (ledger == nullptr)
367  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
368 
369  assert(!ledger->open());
370  }
371  else
372  {
373  if (shortcut == LedgerShortcut::CURRENT)
374  {
375  ledger = context.ledgerMaster.getCurrentLedger();
376  assert(ledger->open());
377  }
378  else if (shortcut == LedgerShortcut::CLOSED)
379  {
380  ledger = context.ledgerMaster.getClosedLedger();
381  assert(!ledger->open());
382  }
383  else
384  {
385  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
386  }
387 
388  if (ledger == nullptr)
389  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
390 
391  static auto const minSequenceGap = 10;
392 
393  if (ledger->info().seq + minSequenceGap <
395  {
396  ledger.reset();
397  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
398  }
399  }
400  return Status::OK;
401 }
402 
403 // Explicit instantiaion of above three functions
404 template Status
405 getLedger<>(std::shared_ptr<ReadView const>&, uint32_t, Context&);
406 
407 template Status
408 getLedger<>(
410  LedgerShortcut shortcut,
411  Context&);
412 
413 bool
415  LedgerMaster& ledgerMaster,
416  ReadView const& ledger,
417  Application& app)
418 {
419  if (ledger.open())
420  return false;
421 
422  if (ledger.info().validated)
423  return true;
424 
425  auto seq = ledger.info().seq;
426  try
427  {
428  // Use the skip list in the last validated ledger to see if ledger
429  // comes before the last validated ledger (and thus has been
430  // validated).
431  auto hash = ledgerMaster.walkHashBySeq(seq);
432 
433  if (!hash || ledger.info().hash != *hash)
434  {
435  // This ledger's hash is not the hash of the validated ledger
436  if (hash)
437  {
438  assert(hash->isNonZero());
439  uint256 valHash = getHashByIndex(seq, app);
440  if (valHash == ledger.info().hash)
441  {
442  // SQL database doesn't match ledger chain
443  ledgerMaster.clearLedger(seq);
444  }
445  }
446  return false;
447  }
448  }
449  catch (SHAMapMissingNode const& mn)
450  {
451  auto stream = app.journal("RPCHandler").warn();
452  JLOG(stream) << "Ledger #" << seq << ": " << mn.what();
453  return false;
454  }
455 
456  // Mark ledger as validated to save time if we see it again.
457  ledger.info().validated = true;
458  return true;
459 }
460 
461 // The previous version of the lookupLedger command would accept the
462 // "ledger_index" argument as a string and silently treat it as a request to
463 // return the current ledger which, while not strictly wrong, could cause a lot
464 // of confusion.
465 //
466 // The code now robustly validates the input and ensures that the only possible
467 // values for the "ledger_index" parameter are the index of a ledger passed as
468 // an integer or one of the strings "current", "closed" or "validated".
469 // Additionally, the code ensures that the value passed in "ledger_hash" is a
470 // string and a valid hash. Invalid values will return an appropriate error
471 // code.
472 //
473 // In the absence of the "ledger_hash" or "ledger_index" parameters, the code
474 // assumes that "ledger_index" has the value "current".
475 //
476 // Returns a Json::objectValue. If there was an error, it will be in that
477 // return value. Otherwise, the object contains the field "validated" and
478 // optionally the fields "ledger_hash", "ledger_index" and
479 // "ledger_current_index", if they are defined.
480 Status
483  JsonContext& context,
484  Json::Value& result)
485 {
486  if (auto status = ledgerFromRequest(ledger, context))
487  return status;
488 
489  auto& info = ledger->info();
490 
491  if (!ledger->open())
492  {
493  result[jss::ledger_hash] = to_string(info.hash);
494  result[jss::ledger_index] = info.seq;
495  }
496  else
497  {
498  result[jss::ledger_current_index] = info.seq;
499  }
500 
501  result[jss::validated] =
502  isValidated(context.ledgerMaster, *ledger, context.app);
503  return Status::OK;
504 }
505 
508 {
509  Json::Value result;
510  if (auto status = lookupLedger(ledger, context, result))
511  status.inject(result);
512 
513  return result;
514 }
515 
518 {
519  hash_set<AccountID> result;
520  for (auto const& jv : jvArray)
521  {
522  if (!jv.isString())
523  return hash_set<AccountID>();
524  auto const id = parseBase58<AccountID>(jv.asString());
525  if (!id)
526  return hash_set<AccountID>();
527  result.insert(*id);
528  }
529  return result;
530 }
531 
532 void
533 injectSLE(Json::Value& jv, SLE const& sle)
534 {
535  jv = sle.getJson(JsonOptions::none);
536  if (sle.getType() == ltACCOUNT_ROOT)
537  {
538  if (sle.isFieldPresent(sfEmailHash))
539  {
540  auto const& hash = sle.getFieldH128(sfEmailHash);
541  Blob const b(hash.begin(), hash.end());
542  std::string md5 = strHex(makeSlice(b));
543  boost::to_lower(md5);
544  // VFALCO TODO Give a name and move this constant
545  // to a more visible location. Also
546  // shouldn't this be https?
547  jv[jss::urlgravatar] =
548  str(boost::format("http://www.gravatar.com/avatar/%s") % md5);
549  }
550  }
551  else
552  {
553  jv[jss::Invalid] = true;
554  }
555 }
556 
557 boost::optional<Json::Value>
559  unsigned int& limit,
560  Tuning::LimitRange const& range,
561  JsonContext const& context)
562 {
563  limit = range.rdefault;
564  if (auto const& jvLimit = context.params[jss::limit])
565  {
566  if (!(jvLimit.isUInt() || (jvLimit.isInt() && jvLimit.asInt() >= 0)))
567  return RPC::expected_field_error(jss::limit, "unsigned integer");
568 
569  limit = jvLimit.asUInt();
570  if (!isUnlimited(context.role))
571  limit = std::max(range.rmin, std::min(range.rmax, limit));
572  }
573  return boost::none;
574 }
575 
576 boost::optional<Seed>
578 {
579  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
580  // non-standard way. While rippled never encode seeds that way, we
581  // try to detect such keys to avoid user confusion.
582  if (!value.isString())
583  return boost::none;
584 
585  auto const result = decodeBase58Token(value.asString(), TokenType::None);
586 
587  if (result.size() == 18 &&
588  static_cast<std::uint8_t>(result[0]) == std::uint8_t(0xE1) &&
589  static_cast<std::uint8_t>(result[1]) == std::uint8_t(0x4B))
590  return Seed(makeSlice(result.substr(2)));
591 
592  return boost::none;
593 }
594 
595 boost::optional<Seed>
596 getSeedFromRPC(Json::Value const& params, Json::Value& error)
597 {
598  // The array should be constexpr, but that makes Visual Studio unhappy.
599  static char const* const seedTypes[]{
600  jss::passphrase.c_str(), jss::seed.c_str(), jss::seed_hex.c_str()};
601 
602  // Identify which seed type is in use.
603  char const* seedType = nullptr;
604  int count = 0;
605  for (auto t : seedTypes)
606  {
607  if (params.isMember(t))
608  {
609  ++count;
610  seedType = t;
611  }
612  }
613 
614  if (count != 1)
615  {
616  error = RPC::make_param_error(
617  "Exactly one of the following must be specified: " +
618  std::string(jss::passphrase) + ", " + std::string(jss::seed) +
619  " or " + std::string(jss::seed_hex));
620  return boost::none;
621  }
622 
623  // Make sure a string is present
624  if (!params[seedType].isString())
625  {
626  error = RPC::expected_field_error(seedType, "string");
627  return boost::none;
628  }
629 
630  auto const fieldContents = params[seedType].asString();
631 
632  // Convert string to seed.
633  boost::optional<Seed> seed;
634 
635  if (seedType == jss::seed.c_str())
636  seed = parseBase58<Seed>(fieldContents);
637  else if (seedType == jss::passphrase.c_str())
638  seed = parseGenericSeed(fieldContents);
639  else if (seedType == jss::seed_hex.c_str())
640  {
641  uint128 s;
642 
643  if (s.SetHexExact(fieldContents))
644  seed.emplace(Slice(s.data(), s.size()));
645  }
646 
647  if (!seed)
648  error = rpcError(rpcBAD_SEED);
649 
650  return seed;
651 }
652 
655 {
656  bool const has_key_type = params.isMember(jss::key_type);
657 
658  // All of the secret types we allow, but only one at a time.
659  // The array should be constexpr, but that makes Visual Studio unhappy.
660  static char const* const secretTypes[]{
661  jss::passphrase.c_str(),
662  jss::secret.c_str(),
663  jss::seed.c_str(),
664  jss::seed_hex.c_str()};
665 
666  // Identify which secret type is in use.
667  char const* secretType = nullptr;
668  int count = 0;
669  for (auto t : secretTypes)
670  {
671  if (params.isMember(t))
672  {
673  ++count;
674  secretType = t;
675  }
676  }
677 
678  if (count == 0 || secretType == nullptr)
679  {
680  error = RPC::missing_field_error(jss::secret);
681  return {};
682  }
683 
684  if (count > 1)
685  {
686  error = RPC::make_param_error(
687  "Exactly one of the following must be specified: " +
688  std::string(jss::passphrase) + ", " + std::string(jss::secret) +
689  ", " + std::string(jss::seed) + " or " +
690  std::string(jss::seed_hex));
691  return {};
692  }
693 
694  boost::optional<KeyType> keyType;
695  boost::optional<Seed> seed;
696 
697  if (has_key_type)
698  {
699  if (!params[jss::key_type].isString())
700  {
701  error = RPC::expected_field_error(jss::key_type, "string");
702  return {};
703  }
704 
705  keyType = keyTypeFromString(params[jss::key_type].asString());
706 
707  if (!keyType)
708  {
709  error = RPC::invalid_field_error(jss::key_type);
710  return {};
711  }
712 
713  if (secretType == jss::secret.c_str())
714  {
715  error = RPC::make_param_error(
716  "The secret field is not allowed if " +
717  std::string(jss::key_type) + " is used.");
718  return {};
719  }
720  }
721 
722  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
723  // non-standard way. While we never encode seeds that way, we try
724  // to detect such keys to avoid user confusion.
725  if (secretType != jss::seed_hex.c_str())
726  {
727  seed = RPC::parseRippleLibSeed(params[secretType]);
728 
729  if (seed)
730  {
731  // If the user passed in an Ed25519 seed but *explicitly*
732  // requested another key type, return an error.
733  if (keyType.value_or(KeyType::ed25519) != KeyType::ed25519)
734  {
735  error = RPC::make_error(
736  rpcBAD_SEED, "Specified seed is for an Ed25519 wallet.");
737  return {};
738  }
739 
740  keyType = KeyType::ed25519;
741  }
742  }
743 
744  if (!keyType)
745  keyType = KeyType::secp256k1;
746 
747  if (!seed)
748  {
749  if (has_key_type)
750  seed = getSeedFromRPC(params, error);
751  else
752  {
753  if (!params[jss::secret].isString())
754  {
755  error = RPC::expected_field_error(jss::secret, "string");
756  return {};
757  }
758 
759  seed = parseGenericSeed(params[jss::secret].asString());
760  }
761  }
762 
763  if (!seed)
764  {
765  if (!contains_error(error))
766  {
767  error = RPC::make_error(
769  }
770 
771  return {};
772  }
773 
774  if (keyType != KeyType::secp256k1 && keyType != KeyType::ed25519)
775  LogicError("keypairForSignature: invalid key type");
776 
777  return generateKeyPair(*keyType, *seed);
778 }
779 
782 {
784  if (params.isMember(jss::type))
785  {
787  types{
788  {{jss::account, ltACCOUNT_ROOT},
789  {jss::amendments, ltAMENDMENTS},
790  {jss::check, ltCHECK},
791  {jss::deposit_preauth, ltDEPOSIT_PREAUTH},
792  {jss::directory, ltDIR_NODE},
793  {jss::escrow, ltESCROW},
794  {jss::fee, ltFEE_SETTINGS},
795  {jss::hashes, ltLEDGER_HASHES},
796  {jss::offer, ltOFFER},
797  {jss::payment_channel, ltPAYCHAN},
798  {jss::signer_list, ltSIGNER_LIST},
799  {jss::state, ltRIPPLE_STATE},
800  {jss::ticket, ltTICKET}}};
801 
802  auto const& p = params[jss::type];
803  if (!p.isString())
804  {
805  result.first = RPC::Status{
806  rpcINVALID_PARAMS, "Invalid field 'type', not string."};
807  assert(result.first.type() == RPC::Status::Type::error_code_i);
808  return result;
809  }
810 
811  auto const filter = p.asString();
812  auto iter = std::find_if(
813  types.begin(), types.end(), [&filter](decltype(types.front())& t) {
814  return t.first == filter;
815  });
816  if (iter == types.end())
817  {
818  result.first =
819  RPC::Status{rpcINVALID_PARAMS, "Invalid field 'type'."};
820  assert(result.first.type() == RPC::Status::Type::error_code_i);
821  return result;
822  }
823  result.second = iter->second;
824  }
825  return result;
826 }
827 
828 beast::SemanticVersion const firstVersion("1.0.0");
829 beast::SemanticVersion const goodVersion("1.0.0");
830 beast::SemanticVersion const lastVersion("1.0.0");
831 
832 unsigned int
834 {
835  static Json::Value const minVersion(RPC::ApiMinimumSupportedVersion);
836  static Json::Value const maxVersion(RPC::ApiMaximumSupportedVersion);
837  static Json::Value const invalidVersion(RPC::APIInvalidVersion);
838 
839  Json::Value requestedVersion(RPC::APIVersionIfUnspecified);
840  if (jv.isObject())
841  {
842  requestedVersion = jv.get(jss::api_version, requestedVersion);
843  }
844  if (!(requestedVersion.isInt() || requestedVersion.isUInt()) ||
845  requestedVersion < minVersion || requestedVersion > maxVersion)
846  {
847  requestedVersion = invalidVersion;
848  }
849  return requestedVersion.asUInt();
850 }
851 
852 } // namespace RPC
853 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
ripple::ReadView::info
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
ripple::RPC::Status::OK
static constexpr Code OK
Definition: Status.h:46
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:276
ripple::Application
Definition: Application.h:97
ripple::rpcNO_NETWORK
@ rpcNO_NETWORK
Definition: ErrorCodes.h:66
ripple::RPC::getLedger
Status getLedger(std::shared_ptr< ReadView const > &ledger, uint256 const &ledgerHash, Context &context)
Get ledger by hash If there is no error in the return value, the ledger pointer will have been filled...
Definition: RPCHelpers.cpp:318
ripple::RPC::JsonContext
Definition: Context.h:52
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
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:194
ripple::sfIndexNext
const SF_U64 sfIndexNext(access, STI_UINT64, 1, "IndexNext")
Definition: SField.h:394
ripple::STLedgerEntry::getJson
Json::Value getJson(JsonOptions options) const override
Definition: STLedgerEntry.cpp:102
ripple::STLedgerEntry
Definition: STLedgerEntry.h:30
ripple::RPC::firstVersion
const beast::SemanticVersion firstVersion("1.0.0")
API version numbers used in API version 1.
Definition: RPCHelpers.h:189
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
ripple::RPC::goodVersion
const beast::SemanticVersion goodVersion("1.0.0")
Definition: RPCHelpers.h:190
std::string
STL class.
std::shared_ptr
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::RPC::getAPIVersionNumber
unsigned int getAPIVersionNumber(Json::Value const &jv)
Retrieve the api version number from the json value.
Definition: RPCHelpers.cpp:833
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:43
std::unordered_set
STL class.
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::RPC::injectSLE
void injectSLE(Json::Value &jv, SLE const &sle)
Inject JSON describing ledger entry.
Definition: RPCHelpers.cpp:533
std::pair
ripple::RPC::LedgerShortcut
LedgerShortcut
Definition: RPCHelpers.h:111
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:96
ripple::LedgerMaster
Definition: LedgerMaster.h:54
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:209
Json::Value::get
Value get(UInt index, const Value &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
Definition: json_value.cpp:834
ripple::ltESCROW
@ ltESCROW
Definition: LedgerFormats.h:80
std::vector
STL class.
std::find
T find(T... args)
ripple::RPC::parseRippleLibSeed
boost::optional< Seed > parseRippleLibSeed(Json::Value const &value)
Definition: RPCHelpers.cpp:577
ripple::deprecatedParseBitcoinAccountID
boost::optional< AccountID > deprecatedParseBitcoinAccountID(std::string const &s)
Definition: AccountID.cpp:49
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
ripple::RPC::getAccountObjects
bool getAccountObjects(ReadView const &ledger, AccountID const &account, boost::optional< std::vector< LedgerEntryType >> const &typeFilter, uint256 dirIndex, uint256 const &entryIndex, std::uint32_t const limit, Json::Value &jvResult)
Gathers all objects for an account in a ledger.
Definition: RPCHelpers.cpp:95
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::keylet::child
Keylet child(uint256 const &key) noexcept
Any item that can be in an owner dir.
Definition: Indexes.cpp:126
ripple::STObject::getFieldH128
uint128 getFieldH128(SField const &field) const
Definition: STObject.cpp:544
ripple::LedgerMaster::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
Definition: LedgerMaster.cpp:1649
ripple::RPC::APIVersionIfUnspecified
constexpr unsigned int APIVersionIfUnspecified
Definition: RPCHelpers.h:212
beast::SemanticVersion
A Semantic Version number.
Definition: SemanticVersion.h:35
ripple::ltLEDGER_HASHES
@ ltLEDGER_HASHES
Definition: LedgerFormats.h:74
ripple::ltAMENDMENTS
@ ltAMENDMENTS
Definition: LedgerFormats.h:76
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:88
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::ltSIGNER_LIST
@ ltSIGNER_LIST
Definition: LedgerFormats.h:70
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::TokenType::None
@ None
ripple::rpcLGR_NOT_FOUND
@ rpcLGR_NOT_FOUND
Definition: ErrorCodes.h:72
ripple::base_uint::data
pointer data()
Definition: base_uint.h:103
ripple::RPC::lookupLedger
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext &context, Json::Value &result)
Look up a ledger from a request and fill a Json::Result with the data representing a ledger.
Definition: RPCHelpers.cpp:481
ripple::generateKeyPair
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:243
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::ltTICKET
@ ltTICKET
Definition: LedgerFormats.h:68
ripple::ltCHECK
@ ltCHECK
Definition: LedgerFormats.h:85
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:302
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:462
ripple::getHashByIndex
uint256 getHashByIndex(std::uint32_t ledgerIndex, Application &app)
Definition: Ledger.cpp:1134
ripple::SHAMapMissingNode
Definition: SHAMapMissingNode.h:55
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:493
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:236
ripple::keyTypeFromString
boost::optional< KeyType > keyTypeFromString(std::string const &s)
Definition: KeyType.h:34
ripple::KeyType::ed25519
@ ed25519
ripple::RPC::readLimitField
boost::optional< Json::Value > readLimitField(unsigned int &limit, Tuning::LimitRange const &range, JsonContext const &context)
Retrieve the limit value from a JsonContext, or set a default - then restrict the limit by max and mi...
Definition: RPCHelpers.cpp:558
ripple::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint
Definition: base_uint.h:63
ripple::RPC::ApiMinimumSupportedVersion
constexpr unsigned int ApiMinimumSupportedVersion
Definition: RPCHelpers.h:213
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
ripple::ltINVALID
@ ltINVALID
Definition: LedgerFormats.h:49
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:475
ripple::ltFEE_SETTINGS
@ ltFEE_SETTINGS
Definition: LedgerFormats.h:78
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:218
ripple::RPC::accountFromStringWithCode
error_code_i accountFromStringWithCode(AccountID &result, std::string const &strIdent, bool bStrict)
Decode account ID from string.
Definition: RPCHelpers.cpp:54
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::rpcBAD_SEED
@ rpcBAD_SEED
Definition: ErrorCodes.h:99
ripple::keylet::page
Keylet page(uint256 const &key, std::uint64_t index) noexcept
A page in a directory.
Definition: Indexes.cpp:282
ripple::Config::standalone
bool standalone() const
Definition: Config.h:218
ripple::RPC::GRPCContext
Definition: Context.h:70
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:131
std::array
STL class.
ripple::LedgerMaster::getValidatedLedger
std::shared_ptr< Ledger const > getValidatedLedger()
Definition: LedgerMaster.h:90
ripple::RPC::Status::Type::error_code_i
@ error_code_i
ripple::RPC::ApiMaximumSupportedVersion
constexpr unsigned int ApiMaximumSupportedVersion
Definition: RPCHelpers.h:214
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::RPC::accountFromStringStrict
boost::optional< AccountID > accountFromStringStrict(std::string const &account)
Get an AccountID from an account ID or public key.
Definition: RPCHelpers.cpp:38
ripple::parseGenericSeed
boost::optional< Seed > parseGenericSeed(std::string const &str)
Attempt to parse a string as a seed.
Definition: Seed.cpp:90
ripple::LedgerMaster::getLedgerBySeq
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
Definition: LedgerMaster.cpp:1613
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::uint32_t
ripple::ltDEPOSIT_PREAUTH
@ ltDEPOSIT_PREAUTH
Definition: LedgerFormats.h:87
ripple::sfIndexes
const SF_Vec256 sfIndexes(access, STI_VECTOR256, 1, "Indexes", SField::sMD_Never)
Definition: SField.h:489
ripple::range
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition: RangeSet.h:53
ripple::STLedgerEntry::getType
LedgerEntryType getType() const
Definition: STLedgerEntry.h:98
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple::LedgerMaster::getCurrentLedger
std::shared_ptr< ReadView const > getCurrentLedger()
Definition: LedgerMaster.cpp:1475
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::RPC::APIInvalidVersion
constexpr unsigned int APIInvalidVersion
API version numbers used in later API versions.
Definition: RPCHelpers.h:211
ripple::base_uint::SetHexExact
bool SetHexExact(const char *psz)
Parse a hex string into a base_uint The string must contain exactly bytes * 2 hex characters and must...
Definition: base_uint.h:370
ripple::RPC::Status
Status represents the results of an operation that might fail.
Definition: Status.h:39
ripple::rpcACT_BITCOIN
@ rpcACT_BITCOIN
Definition: ErrorCodes.h:89
ripple::KeyType::secp256k1
@ secp256k1
std::min
T min(T... args)
ripple::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:94
ripple::NodeStore::Status
Status
Return codes from Backend operations.
Definition: nodestore/Types.h:44
ripple::LedgerMaster::getClosedLedger
std::shared_ptr< Ledger const > getClosedLedger()
Definition: LedgerMaster.h:83
ripple::RPC::invalid_field_message
std::string invalid_field_message(std::string const &name)
Definition: ErrorCodes.h:266
ripple::RPC::GRPCContext::params
RequestType params
Definition: Context.h:72
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:188
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ltRIPPLE_STATE
@ ltRIPPLE_STATE
Definition: LedgerFormats.h:66
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::RPC::isValidated
bool isValidated(LedgerMaster &ledgerMaster, ReadView const &ledger, Application &app)
Definition: RPCHelpers.cpp:414
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::Seed
Seeds are used to generate deterministic secret keys.
Definition: Seed.h:32
ripple::LedgerEntryType
LedgerEntryType
Ledger entry types.
Definition: LedgerFormats.h:36
ripple::RPC::chooseLedgerEntryType
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:781
std::vector::begin
T begin(T... args)
ripple::decodeBase58Token
static std::string decodeBase58Token(std::string const &s, TokenType type, InverseArray const &inv)
Definition: tokens.cpp:256
ripple::LogicError
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:48
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:401
std::unordered_set::insert
T insert(T... args)
ripple::base_uint< 256 >::fromVoid
static base_uint fromVoid(void const *data)
Definition: base_uint.h:213
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
Json::Value::isUInt
bool isUInt() const
Definition: json_value.cpp:985
ripple::RPC::keypairForSignature
std::pair< PublicKey, SecretKey > keypairForSignature(Json::Value const &params, Json::Value &error)
Definition: RPCHelpers.cpp:654
ripple::TokenType::AccountPublic
@ AccountPublic
ripple::ltPAYCHAN
@ ltPAYCHAN
Definition: LedgerFormats.h:83
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
std::vector::end
T end(T... args)
ripple::ltDIR_NODE
@ ltDIR_NODE
Directory node.
Definition: LedgerFormats.h:64
ripple::RPC::parseAccountIds
hash_set< AccountID > parseAccountIds(Json::Value const &jvArray)
Definition: RPCHelpers.cpp:517
ripple::ltOFFER
@ ltOFFER
Definition: LedgerFormats.h:72
std::max
T max(T... args)
ripple::RPC::Tuning::LimitRange
Represents RPC limit parameter values that have a min, default and max.
Definition: rpc/impl/Tuning.h:31
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:224
ripple::LedgerInfo::validated
bool validated
Definition: ReadView.h:106
ripple::ltACCOUNT_ROOT
@ ltACCOUNT_ROOT
Definition: LedgerFormats.h:53
ripple::ReadView::open
virtual bool open() const =0
Returns true if this reflects an open ledger.
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:63
ripple::RPC::lastVersion
const beast::SemanticVersion lastVersion("1.0.0")
Definition: RPCHelpers.h:191
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:278
ripple::RPC::Context
The context of information needed to call an RPC.
Definition: Context.h:39
ripple::RPC::accountFromString
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
Definition: RPCHelpers.cpp:85
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:202
ripple::RPC::Tuning::maxValidatedLedgerAge
constexpr auto maxValidatedLedgerAge
Definition: rpc/impl/Tuning.h:59
ripple::sfEmailHash
const SF_U128 sfEmailHash(access, STI_HASH128, 1, "EmailHash")
Definition: SField.h:407
std::runtime_error::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::RPC::getSeedFromRPC
boost::optional< Seed > getSeedFromRPC(Json::Value const &params, Json::Value &error)
Definition: RPCHelpers.cpp:596
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::RPC::ledgerFromRequest
Status ledgerFromRequest(T &ledger, GRPCContext< org::xrpl::rpc::v1::GetAccountInfoRequest > &context)
Definition: RPCHelpers.cpp:261