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