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 standaloneOrReporting)
190 {
191  if (standaloneOrReporting)
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 == "current" ||
232  (index.empty() && !context.app.config().reporting()))
233  return getLedger(ledger, LedgerShortcut::CURRENT, context);
234 
235  if (index == "validated" ||
236  (index.empty() && context.app.config().reporting()))
237  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
238 
239  if (index == "closed")
240  return getLedger(ledger, LedgerShortcut::CLOSED, context);
241 
242  std::uint32_t iVal;
243  if (beast::lexicalCastChecked(iVal, index))
244  return getLedger(ledger, iVal, context);
245 
246  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
247 }
248 } // namespace
249 
250 template <class T, class R>
251 Status
252 ledgerFromRequest(T& ledger, GRPCContext<R>& context)
253 {
254  R& request = context.params;
255  return ledgerFromSpecifier(ledger, request.ledger(), context);
256 }
257 
258 // explicit instantiation of above function
259 template Status
260 ledgerFromRequest<>(
262  GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>&);
263 
264 // explicit instantiation of above function
265 template Status
266 ledgerFromRequest<>(
268  GRPCContext<org::xrpl::rpc::v1::GetLedgerEntryRequest>&);
269 
270 // explicit instantiation of above function
271 template Status
272 ledgerFromRequest<>(
274  GRPCContext<org::xrpl::rpc::v1::GetLedgerDataRequest>&);
275 
276 // explicit instantiation of above function
277 template Status
278 ledgerFromRequest<>(
280  GRPCContext<org::xrpl::rpc::v1::GetLedgerRequest>&);
281 
282 template <class T>
283 Status
285  T& ledger,
286  org::xrpl::rpc::v1::LedgerSpecifier const& specifier,
287  Context& context)
288 {
289  ledger.reset();
290 
291  using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
292  LedgerCase ledgerCase = specifier.ledger_case();
293  switch (ledgerCase)
294  {
295  case LedgerCase::kHash: {
296  uint256 ledgerHash = uint256::fromVoid(specifier.hash().data());
297  return getLedger(ledger, ledgerHash, context);
298  }
299  case LedgerCase::kSequence:
300  return getLedger(ledger, specifier.sequence(), context);
301  case LedgerCase::kShortcut:
302  [[fallthrough]];
303  case LedgerCase::LEDGER_NOT_SET: {
304  auto const shortcut = specifier.shortcut();
305  // note, unspecified defaults to validated in reporting mode
306  if (shortcut ==
307  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED ||
308  (shortcut ==
309  org::xrpl::rpc::v1::LedgerSpecifier::
310  SHORTCUT_UNSPECIFIED &&
311  context.app.config().reporting()))
312  {
313  return getLedger(ledger, LedgerShortcut::VALIDATED, context);
314  }
315  else
316  {
317  if (shortcut ==
318  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT ||
319  shortcut ==
320  org::xrpl::rpc::v1::LedgerSpecifier::
321  SHORTCUT_UNSPECIFIED)
322  {
323  return getLedger(ledger, LedgerShortcut::CURRENT, context);
324  }
325  else if (
326  shortcut ==
327  org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
328  {
329  return getLedger(ledger, LedgerShortcut::CLOSED, context);
330  }
331  }
332  }
333  }
334 
335  return Status::OK;
336 }
337 
338 template <class T>
339 Status
340 getLedger(T& ledger, uint256 const& ledgerHash, Context& context)
341 {
342  ledger = context.ledgerMaster.getLedgerByHash(ledgerHash);
343  if (ledger == nullptr)
344  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
345  return Status::OK;
346 }
347 
348 template <class T>
349 Status
350 getLedger(T& ledger, uint32_t ledgerIndex, Context& context)
351 {
352  ledger = context.ledgerMaster.getLedgerBySeq(ledgerIndex);
353  if (ledger == nullptr)
354  {
355  if (context.app.config().reporting())
356  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
357  auto cur = context.ledgerMaster.getCurrentLedger();
358  if (cur->info().seq == ledgerIndex)
359  {
360  ledger = cur;
361  }
362  }
363 
364  if (ledger == nullptr)
365  return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
366 
367  if (ledger->info().seq > context.ledgerMaster.getValidLedgerIndex() &&
368  isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
369  {
370  ledger.reset();
371  if (context.apiVersion == 1)
372  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
373  return {rpcNOT_SYNCED, "notSynced"};
374  }
375 
376  return Status::OK;
377 }
378 
379 template <class T>
380 Status
381 getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
382 {
383  if (isValidatedOld(
384  context.ledgerMaster,
385  context.app.config().standalone() ||
386  context.app.config().reporting()))
387  {
388  if (context.apiVersion == 1)
389  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
390  return {rpcNOT_SYNCED, "notSynced"};
391  }
392 
393  if (shortcut == LedgerShortcut::VALIDATED)
394  {
395  ledger = context.ledgerMaster.getValidatedLedger();
396  if (ledger == nullptr)
397  {
398  if (context.apiVersion == 1)
399  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
400  return {rpcNOT_SYNCED, "notSynced"};
401  }
402 
403  assert(!ledger->open());
404  }
405  else
406  {
407  if (shortcut == LedgerShortcut::CURRENT)
408  {
409  if (context.app.config().reporting())
410  return {
412  "Reporting does not track current ledger"};
413  ledger = context.ledgerMaster.getCurrentLedger();
414  assert(ledger->open());
415  }
416  else if (shortcut == LedgerShortcut::CLOSED)
417  {
418  if (context.app.config().reporting())
419  return {
420  rpcLGR_NOT_FOUND, "Reporting does not track closed ledger"};
421  ledger = context.ledgerMaster.getClosedLedger();
422  assert(!ledger->open());
423  }
424  else
425  {
426  return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
427  }
428 
429  if (ledger == nullptr)
430  {
431  if (context.apiVersion == 1)
432  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
433  return {rpcNOT_SYNCED, "notSynced"};
434  }
435 
436  static auto const minSequenceGap = 10;
437 
438  if (ledger->info().seq + minSequenceGap <
440  {
441  ledger.reset();
442  if (context.apiVersion == 1)
443  return {rpcNO_NETWORK, "InsufficientNetworkMode"};
444  return {rpcNOT_SYNCED, "notSynced"};
445  }
446  }
447  return Status::OK;
448 }
449 
450 // Explicit instantiaion of above three functions
451 template Status
452 getLedger<>(std::shared_ptr<ReadView const>&, uint32_t, Context&);
453 
454 template Status
455 getLedger<>(
457  LedgerShortcut shortcut,
458  Context&);
459 
460 template Status
461 getLedger<>(std::shared_ptr<ReadView const>&, uint256 const&, Context&);
462 
463 bool
465  LedgerMaster& ledgerMaster,
466  ReadView const& ledger,
467  Application& app)
468 {
469  if (app.config().reporting())
470  return true;
471 
472  if (ledger.open())
473  return false;
474 
475  if (ledger.info().validated)
476  return true;
477 
478  auto seq = ledger.info().seq;
479  try
480  {
481  // Use the skip list in the last validated ledger to see if ledger
482  // comes before the last validated ledger (and thus has been
483  // validated).
484  auto hash =
485  ledgerMaster.walkHashBySeq(seq, InboundLedger::Reason::GENERIC);
486 
487  if (!hash || ledger.info().hash != *hash)
488  {
489  // This ledger's hash is not the hash of the validated ledger
490  if (hash)
491  {
492  assert(hash->isNonZero());
493  uint256 valHash = getHashByIndex(seq, app);
494  if (valHash == ledger.info().hash)
495  {
496  // SQL database doesn't match ledger chain
497  ledgerMaster.clearLedger(seq);
498  }
499  }
500  return false;
501  }
502  }
503  catch (SHAMapMissingNode const& mn)
504  {
505  auto stream = app.journal("RPCHandler").warn();
506  JLOG(stream) << "Ledger #" << seq << ": " << mn.what();
507  return false;
508  }
509 
510  // Mark ledger as validated to save time if we see it again.
511  ledger.info().validated = true;
512  return true;
513 }
514 
515 // The previous version of the lookupLedger command would accept the
516 // "ledger_index" argument as a string and silently treat it as a request to
517 // return the current ledger which, while not strictly wrong, could cause a lot
518 // of confusion.
519 //
520 // The code now robustly validates the input and ensures that the only possible
521 // values for the "ledger_index" parameter are the index of a ledger passed as
522 // an integer or one of the strings "current", "closed" or "validated".
523 // Additionally, the code ensures that the value passed in "ledger_hash" is a
524 // string and a valid hash. Invalid values will return an appropriate error
525 // code.
526 //
527 // In the absence of the "ledger_hash" or "ledger_index" parameters, the code
528 // assumes that "ledger_index" has the value "current".
529 //
530 // Returns a Json::objectValue. If there was an error, it will be in that
531 // return value. Otherwise, the object contains the field "validated" and
532 // optionally the fields "ledger_hash", "ledger_index" and
533 // "ledger_current_index", if they are defined.
534 Status
537  JsonContext& context,
538  Json::Value& result)
539 {
540  if (auto status = ledgerFromRequest(ledger, context))
541  return status;
542 
543  auto& info = ledger->info();
544 
545  if (!ledger->open())
546  {
547  result[jss::ledger_hash] = to_string(info.hash);
548  result[jss::ledger_index] = info.seq;
549  }
550  else
551  {
552  result[jss::ledger_current_index] = info.seq;
553  }
554 
555  result[jss::validated] =
556  isValidated(context.ledgerMaster, *ledger, context.app);
557  return Status::OK;
558 }
559 
562 {
563  Json::Value result;
564  if (auto status = lookupLedger(ledger, context, result))
565  status.inject(result);
566 
567  return result;
568 }
569 
572 {
573  hash_set<AccountID> result;
574  for (auto const& jv : jvArray)
575  {
576  if (!jv.isString())
577  return hash_set<AccountID>();
578  auto const id = parseBase58<AccountID>(jv.asString());
579  if (!id)
580  return hash_set<AccountID>();
581  result.insert(*id);
582  }
583  return result;
584 }
585 
586 void
587 injectSLE(Json::Value& jv, SLE const& sle)
588 {
589  jv = sle.getJson(JsonOptions::none);
590  if (sle.getType() == ltACCOUNT_ROOT)
591  {
592  if (sle.isFieldPresent(sfEmailHash))
593  {
594  auto const& hash = sle.getFieldH128(sfEmailHash);
595  Blob const b(hash.begin(), hash.end());
596  std::string md5 = strHex(makeSlice(b));
597  boost::to_lower(md5);
598  // VFALCO TODO Give a name and move this constant
599  // to a more visible location. Also
600  // shouldn't this be https?
601  jv[jss::urlgravatar] =
602  str(boost::format("http://www.gravatar.com/avatar/%s") % md5);
603  }
604  }
605  else
606  {
607  jv[jss::Invalid] = true;
608  }
609 }
610 
611 boost::optional<Json::Value>
613  unsigned int& limit,
614  Tuning::LimitRange const& range,
615  JsonContext const& context)
616 {
617  limit = range.rdefault;
618  if (auto const& jvLimit = context.params[jss::limit])
619  {
620  if (!(jvLimit.isUInt() || (jvLimit.isInt() && jvLimit.asInt() >= 0)))
621  return RPC::expected_field_error(jss::limit, "unsigned integer");
622 
623  limit = jvLimit.asUInt();
624  if (!isUnlimited(context.role))
625  limit = std::max(range.rmin, std::min(range.rmax, limit));
626  }
627  return boost::none;
628 }
629 
630 boost::optional<Seed>
632 {
633  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
634  // non-standard way. While rippled never encode seeds that way, we
635  // try to detect such keys to avoid user confusion.
636  if (!value.isString())
637  return boost::none;
638 
639  auto const result = decodeBase58Token(value.asString(), TokenType::None);
640 
641  if (result.size() == 18 &&
642  static_cast<std::uint8_t>(result[0]) == std::uint8_t(0xE1) &&
643  static_cast<std::uint8_t>(result[1]) == std::uint8_t(0x4B))
644  return Seed(makeSlice(result.substr(2)));
645 
646  return boost::none;
647 }
648 
649 boost::optional<Seed>
650 getSeedFromRPC(Json::Value const& params, Json::Value& error)
651 {
652  // The array should be constexpr, but that makes Visual Studio unhappy.
653  static char const* const seedTypes[]{
654  jss::passphrase.c_str(), jss::seed.c_str(), jss::seed_hex.c_str()};
655 
656  // Identify which seed type is in use.
657  char const* seedType = nullptr;
658  int count = 0;
659  for (auto t : seedTypes)
660  {
661  if (params.isMember(t))
662  {
663  ++count;
664  seedType = t;
665  }
666  }
667 
668  if (count != 1)
669  {
670  error = RPC::make_param_error(
671  "Exactly one of the following must be specified: " +
672  std::string(jss::passphrase) + ", " + std::string(jss::seed) +
673  " or " + std::string(jss::seed_hex));
674  return boost::none;
675  }
676 
677  // Make sure a string is present
678  if (!params[seedType].isString())
679  {
680  error = RPC::expected_field_error(seedType, "string");
681  return boost::none;
682  }
683 
684  auto const fieldContents = params[seedType].asString();
685 
686  // Convert string to seed.
687  boost::optional<Seed> seed;
688 
689  if (seedType == jss::seed.c_str())
690  seed = parseBase58<Seed>(fieldContents);
691  else if (seedType == jss::passphrase.c_str())
692  seed = parseGenericSeed(fieldContents);
693  else if (seedType == jss::seed_hex.c_str())
694  {
695  uint128 s;
696 
697  if (s.parseHex(fieldContents))
698  seed.emplace(Slice(s.data(), s.size()));
699  }
700 
701  if (!seed)
702  error = rpcError(rpcBAD_SEED);
703 
704  return seed;
705 }
706 
709 {
710  bool const has_key_type = params.isMember(jss::key_type);
711 
712  // All of the secret types we allow, but only one at a time.
713  // The array should be constexpr, but that makes Visual Studio unhappy.
714  static char const* const secretTypes[]{
715  jss::passphrase.c_str(),
716  jss::secret.c_str(),
717  jss::seed.c_str(),
718  jss::seed_hex.c_str()};
719 
720  // Identify which secret type is in use.
721  char const* secretType = nullptr;
722  int count = 0;
723  for (auto t : secretTypes)
724  {
725  if (params.isMember(t))
726  {
727  ++count;
728  secretType = t;
729  }
730  }
731 
732  if (count == 0 || secretType == nullptr)
733  {
734  error = RPC::missing_field_error(jss::secret);
735  return {};
736  }
737 
738  if (count > 1)
739  {
740  error = RPC::make_param_error(
741  "Exactly one of the following must be specified: " +
742  std::string(jss::passphrase) + ", " + std::string(jss::secret) +
743  ", " + std::string(jss::seed) + " or " +
744  std::string(jss::seed_hex));
745  return {};
746  }
747 
748  boost::optional<KeyType> keyType;
749  boost::optional<Seed> seed;
750 
751  if (has_key_type)
752  {
753  if (!params[jss::key_type].isString())
754  {
755  error = RPC::expected_field_error(jss::key_type, "string");
756  return {};
757  }
758 
759  keyType = keyTypeFromString(params[jss::key_type].asString());
760 
761  if (!keyType)
762  {
763  error = RPC::invalid_field_error(jss::key_type);
764  return {};
765  }
766 
767  if (secretType == jss::secret.c_str())
768  {
769  error = RPC::make_param_error(
770  "The secret field is not allowed if " +
771  std::string(jss::key_type) + " is used.");
772  return {};
773  }
774  }
775 
776  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
777  // non-standard way. While we never encode seeds that way, we try
778  // to detect such keys to avoid user confusion.
779  if (secretType != jss::seed_hex.c_str())
780  {
781  seed = RPC::parseRippleLibSeed(params[secretType]);
782 
783  if (seed)
784  {
785  // If the user passed in an Ed25519 seed but *explicitly*
786  // requested another key type, return an error.
787  if (keyType.value_or(KeyType::ed25519) != KeyType::ed25519)
788  {
789  error = RPC::make_error(
790  rpcBAD_SEED, "Specified seed is for an Ed25519 wallet.");
791  return {};
792  }
793 
794  keyType = KeyType::ed25519;
795  }
796  }
797 
798  if (!keyType)
799  keyType = KeyType::secp256k1;
800 
801  if (!seed)
802  {
803  if (has_key_type)
804  seed = getSeedFromRPC(params, error);
805  else
806  {
807  if (!params[jss::secret].isString())
808  {
809  error = RPC::expected_field_error(jss::secret, "string");
810  return {};
811  }
812 
813  seed = parseGenericSeed(params[jss::secret].asString());
814  }
815  }
816 
817  if (!seed)
818  {
819  if (!contains_error(error))
820  {
821  error = RPC::make_error(
823  }
824 
825  return {};
826  }
827 
828  if (keyType != KeyType::secp256k1 && keyType != KeyType::ed25519)
829  LogicError("keypairForSignature: invalid key type");
830 
831  return generateKeyPair(*keyType, *seed);
832 }
833 
836 {
838  if (params.isMember(jss::type))
839  {
841  types{
842  {{jss::account, ltACCOUNT_ROOT},
843  {jss::amendments, ltAMENDMENTS},
844  {jss::check, ltCHECK},
845  {jss::deposit_preauth, ltDEPOSIT_PREAUTH},
846  {jss::directory, ltDIR_NODE},
847  {jss::escrow, ltESCROW},
848  {jss::fee, ltFEE_SETTINGS},
849  {jss::hashes, ltLEDGER_HASHES},
850  {jss::offer, ltOFFER},
851  {jss::payment_channel, ltPAYCHAN},
852  {jss::signer_list, ltSIGNER_LIST},
853  {jss::state, ltRIPPLE_STATE},
854  {jss::ticket, ltTICKET}}};
855 
856  auto const& p = params[jss::type];
857  if (!p.isString())
858  {
859  result.first = RPC::Status{
860  rpcINVALID_PARAMS, "Invalid field 'type', not string."};
861  assert(result.first.type() == RPC::Status::Type::error_code_i);
862  return result;
863  }
864 
865  auto const filter = p.asString();
866  auto iter = std::find_if(
867  types.begin(), types.end(), [&filter](decltype(types.front())& t) {
868  return t.first == filter;
869  });
870  if (iter == types.end())
871  {
872  result.first =
873  RPC::Status{rpcINVALID_PARAMS, "Invalid field 'type'."};
874  assert(result.first.type() == RPC::Status::Type::error_code_i);
875  return result;
876  }
877  result.second = iter->second;
878  }
879  return result;
880 }
881 
882 beast::SemanticVersion const firstVersion("1.0.0");
883 beast::SemanticVersion const goodVersion("1.0.0");
884 beast::SemanticVersion const lastVersion("1.0.0");
885 
886 unsigned int
888 {
889  static Json::Value const minVersion(RPC::ApiMinimumSupportedVersion);
890  static Json::Value const maxVersion(RPC::ApiMaximumSupportedVersion);
891  static Json::Value const invalidVersion(RPC::APIInvalidVersion);
892 
893  Json::Value requestedVersion(RPC::APIVersionIfUnspecified);
894  if (jv.isObject())
895  {
896  requestedVersion = jv.get(jss::api_version, requestedVersion);
897  }
898  if (!(requestedVersion.isInt() || requestedVersion.isUInt()) ||
899  requestedVersion < minVersion || requestedVersion > maxVersion)
900  {
901  requestedVersion = invalidVersion;
902  }
903  return requestedVersion.asUInt();
904 }
905 
906 } // namespace RPC
907 } // 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:101
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::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:195
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
ripple::RPC::goodVersion
const beast::SemanticVersion goodVersion("1.0.0")
Definition: RPCHelpers.h:196
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:887
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:587
std::pair
ripple::RPC::LedgerShortcut
LedgerShortcut
Definition: RPCHelpers.h:109
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:100
ripple::LedgerMaster
Definition: LedgerMaster.h:72
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:215
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:631
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:1776
ripple::RPC::APIVersionIfUnspecified
constexpr unsigned int APIVersionIfUnspecified
Definition: RPCHelpers.h:218
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:45
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:535
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:309
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:1602
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:243
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:612
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:219
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
ripple::ltINVALID
@ ltINVALID
Definition: LedgerFormats.h:49
ripple::Config::reporting
bool reporting() const
Definition: Config.h:267
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:225
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:262
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::RPC::ApiMaximumSupportedVersion
constexpr unsigned int ApiMaximumSupportedVersion
Definition: RPCHelpers.h:220
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:1740
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:1571
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:217
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:105
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
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:464
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:340
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:835
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:708
ripple::RPC::Context::apiVersion
unsigned int apiVersion
Definition: Context.h:50
ripple::TokenType::AccountPublic
@ AccountPublic
ripple::LedgerMaster::getValidatedLedger
std::shared_ptr< Ledger const > getValidatedLedger()
Definition: LedgerMaster.cpp:1581
ripple::RPC::ledgerFromSpecifier
Status ledgerFromSpecifier(T &ledger, org::xrpl::rpc::v1::LedgerSpecifier const &specifier, Context &context)
Definition: RPCHelpers.cpp:284
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:571
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:231
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:197
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:285
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:252
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: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::RPC::getSeedFromRPC
boost::optional< Seed > getSeedFromRPC(Json::Value const &params, Json::Value &error)
Definition: RPCHelpers.cpp:650
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469