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  Json::Value const& params,
852  Json::Value& error,
853  unsigned int apiVersion)
854 {
855  bool const has_key_type = params.isMember(jss::key_type);
856 
857  // All of the secret types we allow, but only one at a time.
858  static char const* const secretTypes[]{
859  jss::passphrase.c_str(),
860  jss::secret.c_str(),
861  jss::seed.c_str(),
862  jss::seed_hex.c_str()};
863 
864  // Identify which secret type is in use.
865  char const* secretType = nullptr;
866  int count = 0;
867  for (auto t : secretTypes)
868  {
869  if (params.isMember(t))
870  {
871  ++count;
872  secretType = t;
873  }
874  }
875 
876  if (count == 0 || secretType == nullptr)
877  {
878  error = RPC::missing_field_error(jss::secret);
879  return {};
880  }
881 
882  if (count > 1)
883  {
884  error = RPC::make_param_error(
885  "Exactly one of the following must be specified: " +
886  std::string(jss::passphrase) + ", " + std::string(jss::secret) +
887  ", " + std::string(jss::seed) + " or " +
888  std::string(jss::seed_hex));
889  return {};
890  }
891 
892  std::optional<KeyType> keyType;
893  std::optional<Seed> seed;
894 
895  if (has_key_type)
896  {
897  if (!params[jss::key_type].isString())
898  {
899  error = RPC::expected_field_error(jss::key_type, "string");
900  return {};
901  }
902 
903  keyType = keyTypeFromString(params[jss::key_type].asString());
904 
905  if (!keyType)
906  {
907  if (apiVersion > 1u)
909  else
910  error = RPC::invalid_field_error(jss::key_type);
911  return {};
912  }
913 
914  // using strcmp as pointers may not match (see
915  // https://developercommunity.visualstudio.com/t/assigning-constexpr-char--to-static-cha/10021357?entry=problem)
916  if (strcmp(secretType, jss::secret.c_str()) == 0)
917  {
918  error = RPC::make_param_error(
919  "The secret field is not allowed if " +
920  std::string(jss::key_type) + " is used.");
921  return {};
922  }
923  }
924 
925  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
926  // non-standard way. While we never encode seeds that way, we try
927  // to detect such keys to avoid user confusion.
928  // using strcmp as pointers may not match (see
929  // https://developercommunity.visualstudio.com/t/assigning-constexpr-char--to-static-cha/10021357?entry=problem)
930  if (strcmp(secretType, jss::seed_hex.c_str()) != 0)
931  {
932  seed = RPC::parseRippleLibSeed(params[secretType]);
933 
934  if (seed)
935  {
936  // If the user passed in an Ed25519 seed but *explicitly*
937  // requested another key type, return an error.
939  {
940  error = RPC::make_error(
941  rpcBAD_SEED, "Specified seed is for an Ed25519 wallet.");
942  return {};
943  }
944 
945  keyType = KeyType::ed25519;
946  }
947  }
948 
949  if (!keyType)
950  keyType = KeyType::secp256k1;
951 
952  if (!seed)
953  {
954  if (has_key_type)
955  seed = getSeedFromRPC(params, error);
956  else
957  {
958  if (!params[jss::secret].isString())
959  {
960  error = RPC::expected_field_error(jss::secret, "string");
961  return {};
962  }
963 
964  seed = parseGenericSeed(params[jss::secret].asString());
965  }
966  }
967 
968  if (!seed)
969  {
970  if (!contains_error(error))
971  {
972  error = RPC::make_error(
974  }
975 
976  return {};
977  }
978 
979  if (keyType != KeyType::secp256k1 && keyType != KeyType::ed25519)
980  LogicError("keypairForSignature: invalid key type");
981 
982  return generateKeyPair(*keyType, *seed);
983 }
984 
987 {
989  if (params.isMember(jss::type))
990  {
992  types{
993  {{jss::account, ltACCOUNT_ROOT},
994  {jss::amendments, ltAMENDMENTS},
995  {jss::check, ltCHECK},
996  {jss::deposit_preauth, ltDEPOSIT_PREAUTH},
997  {jss::directory, ltDIR_NODE},
998  {jss::escrow, ltESCROW},
999  {jss::fee, ltFEE_SETTINGS},
1000  {jss::hashes, ltLEDGER_HASHES},
1001  {jss::offer, ltOFFER},
1002  {jss::payment_channel, ltPAYCHAN},
1003  {jss::signer_list, ltSIGNER_LIST},
1004  {jss::state, ltRIPPLE_STATE},
1005  {jss::ticket, ltTICKET},
1006  {jss::nft_offer, ltNFTOKEN_OFFER},
1007  {jss::nft_page, ltNFTOKEN_PAGE},
1008  {jss::amm, ltAMM},
1009  {jss::bridge, ltBRIDGE},
1010  {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID},
1011  {jss::xchain_owned_create_account_claim_id,
1013  {jss::did, ltDID}}};
1014 
1015  auto const& p = params[jss::type];
1016  if (!p.isString())
1017  {
1018  result.first = RPC::Status{
1019  rpcINVALID_PARAMS, "Invalid field 'type', not string."};
1020  assert(result.first.type() == RPC::Status::Type::error_code_i);
1021  return result;
1022  }
1023 
1024  auto const filter = p.asString();
1025  auto iter = std::find_if(
1026  types.begin(), types.end(), [&filter](decltype(types.front())& t) {
1027  return t.first == filter;
1028  });
1029  if (iter == types.end())
1030  {
1031  result.first =
1032  RPC::Status{rpcINVALID_PARAMS, "Invalid field 'type'."};
1033  assert(result.first.type() == RPC::Status::Type::error_code_i);
1034  return result;
1035  }
1036  result.second = iter->second;
1037  }
1038  return result;
1039 }
1040 
1041 beast::SemanticVersion const firstVersion("1.0.0");
1042 beast::SemanticVersion const goodVersion("1.0.0");
1043 beast::SemanticVersion const lastVersion("1.0.0");
1044 
1045 unsigned int
1046 getAPIVersionNumber(Json::Value const& jv, bool betaEnabled)
1047 {
1048  static Json::Value const minVersion(RPC::apiMinimumSupportedVersion);
1049  static Json::Value const invalidVersion(RPC::apiInvalidVersion);
1050 
1051  Json::Value const maxVersion(
1053  Json::Value requestedVersion(RPC::apiVersionIfUnspecified);
1054  if (jv.isObject())
1055  {
1056  requestedVersion = jv.get(jss::api_version, requestedVersion);
1057  }
1058  if (!(requestedVersion.isInt() || requestedVersion.isUInt()) ||
1059  requestedVersion < minVersion || requestedVersion > maxVersion)
1060  {
1061  requestedVersion = invalidVersion;
1062  }
1063  return requestedVersion.asUInt();
1064 }
1065 
1068 {
1069  if (context.app.config().reporting())
1071 
1072  auto const hasHash = context.params.isMember(jss::ledger_hash);
1073  auto const hasIndex = context.params.isMember(jss::ledger_index);
1074  std::uint32_t ledgerIndex = 0;
1075 
1076  auto& ledgerMaster = context.app.getLedgerMaster();
1077  LedgerHash ledgerHash;
1078 
1079  if ((hasHash && hasIndex) || !(hasHash || hasIndex))
1080  {
1081  return RPC::make_param_error(
1082  "Exactly one of ledger_hash and ledger_index can be set.");
1083  }
1084 
1086 
1087  if (hasHash)
1088  {
1089  auto const& jsonHash = context.params[jss::ledger_hash];
1090  if (!jsonHash.isString() || !ledgerHash.parseHex(jsonHash.asString()))
1091  return RPC::invalid_field_error(jss::ledger_hash);
1092  }
1093  else
1094  {
1095  auto const& jsonIndex = context.params[jss::ledger_index];
1096  if (!jsonIndex.isInt())
1097  return RPC::invalid_field_error(jss::ledger_index);
1098 
1099  // We need a validated ledger to get the hash from the sequence
1100  if (ledgerMaster.getValidatedLedgerAge() >
1102  {
1103  if (context.apiVersion == 1)
1104  return rpcError(rpcNO_CURRENT);
1105  return rpcError(rpcNOT_SYNCED);
1106  }
1107 
1108  ledgerIndex = jsonIndex.asInt();
1109  auto ledger = ledgerMaster.getValidatedLedger();
1110 
1111  if (ledgerIndex >= ledger->info().seq)
1112  return RPC::make_param_error("Ledger index too large");
1113  if (ledgerIndex <= 0)
1114  return RPC::make_param_error("Ledger index too small");
1115 
1116  auto const j = context.app.journal("RPCHandler");
1117  // Try to get the hash of the desired ledger from the validated
1118  // ledger
1119  auto neededHash = hashOfSeq(*ledger, ledgerIndex, j);
1120  if (!neededHash)
1121  {
1122  // Find a ledger more likely to have the hash of the desired
1123  // ledger
1124  auto const refIndex = getCandidateLedger(ledgerIndex);
1125  auto refHash = hashOfSeq(*ledger, refIndex, j);
1126  assert(refHash);
1127 
1128  ledger = ledgerMaster.getLedgerByHash(*refHash);
1129  if (!ledger)
1130  {
1131  // We don't have the ledger we need to figure out which
1132  // ledger they want. Try to get it.
1133 
1134  if (auto il = context.app.getInboundLedgers().acquire(
1135  *refHash, refIndex, InboundLedger::Reason::GENERIC))
1136  {
1137  Json::Value jvResult = RPC::make_error(
1139  "acquiring ledger containing requested index");
1140  jvResult[jss::acquiring] =
1141  getJson(LedgerFill(*il, &context));
1142  return jvResult;
1143  }
1144 
1145  if (auto il = context.app.getInboundLedgers().find(*refHash))
1146  {
1147  Json::Value jvResult = RPC::make_error(
1149  "acquiring ledger containing requested index");
1150  jvResult[jss::acquiring] = il->getJson(0);
1151  return jvResult;
1152  }
1153 
1154  // Likely the app is shutting down
1155  return Json::Value();
1156  }
1157 
1158  neededHash = hashOfSeq(*ledger, ledgerIndex, j);
1159  }
1160  assert(neededHash);
1161  ledgerHash = neededHash ? *neededHash : beast::zero; // kludge
1162  }
1163 
1164  // Try to get the desired ledger
1165  // Verify all nodes even if we think we have it
1166  auto ledger = context.app.getInboundLedgers().acquire(
1167  ledgerHash, ledgerIndex, InboundLedger::Reason::GENERIC);
1168 
1169  // In standalone mode, accept the ledger from the ledger cache
1170  if (!ledger && context.app.config().standalone())
1171  ledger = ledgerMaster.getLedgerByHash(ledgerHash);
1172 
1173  if (ledger)
1174  return ledger;
1175 
1176  if (auto il = context.app.getInboundLedgers().find(ledgerHash))
1177  return il->getJson(0);
1178 
1179  return RPC::make_error(
1180  rpcNOT_READY, "findCreate failed to return an inbound ledger");
1181 }
1182 
1185 {
1186  using enum RPC::SubmitSync;
1187  if (params.isMember(jss::sync_mode))
1188  {
1189  std::string const syncMode = params[jss::sync_mode].asString();
1190  if (syncMode == "async")
1191  return async;
1192  else if (syncMode == "wait")
1193  return wait;
1194  else if (syncMode != "sync")
1195  return Unexpected(RPC::make_error(
1197  "sync_mode parameter must be one of \"sync\", \"async\", or "
1198  "\"wait\"."));
1199  }
1200  return sync;
1201 }
1202 
1203 } // namespace RPC
1204 } // 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:240
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:312
ripple::Application
Definition: Application.h:116
ripple::RPC::apiVersionIfUnspecified
constexpr unsigned int apiVersionIfUnspecified
Definition: RPCHelpers.h:241
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:214
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
ripple::RPC::goodVersion
const beast::SemanticVersion goodVersion("1.0.0")
Definition: RPCHelpers.h:215
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:207
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:1046
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:148
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:1067
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:244
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::RPC::keypairForSignature
std::pair< PublicKey, SecretKey > keypairForSignature(Json::Value const &params, Json::Value &error, unsigned int apiVersion)
Definition: RPCHelpers.cpp:850
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:341
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:351
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:196
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::ltDID
@ ltDID
The ledger object which tracks the DID.
Definition: LedgerFormats.h:193
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:318
ripple::Config::standalone
bool standalone() const
Definition: Config.h:346
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:349
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:293
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:242
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:986
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::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:1184
ripple::RPC::apiMaximumSupportedVersion
constexpr unsigned int apiMaximumSupportedVersion
Definition: RPCHelpers.h:243
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:277
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:216
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:180
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
ripple::rpcBAD_KEY_TYPE
@ rpcBAD_KEY_TYPE
Definition: ErrorCodes.h:133
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
ripple::root
Number root(Number f, unsigned d)
Definition: Number.cpp:624