rippled
TransactionSign.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/main/Application.h>
23 #include <ripple/app/misc/DeliverMax.h>
24 #include <ripple/app/misc/LoadFeeTrack.h>
25 #include <ripple/app/misc/Transaction.h>
26 #include <ripple/app/misc/TxQ.h>
27 #include <ripple/app/paths/Pathfinder.h>
28 #include <ripple/app/tx/apply.h> // Validity::Valid
29 #include <ripple/basics/Log.h>
30 #include <ripple/basics/mulDiv.h>
31 #include <ripple/json/json_writer.h>
32 #include <ripple/net/RPCErr.h>
33 #include <ripple/protocol/ErrorCodes.h>
34 #include <ripple/protocol/Feature.h>
35 #include <ripple/protocol/STAccount.h>
36 #include <ripple/protocol/STParsedJSON.h>
37 #include <ripple/protocol/Sign.h>
38 #include <ripple/protocol/TxFlags.h>
39 #include <ripple/rpc/impl/LegacyPathFind.h>
40 #include <ripple/rpc/impl/RPCHelpers.h>
41 #include <ripple/rpc/impl/TransactionSign.h>
42 #include <ripple/rpc/impl/Tuning.h>
43 #include <algorithm>
44 #include <iterator>
45 
46 namespace ripple {
47 namespace RPC {
48 namespace detail {
49 
50 // Used to pass extra parameters used when returning a
51 // a SigningFor object.
53 {
54 private:
58 
59 public:
60  explicit SigningForParams()
61  : multiSigningAcctID_(nullptr)
62  , multiSignPublicKey_(nullptr)
63  , multiSignature_(nullptr)
64  {
65  }
66 
67  SigningForParams(SigningForParams const& rhs) = delete;
68 
70  AccountID const& multiSigningAcctID,
71  PublicKey& multiSignPublicKey,
72  Buffer& multiSignature)
73  : multiSigningAcctID_(&multiSigningAcctID)
74  , multiSignPublicKey_(&multiSignPublicKey)
75  , multiSignature_(&multiSignature)
76  {
77  }
78 
79  bool
81  {
82  return (
83  (multiSigningAcctID_ != nullptr) &&
84  (multiSignPublicKey_ != nullptr) && (multiSignature_ != nullptr));
85  }
86 
87  bool
89  {
90  return !isMultiSigning();
91  }
92 
93  // When multi-signing we should not edit the tx_json fields.
94  bool
95  editFields() const
96  {
97  return !isMultiSigning();
98  }
99 
100  // Don't call this method unless isMultiSigning() returns true.
101  AccountID const&
103  {
104  return *multiSigningAcctID_;
105  }
106 
107  void
108  setPublicKey(PublicKey const& multiSignPublicKey)
109  {
110  *multiSignPublicKey_ = multiSignPublicKey;
111  }
112 
113  void
114  moveMultiSignature(Buffer&& multiSignature)
115  {
116  *multiSignature_ = std::move(multiSignature);
117  }
118 };
119 
120 //------------------------------------------------------------------------------
121 
122 static error_code_i
124  std::shared_ptr<SLE const> accountState,
125  AccountID const& accountID,
126  PublicKey const& publicKey)
127 {
128  auto const publicKeyAcctID = calcAccountID(publicKey);
129  bool const isMasterKey = publicKeyAcctID == accountID;
130 
131  // If we can't get the accountRoot, but the accountIDs match, that's
132  // good enough.
133  if (!accountState)
134  {
135  if (isMasterKey)
136  return rpcSUCCESS;
137  return rpcBAD_SECRET;
138  }
139 
140  // If we *can* get to the accountRoot, check for MASTER_DISABLED.
141  auto const& sle = *accountState;
142  if (isMasterKey)
143  {
144  if (sle.isFlag(lsfDisableMaster))
145  return rpcMASTER_DISABLED;
146  return rpcSUCCESS;
147  }
148 
149  // The last gasp is that we have public Regular key.
150  if ((sle.isFieldPresent(sfRegularKey)) &&
151  (publicKeyAcctID == sle.getAccountID(sfRegularKey)))
152  {
153  return rpcSUCCESS;
154  }
155  return rpcBAD_SECRET;
156 }
157 
158 static Json::Value
160  Json::Value const& params,
161  Json::Value& tx_json,
162  AccountID const& srcAddressID,
163  Role const role,
164  Application& app,
165  bool doPath)
166 {
167  // Only path find for Payments.
168  if (tx_json[jss::TransactionType].asString() != jss::Payment)
169  return Json::Value();
170 
171  // DeliverMax is an alias to Amount and we use Amount internally
172  if (tx_json.isMember(jss::DeliverMax))
173  {
174  if (tx_json.isMember(jss::Amount))
175  {
176  if (tx_json[jss::DeliverMax] != tx_json[jss::Amount])
177  return RPC::make_error(
179  "Cannot specify differing 'Amount' and 'DeliverMax'");
180  }
181  else
182  tx_json[jss::Amount] = tx_json[jss::DeliverMax];
183 
184  tx_json.removeMember(jss::DeliverMax);
185  }
186 
187  if (!tx_json.isMember(jss::Amount))
188  return RPC::missing_field_error("tx_json.Amount");
189 
190  STAmount amount;
191 
192  if (!amountFromJsonNoThrow(amount, tx_json[jss::Amount]))
193  return RPC::invalid_field_error("tx_json.Amount");
194 
195  if (!tx_json.isMember(jss::Destination))
196  return RPC::missing_field_error("tx_json.Destination");
197 
198  auto const dstAccountID =
199  parseBase58<AccountID>(tx_json[jss::Destination].asString());
200  if (!dstAccountID)
201  return RPC::invalid_field_error("tx_json.Destination");
202 
203  if ((doPath == false) && params.isMember(jss::build_path))
204  return RPC::make_error(
206  "Field 'build_path' not allowed in this context.");
207 
208  if (tx_json.isMember(jss::Paths) && params.isMember(jss::build_path))
209  return RPC::make_error(
211  "Cannot specify both 'tx_json.Paths' and 'build_path'");
212 
213  if (!tx_json.isMember(jss::Paths) && params.isMember(jss::build_path))
214  {
215  STAmount sendMax;
216 
217  if (tx_json.isMember(jss::SendMax))
218  {
219  if (!amountFromJsonNoThrow(sendMax, tx_json[jss::SendMax]))
220  return RPC::invalid_field_error("tx_json.SendMax");
221  }
222  else
223  {
224  // If no SendMax, default to Amount with sender as issuer.
225  sendMax = amount;
226  sendMax.setIssuer(srcAddressID);
227  }
228 
229  if (sendMax.native() && amount.native())
230  return RPC::make_error(
231  rpcINVALID_PARAMS, "Cannot build XRP to XRP paths.");
232 
233  {
234  LegacyPathFind lpf(isUnlimited(role), app);
235  if (!lpf.isOk())
236  return rpcError(rpcTOO_BUSY);
237 
238  STPathSet result;
239 
240  if (auto ledger = app.openLedger().current())
241  {
242  Pathfinder pf(
243  std::make_shared<RippleLineCache>(
244  ledger, app.journal("RippleLineCache")),
245  srcAddressID,
246  *dstAccountID,
247  sendMax.issue().currency,
248  sendMax.issue().account,
249  amount,
250  std::nullopt,
251  app);
252  if (pf.findPaths(app.config().PATH_SEARCH_OLD))
253  {
254  // 4 is the maxium paths
255  pf.computePathRanks(4);
256  STPath fullLiquidityPath;
257  STPathSet paths;
258  result = pf.getBestPaths(
259  4, fullLiquidityPath, paths, sendMax.issue().account);
260  }
261  }
262 
263  auto j = app.journal("RPCHandler");
264  JLOG(j.debug()) << "transactionSign: build_path: "
265  << result.getJson(JsonOptions::none);
266 
267  if (!result.empty())
268  tx_json[jss::Paths] = result.getJson(JsonOptions::none);
269  }
270  }
271  return Json::Value();
272 }
273 
274 //------------------------------------------------------------------------------
275 
276 // Validate (but don't modify) the contents of the tx_json.
277 //
278 // Returns a pair<Json::Value, AccountID>. The Json::Value will contain error
279 // information if there was an error. On success, the account ID is returned
280 // and the Json::Value will be empty.
281 //
282 // This code does not check the "Sequence" field, since the expectations
283 // for that field are particularly context sensitive.
286  Json::Value const& tx_json,
287  Role const role,
288  bool const verify,
289  std::chrono::seconds validatedLedgerAge,
290  Config const& config,
291  LoadFeeTrack const& feeTrack,
292  unsigned apiVersion)
293 {
295 
296  if (!tx_json.isObject())
297  {
298  ret.first = RPC::object_field_error(jss::tx_json);
299  return ret;
300  }
301 
302  if (!tx_json.isMember(jss::TransactionType))
303  {
304  ret.first = RPC::missing_field_error("tx_json.TransactionType");
305  return ret;
306  }
307 
308  if (!tx_json.isMember(jss::Account))
309  {
310  ret.first = RPC::make_error(
311  rpcSRC_ACT_MISSING, RPC::missing_field_message("tx_json.Account"));
312  return ret;
313  }
314 
315  auto const srcAddressID =
316  parseBase58<AccountID>(tx_json[jss::Account].asString());
317 
318  if (!srcAddressID)
319  {
320  ret.first = RPC::make_error(
322  RPC::invalid_field_message("tx_json.Account"));
323  return ret;
324  }
325 
326  // Check for current ledger.
327  if (verify && !config.standalone() &&
328  (validatedLedgerAge > Tuning::maxValidatedLedgerAge))
329  {
330  if (apiVersion == 1)
332  else
334  return ret;
335  }
336 
337  // Check for load.
338  if (feeTrack.isLoadedCluster() && !isUnlimited(role))
339  {
340  ret.first = rpcError(rpcTOO_BUSY);
341  return ret;
342  }
343 
344  // It's all good. Return the AccountID.
345  ret.second = *srcAddressID;
346  return ret;
347 }
348 
349 //------------------------------------------------------------------------------
350 
351 // A move-only struct that makes it easy to return either a Json::Value or a
352 // std::shared_ptr<STTx const> from transactionPreProcessImpl ().
354 {
357 
358  transactionPreProcessResult() = delete;
361 
363  operator=(transactionPreProcessResult const&) = delete;
366 
368  : first(std::move(json)), second()
369  {
370  }
371 
373  : first(), second(std::move(st))
374  {
375  }
376 };
377 
378 static transactionPreProcessResult
380  Json::Value& params,
381  Role role,
382  SigningForParams& signingArgs,
383  std::chrono::seconds validatedLedgerAge,
384  Application& app)
385 {
386  auto j = app.journal("RPCHandler");
387 
388  Json::Value jvResult;
389  auto const [pk, sk] = keypairForSignature(params, jvResult);
390  if (contains_error(jvResult))
391  return jvResult;
392 
393  bool const verify =
394  !(params.isMember(jss::offline) && params[jss::offline].asBool());
395 
396  if (!params.isMember(jss::tx_json))
397  return RPC::missing_field_error(jss::tx_json);
398 
399  Json::Value& tx_json(params[jss::tx_json]);
400 
401  // Check tx_json fields, but don't add any.
402  auto [txJsonResult, srcAddressID] = checkTxJsonFields(
403  tx_json,
404  role,
405  verify,
406  validatedLedgerAge,
407  app.config(),
408  app.getFeeTrack(),
409  getAPIVersionNumber(params, app.config().BETA_RPC_API));
410 
411  if (RPC::contains_error(txJsonResult))
412  return std::move(txJsonResult);
413 
414  // This test covers the case where we're offline so the sequence number
415  // cannot be determined locally. If we're offline then the caller must
416  // provide the sequence number.
417  if (!verify && !tx_json.isMember(jss::Sequence))
418  return RPC::missing_field_error("tx_json.Sequence");
419 
421  if (verify)
422  sle = app.openLedger().current()->read(keylet::account(srcAddressID));
423 
424  if (verify && !sle)
425  {
426  // If not offline and did not find account, error.
427  JLOG(j.debug()) << "transactionSign: Failed to find source account "
428  << "in current ledger: " << toBase58(srcAddressID);
429 
431  }
432 
433  {
434  Json::Value err = checkFee(
435  params,
436  role,
437  verify && signingArgs.editFields(),
438  app.config(),
439  app.getFeeTrack(),
440  app.getTxQ(),
441  app);
442 
443  if (RPC::contains_error(err))
444  return err;
445 
446  err = checkPayment(
447  params,
448  tx_json,
449  srcAddressID,
450  role,
451  app,
452  verify && signingArgs.editFields());
453 
454  if (RPC::contains_error(err))
455  return err;
456  }
457 
458  if (signingArgs.editFields())
459  {
460  if (!tx_json.isMember(jss::Sequence))
461  {
462  bool const hasTicketSeq =
464  if (!hasTicketSeq && !sle)
465  {
466  JLOG(j.debug())
467  << "transactionSign: Failed to find source account "
468  << "in current ledger: " << toBase58(srcAddressID);
469 
471  }
472  tx_json[jss::Sequence] =
473  hasTicketSeq ? 0 : app.getTxQ().nextQueuableSeq(sle).value();
474  }
475 
476  if (!tx_json.isMember(jss::Flags))
477  tx_json[jss::Flags] = tfFullyCanonicalSig;
478  }
479 
480  // If multisigning there should not be a single signature and vice versa.
481  if (signingArgs.isMultiSigning())
482  {
483  if (tx_json.isMember(sfTxnSignature.jsonName))
485 
486  // If multisigning then we need to return the public key.
487  signingArgs.setPublicKey(pk);
488  }
489  else if (signingArgs.isSingleSigning())
490  {
491  if (tx_json.isMember(sfSigners.jsonName))
493  }
494 
495  if (verify)
496  {
497  if (!sle)
498  // XXX Ignore transactions for accounts not created.
500 
501  JLOG(j.trace()) << "verify: " << toBase58(calcAccountID(pk)) << " : "
502  << toBase58(srcAddressID);
503 
504  // Don't do this test if multisigning since the account and secret
505  // probably don't belong together in that case.
506  if (!signingArgs.isMultiSigning())
507  {
508  // Make sure the account and secret belong together.
509  auto const err = acctMatchesPubKey(sle, srcAddressID, pk);
510 
511  if (err != rpcSUCCESS)
512  return rpcError(err);
513  }
514  }
515 
516  STParsedJSONObject parsed(std::string(jss::tx_json), tx_json);
517  if (!parsed.object.has_value())
518  {
519  Json::Value err;
520  err[jss::error] = parsed.error[jss::error];
521  err[jss::error_code] = parsed.error[jss::error_code];
522  err[jss::error_message] = parsed.error[jss::error_message];
523  return err;
524  }
525 
526  std::shared_ptr<STTx> stpTrans;
527  try
528  {
529  // If we're generating a multi-signature the SigningPubKey must be
530  // empty, otherwise it must be the master account's public key.
531  parsed.object->setFieldVL(
533  signingArgs.isMultiSigning() ? Slice(nullptr, 0) : pk.slice());
534 
535  stpTrans = std::make_shared<STTx>(std::move(parsed.object.value()));
536  }
537  catch (STObject::FieldErr& err)
538  {
539  return RPC::make_error(rpcINVALID_PARAMS, err.what());
540  }
541  catch (std::exception&)
542  {
543  return RPC::make_error(
544  rpcINTERNAL,
545  "Exception occurred constructing serialized transaction");
546  }
547 
548  std::string reason;
549  if (!passesLocalChecks(*stpTrans, reason))
550  return RPC::make_error(rpcINVALID_PARAMS, reason);
551 
552  // If multisign then return multiSignature, else set TxnSignature field.
553  if (signingArgs.isMultiSigning())
554  {
555  Serializer s =
556  buildMultiSigningData(*stpTrans, signingArgs.getSigner());
557 
558  auto multisig = ripple::sign(pk, sk, s.slice());
559 
560  signingArgs.moveMultiSignature(std::move(multisig));
561  }
562  else if (signingArgs.isSingleSigning())
563  {
564  stpTrans->sign(pk, sk);
565  }
566 
567  return transactionPreProcessResult{std::move(stpTrans)};
568 }
569 
572  std::shared_ptr<STTx const> const& stpTrans,
573  Rules const& rules,
574  Application& app)
575 {
577 
578  // Turn the passed in STTx into a Transaction.
579  Transaction::pointer tpTrans;
580  {
581  std::string reason;
582  tpTrans = std::make_shared<Transaction>(stpTrans, reason, app);
583  if (tpTrans->getStatus() != NEW)
584  {
585  ret.first = RPC::make_error(
586  rpcINTERNAL, "Unable to construct transaction: " + reason);
587  return ret;
588  }
589  }
590  try
591  {
592  // Make sure the Transaction we just built is legit by serializing it
593  // and then de-serializing it. If the result isn't equivalent
594  // to the initial transaction then there's something wrong with the
595  // passed-in STTx.
596  {
597  Serializer s;
598  tpTrans->getSTransaction()->add(s);
599  Blob transBlob = s.getData();
600  SerialIter sit{makeSlice(transBlob)};
601 
602  // Check the signature if that's called for.
603  auto sttxNew = std::make_shared<STTx const>(sit);
604  if (!app.checkSigs())
606  app.getHashRouter(),
607  sttxNew->getTransactionID(),
609  if (checkValidity(
610  app.getHashRouter(), *sttxNew, rules, app.config())
611  .first != Validity::Valid)
612  {
613  ret.first = RPC::make_error(rpcINTERNAL, "Invalid signature.");
614  return ret;
615  }
616 
617  std::string reason;
618  auto tpTransNew =
619  std::make_shared<Transaction>(sttxNew, reason, app);
620 
621  if (tpTransNew)
622  {
623  if (!tpTransNew->getSTransaction()->isEquivalent(
624  *tpTrans->getSTransaction()))
625  {
626  tpTransNew.reset();
627  }
628  tpTrans = std::move(tpTransNew);
629  }
630  }
631  }
632  catch (std::exception&)
633  {
634  // Assume that any exceptions are related to transaction sterilization.
635  tpTrans.reset();
636  }
637 
638  if (!tpTrans)
639  {
640  ret.first =
641  RPC::make_error(rpcINTERNAL, "Unable to sterilize transaction.");
642  return ret;
643  }
644  ret.second = std::move(tpTrans);
645  return ret;
646 }
647 
648 static Json::Value
650 {
651  Json::Value jvResult;
652  try
653  {
654  if (apiVersion > 1)
655  {
656  jvResult[jss::tx_json] =
657  tpTrans->getJson(JsonOptions::disable_API_prior_V2);
658  jvResult[jss::hash] = to_string(tpTrans->getID());
659  }
660  else
661  jvResult[jss::tx_json] = tpTrans->getJson(JsonOptions::none);
662 
664  jvResult[jss::tx_json],
665  tpTrans->getSTransaction()->getTxnType(),
666  apiVersion);
667 
668  jvResult[jss::tx_blob] =
669  strHex(tpTrans->getSTransaction()->getSerializer().peekData());
670 
671  if (temUNCERTAIN != tpTrans->getResult())
672  {
673  std::string sToken;
674  std::string sHuman;
675 
676  transResultInfo(tpTrans->getResult(), sToken, sHuman);
677 
678  jvResult[jss::engine_result] = sToken;
679  jvResult[jss::engine_result_code] = tpTrans->getResult();
680  jvResult[jss::engine_result_message] = sHuman;
681  }
682  }
683  catch (std::exception&)
684  {
685  jvResult = RPC::make_error(
686  rpcINTERNAL, "Exception occurred during JSON handling.");
687  }
688  return jvResult;
689 }
690 
691 } // namespace detail
692 
693 //------------------------------------------------------------------------------
694 
697  Json::Value& request,
698  Role const role,
699  bool doAutoFill,
700  Config const& config,
701  LoadFeeTrack const& feeTrack,
702  TxQ const& txQ,
703  Application const& app)
704 {
705  Json::Value& tx(request[jss::tx_json]);
706  if (tx.isMember(jss::Fee))
707  return Json::Value();
708 
709  if (!doAutoFill)
710  return RPC::missing_field_error("tx_json.Fee");
711 
714  if (request.isMember(jss::fee_mult_max))
715  {
716  if (request[jss::fee_mult_max].isInt())
717  {
718  mult = request[jss::fee_mult_max].asInt();
719  if (mult < 0)
720  return RPC::make_error(
723  jss::fee_mult_max, "a positive integer"));
724  }
725  else
726  {
727  return RPC::make_error(
728  rpcHIGH_FEE,
730  jss::fee_mult_max, "a positive integer"));
731  }
732  }
733  if (request.isMember(jss::fee_div_max))
734  {
735  if (request[jss::fee_div_max].isInt())
736  {
737  div = request[jss::fee_div_max].asInt();
738  if (div <= 0)
739  return RPC::make_error(
742  jss::fee_div_max, "a positive integer"));
743  }
744  else
745  {
746  return RPC::make_error(
747  rpcHIGH_FEE,
749  jss::fee_div_max, "a positive integer"));
750  }
751  }
752 
753  XRPAmount const feeDefault = config.FEES.reference_fee;
754 
755  auto ledger = app.openLedger().current();
756  // Administrative and identified endpoints are exempt from local fees.
757  XRPAmount const loadFee =
758  scaleFeeLoad(feeDefault, feeTrack, ledger->fees(), isUnlimited(role));
759  XRPAmount fee = loadFee;
760  {
761  auto const metrics = txQ.getMetrics(*ledger);
762  auto const baseFee = ledger->fees().base;
763  auto escalatedFee =
764  toDrops(metrics.openLedgerFeeLevel - FeeLevel64(1), baseFee) + 1;
765  fee = std::max(fee, escalatedFee);
766  }
767 
768  auto const limit = [&]() {
769  // Scale fee units to drops:
770  auto const result = mulDiv(feeDefault, mult, div);
771  if (!result)
772  Throw<std::overflow_error>("mulDiv");
773  return *result;
774  }();
775 
776  if (fee > limit)
777  {
779  ss << "Fee of " << fee << " exceeds the requested tx limit of "
780  << limit;
781  return RPC::make_error(rpcHIGH_FEE, ss.str());
782  }
783 
784  tx[jss::Fee] = fee.jsonClipped();
785  return Json::Value();
786 }
787 
788 //------------------------------------------------------------------------------
789 
793  Json::Value jvRequest,
794  unsigned apiVersion,
795  NetworkOPs::FailHard failType,
796  Role role,
797  std::chrono::seconds validatedLedgerAge,
798  Application& app)
799 {
800  using namespace detail;
801 
802  auto j = app.journal("RPCHandler");
803  JLOG(j.debug()) << "transactionSign: " << jvRequest;
804 
805  // Add and amend fields based on the transaction type.
806  SigningForParams signForParams;
807  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
808  jvRequest, role, signForParams, validatedLedgerAge, app);
809 
810  if (!preprocResult.second)
811  return preprocResult.first;
812 
814  if (app.config().reporting())
815  ledger = app.getLedgerMaster().getValidatedLedger();
816  else
817  ledger = app.openLedger().current();
818  // Make sure the STTx makes a legitimate Transaction.
820  transactionConstructImpl(preprocResult.second, ledger->rules(), app);
821 
822  if (!txn.second)
823  return txn.first;
824 
825  return transactionFormatResultImpl(txn.second, apiVersion);
826 }
827 
831  Json::Value jvRequest,
832  unsigned apiVersion,
833  NetworkOPs::FailHard failType,
834  Role role,
835  std::chrono::seconds validatedLedgerAge,
836  Application& app,
837  ProcessTransactionFn const& processTransaction,
838  RPC::SubmitSync sync)
839 {
840  using namespace detail;
841 
842  auto const& ledger = app.openLedger().current();
843  auto j = app.journal("RPCHandler");
844  JLOG(j.debug()) << "transactionSubmit: " << jvRequest;
845 
846  // Add and amend fields based on the transaction type.
847  SigningForParams signForParams;
848  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
849  jvRequest, role, signForParams, validatedLedgerAge, app);
850 
851  if (!preprocResult.second)
852  return preprocResult.first;
853 
854  // Make sure the STTx makes a legitimate Transaction.
856  transactionConstructImpl(preprocResult.second, ledger->rules(), app);
857 
858  if (!txn.second)
859  return txn.first;
860 
861  // Finally, submit the transaction.
862  try
863  {
864  processTransaction(txn.second, isUnlimited(role), sync, failType);
865  }
866  catch (std::exception&)
867  {
868  return RPC::make_error(
869  rpcINTERNAL, "Exception occurred during transaction submission.");
870  }
871 
872  return transactionFormatResultImpl(txn.second, apiVersion);
873 }
874 
875 namespace detail {
876 // There are a some field checks shared by transactionSignFor
877 // and transactionSubmitMultiSigned. Gather them together here.
878 static Json::Value
880 {
881  if (!jvRequest.isMember(jss::tx_json))
882  return RPC::missing_field_error(jss::tx_json);
883 
884  Json::Value const& tx_json(jvRequest[jss::tx_json]);
885 
886  if (!tx_json.isObject())
887  return RPC::invalid_field_message(jss::tx_json);
888 
889  // There are a couple of additional fields we need to check before
890  // we serialize. If we serialize first then we generate less useful
891  // error messages.
892  if (!tx_json.isMember(jss::Sequence))
893  return RPC::missing_field_error("tx_json.Sequence");
894 
895  if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
896  return RPC::missing_field_error("tx_json.SigningPubKey");
897 
898  if (!tx_json[sfSigningPubKey.getJsonName()].asString().empty())
899  return RPC::make_error(
901  "When multi-signing 'tx_json.SigningPubKey' must be empty.");
902 
903  return Json::Value();
904 }
905 
906 // Sort and validate an stSigners array.
907 //
908 // Returns a null Json::Value if there are no errors.
909 static Json::Value
910 sortAndValidateSigners(STArray& signers, AccountID const& signingForID)
911 {
912  if (signers.empty())
913  return RPC::make_param_error("Signers array may not be empty.");
914 
915  // Signers must be sorted by Account.
916  std::sort(
917  signers.begin(),
918  signers.end(),
919  [](STObject const& a, STObject const& b) {
920  return (a[sfAccount] < b[sfAccount]);
921  });
922 
923  // Signers may not contain any duplicates.
924  auto const dupIter = std::adjacent_find(
925  signers.begin(),
926  signers.end(),
927  [](STObject const& a, STObject const& b) {
928  return (a[sfAccount] == b[sfAccount]);
929  });
930 
931  if (dupIter != signers.end())
932  {
933  std::ostringstream err;
934  err << "Duplicate Signers:Signer:Account entries ("
935  << toBase58((*dupIter)[sfAccount]) << ") are not allowed.";
936  return RPC::make_param_error(err.str());
937  }
938 
939  // An account may not sign for itself.
940  if (signers.end() !=
941  std::find_if(
942  signers.begin(),
943  signers.end(),
944  [&signingForID](STObject const& elem) {
945  return elem[sfAccount] == signingForID;
946  }))
947  {
948  std::ostringstream err;
949  err << "A Signer may not be the transaction's Account ("
950  << toBase58(signingForID) << ").";
951  return RPC::make_param_error(err.str());
952  }
953  return {};
954 }
955 
956 } // namespace detail
957 
961  Json::Value jvRequest,
962  unsigned apiVersion,
963  NetworkOPs::FailHard failType,
964  Role role,
965  std::chrono::seconds validatedLedgerAge,
966  Application& app)
967 {
968  auto const& ledger = app.openLedger().current();
969  auto j = app.journal("RPCHandler");
970  JLOG(j.debug()) << "transactionSignFor: " << jvRequest;
971 
972  // Verify presence of the signer's account field.
973  const char accountField[] = "account";
974 
975  if (!jvRequest.isMember(accountField))
976  return RPC::missing_field_error(accountField);
977 
978  // Turn the signer's account into an AccountID for multi-sign.
979  auto const signerAccountID =
980  parseBase58<AccountID>(jvRequest[accountField].asString());
981  if (!signerAccountID)
982  {
983  return RPC::make_error(
985  }
986 
987  if (!jvRequest.isMember(jss::tx_json))
988  return RPC::missing_field_error(jss::tx_json);
989 
990  {
991  Json::Value& tx_json(jvRequest[jss::tx_json]);
992 
993  if (!tx_json.isObject())
994  return RPC::object_field_error(jss::tx_json);
995 
996  // If the tx_json.SigningPubKey field is missing,
997  // insert an empty one.
998  if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
999  tx_json[sfSigningPubKey.getJsonName()] = "";
1000  }
1001 
1002  // When multi-signing, the "Sequence" and "SigningPubKey" fields must
1003  // be passed in by the caller.
1004  using namespace detail;
1005  {
1006  Json::Value err = checkMultiSignFields(jvRequest);
1007  if (RPC::contains_error(err))
1008  return err;
1009  }
1010 
1011  // Add and amend fields based on the transaction type.
1012  Buffer multiSignature;
1013  PublicKey multiSignPubKey;
1014  SigningForParams signForParams(
1015  *signerAccountID, multiSignPubKey, multiSignature);
1016 
1017  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
1018  jvRequest, role, signForParams, validatedLedgerAge, app);
1019 
1020  if (!preprocResult.second)
1021  return preprocResult.first;
1022 
1023  {
1024  std::shared_ptr<SLE const> account_state =
1025  ledger->read(keylet::account(*signerAccountID));
1026  // Make sure the account and secret belong together.
1027  auto const err =
1028  acctMatchesPubKey(account_state, *signerAccountID, multiSignPubKey);
1029 
1030  if (err != rpcSUCCESS)
1031  return rpcError(err);
1032  }
1033 
1034  // Inject the newly generated signature into tx_json.Signers.
1035  auto& sttx = preprocResult.second;
1036  {
1037  // Make the signer object that we'll inject.
1038  STObject signer(sfSigner);
1039  signer[sfAccount] = *signerAccountID;
1040  signer.setFieldVL(sfTxnSignature, multiSignature);
1041  signer.setFieldVL(sfSigningPubKey, multiSignPubKey.slice());
1042 
1043  // If there is not yet a Signers array, make one.
1044  if (!sttx->isFieldPresent(sfSigners))
1045  sttx->setFieldArray(sfSigners, {});
1046 
1047  auto& signers = sttx->peekFieldArray(sfSigners);
1048  signers.emplace_back(std::move(signer));
1049 
1050  // The array must be sorted and validated.
1051  auto err = sortAndValidateSigners(signers, (*sttx)[sfAccount]);
1052  if (RPC::contains_error(err))
1053  return err;
1054  }
1055 
1056  // Make sure the STTx makes a legitimate Transaction.
1058  transactionConstructImpl(sttx, ledger->rules(), app);
1059 
1060  if (!txn.second)
1061  return txn.first;
1062 
1063  return transactionFormatResultImpl(txn.second, apiVersion);
1064 }
1065 
1069  Json::Value jvRequest,
1070  unsigned apiVersion,
1071  NetworkOPs::FailHard failType,
1072  Role role,
1073  std::chrono::seconds validatedLedgerAge,
1074  Application& app,
1075  ProcessTransactionFn const& processTransaction,
1076  RPC::SubmitSync sync)
1077 {
1078  auto const& ledger = app.openLedger().current();
1079  auto j = app.journal("RPCHandler");
1080  JLOG(j.debug()) << "transactionSubmitMultiSigned: " << jvRequest;
1081 
1082  // When multi-signing, the "Sequence" and "SigningPubKey" fields must
1083  // be passed in by the caller.
1084  using namespace detail;
1085  {
1086  Json::Value err = checkMultiSignFields(jvRequest);
1087  if (RPC::contains_error(err))
1088  return err;
1089  }
1090 
1091  Json::Value& tx_json(jvRequest["tx_json"]);
1092 
1093  auto [txJsonResult, srcAddressID] = checkTxJsonFields(
1094  tx_json,
1095  role,
1096  true,
1097  validatedLedgerAge,
1098  app.config(),
1099  app.getFeeTrack(),
1100  getAPIVersionNumber(jvRequest, app.config().BETA_RPC_API));
1101 
1102  if (RPC::contains_error(txJsonResult))
1103  return std::move(txJsonResult);
1104 
1106  ledger->read(keylet::account(srcAddressID));
1107 
1108  if (!sle)
1109  {
1110  // If did not find account, error.
1111  JLOG(j.debug())
1112  << "transactionSubmitMultiSigned: Failed to find source account "
1113  << "in current ledger: " << toBase58(srcAddressID);
1114 
1116  }
1117 
1118  {
1119  Json::Value err = checkFee(
1120  jvRequest,
1121  role,
1122  false,
1123  app.config(),
1124  app.getFeeTrack(),
1125  app.getTxQ(),
1126  app);
1127 
1128  if (RPC::contains_error(err))
1129  return err;
1130 
1131  err = checkPayment(jvRequest, tx_json, srcAddressID, role, app, false);
1132 
1133  if (RPC::contains_error(err))
1134  return err;
1135  }
1136 
1137  // Grind through the JSON in tx_json to produce a STTx.
1138  std::shared_ptr<STTx> stpTrans;
1139  {
1140  STParsedJSONObject parsedTx_json("tx_json", tx_json);
1141  if (!parsedTx_json.object)
1142  {
1143  Json::Value jvResult;
1144  jvResult["error"] = parsedTx_json.error["error"];
1145  jvResult["error_code"] = parsedTx_json.error["error_code"];
1146  jvResult["error_message"] = parsedTx_json.error["error_message"];
1147  return jvResult;
1148  }
1149  try
1150  {
1151  stpTrans =
1152  std::make_shared<STTx>(std::move(parsedTx_json.object.value()));
1153  }
1154  catch (STObject::FieldErr& err)
1155  {
1156  return RPC::make_error(rpcINVALID_PARAMS, err.what());
1157  }
1158  catch (std::exception& ex)
1159  {
1160  std::string reason(ex.what());
1161  return RPC::make_error(
1162  rpcINTERNAL,
1163  "Exception while serializing transaction: " + reason);
1164  }
1165  std::string reason;
1166  if (!passesLocalChecks(*stpTrans, reason))
1167  return RPC::make_error(rpcINVALID_PARAMS, reason);
1168  }
1169 
1170  // Validate the fields in the serialized transaction.
1171  {
1172  // We now have the transaction text serialized and in the right format.
1173  // Verify the values of select fields.
1174  //
1175  // The SigningPubKey must be present but empty.
1176  if (!stpTrans->getFieldVL(sfSigningPubKey).empty())
1177  {
1178  std::ostringstream err;
1179  err << "Invalid " << sfSigningPubKey.fieldName
1180  << " field. Field must be empty when multi-signing.";
1181  return RPC::make_error(rpcINVALID_PARAMS, err.str());
1182  }
1183 
1184  // There may not be a TxnSignature field.
1185  if (stpTrans->isFieldPresent(sfTxnSignature))
1187 
1188  // The Fee field must be in XRP and greater than zero.
1189  auto const fee = stpTrans->getFieldAmount(sfFee);
1190 
1191  if (!isLegalNet(fee))
1192  {
1193  std::ostringstream err;
1194  err << "Invalid " << sfFee.fieldName
1195  << " field. Fees must be specified in XRP.";
1196  return RPC::make_error(rpcINVALID_PARAMS, err.str());
1197  }
1198  if (fee <= STAmount{0})
1199  {
1200  std::ostringstream err;
1201  err << "Invalid " << sfFee.fieldName
1202  << " field. Fees must be greater than zero.";
1203  return RPC::make_error(rpcINVALID_PARAMS, err.str());
1204  }
1205  }
1206 
1207  // Verify that the Signers field is present.
1208  if (!stpTrans->isFieldPresent(sfSigners))
1209  return RPC::missing_field_error("tx_json.Signers");
1210 
1211  // If the Signers field is present the SField guarantees it to be an array.
1212  // Get a reference to the Signers array so we can verify and sort it.
1213  auto& signers = stpTrans->peekFieldArray(sfSigners);
1214 
1215  if (signers.empty())
1216  return RPC::make_param_error("tx_json.Signers array may not be empty.");
1217 
1218  // The Signers array may only contain Signer objects.
1219  if (std::find_if_not(
1220  signers.begin(), signers.end(), [](STObject const& obj) {
1221  return (
1222  // A Signer object always contains these fields and no
1223  // others.
1224  obj.isFieldPresent(sfAccount) &&
1225  obj.isFieldPresent(sfSigningPubKey) &&
1226  obj.isFieldPresent(sfTxnSignature) && obj.getCount() == 3);
1227  }) != signers.end())
1228  {
1229  return RPC::make_param_error(
1230  "Signers array may only contain Signer entries.");
1231  }
1232 
1233  // The array must be sorted and validated.
1234  auto err = sortAndValidateSigners(signers, srcAddressID);
1235  if (RPC::contains_error(err))
1236  return err;
1237 
1238  // Make sure the SerializedTransaction makes a legitimate Transaction.
1240  transactionConstructImpl(stpTrans, ledger->rules(), app);
1241 
1242  if (!txn.second)
1243  return txn.first;
1244 
1245  // Finally, submit the transaction.
1246  try
1247  {
1248  // FIXME: For performance, should use asynch interface
1249  processTransaction(txn.second, isUnlimited(role), sync, failType);
1250  }
1251  catch (std::exception&)
1252  {
1253  return RPC::make_error(
1254  rpcINTERNAL, "Exception occurred during transaction submission.");
1255  }
1256 
1257  return transactionFormatResultImpl(txn.second, apiVersion);
1258 }
1259 
1260 } // namespace RPC
1261 } // namespace ripple
ripple::JsonOptions::disable_API_prior_V2
@ disable_API_prior_V2
Definition: STBase.h:44
ripple::RPC::detail::SigningForParams::multiSigningAcctID_
AccountID const *const multiSigningAcctID_
Definition: TransactionSign.cpp:55
ripple::FeeSetup::reference_fee
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition: Config.h:75
ripple::Application
Definition: Application.h:116
ripple::Application::checkSigs
virtual bool checkSigs() const =0
ripple::amountFromJsonNoThrow
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1032
ripple::RPC::SubmitSync
SubmitSync
Possible values for defining synchronous behavior of the transaction submission API.
Definition: SubmitSync.h:36
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:241
ripple::RPC::detail::transactionPreProcessResult::operator=
transactionPreProcessResult & operator=(transactionPreProcessResult const &)=delete
ripple::mulDiv
std::optional< Dest > mulDiv(Source1 value, Dest mul, Source2 div)
Definition: FeeUnits.h:468
ripple::OpenLedger::current
std::shared_ptr< OpenView const > current() const
Returns a view to the current open ledger.
Definition: OpenLedger.cpp:50
ripple::RPC::detail::SigningForParams::SigningForParams
SigningForParams()
Definition: TransactionSign.cpp:60
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
std::string
STL class.
std::shared_ptr
STL class.
ripple::sfSigners
const SField sfSigners
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
std::exception
STL class.
ripple::RPC::insertDeliverMax
void insertDeliverMax(Json::Value &tx_json, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
Definition: DeliverMax.cpp:28
ripple::lsfDisableMaster
@ lsfDisableMaster
Definition: LedgerFormats.h:260
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:350
ripple::RPC::missing_field_message
std::string missing_field_message(std::string const &name)
Definition: ErrorCodes.h:258
ripple::Pathfinder
Calculates payment paths.
Definition: Pathfinder.h:38
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
ripple::rpcSRC_ACT_NOT_FOUND
@ rpcSRC_ACT_NOT_FOUND
Definition: ErrorCodes.h:122
std::pair
ripple::RPC::detail::SigningForParams::editFields
bool editFields() const
Definition: TransactionSign.cpp:95
ripple::sfRegularKey
const SF_ACCOUNT sfRegularKey
ripple::RPC::detail::SigningForParams::multiSignPublicKey_
PublicKey *const multiSignPublicKey_
Definition: TransactionSign.cpp:56
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical) noexcept
Verify a signature on a message.
Definition: PublicKey.cpp:272
ripple::Pathfinder::computePathRanks
void computePathRanks(int maxPaths, std::function< bool(void)> const &continueCallback={})
Compute the rankings of the paths.
Definition: Pathfinder.cpp:411
ripple::RPC::getAPIVersionNumber
unsigned int getAPIVersionNumber(Json::Value const &jv, bool betaEnabled)
Retrieve the api version number from the json value.
Definition: RPCHelpers.cpp:992
std::vector< unsigned char >
std::find_if
T find_if(T... args)
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:159
ripple::sfSigningPubKey
const SF_VL sfSigningPubKey
ripple::rpcSIGNING_MALFORMED
@ rpcSIGNING_MALFORMED
Definition: ErrorCodes.h:118
ripple::RPC::detail::transactionPreProcessResult::second
const std::shared_ptr< STTx > second
Definition: TransactionSign.cpp:356
std::chrono::seconds
iterator
ripple::NEW
@ NEW
Definition: Transaction.h:47
ripple::Issue::currency
Currency currency
Definition: Issue.h:38
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::tfFullyCanonicalSig
constexpr std::uint32_t tfFullyCanonicalSig
Transaction flags.
Definition: TxFlags.h:58
ripple::RPC::detail::transactionPreProcessResult::first
const Json::Value first
Definition: TransactionSign.cpp:355
std::stringstream
STL class.
ripple::RPC::detail::checkPayment
static Json::Value checkPayment(Json::Value const &params, Json::Value &tx_json, AccountID const &srcAddressID, Role const role, Application &app, bool doPath)
Definition: TransactionSign.cpp:159
ripple::PublicKey::slice
Slice slice() const noexcept
Definition: PublicKey.h:125
ripple::rpcTOO_BUSY
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
ripple::Buffer
Like std::vector<char> but better.
Definition: Buffer.h:35
ripple::STParsedJSONObject
Holds the serialized result of parsing an input JSON object.
Definition: STParsedJSON.h:31
ripple::sfTicketSequence
const SF_UINT32 sfTicketSequence
ripple::isLegalNet
bool isLegalNet(STAmount const &value)
Definition: STAmount.h:449
ripple::Pathfinder::findPaths
bool findPaths(int searchLevel, std::function< bool(void)> const &continueCallback={})
Definition: Pathfinder.cpp:195
std::function
ripple::STObject::setFieldVL
void setFieldVL(SField const &field, Blob const &)
Definition: STObject.cpp:695
ripple::STAmount::setIssuer
void setIssuer(AccountID const &uIssuer)
Definition: STAmount.h:436
ripple::SField::getJsonName
Json::StaticString const & getJsonName() const
Definition: SField.h:214
ripple::Application::openLedger
virtual OpenLedger & openLedger()=0
ripple::STParsedJSONObject::object
std::optional< STObject > object
The STObject if the parse was successful.
Definition: STParsedJSON.h:50
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:163
std::sort
T sort(T... args)
ripple::RPC::detail::transactionConstructImpl
static std::pair< Json::Value, Transaction::pointer > transactionConstructImpl(std::shared_ptr< STTx const > const &stpTrans, Rules const &rules, Application &app)
Definition: TransactionSign.cpp:571
std::shared_ptr::reset
T reset(T... args)
ripple::STPathSet
Definition: STPathSet.h:176
ripple::RPC::object_field_error
Json::Value object_field_error(std::string const &name)
Definition: ErrorCodes.h:282
algorithm
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1068
ripple::forceValidity
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
Definition: apply.cpp:89
ripple::STPathSet::empty
bool empty() const
Definition: STPathSet.h:503
ripple::RPC::detail::transactionPreProcessResult::transactionPreProcessResult
transactionPreProcessResult(std::shared_ptr< STTx > &&st)
Definition: TransactionSign.cpp:372
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::STParsedJSONObject::error
Json::Value error
On failure, an appropriate set of error values.
Definition: STParsedJSON.h:53
ripple::RPC::detail::SigningForParams::setPublicKey
void setPublicKey(PublicKey const &multiSignPublicKey)
Definition: TransactionSign.cpp:108
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::temUNCERTAIN
@ temUNCERTAIN
Definition: TER.h:122
ripple::Validity::SigGoodOnly
@ SigGoodOnly
Signature is good, but local checks fail.
ripple::RPC::detail::acctMatchesPubKey
static error_code_i acctMatchesPubKey(std::shared_ptr< SLE const > accountState, AccountID const &accountID, PublicKey const &publicKey)
Definition: TransactionSign.cpp:123
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:264
ripple::RPC::detail::SigningForParams::getSigner
AccountID const & getSigner()
Definition: TransactionSign.cpp:102
ripple::RPC::checkFee
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Definition: TransactionSign.cpp:696
ripple::base_uint< 160, detail::AccountIDTag >
ripple::RPC::keypairForSignature
std::pair< PublicKey, SecretKey > keypairForSignature(Json::Value const &params, Json::Value &error, unsigned int apiVersion)
Definition: RPCHelpers.cpp:796
ripple::RPC::expected_field_message
std::string expected_field_message(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:318
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
ripple::STObject::FieldErr
Definition: STObject.h:647
ripple::Config::reporting
bool reporting() const
Definition: Config.h:351
ripple::RPC::detail::transactionPreProcessImpl
static transactionPreProcessResult transactionPreProcessImpl(Json::Value &params, Role role, SigningForParams &signingArgs, std::chrono::seconds validatedLedgerAge, Application &app)
Definition: TransactionSign.cpp:379
ripple::TxQ
Transaction Queue.
Definition: TxQ.h:57
ripple::checkValidity
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
Definition: apply.cpp:37
ripple::passesLocalChecks
bool passesLocalChecks(STObject const &st, std::string &reason)
Definition: STTx.cpp:547
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:196
ripple::RPC::detail::checkTxJsonFields
static std::pair< Json::Value, AccountID > checkTxJsonFields(Json::Value const &tx_json, Role const role, bool const verify, std::chrono::seconds validatedLedgerAge, Config const &config, LoadFeeTrack const &feeTrack, unsigned apiVersion)
Definition: TransactionSign.cpp:285
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::PublicKey
A public key.
Definition: PublicKey.h:61
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:142
ripple::Config
Definition: Config.h:92
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:830
ripple::rpcSRC_ACT_MISSING
@ rpcSRC_ACT_MISSING
Definition: ErrorCodes.h:121
ripple::Application::config
virtual Config & config()=0
ripple::rpcALREADY_SINGLE_SIG
@ rpcALREADY_SINGLE_SIG
Definition: ErrorCodes.h:92
ripple::RPC::detail::sortAndValidateSigners
static Json::Value sortAndValidateSigners(STArray &signers, AccountID const &signingForID)
Definition: TransactionSign.cpp:910
ripple::Config::standalone
bool standalone() const
Definition: Config.h:346
ripple::rpcHIGH_FEE
@ rpcHIGH_FEE
Definition: ErrorCodes.h:58
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:158
ripple::STArray
Definition: STArray.h:28
ripple::Application::getTxQ
virtual TxQ & getTxQ()=0
ripple::LoadFeeTrack
Manages the current fee schedule.
Definition: LoadFeeTrack.h:44
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:792
ripple::STAmount
Definition: STAmount.h:46
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:64
ripple::Config::BETA_RPC_API
bool BETA_RPC_API
Definition: Config.h:299
ripple::TxQ::nextQueuableSeq
SeqProxy nextQueuableSeq(std::shared_ptr< SLE const > const &sleAccount) const
Return the next sequence that would go in the TxQ for an account.
Definition: TxQ.cpp:1587
ripple::RPC::detail::transactionPreProcessResult
Definition: TransactionSign.cpp:353
ripple::SerialIter
Definition: Serializer.h:311
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::rpcNO_CURRENT
@ rpcNO_CURRENT
Definition: ErrorCodes.h:65
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:960
ripple::feeunit::TaggedFee
Definition: FeeUnits.h:70
ripple::rpcALREADY_MULTISIG
@ rpcALREADY_MULTISIG
Definition: ErrorCodes.h:91
ripple::RPC::SubmitSync::sync
@ sync
ripple::NetworkOPs::FailHard
FailHard
Definition: NetworkOPs.h:95
ripple::sfSigner
const SField sfSigner
ripple::Config::PATH_SEARCH_OLD
int PATH_SEARCH_OLD
Definition: Config.h:205
ripple::RPC::detail::transactionFormatResultImpl
static Json::Value transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion)
Definition: TransactionSign.cpp:649
ripple::rpcINTERNAL
@ rpcINTERNAL
Definition: ErrorCodes.h:130
ripple::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:124
ripple::Serializer
Definition: Serializer.h:40
std::ostringstream
STL class.
ripple::Pathfinder::getBestPaths
STPathSet getBestPaths(int maxPaths, STPath &fullLiquidityPath, STPathSet const &extraPaths, AccountID const &srcIssuer, std::function< bool(void)> const &continueCallback={})
Definition: Pathfinder.cpp:567
ripple::RPC::detail::transactionPreProcessResult::transactionPreProcessResult
transactionPreProcessResult(Json::Value &&json)
Definition: TransactionSign.cpp:367
ripple::RPC::invalid_field_message
std::string invalid_field_message(std::string const &name)
Definition: ErrorCodes.h:294
ripple::STObject
Definition: STObject.h:53
ripple::sfTxnSignature
const SF_VL sfTxnSignature
ripple::SeqProxy::value
constexpr std::uint32_t value() const
Definition: SeqProxy.h:82
ripple::rpcSRC_ACT_MALFORMED
@ rpcSRC_ACT_MALFORMED
Definition: ErrorCodes.h:120
ripple::STAmount::native
bool native() const noexcept
Definition: STAmount.h:332
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::transResultInfo
bool transResultInfo(TER code, std::string &token, std::string &text)
Definition: TER.cpp:226
ripple::RPC::LegacyPathFind::isOk
bool isOk() const
Definition: LegacyPathFind.h:38
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::JsonOptions::none
@ none
Definition: STBase.h:42
Json::Value::removeMember
Value removeMember(const char *key)
Remove and return the named member.
Definition: json_value.cpp:907
ripple::Validity::Valid
@ Valid
Signature and local checks are good / passed.
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:238
ripple::RPC::detail::SigningForParams::multiSignature_
Buffer *const multiSignature_
Definition: TransactionSign.cpp:57
ripple::RPC::detail::SigningForParams::moveMultiSignature
void moveMultiSignature(Buffer &&multiSignature)
Definition: TransactionSign.cpp:114
std
STL namespace.
ripple::LoadFeeTrack::isLoadedCluster
bool isLoadedCluster() const
Definition: LoadFeeTrack.h:133
ripple::STPathSet::getJson
Json::Value getJson(JsonOptions) const override
Definition: STPathSet.cpp:193
ripple::RPC::detail::SigningForParams::isSingleSigning
bool isSingleSigning() const
Definition: TransactionSign.cpp:88
std::adjacent_find
T adjacent_find(T... args)
ripple::RPC::detail::SigningForParams::isMultiSigning
bool isMultiSigning() const
Definition: TransactionSign.cpp:80
ripple::LedgerMaster::getValidatedLedger
std::shared_ptr< Ledger const > getValidatedLedger()
Definition: LedgerMaster.cpp:1717
std::string::empty
T empty(T... args)
ripple::Rules
Rules controlling protocol behavior.
Definition: Rules.h:33
ripple::RPC::detail::checkMultiSignFields
static Json::Value checkMultiSignFields(Json::Value const &jvRequest)
Definition: TransactionSign.cpp:879
std::stringstream::str
T str(T... args)
ripple::RPC::detail::SigningForParams::SigningForParams
SigningForParams(AccountID const &multiSigningAcctID, PublicKey &multiSignPublicKey, Buffer &multiSignature)
Definition: TransactionSign.cpp:69
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::scaleFeeLoad
XRPAmount scaleFeeLoad(XRPAmount fee, LoadFeeTrack const &feeTrack, Fees const &fees, bool bUnlimited)
Definition: LoadFeeTrack.cpp:89
ripple::sfFee
const SF_AMOUNT sfFee
ripple::sfAccount
const SF_ACCOUNT sfAccount
Json::Value::asInt
Int asInt() const
Definition: json_value.cpp:503
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::Serializer::getData
Blob getData() const
Definition: Serializer.h:174
std::max
T max(T... args)
ripple::TxQ::getMetrics
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition: TxQ.cpp:1748
ripple::RPC::make_param_error
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
Definition: ErrorCodes.h:252
ripple::RPC::detail::SigningForParams
Definition: TransactionSign.cpp:52
ripple::rpcBAD_SECRET
@ rpcBAD_SECRET
Definition: ErrorCodes.h:98
ripple::RPC::Tuning::defaultAutoFillFeeMultiplier
static constexpr int defaultAutoFillFeeMultiplier
Definition: rpc/impl/Tuning.h:60
ripple::STPath
Definition: STPathSet.h:118
ripple::Config::FEES
FeeSetup FEES
Definition: Config.h:214
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:306
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
ripple::toDrops
XRPAmount toDrops(FeeLevel< T > const &level, XRPAmount baseFee)
Definition: TxQ.h:863
ripple::RPC::Tuning::defaultAutoFillFeeDivisor
static constexpr int defaultAutoFillFeeDivisor
Definition: rpc/impl/Tuning.h:61
ripple::Role
Role
Indicates the level of administrative permission to grant.
Definition: Role.h:43
ripple::rpcMASTER_DISABLED
@ rpcMASTER_DISABLED
Definition: ErrorCodes.h:74
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:180
ripple::RPC::Tuning::maxValidatedLedgerAge
constexpr auto maxValidatedLedgerAge
Definition: rpc/impl/Tuning.h:65
ripple::RPC::LegacyPathFind
Definition: LegacyPathFind.h:31
ripple::XRPAmount::jsonClipped
Json::Value jsonClipped() const
Definition: XRPAmount.h:209
ripple::buildMultiSigningData
Serializer buildMultiSigningData(STObject const &obj, AccountID const &signingID)
Return a Serializer suitable for computing a multisigning TxnSignature.
Definition: Sign.cpp:87
ripple::Issue::account
AccountID account
Definition: Issue.h:39
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::XRPAmount
Definition: XRPAmount.h:46
ripple::RPC::detail::transactionPreProcessResult::transactionPreProcessResult
transactionPreProcessResult()=delete
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469