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  {
67  auto id = deprecatedParseBitcoinAccountID(strIdent);
68  return id ? rpcACT_BITCOIN : rpcACT_MALFORMED;
69  }
70 
71  // We allow the use of the seeds which is poor practice
72  // and merely for debugging convenience.
73  auto const seed = parseGenericSeed(strIdent);
74 
75  if (!seed)
76  return rpcBAD_SEED;
77 
78  auto const keypair = generateKeyPair(KeyType::secp256k1, *seed);
79 
80  result = calcAccountID(keypair.first);
81  return rpcSUCCESS;
82 }
83 
85 accountFromString(AccountID& result, std::string const& strIdent, bool bStrict)
86 {
87  error_code_i code = accountFromStringWithCode(result, strIdent, bStrict);
88  if (code != rpcSUCCESS)
89  return rpcError(code);
90  else
91  return Json::objectValue;
92 }
93 
94 bool
96  ReadView const& ledger,
97  AccountID const& account,
98  boost::optional<std::vector<LedgerEntryType>> const& typeFilter,
99  uint256 dirIndex,
100  uint256 const& entryIndex,
101  std::uint32_t const limit,
102  Json::Value& jvResult)
103 {
104  auto const root = keylet::ownerDir(account);
105  auto found = false;
106 
107  if (dirIndex.isZero())
108  {
109  dirIndex = root.key;
110  found = true;
111  }
112 
113  auto dir = ledger.read({ltDIR_NODE, dirIndex});
114  if (!dir)
115  return false;
116 
117  std::uint32_t i = 0;
118  auto& jvObjects = (jvResult[jss::account_objects] = Json::arrayValue);
119  for (;;)
120  {
121  auto const& entries = dir->getFieldV256(sfIndexes);
122  auto iter = entries.begin();
123 
124  if (!found)
125  {
126  iter = std::find(iter, entries.end(), entryIndex);
127  if (iter == entries.end())
128  return false;
129 
130  found = true;
131  }
132 
133  for (; iter != entries.end(); ++iter)
134  {
135  auto const sleNode = ledger.read(keylet::child(*iter));
136 
137  auto typeMatchesFilter =
138  [](std::vector<LedgerEntryType> const& typeFilter,
139  LedgerEntryType ledgerType) {
140  auto it = std::find(
141  typeFilter.begin(), typeFilter.end(), ledgerType);
142  return it != typeFilter.end();
143  };
144 
145  if (!typeFilter.has_value() ||
146  typeMatchesFilter(typeFilter.value(), sleNode->getType()))
147  {
148  jvObjects.append(sleNode->getJson(JsonOptions::none));
149 
150  if (++i == limit)
151  {
152  if (++iter != entries.end())
153  {
154  jvResult[jss::limit] = limit;
155  jvResult[jss::marker] =
156  to_string(dirIndex) + ',' + to_string(*iter);
157  return true;
158  }
159 
160  break;
161  }
162  }
163  }
164 
165  auto const nodeIndex = dir->getFieldU64(sfIndexNext);
166  if (nodeIndex == 0)
167  return true;
168 
169  dirIndex = keylet::page(root, nodeIndex).key;
170  dir = ledger.read({ltDIR_NODE, dirIndex});
171  if (!dir)
172  return true;
173 
174  if (i == limit)
175  {
176  auto const& e = dir->getFieldV256(sfIndexes);
177  if (!e.empty())
178  {
179  jvResult[jss::limit] = limit;
180  jvResult[jss::marker] =
181  to_string(dirIndex) + ',' + to_string(*e.begin());
182  }
183 
184  return true;
185  }
186  }
187 }
188 
189 namespace {
190 
191 bool
192 isValidatedOld(LedgerMaster& ledgerMaster, bool standalone)
193 {
194  if (standalone)
195  return false;
196 
197  return ledgerMaster.getValidatedLedgerAge() > Tuning::maxValidatedLedgerAge;
198 }
199 
200 template <class T>
201 Status
202 ledgerFromRequest(T& ledger, JsonContext& context)
203 {
204  ledger.reset();
205 
206  auto& params = context.params;
207 
208  auto indexValue = params[jss::ledger_index];
209  auto hashValue = params[jss::ledger_hash];
210 
211  // We need to support the legacy "ledger" field.
212  auto& legacyLedger = params[jss::ledger];
213  if (legacyLedger)
214  {
215  if (legacyLedger.asString().size() > 12)
216  hashValue = legacyLedger;
217  else
218  indexValue = legacyLedger;
219  }
220 
221  if (hashValue)
222  {
223  if (!hashValue.isString())
224  return {rpcINVALID_PARAMS, "ledgerHashNotString"};
225 
226  uint256 ledgerHash;
227  if (!ledgerHash.SetHex(hashValue.asString()))
228  return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
229  return getLedger(ledger, ledgerHash, context);
230  }
231  else if (indexValue.isNumeric())
232  {
233  return getLedger(ledger, indexValue.asInt(), context);
234  }
235  else
236  {
237  auto const index = indexValue.asString();
238  if (index == "validated")
239  {
240  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
241  }
242  else
243  {
244  if (index.empty() || index == "current")
245  return getLedger(ledger, LedgerShortcut::CURRENT, context);
246  else if (index == "closed")
247  return getLedger(ledger, LedgerShortcut::CLOSED, context);
248  else
249  {
250  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
251  }
252  }
253  }
254 
255  return Status::OK;
256 }
257 } // namespace
258 
259 template <class T>
260 Status
262  T& ledger,
264 {
265  ledger.reset();
266 
267  org::xrpl::rpc::v1::GetAccountInfoRequest& request = context.params;
268 
269  using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
270  LedgerCase ledgerCase = request.ledger().ledger_case();
271  switch (ledgerCase)
272  {
273  case LedgerCase::kHash: {
274  uint256 ledgerHash =
275  uint256::fromVoid(request.ledger().hash().data());
276  return getLedger(ledger, ledgerHash, context);
277  }
278  case LedgerCase::kSequence:
279  return getLedger(ledger, request.ledger().sequence(), context);
280  case LedgerCase::kShortcut:
281  [[fallthrough]];
282  case LedgerCase::LEDGER_NOT_SET: {
283  auto const shortcut = request.ledger().shortcut();
284  if (shortcut ==
285  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED)
286  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
287  else
288  {
289  // note, if unspecified, defaults to current ledger
290  if (shortcut ==
291  org::xrpl::rpc::v1::LedgerSpecifier::
292  SHORTCUT_UNSPECIFIED ||
293  shortcut ==
294  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT)
295  {
296  return getLedger(ledger, LedgerShortcut::CURRENT, context);
297  }
298  else if (
299  shortcut ==
300  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
301  {
302  return getLedger(ledger, LedgerShortcut::CLOSED, context);
303  }
304  }
305  }
306  }
307 
308  return Status::OK;
309 }
310 
311 // explicit instantiation of above function
312 template Status
313 ledgerFromRequest<>(
315  GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>&);
316 
317 Status
320  uint256 const& ledgerHash,
321  Context& context)
322 {
323  ledger = context.ledgerMaster.getLedgerByHash(ledgerHash);
324  if (ledger == nullptr)
325  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
326  return Status::OK;
327 }
328 
329 template <class T>
330 Status
331 getLedger(T& ledger, uint32_t ledgerIndex, Context& context)
332 {
333  ledger = context.ledgerMaster.getLedgerBySeq(ledgerIndex);
334  if (ledger == nullptr)
335  {
336  auto cur = context.ledgerMaster.getCurrentLedger();
337  if (cur->info().seq == ledgerIndex)
338  {
339  ledger = cur;
340  }
341  }
342 
343  if (ledger == nullptr)
344  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
345 
346  if (ledger->info().seq > context.ledgerMaster.getValidLedgerIndex() &&
347  isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
348  {
349  ledger.reset();
350  if (context.apiVersion == 1)
351  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
352  return {rpcNOT_SYNCED, "notSynced"};
353  }
354 
355  return Status::OK;
356 }
357 
358 template <class T>
359 Status
360 getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
361 {
362  if (isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
363  {
364  if (context.apiVersion == 1)
365  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
366  return {rpcNOT_SYNCED, "notSynced"};
367  }
368 
369  if (shortcut == LedgerShortcut::VALIDATED)
370  {
371  ledger = context.ledgerMaster.getValidatedLedger();
372  if (ledger == nullptr)
373  {
374  if (context.apiVersion == 1)
375  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
376  return {rpcNOT_SYNCED, "notSynced"};
377  }
378 
379  assert(!ledger->open());
380  }
381  else
382  {
383  if (shortcut == LedgerShortcut::CURRENT)
384  {
385  ledger = context.ledgerMaster.getCurrentLedger();
386  assert(ledger->open());
387  }
388  else if (shortcut == LedgerShortcut::CLOSED)
389  {
390  ledger = context.ledgerMaster.getClosedLedger();
391  assert(!ledger->open());
392  }
393  else
394  {
395  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
396  }
397 
398  if (ledger == nullptr)
399  {
400  if (context.apiVersion == 1)
401  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
402  return {rpcNOT_SYNCED, "notSynced"};
403  }
404 
405  static auto const minSequenceGap = 10;
406 
407  if (ledger->info().seq + minSequenceGap <
409  {
410  ledger.reset();
411  if (context.apiVersion == 1)
412  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
413  return {rpcNOT_SYNCED, "notSynced"};
414  }
415  }
416  return Status::OK;
417 }
418 
419 // Explicit instantiaion of above three functions
420 template Status
421 getLedger<>(std::shared_ptr<ReadView const>&, uint32_t, Context&);
422 
423 template Status
424 getLedger<>(
426  LedgerShortcut shortcut,
427  Context&);
428 
429 bool
431  LedgerMaster& ledgerMaster,
432  ReadView const& ledger,
433  Application& app)
434 {
435  if (ledger.open())
436  return false;
437 
438  if (ledger.info().validated)
439  return true;
440 
441  auto seq = ledger.info().seq;
442  try
443  {
444  // Use the skip list in the last validated ledger to see if ledger
445  // comes before the last validated ledger (and thus has been
446  // validated).
447  auto hash =
448  ledgerMaster.walkHashBySeq(seq, InboundLedger::Reason::GENERIC);
449 
450  if (!hash || ledger.info().hash != *hash)
451  {
452  // This ledger's hash is not the hash of the validated ledger
453  if (hash)
454  {
455  assert(hash->isNonZero());
456  uint256 valHash = getHashByIndex(seq, app);
457  if (valHash == ledger.info().hash)
458  {
459  // SQL database doesn't match ledger chain
460  ledgerMaster.clearLedger(seq);
461  }
462  }
463  return false;
464  }
465  }
466  catch (SHAMapMissingNode const& mn)
467  {
468  auto stream = app.journal("RPCHandler").warn();
469  JLOG(stream) << "Ledger #" << seq << ": " << mn.what();
470  return false;
471  }
472 
473  // Mark ledger as validated to save time if we see it again.
474  ledger.info().validated = true;
475  return true;
476 }
477 
478 // The previous version of the lookupLedger command would accept the
479 // "ledger_index" argument as a string and silently treat it as a request to
480 // return the current ledger which, while not strictly wrong, could cause a lot
481 // of confusion.
482 //
483 // The code now robustly validates the input and ensures that the only possible
484 // values for the "ledger_index" parameter are the index of a ledger passed as
485 // an integer or one of the strings "current", "closed" or "validated".
486 // Additionally, the code ensures that the value passed in "ledger_hash" is a
487 // string and a valid hash. Invalid values will return an appropriate error
488 // code.
489 //
490 // In the absence of the "ledger_hash" or "ledger_index" parameters, the code
491 // assumes that "ledger_index" has the value "current".
492 //
493 // Returns a Json::objectValue. If there was an error, it will be in that
494 // return value. Otherwise, the object contains the field "validated" and
495 // optionally the fields "ledger_hash", "ledger_index" and
496 // "ledger_current_index", if they are defined.
497 Status
500  JsonContext& context,
501  Json::Value& result)
502 {
503  if (auto status = ledgerFromRequest(ledger, context))
504  return status;
505 
506  auto& info = ledger->info();
507 
508  if (!ledger->open())
509  {
510  result[jss::ledger_hash] = to_string(info.hash);
511  result[jss::ledger_index] = info.seq;
512  }
513  else
514  {
515  result[jss::ledger_current_index] = info.seq;
516  }
517 
518  result[jss::validated] =
519  isValidated(context.ledgerMaster, *ledger, context.app);
520  return Status::OK;
521 }
522 
525 {
526  Json::Value result;
527  if (auto status = lookupLedger(ledger, context, result))
528  status.inject(result);
529 
530  return result;
531 }
532 
535 {
536  hash_set<AccountID> result;
537  for (auto const& jv : jvArray)
538  {
539  if (!jv.isString())
540  return hash_set<AccountID>();
541  auto const id = parseBase58<AccountID>(jv.asString());
542  if (!id)
543  return hash_set<AccountID>();
544  result.insert(*id);
545  }
546  return result;
547 }
548 
549 void
550 injectSLE(Json::Value& jv, SLE const& sle)
551 {
552  jv = sle.getJson(JsonOptions::none);
553  if (sle.getType() == ltACCOUNT_ROOT)
554  {
555  if (sle.isFieldPresent(sfEmailHash))
556  {
557  auto const& hash = sle.getFieldH128(sfEmailHash);
558  Blob const b(hash.begin(), hash.end());
559  std::string md5 = strHex(makeSlice(b));
560  boost::to_lower(md5);
561  // VFALCO TODO Give a name and move this constant
562  // to a more visible location. Also
563  // shouldn't this be https?
564  jv[jss::urlgravatar] =
565  str(boost::format("http://www.gravatar.com/avatar/%s") % md5);
566  }
567  }
568  else
569  {
570  jv[jss::Invalid] = true;
571  }
572 }
573 
574 boost::optional<Json::Value>
576  unsigned int& limit,
577  Tuning::LimitRange const& range,
578  JsonContext const& context)
579 {
580  limit = range.rdefault;
581  if (auto const& jvLimit = context.params[jss::limit])
582  {
583  if (!(jvLimit.isUInt() || (jvLimit.isInt() && jvLimit.asInt() >= 0)))
584  return RPC::expected_field_error(jss::limit, "unsigned integer");
585 
586  limit = jvLimit.asUInt();
587  if (!isUnlimited(context.role))
588  limit = std::max(range.rmin, std::min(range.rmax, limit));
589  }
590  return boost::none;
591 }
592 
593 boost::optional<Seed>
595 {
596  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
597  // non-standard way. While rippled never encode seeds that way, we
598  // try to detect such keys to avoid user confusion.
599  if (!value.isString())
600  return boost::none;
601 
602  auto const result = decodeBase58Token(value.asString(), TokenType::None);
603 
604  if (result.size() == 18 &&
605  static_cast<std::uint8_t>(result[0]) == std::uint8_t(0xE1) &&
606  static_cast<std::uint8_t>(result[1]) == std::uint8_t(0x4B))
607  return Seed(makeSlice(result.substr(2)));
608 
609  return boost::none;
610 }
611 
612 boost::optional<Seed>
613 getSeedFromRPC(Json::Value const& params, Json::Value& error)
614 {
615  // The array should be constexpr, but that makes Visual Studio unhappy.
616  static char const* const seedTypes[]{
617  jss::passphrase.c_str(), jss::seed.c_str(), jss::seed_hex.c_str()};
618 
619  // Identify which seed type is in use.
620  char const* seedType = nullptr;
621  int count = 0;
622  for (auto t : seedTypes)
623  {
624  if (params.isMember(t))
625  {
626  ++count;
627  seedType = t;
628  }
629  }
630 
631  if (count != 1)
632  {
633  error = RPC::make_param_error(
634  "Exactly one of the following must be specified: " +
635  std::string(jss::passphrase) + ", " + std::string(jss::seed) +
636  " or " + std::string(jss::seed_hex));
637  return boost::none;
638  }
639 
640  // Make sure a string is present
641  if (!params[seedType].isString())
642  {
643  error = RPC::expected_field_error(seedType, "string");
644  return boost::none;
645  }
646 
647  auto const fieldContents = params[seedType].asString();
648 
649  // Convert string to seed.
650  boost::optional<Seed> seed;
651 
652  if (seedType == jss::seed.c_str())
653  seed = parseBase58<Seed>(fieldContents);
654  else if (seedType == jss::passphrase.c_str())
655  seed = parseGenericSeed(fieldContents);
656  else if (seedType == jss::seed_hex.c_str())
657  {
658  uint128 s;
659 
660  if (s.SetHexExact(fieldContents))
661  seed.emplace(Slice(s.data(), s.size()));
662  }
663 
664  if (!seed)
665  error = rpcError(rpcBAD_SEED);
666 
667  return seed;
668 }
669 
672 {
673  bool const has_key_type = params.isMember(jss::key_type);
674 
675  // All of the secret types we allow, but only one at a time.
676  // The array should be constexpr, but that makes Visual Studio unhappy.
677  static char const* const secretTypes[]{
678  jss::passphrase.c_str(),
679  jss::secret.c_str(),
680  jss::seed.c_str(),
681  jss::seed_hex.c_str()};
682 
683  // Identify which secret type is in use.
684  char const* secretType = nullptr;
685  int count = 0;
686  for (auto t : secretTypes)
687  {
688  if (params.isMember(t))
689  {
690  ++count;
691  secretType = t;
692  }
693  }
694 
695  if (count == 0 || secretType == nullptr)
696  {
697  error = RPC::missing_field_error(jss::secret);
698  return {};
699  }
700 
701  if (count > 1)
702  {
703  error = RPC::make_param_error(
704  "Exactly one of the following must be specified: " +
705  std::string(jss::passphrase) + ", " + std::string(jss::secret) +
706  ", " + std::string(jss::seed) + " or " +
707  std::string(jss::seed_hex));
708  return {};
709  }
710 
711  boost::optional<KeyType> keyType;
712  boost::optional<Seed> seed;
713 
714  if (has_key_type)
715  {
716  if (!params[jss::key_type].isString())
717  {
718  error = RPC::expected_field_error(jss::key_type, "string");
719  return {};
720  }
721 
722  keyType = keyTypeFromString(params[jss::key_type].asString());
723 
724  if (!keyType)
725  {
726  error = RPC::invalid_field_error(jss::key_type);
727  return {};
728  }
729 
730  if (secretType == jss::secret.c_str())
731  {
732  error = RPC::make_param_error(
733  "The secret field is not allowed if " +
734  std::string(jss::key_type) + " is used.");
735  return {};
736  }
737  }
738 
739  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
740  // non-standard way. While we never encode seeds that way, we try
741  // to detect such keys to avoid user confusion.
742  if (secretType != jss::seed_hex.c_str())
743  {
744  seed = RPC::parseRippleLibSeed(params[secretType]);
745 
746  if (seed)
747  {
748  // If the user passed in an Ed25519 seed but *explicitly*
749  // requested another key type, return an error.
750  if (keyType.value_or(KeyType::ed25519) != KeyType::ed25519)
751  {
752  error = RPC::make_error(
753  rpcBAD_SEED, "Specified seed is for an Ed25519 wallet.");
754  return {};
755  }
756 
757  keyType = KeyType::ed25519;
758  }
759  }
760 
761  if (!keyType)
762  keyType = KeyType::secp256k1;
763 
764  if (!seed)
765  {
766  if (has_key_type)
767  seed = getSeedFromRPC(params, error);
768  else
769  {
770  if (!params[jss::secret].isString())
771  {
772  error = RPC::expected_field_error(jss::secret, "string");
773  return {};
774  }
775 
776  seed = parseGenericSeed(params[jss::secret].asString());
777  }
778  }
779 
780  if (!seed)
781  {
782  if (!contains_error(error))
783  {
784  error = RPC::make_error(
786  }
787 
788  return {};
789  }
790 
791  if (keyType != KeyType::secp256k1 && keyType != KeyType::ed25519)
792  LogicError("keypairForSignature: invalid key type");
793 
794  return generateKeyPair(*keyType, *seed);
795 }
796 
799 {
801  if (params.isMember(jss::type))
802  {
804  types{
805  {{jss::account, ltACCOUNT_ROOT},
806  {jss::amendments, ltAMENDMENTS},
807  {jss::check, ltCHECK},
808  {jss::deposit_preauth, ltDEPOSIT_PREAUTH},
809  {jss::directory, ltDIR_NODE},
810  {jss::escrow, ltESCROW},
811  {jss::fee, ltFEE_SETTINGS},
812  {jss::hashes, ltLEDGER_HASHES},
813  {jss::offer, ltOFFER},
814  {jss::payment_channel, ltPAYCHAN},
815  {jss::signer_list, ltSIGNER_LIST},
816  {jss::state, ltRIPPLE_STATE},
817  {jss::ticket, ltTICKET}}};
818 
819  auto const& p = params[jss::type];
820  if (!p.isString())
821  {
822  result.first = RPC::Status{
823  rpcINVALID_PARAMS, "Invalid field 'type', not string."};
824  assert(result.first.type() == RPC::Status::Type::error_code_i);
825  return result;
826  }
827 
828  auto const filter = p.asString();
829  auto iter = std::find_if(
830  types.begin(), types.end(), [&filter](decltype(types.front())& t) {
831  return t.first == filter;
832  });
833  if (iter == types.end())
834  {
835  result.first =
836  RPC::Status{rpcINVALID_PARAMS, "Invalid field 'type'."};
837  assert(result.first.type() == RPC::Status::Type::error_code_i);
838  return result;
839  }
840  result.second = iter->second;
841  }
842  return result;
843 }
844 
845 beast::SemanticVersion const firstVersion("1.0.0");
846 beast::SemanticVersion const goodVersion("1.0.0");
847 beast::SemanticVersion const lastVersion("1.0.0");
848 
849 unsigned int
851 {
852  static Json::Value const minVersion(RPC::ApiMinimumSupportedVersion);
853  static Json::Value const maxVersion(RPC::ApiMaximumSupportedVersion);
854  static Json::Value const invalidVersion(RPC::APIInvalidVersion);
855 
856  Json::Value requestedVersion(RPC::APIVersionIfUnspecified);
857  if (jv.isObject())
858  {
859  requestedVersion = jv.get(jss::api_version, requestedVersion);
860  }
861  if (!(requestedVersion.isInt() || requestedVersion.isUInt()) ||
862  requestedVersion < minVersion || requestedVersion > maxVersion)
863  {
864  requestedVersion = invalidVersion;
865  }
866  return requestedVersion.asUInt();
867 }
868 
869 } // namespace RPC
870 } // 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::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:285
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:318
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::sfIndexNext
const SF_U64 sfIndexNext(access, STI_UINT64, 1, "IndexNext")
Definition: SField.h:395
ripple::STLedgerEntry::getJson
Json::Value getJson(JsonOptions options) const override
Definition: STLedgerEntry.cpp:102
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:850
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:550
std::pair
ripple::RPC::LedgerShortcut
LedgerShortcut
Definition: RPCHelpers.h:111
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:96
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:594
ripple::deprecatedParseBitcoinAccountID
boost::optional< AccountID > deprecatedParseBitcoinAccountID(std::string const &s)
Definition: AccountID.cpp:49
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
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:95
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:127
ripple::STObject::getFieldH128
uint128 getFieldH128(SField const &field) const
Definition: STObject.cpp:544
ripple::LedgerMaster::getLedgerByHash
std::shared_ptr< Ledger const > getLedgerByHash(uint256 const &hash)
Definition: LedgerMaster.cpp:1705
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:88
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:103
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:498
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:462
ripple::getHashByIndex
uint256 getHashByIndex(std::uint32_t ledgerIndex, Application &app)
Definition: Ledger.cpp:1258
ripple::SHAMapMissingNode
Definition: SHAMapMissingNode.h:55
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:493
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:236
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:575
ripple::Keylet::key
uint256 key
Definition: Keylet.h:41
ripple::base_uint
Definition: base_uint.h:63
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:475
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:219
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:291
ripple::Config::standalone
bool standalone() const
Definition: Config.h:222
ripple::RPC::GRPCContext
Definition: Context.h:70
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:131
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:1669
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::sfIndexes
const SF_Vec256 sfIndexes(access, STI_VECTOR256, 1, "Indexes", SField::sMD_Never)
Definition: SField.h:493
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:98
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:1530
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::base_uint::SetHexExact
bool SetHexExact(const char *psz)
Parse a hex string into a base_uint The string must contain exactly bytes * 2 hex characters and must...
Definition: base_uint.h:370
ripple::RPC::Status
Status represents the results of an operation that might fail.
Definition: Status.h:39
ripple::rpcACT_BITCOIN
@ rpcACT_BITCOIN
Definition: ErrorCodes.h:89
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:188
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:430
ripple::rpcACT_MALFORMED
@ rpcACT_MALFORMED
Definition: ErrorCodes.h:90
ripple::Seed
Seeds are used to generate deterministic secret keys.
Definition: Seed.h:32
ripple::LedgerEntryType
LedgerEntryType
Ledger entry types.
Definition: LedgerFormats.h:36
ripple::RPC::chooseLedgerEntryType
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:798
std::vector::begin
T begin(T... args)
ripple::decodeBase58Token
static std::string decodeBase58Token(std::string const &s, TokenType type, InverseArray const &inv)
Definition: tokens.cpp:256
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:213
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:671
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:67
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:534
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:106
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:85
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:203
ripple::RPC::Tuning::maxValidatedLedgerAge
constexpr auto maxValidatedLedgerAge
Definition: rpc/impl/Tuning.h:59
ripple::sfEmailHash
const SF_U128 sfEmailHash(access, STI_HASH128, 1, "EmailHash")
Definition: SField.h:408
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:613
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:261