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