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