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