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/app/tx/impl/details/NFTokenUtils.h>
27 #include <ripple/ledger/View.h>
28 #include <ripple/net/RPCErr.h>
29 #include <ripple/protocol/AccountID.h>
30 #include <ripple/protocol/Feature.h>
31 #include <ripple/protocol/nftPageMask.h>
32 #include <ripple/resource/Fees.h>
33 #include <ripple/rpc/Context.h>
34 #include <ripple/rpc/DeliveredAmount.h>
35 #include <ripple/rpc/impl/RPCHelpers.h>
36 #include <boost/algorithm/string/case_conv.hpp>
37 
38 namespace ripple {
39 namespace RPC {
40 
43 {
45 
46  auto const publicKey =
47  parseBase58<PublicKey>(TokenType::AccountPublic, account);
48 
49  if (publicKey)
50  result = calcAccountID(*publicKey);
51  else
52  result = parseBase58<AccountID>(account);
53 
54  return result;
55 }
56 
59  AccountID& result,
60  std::string const& strIdent,
61  bool bStrict)
62 {
63  if (auto accountID = accountFromStringStrict(strIdent))
64  {
65  result = *accountID;
66  return rpcSUCCESS;
67  }
68 
69  if (bStrict)
70  return rpcACT_MALFORMED;
71 
72  // We allow the use of the seeds which is poor practice
73  // and merely for debugging convenience.
74  auto const seed = parseGenericSeed(strIdent);
75 
76  if (!seed)
77  return rpcBAD_SEED;
78 
79  auto const keypair = generateKeyPair(KeyType::secp256k1, *seed);
80 
81  result = calcAccountID(keypair.first);
82  return rpcSUCCESS;
83 }
84 
86 accountFromString(AccountID& result, std::string const& strIdent, bool bStrict)
87 {
88  error_code_i code = accountFromStringWithCode(result, strIdent, bStrict);
89  if (code != rpcSUCCESS)
90  return rpcError(code);
91  else
92  return Json::objectValue;
93 }
94 
96 getStartHint(std::shared_ptr<SLE const> const& sle, AccountID const& accountID)
97 {
98  if (sle->getType() == ltRIPPLE_STATE)
99  {
100  if (sle->getFieldAmount(sfLowLimit).getIssuer() == accountID)
101  return sle->getFieldU64(sfLowNode);
102  else if (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID)
103  return sle->getFieldU64(sfHighNode);
104  }
105 
106  if (!sle->isFieldPresent(sfOwnerNode))
107  return 0;
108 
109  return sle->getFieldU64(sfOwnerNode);
110 }
111 
112 bool
114  ReadView const& ledger,
115  std::shared_ptr<SLE const> const& sle,
116  AccountID const& accountID)
117 {
118  if (sle->getType() == ltRIPPLE_STATE)
119  {
120  return (sle->getFieldAmount(sfLowLimit).getIssuer() == accountID) ||
121  (sle->getFieldAmount(sfHighLimit).getIssuer() == accountID);
122  }
123  else if (sle->isFieldPresent(sfAccount))
124  {
125  // If there's an sfAccount present, also test the sfDestination, if
126  // present. This will match objects such as Escrows (ltESCROW), Payment
127  // Channels (ltPAYCHAN), and Checks (ltCHECK) because those are added to
128  // the Destination account's directory. It intentionally EXCLUDES
129  // NFToken Offers (ltNFTOKEN_OFFER). NFToken Offers are NOT added to the
130  // Destination account's directory.
131  return sle->getAccountID(sfAccount) == accountID ||
132  (sle->isFieldPresent(sfDestination) &&
133  sle->getAccountID(sfDestination) == accountID);
134  }
135  else if (sle->getType() == ltSIGNER_LIST)
136  {
137  Keylet const accountSignerList = keylet::signers(accountID);
138  return sle->key() == accountSignerList.key;
139  }
140  else if (sle->getType() == ltNFTOKEN_OFFER)
141  {
142  // Do not check the sfDestination field. NFToken Offers are NOT added to
143  // the Destination account's directory.
144  return sle->getAccountID(sfOwner) == accountID;
145  }
146 
147  return false;
148 }
149 
150 bool
152  ReadView const& ledger,
153  AccountID const& account,
154  std::optional<std::vector<LedgerEntryType>> const& typeFilter,
155  uint256 dirIndex,
156  uint256 entryIndex,
157  std::uint32_t const limit,
158  Json::Value& jvResult)
159 {
160  auto typeMatchesFilter = [](std::vector<LedgerEntryType> const& typeFilter,
161  LedgerEntryType ledgerType) {
162  auto it = std::find(typeFilter.begin(), typeFilter.end(), ledgerType);
163  return it != typeFilter.end();
164  };
165 
166  // if dirIndex != 0, then all NFTs have already been returned. only
167  // iterate NFT pages if the filter says so AND dirIndex == 0
168  bool iterateNFTPages =
169  (!typeFilter.has_value() ||
170  typeMatchesFilter(typeFilter.value(), ltNFTOKEN_PAGE)) &&
171  dirIndex == beast::zero;
172 
173  Keylet const firstNFTPage = keylet::nftpage_min(account);
174 
175  // we need to check the marker to see if it is an NFTTokenPage index.
176  if (iterateNFTPages && entryIndex != beast::zero)
177  {
178  // if it is we will try to iterate the pages up to the limit
179  // and then change over to the owner directory
180 
181  if (firstNFTPage.key != (entryIndex & ~nft::pageMask))
182  iterateNFTPages = false;
183  }
184 
185  auto& jvObjects = (jvResult[jss::account_objects] = Json::arrayValue);
186 
187  // this is a mutable version of limit, used to seemlessly switch
188  // to iterating directory entries when nftokenpages are exhausted
189  uint32_t mlimit = limit;
190 
191  // iterate NFTokenPages preferentially
192  if (iterateNFTPages)
193  {
194  Keylet const first = entryIndex == beast::zero
195  ? firstNFTPage
196  : Keylet{ltNFTOKEN_PAGE, entryIndex};
197 
198  Keylet const last = keylet::nftpage_max(account);
199 
200  // current key
201  uint256 ck = ledger.succ(first.key, last.key.next()).value_or(last.key);
202 
203  // current page
204  auto cp = ledger.read(Keylet{ltNFTOKEN_PAGE, ck});
205 
206  while (cp)
207  {
208  jvObjects.append(cp->getJson(JsonOptions::none));
209  auto const npm = (*cp)[~sfNextPageMin];
210  if (npm)
211  cp = ledger.read(Keylet(ltNFTOKEN_PAGE, *npm));
212  else
213  cp = nullptr;
214 
215  if (--mlimit == 0)
216  {
217  if (cp)
218  {
219  jvResult[jss::limit] = limit;
220  jvResult[jss::marker] = std::string("0,") + to_string(ck);
221  return true;
222  }
223  }
224 
225  if (!npm)
226  break;
227 
228  ck = *npm;
229  }
230 
231  // if execution reaches here then we're about to transition
232  // to iterating the root directory (and the conventional
233  // behaviour of this RPC function.) Therefore we should
234  // zero entryIndex so as not to terribly confuse things.
235  entryIndex = beast::zero;
236  }
237 
238  auto const root = keylet::ownerDir(account);
239  auto found = false;
240 
241  if (dirIndex.isZero())
242  {
243  dirIndex = root.key;
244  found = true;
245  }
246 
247  auto dir = ledger.read({ltDIR_NODE, dirIndex});
248  if (!dir)
249  {
250  // it's possible the user had nftoken pages but no
251  // directory entries
252  return mlimit < limit;
253  }
254 
255  std::uint32_t i = 0;
256  for (;;)
257  {
258  auto const& entries = dir->getFieldV256(sfIndexes);
259  auto iter = entries.begin();
260 
261  if (!found)
262  {
263  iter = std::find(iter, entries.end(), entryIndex);
264  if (iter == entries.end())
265  return false;
266 
267  found = true;
268  }
269 
270  // it's possible that the returned NFTPages exactly filled the
271  // response. Check for that condition.
272  if (i == mlimit && mlimit < limit)
273  {
274  jvResult[jss::limit] = limit;
275  jvResult[jss::marker] =
276  to_string(dirIndex) + ',' + to_string(*iter);
277  return true;
278  }
279 
280  for (; iter != entries.end(); ++iter)
281  {
282  auto const sleNode = ledger.read(keylet::child(*iter));
283 
284  if (!typeFilter.has_value() ||
285  typeMatchesFilter(typeFilter.value(), sleNode->getType()))
286  {
287  jvObjects.append(sleNode->getJson(JsonOptions::none));
288  }
289 
290  if (++i == mlimit)
291  {
292  if (++iter != entries.end())
293  {
294  jvResult[jss::limit] = limit;
295  jvResult[jss::marker] =
296  to_string(dirIndex) + ',' + to_string(*iter);
297  return true;
298  }
299 
300  break;
301  }
302  }
303 
304  auto const nodeIndex = dir->getFieldU64(sfIndexNext);
305  if (nodeIndex == 0)
306  return true;
307 
308  dirIndex = keylet::page(root, nodeIndex).key;
309  dir = ledger.read({ltDIR_NODE, dirIndex});
310  if (!dir)
311  return true;
312 
313  if (i == mlimit)
314  {
315  auto const& e = dir->getFieldV256(sfIndexes);
316  if (!e.empty())
317  {
318  jvResult[jss::limit] = limit;
319  jvResult[jss::marker] =
320  to_string(dirIndex) + ',' + to_string(*e.begin());
321  }
322 
323  return true;
324  }
325  }
326 }
327 
328 namespace {
329 
330 bool
331 isValidatedOld(LedgerMaster& ledgerMaster, bool standaloneOrReporting)
332 {
333  if (standaloneOrReporting)
334  return false;
335 
336  return ledgerMaster.getValidatedLedgerAge() > Tuning::maxValidatedLedgerAge;
337 }
338 
339 template <class T>
340 Status
341 ledgerFromRequest(T& ledger, JsonContext& context)
342 {
343  ledger.reset();
344 
345  auto& params = context.params;
346 
347  auto indexValue = params[jss::ledger_index];
348  auto hashValue = params[jss::ledger_hash];
349 
350  // We need to support the legacy "ledger" field.
351  auto& legacyLedger = params[jss::ledger];
352  if (legacyLedger)
353  {
354  if (legacyLedger.asString().size() > 12)
355  hashValue = legacyLedger;
356  else
357  indexValue = legacyLedger;
358  }
359 
360  if (hashValue)
361  {
362  if (!hashValue.isString())
363  return {rpcINVALID_PARAMS, "ledgerHashNotString"};
364 
365  uint256 ledgerHash;
366  if (!ledgerHash.parseHex(hashValue.asString()))
367  return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
368  return getLedger(ledger, ledgerHash, context);
369  }
370 
371  auto const index = indexValue.asString();
372 
373  if (index == "current" ||
374  (index.empty() && !context.app.config().reporting()))
375  return getLedger(ledger, LedgerShortcut::CURRENT, context);
376 
377  if (index == "validated" ||
378  (index.empty() && context.app.config().reporting()))
379  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
380 
381  if (index == "closed")
382  return getLedger(ledger, LedgerShortcut::CLOSED, context);
383 
384  std::uint32_t iVal;
385  if (beast::lexicalCastChecked(iVal, index))
386  return getLedger(ledger, iVal, context);
387 
388  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
389 }
390 } // namespace
391 
392 template <class T, class R>
393 Status
394 ledgerFromRequest(T& ledger, GRPCContext<R>& context)
395 {
396  R& request = context.params;
397  return ledgerFromSpecifier(ledger, request.ledger(), context);
398 }
399 
400 // explicit instantiation of above function
401 template Status
402 ledgerFromRequest<>(
404  GRPCContext<org::xrpl::rpc::v1::GetLedgerEntryRequest>&);
405 
406 // explicit instantiation of above function
407 template Status
408 ledgerFromRequest<>(
410  GRPCContext<org::xrpl::rpc::v1::GetLedgerDataRequest>&);
411 
412 // explicit instantiation of above function
413 template Status
414 ledgerFromRequest<>(
416  GRPCContext<org::xrpl::rpc::v1::GetLedgerRequest>&);
417 
418 template <class T>
419 Status
421  T& ledger,
422  org::xrpl::rpc::v1::LedgerSpecifier const& specifier,
423  Context& context)
424 {
425  ledger.reset();
426 
427  using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
428  LedgerCase ledgerCase = specifier.ledger_case();
429  switch (ledgerCase)
430  {
431  case LedgerCase::kHash: {
432  if (auto hash = uint256::fromVoidChecked(specifier.hash()))
433  {
434  return getLedger(ledger, *hash, context);
435  }
436  return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
437  }
438  case LedgerCase::kSequence:
439  return getLedger(ledger, specifier.sequence(), context);
440  case LedgerCase::kShortcut:
441  [[fallthrough]];
442  case LedgerCase::LEDGER_NOT_SET: {
443  auto const shortcut = specifier.shortcut();
444  // note, unspecified defaults to validated in reporting mode
445  if (shortcut ==
446  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED ||
447  (shortcut ==
448  org::xrpl::rpc::v1::LedgerSpecifier::
449  SHORTCUT_UNSPECIFIED &&
450  context.app.config().reporting()))
451  {
452  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
453  }
454  else
455  {
456  if (shortcut ==
457  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT ||
458  shortcut ==
459  org::xrpl::rpc::v1::LedgerSpecifier::
460  SHORTCUT_UNSPECIFIED)
461  {
462  return getLedger(ledger, LedgerShortcut::CURRENT, context);
463  }
464  else if (
465  shortcut ==
466  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
467  {
468  return getLedger(ledger, LedgerShortcut::CLOSED, context);
469  }
470  }
471  }
472  }
473 
474  return Status::OK;
475 }
476 
477 template <class T>
478 Status
479 getLedger(T& ledger, uint256 const& ledgerHash, Context& context)
480 {
481  ledger = context.ledgerMaster.getLedgerByHash(ledgerHash);
482  if (ledger == nullptr)
483  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
484  return Status::OK;
485 }
486 
487 template <class T>
488 Status
489 getLedger(T& ledger, uint32_t ledgerIndex, Context& context)
490 {
491  ledger = context.ledgerMaster.getLedgerBySeq(ledgerIndex);
492  if (ledger == nullptr)
493  {
494  if (context.app.config().reporting())
495  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
496  auto cur = context.ledgerMaster.getCurrentLedger();
497  if (cur->info().seq == ledgerIndex)
498  {
499  ledger = cur;
500  }
501  }
502 
503  if (ledger == nullptr)
504  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
505 
506  if (ledger->info().seq > context.ledgerMaster.getValidLedgerIndex() &&
507  isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
508  {
509  ledger.reset();
510  if (context.apiVersion == 1)
511  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
512  return {rpcNOT_SYNCED, "notSynced"};
513  }
514 
515  return Status::OK;
516 }
517 
518 template <class T>
519 Status
520 getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
521 {
522  if (isValidatedOld(
523  context.ledgerMaster,
524  context.app.config().standalone() ||
525  context.app.config().reporting()))
526  {
527  if (context.apiVersion == 1)
528  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
529  return {rpcNOT_SYNCED, "notSynced"};
530  }
531 
532  if (shortcut == LedgerShortcut::VALIDATED)
533  {
534  ledger = context.ledgerMaster.getValidatedLedger();
535  if (ledger == nullptr)
536  {
537  if (context.apiVersion == 1)
538  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
539  return {rpcNOT_SYNCED, "notSynced"};
540  }
541 
542  assert(!ledger->open());
543  }
544  else
545  {
546  if (shortcut == LedgerShortcut::CURRENT)
547  {
548  if (context.app.config().reporting())
549  return {
551  "Reporting does not track current ledger"};
552  ledger = context.ledgerMaster.getCurrentLedger();
553  assert(ledger->open());
554  }
555  else if (shortcut == LedgerShortcut::CLOSED)
556  {
557  if (context.app.config().reporting())
558  return {
559  rpcLGR_NOT_FOUND, "Reporting does not track closed ledger"};
560  ledger = context.ledgerMaster.getClosedLedger();
561  assert(!ledger->open());
562  }
563  else
564  {
565  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
566  }
567 
568  if (ledger == nullptr)
569  {
570  if (context.apiVersion == 1)
571  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
572  return {rpcNOT_SYNCED, "notSynced"};
573  }
574 
575  static auto const minSequenceGap = 10;
576 
577  if (ledger->info().seq + minSequenceGap <
579  {
580  ledger.reset();
581  if (context.apiVersion == 1)
582  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
583  return {rpcNOT_SYNCED, "notSynced"};
584  }
585  }
586  return Status::OK;
587 }
588 
589 // Explicit instantiaion of above three functions
590 template Status
591 getLedger<>(std::shared_ptr<ReadView const>&, uint32_t, Context&);
592 
593 template Status
594 getLedger<>(
596  LedgerShortcut shortcut,
597  Context&);
598 
599 template Status
600 getLedger<>(std::shared_ptr<ReadView const>&, uint256 const&, Context&);
601 
602 bool
604  LedgerMaster& ledgerMaster,
605  ReadView const& ledger,
606  Application& app)
607 {
608  if (app.config().reporting())
609  return true;
610 
611  if (ledger.open())
612  return false;
613 
614  if (ledger.info().validated)
615  return true;
616 
617  auto seq = ledger.info().seq;
618  try
619  {
620  // Use the skip list in the last validated ledger to see if ledger
621  // comes before the last validated ledger (and thus has been
622  // validated).
623  auto hash =
624  ledgerMaster.walkHashBySeq(seq, InboundLedger::Reason::GENERIC);
625 
626  if (!hash || ledger.info().hash != *hash)
627  {
628  // This ledger's hash is not the hash of the validated ledger
629  if (hash)
630  {
631  assert(hash->isNonZero());
632  uint256 valHash =
634  if (valHash == ledger.info().hash)
635  {
636  // SQL database doesn't match ledger chain
637  ledgerMaster.clearLedger(seq);
638  }
639  }
640  return false;
641  }
642  }
643  catch (SHAMapMissingNode const& mn)
644  {
645  auto stream = app.journal("RPCHandler").warn();
646  JLOG(stream) << "Ledger #" << seq << ": " << mn.what();
647  return false;
648  }
649 
650  // Mark ledger as validated to save time if we see it again.
651  ledger.info().validated = true;
652  return true;
653 }
654 
655 // The previous version of the lookupLedger command would accept the
656 // "ledger_index" argument as a string and silently treat it as a request to
657 // return the current ledger which, while not strictly wrong, could cause a lot
658 // of confusion.
659 //
660 // The code now robustly validates the input and ensures that the only possible
661 // values for the "ledger_index" parameter are the index of a ledger passed as
662 // an integer or one of the strings "current", "closed" or "validated".
663 // Additionally, the code ensures that the value passed in "ledger_hash" is a
664 // string and a valid hash. Invalid values will return an appropriate error
665 // code.
666 //
667 // In the absence of the "ledger_hash" or "ledger_index" parameters, the code
668 // assumes that "ledger_index" has the value "current".
669 //
670 // Returns a Json::objectValue. If there was an error, it will be in that
671 // return value. Otherwise, the object contains the field "validated" and
672 // optionally the fields "ledger_hash", "ledger_index" and
673 // "ledger_current_index", if they are defined.
674 Status
677  JsonContext& context,
678  Json::Value& result)
679 {
680  if (auto status = ledgerFromRequest(ledger, context))
681  return status;
682 
683  auto& info = ledger->info();
684 
685  if (!ledger->open())
686  {
687  result[jss::ledger_hash] = to_string(info.hash);
688  result[jss::ledger_index] = info.seq;
689  }
690  else
691  {
692  result[jss::ledger_current_index] = info.seq;
693  }
694 
695  result[jss::validated] =
696  isValidated(context.ledgerMaster, *ledger, context.app);
697  return Status::OK;
698 }
699 
702 {
703  Json::Value result;
704  if (auto status = lookupLedger(ledger, context, result))
705  status.inject(result);
706 
707  return result;
708 }
709 
712 {
713  hash_set<AccountID> result;
714  for (auto const& jv : jvArray)
715  {
716  if (!jv.isString())
717  return hash_set<AccountID>();
718  auto const id = parseBase58<AccountID>(jv.asString());
719  if (!id)
720  return hash_set<AccountID>();
721  result.insert(*id);
722  }
723  return result;
724 }
725 
726 void
727 injectSLE(Json::Value& jv, SLE const& sle)
728 {
729  jv = sle.getJson(JsonOptions::none);
730  if (sle.getType() == ltACCOUNT_ROOT)
731  {
732  if (sle.isFieldPresent(sfEmailHash))
733  {
734  auto const& hash = sle.getFieldH128(sfEmailHash);
735  Blob const b(hash.begin(), hash.end());
736  std::string md5 = strHex(makeSlice(b));
737  boost::to_lower(md5);
738  // VFALCO TODO Give a name and move this constant
739  // to a more visible location. Also
740  // shouldn't this be https?
741  jv[jss::urlgravatar] =
742  str(boost::format("http://www.gravatar.com/avatar/%s") % md5);
743  }
744  }
745  else
746  {
747  jv[jss::Invalid] = true;
748  }
749 }
750 
753  unsigned int& limit,
754  Tuning::LimitRange const& range,
755  JsonContext const& context)
756 {
757  limit = range.rdefault;
758  if (auto const& jvLimit = context.params[jss::limit])
759  {
760  if (!(jvLimit.isUInt() || (jvLimit.isInt() && jvLimit.asInt() >= 0)))
761  return RPC::expected_field_error(jss::limit, "unsigned integer");
762 
763  limit = jvLimit.asUInt();
764  if (!isUnlimited(context.role))
765  limit = std::max(range.rmin, std::min(range.rmax, limit));
766  }
767  return std::nullopt;
768 }
769 
772 {
773  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
774  // non-standard way. While rippled never encode seeds that way, we
775  // try to detect such keys to avoid user confusion.
776  if (!value.isString())
777  return std::nullopt;
778 
779  auto const result = decodeBase58Token(value.asString(), TokenType::None);
780 
781  if (result.size() == 18 &&
782  static_cast<std::uint8_t>(result[0]) == std::uint8_t(0xE1) &&
783  static_cast<std::uint8_t>(result[1]) == std::uint8_t(0x4B))
784  return Seed(makeSlice(result.substr(2)));
785 
786  return std::nullopt;
787 }
788 
790 getSeedFromRPC(Json::Value const& params, Json::Value& error)
791 {
792  using string_to_seed_t =
794  using seed_match_t = std::pair<char const*, string_to_seed_t>;
795 
796  static seed_match_t const seedTypes[]{
797  {jss::passphrase.c_str(),
798  [](std::string const& s) { return parseGenericSeed(s); }},
799  {jss::seed.c_str(),
800  [](std::string const& s) { return parseBase58<Seed>(s); }},
801  {jss::seed_hex.c_str(), [](std::string const& s) {
802  uint128 i;
803  if (i.parseHex(s))
804  return std::optional<Seed>(Slice(i.data(), i.size()));
805  return std::optional<Seed>{};
806  }}};
807 
808  // Identify which seed type is in use.
809  seed_match_t const* seedType = nullptr;
810  int count = 0;
811  for (auto const& t : seedTypes)
812  {
813  if (params.isMember(t.first))
814  {
815  ++count;
816  seedType = &t;
817  }
818  }
819 
820  if (count != 1)
821  {
822  error = RPC::make_param_error(
823  "Exactly one of the following must be specified: " +
824  std::string(jss::passphrase) + ", " + std::string(jss::seed) +
825  " or " + std::string(jss::seed_hex));
826  return std::nullopt;
827  }
828 
829  // Make sure a string is present
830  auto const& param = params[seedType->first];
831  if (!param.isString())
832  {
833  error = RPC::expected_field_error(seedType->first, "string");
834  return std::nullopt;
835  }
836 
837  auto const fieldContents = param.asString();
838 
839  // Convert string to seed.
840  std::optional<Seed> seed = seedType->second(fieldContents);
841 
842  if (!seed)
843  error = rpcError(rpcBAD_SEED);
844 
845  return seed;
846 }
847 
850 {
851  bool const has_key_type = params.isMember(jss::key_type);
852 
853  // All of the secret types we allow, but only one at a time.
854  static char const* const secretTypes[]{
855  jss::passphrase.c_str(),
856  jss::secret.c_str(),
857  jss::seed.c_str(),
858  jss::seed_hex.c_str()};
859 
860  // Identify which secret type is in use.
861  char const* secretType = nullptr;
862  int count = 0;
863  for (auto t : secretTypes)
864  {
865  if (params.isMember(t))
866  {
867  ++count;
868  secretType = t;
869  }
870  }
871 
872  if (count == 0 || secretType == nullptr)
873  {
874  error = RPC::missing_field_error(jss::secret);
875  return {};
876  }
877 
878  if (count > 1)
879  {
880  error = RPC::make_param_error(
881  "Exactly one of the following must be specified: " +
882  std::string(jss::passphrase) + ", " + std::string(jss::secret) +
883  ", " + std::string(jss::seed) + " or " +
884  std::string(jss::seed_hex));
885  return {};
886  }
887 
888  std::optional<KeyType> keyType;
889  std::optional<Seed> seed;
890 
891  if (has_key_type)
892  {
893  if (!params[jss::key_type].isString())
894  {
895  error = RPC::expected_field_error(jss::key_type, "string");
896  return {};
897  }
898 
899  keyType = keyTypeFromString(params[jss::key_type].asString());
900 
901  if (!keyType)
902  {
903  error = RPC::invalid_field_error(jss::key_type);
904  return {};
905  }
906 
907  // using strcmp as pointers may not match (see
908  // https://developercommunity.visualstudio.com/t/assigning-constexpr-char--to-static-cha/10021357?entry=problem)
909  if (strcmp(secretType, jss::secret.c_str()) == 0)
910  {
911  error = RPC::make_param_error(
912  "The secret field is not allowed if " +
913  std::string(jss::key_type) + " is used.");
914  return {};
915  }
916  }
917 
918  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
919  // non-standard way. While we never encode seeds that way, we try
920  // to detect such keys to avoid user confusion.
921  // using strcmp as pointers may not match (see
922  // https://developercommunity.visualstudio.com/t/assigning-constexpr-char--to-static-cha/10021357?entry=problem)
923  if (strcmp(secretType, jss::seed_hex.c_str()) != 0)
924  {
925  seed = RPC::parseRippleLibSeed(params[secretType]);
926 
927  if (seed)
928  {
929  // If the user passed in an Ed25519 seed but *explicitly*
930  // requested another key type, return an error.
932  {
933  error = RPC::make_error(
934  rpcBAD_SEED, "Specified seed is for an Ed25519 wallet.");
935  return {};
936  }
937 
938  keyType = KeyType::ed25519;
939  }
940  }
941 
942  if (!keyType)
943  keyType = KeyType::secp256k1;
944 
945  if (!seed)
946  {
947  if (has_key_type)
948  seed = getSeedFromRPC(params, error);
949  else
950  {
951  if (!params[jss::secret].isString())
952  {
953  error = RPC::expected_field_error(jss::secret, "string");
954  return {};
955  }
956 
957  seed = parseGenericSeed(params[jss::secret].asString());
958  }
959  }
960 
961  if (!seed)
962  {
963  if (!contains_error(error))
964  {
965  error = RPC::make_error(
967  }
968 
969  return {};
970  }
971 
972  if (keyType != KeyType::secp256k1 && keyType != KeyType::ed25519)
973  LogicError("keypairForSignature: invalid key type");
974 
975  return generateKeyPair(*keyType, *seed);
976 }
977 
980 {
982  if (params.isMember(jss::type))
983  {
985  types{
986  {{jss::account, ltACCOUNT_ROOT},
987  {jss::amendments, ltAMENDMENTS},
988  {jss::check, ltCHECK},
989  {jss::deposit_preauth, ltDEPOSIT_PREAUTH},
990  {jss::directory, ltDIR_NODE},
991  {jss::escrow, ltESCROW},
992  {jss::fee, ltFEE_SETTINGS},
993  {jss::hashes, ltLEDGER_HASHES},
994  {jss::offer, ltOFFER},
995  {jss::payment_channel, ltPAYCHAN},
996  {jss::signer_list, ltSIGNER_LIST},
997  {jss::state, ltRIPPLE_STATE},
998  {jss::ticket, ltTICKET},
999  {jss::nft_offer, ltNFTOKEN_OFFER},
1000  {jss::nft_page, ltNFTOKEN_PAGE}}};
1001 
1002  auto const& p = params[jss::type];
1003  if (!p.isString())
1004  {
1005  result.first = RPC::Status{
1006  rpcINVALID_PARAMS, "Invalid field 'type', not string."};
1007  assert(result.first.type() == RPC::Status::Type::error_code_i);
1008  return result;
1009  }
1010 
1011  auto const filter = p.asString();
1012  auto iter = std::find_if(
1013  types.begin(), types.end(), [&filter](decltype(types.front())& t) {
1014  return t.first == filter;
1015  });
1016  if (iter == types.end())
1017  {
1018  result.first =
1019  RPC::Status{rpcINVALID_PARAMS, "Invalid field 'type'."};
1020  assert(result.first.type() == RPC::Status::Type::error_code_i);
1021  return result;
1022  }
1023  result.second = iter->second;
1024  }
1025  return result;
1026 }
1027 
1028 beast::SemanticVersion const firstVersion("1.0.0");
1029 beast::SemanticVersion const goodVersion("1.0.0");
1030 beast::SemanticVersion const lastVersion("1.0.0");
1031 
1032 unsigned int
1033 getAPIVersionNumber(Json::Value const& jv, bool betaEnabled)
1034 {
1035  static Json::Value const minVersion(RPC::apiMinimumSupportedVersion);
1036  static Json::Value const invalidVersion(RPC::apiInvalidVersion);
1037 
1038  Json::Value const maxVersion(
1040  Json::Value requestedVersion(RPC::apiVersionIfUnspecified);
1041  if (jv.isObject())
1042  {
1043  requestedVersion = jv.get(jss::api_version, requestedVersion);
1044  }
1045  if (!(requestedVersion.isInt() || requestedVersion.isUInt()) ||
1046  requestedVersion < minVersion || requestedVersion > maxVersion)
1047  {
1048  requestedVersion = invalidVersion;
1049  }
1050  return requestedVersion.asUInt();
1051 }
1052 
1055 {
1056  if (context.app.config().reporting())
1058 
1059  auto const hasHash = context.params.isMember(jss::ledger_hash);
1060  auto const hasIndex = context.params.isMember(jss::ledger_index);
1061  std::uint32_t ledgerIndex = 0;
1062 
1063  auto& ledgerMaster = context.app.getLedgerMaster();
1064  LedgerHash ledgerHash;
1065 
1066  if ((hasHash && hasIndex) || !(hasHash || hasIndex))
1067  {
1068  return RPC::make_param_error(
1069  "Exactly one of ledger_hash and ledger_index can be set.");
1070  }
1071 
1073 
1074  if (hasHash)
1075  {
1076  auto const& jsonHash = context.params[jss::ledger_hash];
1077  if (!jsonHash.isString() || !ledgerHash.parseHex(jsonHash.asString()))
1078  return RPC::invalid_field_error(jss::ledger_hash);
1079  }
1080  else
1081  {
1082  auto const& jsonIndex = context.params[jss::ledger_index];
1083  if (!jsonIndex.isInt())
1084  return RPC::invalid_field_error(jss::ledger_index);
1085 
1086  // We need a validated ledger to get the hash from the sequence
1087  if (ledgerMaster.getValidatedLedgerAge() >
1089  {
1090  if (context.apiVersion == 1)
1091  return rpcError(rpcNO_CURRENT);
1092  return rpcError(rpcNOT_SYNCED);
1093  }
1094 
1095  ledgerIndex = jsonIndex.asInt();
1096  auto ledger = ledgerMaster.getValidatedLedger();
1097 
1098  if (ledgerIndex >= ledger->info().seq)
1099  return RPC::make_param_error("Ledger index too large");
1100  if (ledgerIndex <= 0)
1101  return RPC::make_param_error("Ledger index too small");
1102 
1103  auto const j = context.app.journal("RPCHandler");
1104  // Try to get the hash of the desired ledger from the validated ledger
1105  auto neededHash = hashOfSeq(*ledger, ledgerIndex, j);
1106  if (!neededHash)
1107  {
1108  // Find a ledger more likely to have the hash of the desired ledger
1109  auto const refIndex = getCandidateLedger(ledgerIndex);
1110  auto refHash = hashOfSeq(*ledger, refIndex, j);
1111  assert(refHash);
1112 
1113  ledger = ledgerMaster.getLedgerByHash(*refHash);
1114  if (!ledger)
1115  {
1116  // We don't have the ledger we need to figure out which ledger
1117  // they want. Try to get it.
1118 
1119  if (auto il = context.app.getInboundLedgers().acquire(
1120  *refHash, refIndex, InboundLedger::Reason::GENERIC))
1121  {
1122  Json::Value jvResult = RPC::make_error(
1124  "acquiring ledger containing requested index");
1125  jvResult[jss::acquiring] =
1126  getJson(LedgerFill(*il, &context));
1127  return jvResult;
1128  }
1129 
1130  if (auto il = context.app.getInboundLedgers().find(*refHash))
1131  {
1132  Json::Value jvResult = RPC::make_error(
1134  "acquiring ledger containing requested index");
1135  jvResult[jss::acquiring] = il->getJson(0);
1136  return jvResult;
1137  }
1138 
1139  // Likely the app is shutting down
1140  return Json::Value();
1141  }
1142 
1143  neededHash = hashOfSeq(*ledger, ledgerIndex, j);
1144  }
1145  assert(neededHash);
1146  ledgerHash = neededHash ? *neededHash : beast::zero; // kludge
1147  }
1148 
1149  // Try to get the desired ledger
1150  // Verify all nodes even if we think we have it
1151  auto ledger = context.app.getInboundLedgers().acquire(
1152  ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
1153 
1154  // In standalone mode, accept the ledger from the ledger cache
1155  if (!ledger && context.app.config().standalone())
1156  ledger = ledgerMaster.getLedgerByHash(ledgerHash);
1157 
1158  if (ledger)
1159  return ledger;
1160 
1161  if (auto il = context.app.getInboundLedgers().find(ledgerHash))
1162  return il->getJson(0);
1163 
1164  return RPC::make_error(
1165  rpcNOT_READY, "findCreate failed to return an inbound ledger");
1166 }
1167 } // namespace RPC
1168 } // 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::sfDestination
const SF_ACCOUNT sfDestination
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:727
std::pair
ripple::RPC::LedgerShortcut
LedgerShortcut
Definition: RPCHelpers.h:129
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:91
ripple::sfOwner
const SF_ACCOUNT sfOwner
ripple::LedgerMaster
Definition: LedgerMaster.h:70
ripple::RPC::getAccountObjects
bool getAccountObjects(ReadView const &ledger, AccountID const &account, std::optional< std::vector< LedgerEntryType >> const &typeFilter, uint256 dirIndex, uint256 entryIndex, std::uint32_t const limit, Json::Value &jvResult)
Gathers all objects for an account in a ledger.
Definition: RPCHelpers.cpp:151
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:1033
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:752
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:1854
beast::SemanticVersion
A Semantic Version number.
Definition: SemanticVersion.h:35
ripple::base_uint::next
base_uint next() const
Definition: base_uint.h:448
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:319
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:1054
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:122
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:675
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:519
ripple::ltDIR_NODE
@ ltDIR_NODE
A ledger object which contains a list of object identifiers.
Definition: LedgerFormats.h:66
ripple::nft::pageMask
constexpr uint256 pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))
ripple::SHAMapMissingNode
Definition: SHAMapMissingNode.h:55
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:550
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::keylet::nftpage_min
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Definition: Indexes.cpp:332
ripple::RPC::parseRippleLibSeed
std::optional< Seed > parseRippleLibSeed(Json::Value const &value)
Definition: RPCHelpers.cpp:771
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:337
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:532
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:58
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::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:332
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::keylet::nftpage_max
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Definition: Indexes.cpp:340
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:1818
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::ReadView::succ
virtual std::optional< key_type > succ(key_type const &key, std::optional< key_type > const &last=std::nullopt) const =0
Return the key of the next state item.
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:1654
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:296
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::ltNFTOKEN_PAGE
@ ltNFTOKEN_PAGE
A ledger object which contains a list of NFTs.
Definition: LedgerFormats.h:156
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:603
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:479
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:979
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:96
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:849
ripple::RPC::getSeedFromRPC
std::optional< Seed > getSeedFromRPC(Json::Value const &params, Json::Value &error)
Definition: RPCHelpers.cpp:790
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:1664
ripple::RPC::ledgerFromSpecifier
Status ledgerFromSpecifier(T &ledger, org::xrpl::rpc::v1::LedgerSpecifier const &specifier, Context &context)
Definition: RPCHelpers.cpp:420
ripple::sfNextPageMin
const SF_UINT256 sfNextPageMin
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:711
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:496
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:42
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:394
ripple::Resource::feeHighBurdenRPC
const Charge feeHighBurdenRPC
ripple::RPC::accountFromString
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
Definition: RPCHelpers.cpp:86
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
ripple::RPC::isRelatedToAccount
bool isRelatedToAccount(ReadView const &ledger, std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Tests if a SLE is owned by accountID.
Definition: RPCHelpers.cpp:113
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
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