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/LedgerToJson.h>
22 #include <ripple/app/ledger/OpenLedger.h>
23 #include <ripple/app/misc/Transaction.h>
24 #include <ripple/app/paths/TrustLine.h>
25 #include <ripple/app/rdb/RelationalDatabase.h>
26 #include <ripple/ledger/View.h>
27 #include <ripple/net/RPCErr.h>
28 #include <ripple/protocol/AccountID.h>
29 #include <ripple/protocol/Feature.h>
30 #include <ripple/rpc/Context.h>
31 #include <ripple/rpc/DeliveredAmount.h>
32 #include <ripple/rpc/impl/RPCHelpers.h>
33 #include <boost/algorithm/string/case_conv.hpp>
34 
35 #include <ripple/resource/Fees.h>
36 
37 namespace ripple {
38 namespace RPC {
39 
42 {
44 
45  auto const publicKey =
46  parseBase58<PublicKey>(TokenType::AccountPublic, account);
47 
48  if (publicKey)
49  result = calcAccountID(*publicKey);
50  else
51  result = parseBase58<AccountID>(account);
52 
53  return result;
54 }
55 
58  AccountID& result,
59  std::string const& strIdent,
60  bool bStrict)
61 {
62  if (auto accountID = accountFromStringStrict(strIdent))
63  {
64  result = *accountID;
65  return rpcSUCCESS;
66  }
67 
68  if (bStrict)
69  return rpcACT_MALFORMED;
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 
95 getStartHint(std::shared_ptr<SLE const> const& sle, AccountID const& accountID)
96 {
97  if (sle->getType() == ltRIPPLE_STATE)
98  {
99  if (sle->getFieldAmount(sfLowLimit).getIssuer() == accountID)
100  return sle->getFieldU64(sfLowNode);
101  else if (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID)
102  return sle->getFieldU64(sfHighNode);
103  }
104 
105  if (!sle->isFieldPresent(sfOwnerNode))
106  return 0;
107 
108  return sle->getFieldU64(sfOwnerNode);
109 }
110 
111 bool
113  ReadView const& ledger,
114  std::shared_ptr<SLE const> const& sle,
115  AccountID const& accountID)
116 {
117  if (sle->getType() == ltRIPPLE_STATE)
118  {
119  return (sle->getFieldAmount(sfLowLimit).getIssuer() == accountID) ||
120  (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID);
121  }
122  else if (sle->isFieldPresent(sfAccount))
123  {
124  return sle->getAccountID(sfAccount) == accountID;
125  }
126  else if (sle->getType() == ltSIGNER_LIST)
127  {
128  Keylet const accountSignerList = keylet::signers(accountID);
129  return sle->key() == accountSignerList.key;
130  }
131 
132  return false;
133 }
134 
135 bool
137  ReadView const& ledger,
138  AccountID const& account,
139  std::optional<std::vector<LedgerEntryType>> const& typeFilter,
140  uint256 dirIndex,
141  uint256 const& entryIndex,
142  std::uint32_t const limit,
143  Json::Value& jvResult)
144 {
145  auto const root = keylet::ownerDir(account);
146  auto found = false;
147 
148  if (dirIndex.isZero())
149  {
150  dirIndex = root.key;
151  found = true;
152  }
153 
154  auto dir = ledger.read({ltDIR_NODE, dirIndex});
155  if (!dir)
156  return false;
157 
158  std::uint32_t i = 0;
159  auto& jvObjects = (jvResult[jss::account_objects] = Json::arrayValue);
160  for (;;)
161  {
162  auto const& entries = dir->getFieldV256(sfIndexes);
163  auto iter = entries.begin();
164 
165  if (!found)
166  {
167  iter = std::find(iter, entries.end(), entryIndex);
168  if (iter == entries.end())
169  return false;
170 
171  found = true;
172  }
173 
174  for (; iter != entries.end(); ++iter)
175  {
176  auto const sleNode = ledger.read(keylet::child(*iter));
177 
178  auto typeMatchesFilter =
179  [](std::vector<LedgerEntryType> const& typeFilter,
180  LedgerEntryType ledgerType) {
181  auto it = std::find(
182  typeFilter.begin(), typeFilter.end(), ledgerType);
183  return it != typeFilter.end();
184  };
185 
186  if (!typeFilter.has_value() ||
187  typeMatchesFilter(typeFilter.value(), sleNode->getType()))
188  {
189  jvObjects.append(sleNode->getJson(JsonOptions::none));
190  }
191 
192  if (++i == limit)
193  {
194  if (++iter != entries.end())
195  {
196  jvResult[jss::limit] = limit;
197  jvResult[jss::marker] =
198  to_string(dirIndex) + ',' + to_string(*iter);
199  return true;
200  }
201 
202  break;
203  }
204  }
205 
206  auto const nodeIndex = dir->getFieldU64(sfIndexNext);
207  if (nodeIndex == 0)
208  return true;
209 
210  dirIndex = keylet::page(root, nodeIndex).key;
211  dir = ledger.read({ltDIR_NODE, dirIndex});
212  if (!dir)
213  return true;
214 
215  if (i == limit)
216  {
217  auto const& e = dir->getFieldV256(sfIndexes);
218  if (!e.empty())
219  {
220  jvResult[jss::limit] = limit;
221  jvResult[jss::marker] =
222  to_string(dirIndex) + ',' + to_string(*e.begin());
223  }
224 
225  return true;
226  }
227  }
228 }
229 
230 namespace {
231 
232 bool
233 isValidatedOld(LedgerMaster& ledgerMaster, bool standaloneOrReporting)
234 {
235  if (standaloneOrReporting)
236  return false;
237 
238  return ledgerMaster.getValidatedLedgerAge() > Tuning::maxValidatedLedgerAge;
239 }
240 
241 template <class T>
242 Status
243 ledgerFromRequest(T& ledger, JsonContext& context)
244 {
245  ledger.reset();
246 
247  auto& params = context.params;
248 
249  auto indexValue = params[jss::ledger_index];
250  auto hashValue = params[jss::ledger_hash];
251 
252  // We need to support the legacy "ledger" field.
253  auto& legacyLedger = params[jss::ledger];
254  if (legacyLedger)
255  {
256  if (legacyLedger.asString().size() > 12)
257  hashValue = legacyLedger;
258  else
259  indexValue = legacyLedger;
260  }
261 
262  if (hashValue)
263  {
264  if (!hashValue.isString())
265  return {rpcINVALID_PARAMS, "ledgerHashNotString"};
266 
267  uint256 ledgerHash;
268  if (!ledgerHash.parseHex(hashValue.asString()))
269  return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
270  return getLedger(ledger, ledgerHash, context);
271  }
272 
273  auto const index = indexValue.asString();
274 
275  if (index == "current" ||
276  (index.empty() && !context.app.config().reporting()))
277  return getLedger(ledger, LedgerShortcut::CURRENT, context);
278 
279  if (index == "validated" ||
280  (index.empty() && context.app.config().reporting()))
281  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
282 
283  if (index == "closed")
284  return getLedger(ledger, LedgerShortcut::CLOSED, context);
285 
286  std::uint32_t iVal;
287  if (beast::lexicalCastChecked(iVal, index))
288  return getLedger(ledger, iVal, context);
289 
290  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
291 }
292 } // namespace
293 
294 template <class T, class R>
295 Status
296 ledgerFromRequest(T& ledger, GRPCContext<R>& context)
297 {
298  R& request = context.params;
299  return ledgerFromSpecifier(ledger, request.ledger(), context);
300 }
301 
302 // explicit instantiation of above function
303 template Status
304 ledgerFromRequest<>(
306  GRPCContext<org::xrpl::rpc::v1::GetLedgerEntryRequest>&);
307 
308 // explicit instantiation of above function
309 template Status
310 ledgerFromRequest<>(
312  GRPCContext<org::xrpl::rpc::v1::GetLedgerDataRequest>&);
313 
314 // explicit instantiation of above function
315 template Status
316 ledgerFromRequest<>(
318  GRPCContext<org::xrpl::rpc::v1::GetLedgerRequest>&);
319 
320 template <class T>
321 Status
323  T& ledger,
324  org::xrpl::rpc::v1::LedgerSpecifier const& specifier,
325  Context& context)
326 {
327  ledger.reset();
328 
329  using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
330  LedgerCase ledgerCase = specifier.ledger_case();
331  switch (ledgerCase)
332  {
333  case LedgerCase::kHash: {
334  if (auto hash = uint256::fromVoidChecked(specifier.hash()))
335  {
336  return getLedger(ledger, *hash, context);
337  }
338  return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
339  }
340  case LedgerCase::kSequence:
341  return getLedger(ledger, specifier.sequence(), context);
342  case LedgerCase::kShortcut:
343  [[fallthrough]];
344  case LedgerCase::LEDGER_NOT_SET: {
345  auto const shortcut = specifier.shortcut();
346  // note, unspecified defaults to validated in reporting mode
347  if (shortcut ==
348  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED ||
349  (shortcut ==
350  org::xrpl::rpc::v1::LedgerSpecifier::
351  SHORTCUT_UNSPECIFIED &&
352  context.app.config().reporting()))
353  {
354  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
355  }
356  else
357  {
358  if (shortcut ==
359  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT ||
360  shortcut ==
361  org::xrpl::rpc::v1::LedgerSpecifier::
362  SHORTCUT_UNSPECIFIED)
363  {
364  return getLedger(ledger, LedgerShortcut::CURRENT, context);
365  }
366  else if (
367  shortcut ==
368  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
369  {
370  return getLedger(ledger, LedgerShortcut::CLOSED, context);
371  }
372  }
373  }
374  }
375 
376  return Status::OK;
377 }
378 
379 template <class T>
380 Status
381 getLedger(T& ledger, uint256 const& ledgerHash, Context& context)
382 {
383  ledger = context.ledgerMaster.getLedgerByHash(ledgerHash);
384  if (ledger == nullptr)
385  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
386  return Status::OK;
387 }
388 
389 template <class T>
390 Status
391 getLedger(T& ledger, uint32_t ledgerIndex, Context& context)
392 {
393  ledger = context.ledgerMaster.getLedgerBySeq(ledgerIndex);
394  if (ledger == nullptr)
395  {
396  if (context.app.config().reporting())
397  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
398  auto cur = context.ledgerMaster.getCurrentLedger();
399  if (cur->info().seq == ledgerIndex)
400  {
401  ledger = cur;
402  }
403  }
404 
405  if (ledger == nullptr)
406  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
407 
408  if (ledger->info().seq > context.ledgerMaster.getValidLedgerIndex() &&
409  isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
410  {
411  ledger.reset();
412  if (context.apiVersion == 1)
413  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
414  return {rpcNOT_SYNCED, "notSynced"};
415  }
416 
417  return Status::OK;
418 }
419 
420 template <class T>
421 Status
422 getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
423 {
424  if (isValidatedOld(
425  context.ledgerMaster,
426  context.app.config().standalone() ||
427  context.app.config().reporting()))
428  {
429  if (context.apiVersion == 1)
430  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
431  return {rpcNOT_SYNCED, "notSynced"};
432  }
433 
434  if (shortcut == LedgerShortcut::VALIDATED)
435  {
436  ledger = context.ledgerMaster.getValidatedLedger();
437  if (ledger == nullptr)
438  {
439  if (context.apiVersion == 1)
440  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
441  return {rpcNOT_SYNCED, "notSynced"};
442  }
443 
444  assert(!ledger->open());
445  }
446  else
447  {
448  if (shortcut == LedgerShortcut::CURRENT)
449  {
450  if (context.app.config().reporting())
451  return {
453  "Reporting does not track current ledger"};
454  ledger = context.ledgerMaster.getCurrentLedger();
455  assert(ledger->open());
456  }
457  else if (shortcut == LedgerShortcut::CLOSED)
458  {
459  if (context.app.config().reporting())
460  return {
461  rpcLGR_NOT_FOUND, "Reporting does not track closed ledger"};
462  ledger = context.ledgerMaster.getClosedLedger();
463  assert(!ledger->open());
464  }
465  else
466  {
467  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
468  }
469 
470  if (ledger == nullptr)
471  {
472  if (context.apiVersion == 1)
473  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
474  return {rpcNOT_SYNCED, "notSynced"};
475  }
476 
477  static auto const minSequenceGap = 10;
478 
479  if (ledger->info().seq + minSequenceGap <
481  {
482  ledger.reset();
483  if (context.apiVersion == 1)
484  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
485  return {rpcNOT_SYNCED, "notSynced"};
486  }
487  }
488  return Status::OK;
489 }
490 
491 // Explicit instantiaion of above three functions
492 template Status
493 getLedger<>(std::shared_ptr<ReadView const>&, uint32_t, Context&);
494 
495 template Status
496 getLedger<>(
498  LedgerShortcut shortcut,
499  Context&);
500 
501 template Status
502 getLedger<>(std::shared_ptr<ReadView const>&, uint256 const&, Context&);
503 
504 bool
506  LedgerMaster& ledgerMaster,
507  ReadView const& ledger,
508  Application& app)
509 {
510  if (app.config().reporting())
511  return true;
512 
513  if (ledger.open())
514  return false;
515 
516  if (ledger.info().validated)
517  return true;
518 
519  auto seq = ledger.info().seq;
520  try
521  {
522  // Use the skip list in the last validated ledger to see if ledger
523  // comes before the last validated ledger (and thus has been
524  // validated).
525  auto hash =
526  ledgerMaster.walkHashBySeq(seq, InboundLedger::Reason::GENERIC);
527 
528  if (!hash || ledger.info().hash != *hash)
529  {
530  // This ledger's hash is not the hash of the validated ledger
531  if (hash)
532  {
533  assert(hash->isNonZero());
534  uint256 valHash =
536  if (valHash == ledger.info().hash)
537  {
538  // SQL database doesn't match ledger chain
539  ledgerMaster.clearLedger(seq);
540  }
541  }
542  return false;
543  }
544  }
545  catch (SHAMapMissingNode const& mn)
546  {
547  auto stream = app.journal("RPCHandler").warn();
548  JLOG(stream) << "Ledger #" << seq << ": " << mn.what();
549  return false;
550  }
551 
552  // Mark ledger as validated to save time if we see it again.
553  ledger.info().validated = true;
554  return true;
555 }
556 
557 // The previous version of the lookupLedger command would accept the
558 // "ledger_index" argument as a string and silently treat it as a request to
559 // return the current ledger which, while not strictly wrong, could cause a lot
560 // of confusion.
561 //
562 // The code now robustly validates the input and ensures that the only possible
563 // values for the "ledger_index" parameter are the index of a ledger passed as
564 // an integer or one of the strings "current", "closed" or "validated".
565 // Additionally, the code ensures that the value passed in "ledger_hash" is a
566 // string and a valid hash. Invalid values will return an appropriate error
567 // code.
568 //
569 // In the absence of the "ledger_hash" or "ledger_index" parameters, the code
570 // assumes that "ledger_index" has the value "current".
571 //
572 // Returns a Json::objectValue. If there was an error, it will be in that
573 // return value. Otherwise, the object contains the field "validated" and
574 // optionally the fields "ledger_hash", "ledger_index" and
575 // "ledger_current_index", if they are defined.
576 Status
579  JsonContext& context,
580  Json::Value& result)
581 {
582  if (auto status = ledgerFromRequest(ledger, context))
583  return status;
584 
585  auto& info = ledger->info();
586 
587  if (!ledger->open())
588  {
589  result[jss::ledger_hash] = to_string(info.hash);
590  result[jss::ledger_index] = info.seq;
591  }
592  else
593  {
594  result[jss::ledger_current_index] = info.seq;
595  }
596 
597  result[jss::validated] =
598  isValidated(context.ledgerMaster, *ledger, context.app);
599  return Status::OK;
600 }
601 
604 {
605  Json::Value result;
606  if (auto status = lookupLedger(ledger, context, result))
607  status.inject(result);
608 
609  return result;
610 }
611 
614 {
615  hash_set<AccountID> result;
616  for (auto const& jv : jvArray)
617  {
618  if (!jv.isString())
619  return hash_set<AccountID>();
620  auto const id = parseBase58<AccountID>(jv.asString());
621  if (!id)
622  return hash_set<AccountID>();
623  result.insert(*id);
624  }
625  return result;
626 }
627 
628 void
629 injectSLE(Json::Value& jv, SLE const& sle)
630 {
631  jv = sle.getJson(JsonOptions::none);
632  if (sle.getType() == ltACCOUNT_ROOT)
633  {
634  if (sle.isFieldPresent(sfEmailHash))
635  {
636  auto const& hash = sle.getFieldH128(sfEmailHash);
637  Blob const b(hash.begin(), hash.end());
638  std::string md5 = strHex(makeSlice(b));
639  boost::to_lower(md5);
640  // VFALCO TODO Give a name and move this constant
641  // to a more visible location. Also
642  // shouldn't this be https?
643  jv[jss::urlgravatar] =
644  str(boost::format("http://www.gravatar.com/avatar/%s") % md5);
645  }
646  }
647  else
648  {
649  jv[jss::Invalid] = true;
650  }
651 }
652 
655  unsigned int& limit,
656  Tuning::LimitRange const& range,
657  JsonContext const& context)
658 {
659  limit = range.rdefault;
660  if (auto const& jvLimit = context.params[jss::limit])
661  {
662  if (!(jvLimit.isUInt() || (jvLimit.isInt() && jvLimit.asInt() >= 0)))
663  return RPC::expected_field_error(jss::limit, "unsigned integer");
664 
665  limit = jvLimit.asUInt();
666  if (!isUnlimited(context.role))
667  limit = std::max(range.rmin, std::min(range.rmax, limit));
668  }
669  return std::nullopt;
670 }
671 
674 {
675  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
676  // non-standard way. While rippled never encode seeds that way, we
677  // try to detect such keys to avoid user confusion.
678  if (!value.isString())
679  return std::nullopt;
680 
681  auto const result = decodeBase58Token(value.asString(), TokenType::None);
682 
683  if (result.size() == 18 &&
684  static_cast<std::uint8_t>(result[0]) == std::uint8_t(0xE1) &&
685  static_cast<std::uint8_t>(result[1]) == std::uint8_t(0x4B))
686  return Seed(makeSlice(result.substr(2)));
687 
688  return std::nullopt;
689 }
690 
692 getSeedFromRPC(Json::Value const& params, Json::Value& error)
693 {
694  using string_to_seed_t =
696  using seed_match_t = std::pair<char const*, string_to_seed_t>;
697 
698  static seed_match_t const seedTypes[]{
699  {jss::passphrase.c_str(),
700  [](std::string const& s) { return parseGenericSeed(s); }},
701  {jss::seed.c_str(),
702  [](std::string const& s) { return parseBase58<Seed>(s); }},
703  {jss::seed_hex.c_str(), [](std::string const& s) {
704  uint128 i;
705  if (i.parseHex(s))
706  return std::optional<Seed>(Slice(i.data(), i.size()));
707  return std::optional<Seed>{};
708  }}};
709 
710  // Identify which seed type is in use.
711  seed_match_t const* seedType = nullptr;
712  int count = 0;
713  for (auto const& t : seedTypes)
714  {
715  if (params.isMember(t.first))
716  {
717  ++count;
718  seedType = &t;
719  }
720  }
721 
722  if (count != 1)
723  {
724  error = RPC::make_param_error(
725  "Exactly one of the following must be specified: " +
726  std::string(jss::passphrase) + ", " + std::string(jss::seed) +
727  " or " + std::string(jss::seed_hex));
728  return std::nullopt;
729  }
730 
731  // Make sure a string is present
732  auto const& param = params[seedType->first];
733  if (!param.isString())
734  {
735  error = RPC::expected_field_error(seedType->first, "string");
736  return std::nullopt;
737  }
738 
739  auto const fieldContents = param.asString();
740 
741  // Convert string to seed.
742  std::optional<Seed> seed = seedType->second(fieldContents);
743 
744  if (!seed)
745  error = rpcError(rpcBAD_SEED);
746 
747  return seed;
748 }
749 
752 {
753  bool const has_key_type = params.isMember(jss::key_type);
754 
755  // All of the secret types we allow, but only one at a time.
756  static char const* const secretTypes[]{
757  jss::passphrase.c_str(),
758  jss::secret.c_str(),
759  jss::seed.c_str(),
760  jss::seed_hex.c_str()};
761 
762  // Identify which secret type is in use.
763  char const* secretType = nullptr;
764  int count = 0;
765  for (auto t : secretTypes)
766  {
767  if (params.isMember(t))
768  {
769  ++count;
770  secretType = t;
771  }
772  }
773 
774  if (count == 0 || secretType == nullptr)
775  {
776  error = RPC::missing_field_error(jss::secret);
777  return {};
778  }
779 
780  if (count > 1)
781  {
782  error = RPC::make_param_error(
783  "Exactly one of the following must be specified: " +
784  std::string(jss::passphrase) + ", " + std::string(jss::secret) +
785  ", " + std::string(jss::seed) + " or " +
786  std::string(jss::seed_hex));
787  return {};
788  }
789 
790  std::optional<KeyType> keyType;
791  std::optional<Seed> seed;
792 
793  if (has_key_type)
794  {
795  if (!params[jss::key_type].isString())
796  {
797  error = RPC::expected_field_error(jss::key_type, "string");
798  return {};
799  }
800 
801  keyType = keyTypeFromString(params[jss::key_type].asString());
802 
803  if (!keyType)
804  {
805  error = RPC::invalid_field_error(jss::key_type);
806  return {};
807  }
808 
809  // using strcmp as pointers may not match (see
810  // https://developercommunity.visualstudio.com/t/assigning-constexpr-char--to-static-cha/10021357?entry=problem)
811  if (strcmp(secretType, jss::secret.c_str()) == 0)
812  {
813  error = RPC::make_param_error(
814  "The secret field is not allowed if " +
815  std::string(jss::key_type) + " is used.");
816  return {};
817  }
818  }
819 
820  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
821  // non-standard way. While we never encode seeds that way, we try
822  // to detect such keys to avoid user confusion.
823  // using strcmp as pointers may not match (see
824  // https://developercommunity.visualstudio.com/t/assigning-constexpr-char--to-static-cha/10021357?entry=problem)
825  if (strcmp(secretType, jss::seed_hex.c_str()) != 0)
826  {
827  seed = RPC::parseRippleLibSeed(params[secretType]);
828 
829  if (seed)
830  {
831  // If the user passed in an Ed25519 seed but *explicitly*
832  // requested another key type, return an error.
834  {
835  error = RPC::make_error(
836  rpcBAD_SEED, "Specified seed is for an Ed25519 wallet.");
837  return {};
838  }
839 
840  keyType = KeyType::ed25519;
841  }
842  }
843 
844  if (!keyType)
845  keyType = KeyType::secp256k1;
846 
847  if (!seed)
848  {
849  if (has_key_type)
850  seed = getSeedFromRPC(params, error);
851  else
852  {
853  if (!params[jss::secret].isString())
854  {
855  error = RPC::expected_field_error(jss::secret, "string");
856  return {};
857  }
858 
859  seed = parseGenericSeed(params[jss::secret].asString());
860  }
861  }
862 
863  if (!seed)
864  {
865  if (!contains_error(error))
866  {
867  error = RPC::make_error(
869  }
870 
871  return {};
872  }
873 
874  if (keyType != KeyType::secp256k1 && keyType != KeyType::ed25519)
875  LogicError("keypairForSignature: invalid key type");
876 
877  return generateKeyPair(*keyType, *seed);
878 }
879 
882 {
884  if (params.isMember(jss::type))
885  {
887  types{
888  {{jss::account, ltACCOUNT_ROOT},
889  {jss::amendments, ltAMENDMENTS},
890  {jss::check, ltCHECK},
891  {jss::deposit_preauth, ltDEPOSIT_PREAUTH},
892  {jss::directory, ltDIR_NODE},
893  {jss::escrow, ltESCROW},
894  {jss::fee, ltFEE_SETTINGS},
895  {jss::hashes, ltLEDGER_HASHES},
896  {jss::offer, ltOFFER},
897  {jss::payment_channel, ltPAYCHAN},
898  {jss::signer_list, ltSIGNER_LIST},
899  {jss::state, ltRIPPLE_STATE},
900  {jss::ticket, ltTICKET},
901  {jss::nft_offer, ltNFTOKEN_OFFER}}};
902 
903  auto const& p = params[jss::type];
904  if (!p.isString())
905  {
906  result.first = RPC::Status{
907  rpcINVALID_PARAMS, "Invalid field 'type', not string."};
908  assert(result.first.type() == RPC::Status::Type::error_code_i);
909  return result;
910  }
911 
912  auto const filter = p.asString();
913  auto iter = std::find_if(
914  types.begin(), types.end(), [&filter](decltype(types.front())& t) {
915  return t.first == filter;
916  });
917  if (iter == types.end())
918  {
919  result.first =
920  RPC::Status{rpcINVALID_PARAMS, "Invalid field 'type'."};
921  assert(result.first.type() == RPC::Status::Type::error_code_i);
922  return result;
923  }
924  result.second = iter->second;
925  }
926  return result;
927 }
928 
929 beast::SemanticVersion const firstVersion("1.0.0");
930 beast::SemanticVersion const goodVersion("1.0.0");
931 beast::SemanticVersion const lastVersion("1.0.0");
932 
933 unsigned int
934 getAPIVersionNumber(Json::Value const& jv, bool betaEnabled)
935 {
936  static Json::Value const minVersion(RPC::apiMinimumSupportedVersion);
937  static Json::Value const invalidVersion(RPC::apiInvalidVersion);
938 
939  Json::Value const maxVersion(
941  Json::Value requestedVersion(RPC::apiVersionIfUnspecified);
942  if (jv.isObject())
943  {
944  requestedVersion = jv.get(jss::api_version, requestedVersion);
945  }
946  if (!(requestedVersion.isInt() || requestedVersion.isUInt()) ||
947  requestedVersion < minVersion || requestedVersion > maxVersion)
948  {
949  requestedVersion = invalidVersion;
950  }
951  return requestedVersion.asUInt();
952 }
953 
956 {
957  if (context.app.config().reporting())
959 
960  auto const hasHash = context.params.isMember(jss::ledger_hash);
961  auto const hasIndex = context.params.isMember(jss::ledger_index);
962  std::uint32_t ledgerIndex = 0;
963 
964  auto& ledgerMaster = context.app.getLedgerMaster();
965  LedgerHash ledgerHash;
966 
967  if ((hasHash && hasIndex) || !(hasHash || hasIndex))
968  {
969  return RPC::make_param_error(
970  "Exactly one of ledger_hash and ledger_index can be set.");
971  }
972 
974 
975  if (hasHash)
976  {
977  auto const& jsonHash = context.params[jss::ledger_hash];
978  if (!jsonHash.isString() || !ledgerHash.parseHex(jsonHash.asString()))
979  return RPC::invalid_field_error(jss::ledger_hash);
980  }
981  else
982  {
983  auto const& jsonIndex = context.params[jss::ledger_index];
984  if (!jsonIndex.isInt())
985  return RPC::invalid_field_error(jss::ledger_index);
986 
987  // We need a validated ledger to get the hash from the sequence
988  if (ledgerMaster.getValidatedLedgerAge() >
990  {
991  if (context.apiVersion == 1)
992  return rpcError(rpcNO_CURRENT);
993  return rpcError(rpcNOT_SYNCED);
994  }
995 
996  ledgerIndex = jsonIndex.asInt();
997  auto ledger = ledgerMaster.getValidatedLedger();
998 
999  if (ledgerIndex >= ledger->info().seq)
1000  return RPC::make_param_error("Ledger index too large");
1001  if (ledgerIndex <= 0)
1002  return RPC::make_param_error("Ledger index too small");
1003 
1004  auto const j = context.app.journal("RPCHandler");
1005  // Try to get the hash of the desired ledger from the validated ledger
1006  auto neededHash = hashOfSeq(*ledger, ledgerIndex, j);
1007  if (!neededHash)
1008  {
1009  // Find a ledger more likely to have the hash of the desired ledger
1010  auto const refIndex = getCandidateLedger(ledgerIndex);
1011  auto refHash = hashOfSeq(*ledger, refIndex, j);
1012  assert(refHash);
1013 
1014  ledger = ledgerMaster.getLedgerByHash(*refHash);
1015  if (!ledger)
1016  {
1017  // We don't have the ledger we need to figure out which ledger
1018  // they want. Try to get it.
1019 
1020  if (auto il = context.app.getInboundLedgers().acquire(
1021  *refHash, refIndex, InboundLedger::Reason::GENERIC))
1022  {
1023  Json::Value jvResult = RPC::make_error(
1025  "acquiring ledger containing requested index");
1026  jvResult[jss::acquiring] =
1027  getJson(LedgerFill(*il, &context));
1028  return jvResult;
1029  }
1030 
1031  if (auto il = context.app.getInboundLedgers().find(*refHash))
1032  {
1033  Json::Value jvResult = RPC::make_error(
1035  "acquiring ledger containing requested index");
1036  jvResult[jss::acquiring] = il->getJson(0);
1037  return jvResult;
1038  }
1039 
1040  // Likely the app is shutting down
1041  return Json::Value();
1042  }
1043 
1044  neededHash = hashOfSeq(*ledger, ledgerIndex, j);
1045  }
1046  assert(neededHash);
1047  ledgerHash = neededHash ? *neededHash : beast::zero; // kludge
1048  }
1049 
1050  // Try to get the desired ledger
1051  // Verify all nodes even if we think we have it
1052  auto ledger = context.app.getInboundLedgers().acquire(
1053  ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
1054 
1055  // In standalone mode, accept the ledger from the ledger cache
1056  if (!ledger && context.app.config().standalone())
1057  ledger = ledgerMaster.getLedgerByHash(ledgerHash);
1058 
1059  if (ledger)
1060  return ledger;
1061 
1062  if (auto il = context.app.getInboundLedgers().find(ledgerHash))
1063  return il->getJson(0);
1064 
1065  return RPC::make_error(
1066  rpcNOT_READY, "findCreate failed to return an inbound ledger");
1067 }
1068 } // namespace RPC
1069 } // 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::apiInvalidVersion
constexpr unsigned int apiInvalidVersion
API version numbers used in later API versions.
Definition: RPCHelpers.h:241
ripple::sfIndexNext
const SF_UINT64 sfIndexNext
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:303
ripple::Application
Definition: Application.h:115
ripple::RPC::apiVersionIfUnspecified
constexpr unsigned int apiVersionIfUnspecified
Definition: RPCHelpers.h:242
ripple::rpcNO_NETWORK
@ rpcNO_NETWORK
Definition: ErrorCodes.h:66
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
ripple::ltTICKET
@ ltTICKET
A ledger object which describes a ticket.
Definition: LedgerFormats.h:80
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:241
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
ripple::STLedgerEntry::getJson
Json::Value getJson(JsonOptions options) const override
Definition: STLedgerEntry.cpp:117
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:215
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
ripple::RPC::goodVersion
const beast::SemanticVersion goodVersion("1.0.0")
Definition: RPCHelpers.h:216
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::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::ltANY
@ ltANY
A special type, matching any ledger entry type.
Definition: LedgerFormats.h:176
ripple::sfOwnerNode
const SF_UINT64 sfOwnerNode
ripple::ltLEDGER_HASHES
@ ltLEDGER_HASHES
A ledger object that contains a list of ledger hashes.
Definition: LedgerFormats.h:102
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
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:629
std::pair
ripple::RPC::LedgerShortcut
LedgerShortcut
Definition: RPCHelpers.h:129
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:91
ripple::LedgerMaster
Definition: LedgerMaster.h:70
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:213
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
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::keyTypeFromString
std::optional< KeyType > keyTypeFromString(std::string const &s)
Definition: KeyType.h:34
ripple::InboundLedger::Reason::GENERIC
@ GENERIC
ripple::RPC::getAPIVersionNumber
unsigned int getAPIVersionNumber(Json::Value const &jv, bool betaEnabled)
Retrieve the api version number from the json value.
Definition: RPCHelpers.cpp:934
std::vector
STL class.
std::find
T find(T... args)
std::optional::value_or
T value_or(T... args)
ripple::ltSIGNER_LIST
@ ltSIGNER_LIST
A ledger object which contains a signer list for an account.
Definition: LedgerFormats.h:86
ripple::rpcNOT_READY
@ rpcNOT_READY
Definition: ErrorCodes.h:60
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
ripple::decodeBase58Token
std::string decodeBase58Token(std::string const &s, TokenType type)
Decode a token of given type encoded using Base58Check and the XRPL alphabet.
Definition: tokens.cpp:223
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:139
ripple::RPC::readLimitField
std::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:654
ripple::STObject::getFieldH128
uint128 getFieldH128(SField const &field) const
Definition: STObject.cpp:571
ripple::LedgerMaster::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
Definition: LedgerMaster.cpp:1852
beast::SemanticVersion
A Semantic Version number.
Definition: SemanticVersion.h:35
std::function
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:83
ripple::ltCHECK
@ ltCHECK
A ledger object which describes a check.
Definition: LedgerFormats.h:136
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::ltFEE_SETTINGS
@ ltFEE_SETTINGS
The ledger object which lists the network's fee settings.
Definition: LedgerFormats.h:118
ripple::base_uint< 256 >::fromVoidChecked
static std::optional< base_uint > fromVoidChecked(T const &from)
Definition: base_uint.h:318
ripple::RPC::getLedgerByContext
std::variant< std::shared_ptr< Ledger const >, Json::Value > getLedgerByContext(RPC::JsonContext &context)
Return a ledger based on ledger_hash or ledger_index, or an RPC error.
Definition: RPCHelpers.cpp:955
ripple::TokenType::None
@ None
ripple::rpcLGR_NOT_FOUND
@ rpcLGR_NOT_FOUND
Definition: ErrorCodes.h:72
ripple::RPC::apiBetaVersion
constexpr unsigned int apiBetaVersion
Definition: RPCHelpers.h:245
ripple::rpcREPORTING_UNSUPPORTED
@ rpcREPORTING_UNSUPPORTED
Definition: ErrorCodes.h:141
ripple::base_uint::data
pointer data()
Definition: base_uint.h:121
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:577
ripple::generateKeyPair
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:351
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:328
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:518
ripple::ltDIR_NODE
@ ltDIR_NODE
A ledger object which contains a list of object identifiers.
Definition: LedgerFormats.h:66
ripple::SHAMapMissingNode
Definition: SHAMapMissingNode.h:55
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:549
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:262
ripple::sfIndexes
const SF_VECTOR256 sfIndexes
ripple::KeyType::ed25519
@ ed25519
ripple::sfLowNode
const SF_UINT64 sfLowNode
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::base_uint< 160, detail::AccountIDTag >
ripple::ltAMENDMENTS
@ ltAMENDMENTS
The ledger object which lists details about amendments on the network.
Definition: LedgerFormats.h:110
ripple::sfLowLimit
const SF_AMOUNT sfLowLimit
ripple::RPC::parseRippleLibSeed
std::optional< Seed > parseRippleLibSeed(Json::Value const &value)
Definition: RPCHelpers.cpp:673
ripple::RPC::Status::OK
static constexpr Code OK
Definition: Status.h:46
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
ripple::ltOFFER
@ ltOFFER
A ledger object which describes an offer on the DEX.
Definition: LedgerFormats.h:92
ripple::Config::reporting
bool reporting() const
Definition: Config.h:318
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:531
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:194
ripple::RPC::accountFromStringWithCode
error_code_i accountFromStringWithCode(AccountID &result, std::string const &strIdent, bool bStrict)
Decode account ID from string.
Definition: RPCHelpers.cpp:57
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::InboundLedgers::acquire
virtual std::shared_ptr< Ledger const > acquire(uint256 const &hash, std::uint32_t seq, InboundLedger::Reason)=0
ripple::RPC::isOwnedByAccount
bool isOwnedByAccount(ReadView const &ledger, std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Tests if a SLE is owned by accountID.
Definition: RPCHelpers.cpp:112
ripple::ltESCROW
@ ltESCROW
A ledger object describing a single escrow.
Definition: LedgerFormats.h:124
ripple::RelationalDatabase::getHashByIndex
virtual uint256 getHashByIndex(LedgerIndex ledgerIndex)=0
getHashByIndex Returns the hash of the ledger with the given sequence.
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::ltNFTOKEN_OFFER
@ ltNFTOKEN_OFFER
A ledger object which identifies an offer to buy or sell an NFT.
Definition: LedgerFormats.h:162
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:309
ripple::Config::standalone
bool standalone() const
Definition: Config.h:313
ripple::RPC::GRPCContext
Definition: Context.h:70
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:158
ripple::Application::getRelationalDatabase
virtual RelationalDatabase & getRelationalDatabase()=0
std::array
STL class.
ripple::RPC::Status::Type::error_code_i
@ error_code_i
ripple::ltDEPOSIT_PREAUTH
@ ltDEPOSIT_PREAUTH
A ledger object which describes a deposit preauthorization.
Definition: LedgerFormats.h:142
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::hashOfSeq
std::optional< uint256 > hashOfSeq(ReadView const &ledger, LedgerIndex seq, beast::Journal journal)
Return the hash of a ledger by sequence.
Definition: View.cpp:644
ripple::LedgerMaster::getLedgerBySeq
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
Definition: LedgerMaster.cpp:1816
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::rpcNO_CURRENT
@ rpcNO_CURRENT
Definition: ErrorCodes.h:65
std::uint64_t
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
ripple::parseGenericSeed
std::optional< Seed > parseGenericSeed(std::string const &str, bool rfc1751)
Attempt to parse a string as a seed.
Definition: Seed.cpp:90
ripple::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:119
ripple::LedgerMaster::getCurrentLedger
std::shared_ptr< ReadView const > getCurrentLedger()
Definition: LedgerMaster.cpp:1652
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::Status
Status represents the results of an operation that might fail.
Definition: Status.h:39
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:124
ripple::sfEmailHash
const SF_UINT128 sfEmailHash
ripple::NodeStore::Status
Status
Return codes from Backend operations.
Definition: nodestore/Types.h:44
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:291
ripple::LedgerMaster::getClosedLedger
std::shared_ptr< Ledger const > getClosedLedger()
Definition: LedgerMaster.h:98
ripple::RPC::invalid_field_message
std::string invalid_field_message(std::string const &name)
Definition: ErrorCodes.h:292
ripple::RPC::GRPCContext::params
RequestType params
Definition: Context.h:72
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:125
ripple::RPC::apiMinimumSupportedVersion
constexpr unsigned int apiMinimumSupportedVersion
Definition: RPCHelpers.h:243
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
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:505
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::RPC::getLedger
Status getLedger(T &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:381
ripple::Seed
Seeds are used to generate deterministic secret keys.
Definition: Seed.h:32
ripple::LedgerEntryType
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:53
beast::lexicalCastChecked
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Definition: LexicalCast.h:266
ripple::RPC::chooseLedgerEntryType
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:881
std::vector::begin
T begin(T... args)
ripple::LogicError
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:48
ripple::ltACCOUNT_ROOT
@ ltACCOUNT_ROOT
A ledger object which describes an account.
Definition: LedgerFormats.h:59
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:428
std::unordered_set::insert
T insert(T... args)
ripple::RPC::getStartHint
std::uint64_t getStartHint(std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Gets the start hint for traversing account objects.
Definition: RPCHelpers.cpp:95
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:751
ripple::RPC::getSeedFromRPC
std::optional< Seed > getSeedFromRPC(Json::Value const &params, Json::Value &error)
Definition: RPCHelpers.cpp:692
ripple::RPC::Context::apiVersion
unsigned int apiVersion
Definition: Context.h:50
ripple::TokenType::AccountPublic
@ AccountPublic
ripple::RPC::apiMaximumSupportedVersion
constexpr unsigned int apiMaximumSupportedVersion
Definition: RPCHelpers.h:244
ripple::LedgerMaster::getValidatedLedger
std::shared_ptr< Ledger const > getValidatedLedger()
Definition: LedgerMaster.cpp:1662
ripple::RPC::ledgerFromSpecifier
Status ledgerFromSpecifier(T &ledger, org::xrpl::rpc::v1::LedgerSpecifier const &specifier, Context &context)
Definition: RPCHelpers.cpp:322
std::optional
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::ltRIPPLE_STATE
@ ltRIPPLE_STATE
A ledger object which describes a bidirectional trust line.
Definition: LedgerFormats.h:74
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
std::vector::end
T end(T... args)
ripple::RPC::parseAccountIds
hash_set< AccountID > parseAccountIds(Json::Value const &jvArray)
Definition: RPCHelpers.cpp:613
std::max
T max(T... args)
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:495
ripple::getCandidateLedger
LedgerIndex getCandidateLedger(LedgerIndex requested)
Find a ledger index from which we could easily get the requested ledger.
Definition: View.h:219
ripple::RPC::Tuning::LimitRange
Represents RPC limit parameter values that have a min, default and max.
Definition: rpc/impl/Tuning.h:31
ripple::keylet::signers
static Keylet signers(AccountID const &account, std::uint32_t page) noexcept
Definition: Indexes.cpp:268
ripple::RPC::make_param_error
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
Definition: ErrorCodes.h:250
ripple::LedgerInfo::validated
bool validated
Definition: ReadView.h:101
ripple::RPC::accountFromStringStrict
std::optional< AccountID > accountFromStringStrict(std::string const &account)
Get an AccountID from an account ID or public key.
Definition: RPCHelpers.cpp:41
ripple::LedgerFill
Definition: LedgerToJson.h:33
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:64
ripple::RPC::lastVersion
const beast::SemanticVersion lastVersion("1.0.0")
Definition: RPCHelpers.h:217
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:304
ripple::sfHighNode
const SF_UINT64 sfHighNode
ripple::RPC::Context
The context of information needed to call an RPC.
Definition: Context.h:39
ripple::RPC::ledgerFromRequest
Status ledgerFromRequest(T &ledger, GRPCContext< R > &context)
Definition: RPCHelpers.cpp:296
ripple::Resource::feeHighBurdenRPC
const Charge feeHighBurdenRPC
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:178
ripple::RPC::Tuning::maxValidatedLedgerAge
constexpr auto maxValidatedLedgerAge
Definition: rpc/impl/Tuning.h:65
ripple::rpcNOT_SYNCED
@ rpcNOT_SYNCED
Definition: ErrorCodes.h:67
std::runtime_error::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::ltPAYCHAN
@ ltPAYCHAN
A ledger object describing a single unidirectional XRP payment channel.
Definition: LedgerFormats.h:130
ripple::InboundLedgers::find
virtual std::shared_ptr< InboundLedger > find(LedgerHash const &hash)=0
ripple::RPC::getAccountObjects
bool getAccountObjects(ReadView const &ledger, AccountID const &account, std::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:136
std::variant
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::root
Number root(Number f, unsigned d)
Definition: Number.cpp:624