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