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 if (!tx_json.isMember(jss::NetworkID))
472 {
473 auto const networkId = app.config().NETWORK_ID;
474 if (networkId > 1024)
475 tx_json[jss::NetworkID] = to_string(networkId);
476 }
477 }
478
479 {
480 Json::Value err = checkFee(
481 params,
482 role,
483 verify && signingArgs.editFields(),
484 app.config(),
485 app.getFeeTrack(),
486 app.getTxQ(),
487 app);
488
489 if (RPC::contains_error(err))
490 return err;
491 }
492
493 {
495 params,
496 tx_json,
497 srcAddressID,
498 role,
499 app,
500 verify && signingArgs.editFields());
501
502 if (RPC::contains_error(err))
503 return err;
504 }
505
506 // If multisigning there should not be a single signature and vice versa.
507 if (signingArgs.isMultiSigning())
508 {
509 if (tx_json.isMember(jss::TxnSignature))
511
512 // If multisigning then we need to return the public key.
513 signingArgs.setPublicKey(pk);
514 }
515 else if (signingArgs.isSingleSigning())
516 {
517 if (tx_json.isMember(jss::Signers))
519 }
520
521 if (verify)
522 {
523 if (!sle)
524 // XXX Ignore transactions for accounts not created.
526
527 JLOG(j.trace()) << "verify: " << toBase58(calcAccountID(pk)) << " : "
528 << toBase58(srcAddressID);
529
530 // Don't do this test if multisigning since the account and secret
531 // probably don't belong together in that case.
532 if (!signingArgs.isMultiSigning())
533 {
534 // Make sure the account and secret belong together.
535 auto const err = acctMatchesPubKey(sle, srcAddressID, pk);
536
537 if (err != rpcSUCCESS)
538 return rpcError(err);
539 }
540 }
541
542 STParsedJSONObject parsed(std::string(jss::tx_json), tx_json);
543 if (!parsed.object.has_value())
544 {
545 Json::Value err;
546 err[jss::error] = parsed.error[jss::error];
547 err[jss::error_code] = parsed.error[jss::error_code];
548 err[jss::error_message] = parsed.error[jss::error_message];
549 return err;
550 }
551
553 try
554 {
555 // If we're generating a multi-signature the SigningPubKey must be
556 // empty, otherwise it must be the master account's public key.
557 parsed.object->setFieldVL(
558 sfSigningPubKey,
559 signingArgs.isMultiSigning() ? Slice(nullptr, 0) : pk.slice());
560
561 stTx = std::make_shared<STTx>(std::move(parsed.object.value()));
562 }
563 catch (STObject::FieldErr& err)
564 {
566 }
567 catch (std::exception&)
568 {
569 return RPC::make_error(
571 "Exception occurred constructing serialized transaction");
572 }
573
574 std::string reason;
575 if (!passesLocalChecks(*stTx, reason))
576 return RPC::make_error(rpcINVALID_PARAMS, reason);
577
578 // If multisign then return multiSignature, else set TxnSignature field.
579 if (signingArgs.isMultiSigning())
580 {
581 Serializer s = buildMultiSigningData(*stTx, signingArgs.getSigner());
582
583 auto multisig = ripple::sign(pk, sk, s.slice());
584
585 signingArgs.moveMultiSignature(std::move(multisig));
586 }
587 else if (signingArgs.isSingleSigning())
588 {
589 stTx->sign(pk, sk);
590 }
591
592 return transactionPreProcessResult{std::move(stTx)};
593}
594
597 std::shared_ptr<STTx const> const& stTx,
598 Rules const& rules,
599 Application& app)
600{
602
603 // Turn the passed in STTx into a Transaction.
604 Transaction::pointer tpTrans;
605 {
606 std::string reason;
607 tpTrans = std::make_shared<Transaction>(stTx, reason, app);
608 if (tpTrans->getStatus() != NEW)
609 {
611 rpcINTERNAL, "Unable to construct transaction: " + reason);
612 return ret;
613 }
614 }
615 try
616 {
617 // Make sure the Transaction we just built is legit by serializing it
618 // and then de-serializing it. If the result isn't equivalent
619 // to the initial transaction then there's something wrong with the
620 // passed-in STTx.
621 {
622 Serializer s;
623 tpTrans->getSTransaction()->add(s);
624 Blob transBlob = s.getData();
625 SerialIter sit{makeSlice(transBlob)};
626
627 // Check the signature if that's called for.
628 auto sttxNew = std::make_shared<STTx const>(sit);
629 if (!app.checkSigs())
631 app.getHashRouter(),
632 sttxNew->getTransactionID(),
634 if (checkValidity(
635 app.getHashRouter(), *sttxNew, rules, app.config())
636 .first != Validity::Valid)
637 {
638 ret.first = RPC::make_error(rpcINTERNAL, "Invalid signature.");
639 return ret;
640 }
641
642 std::string reason;
643 auto tpTransNew =
644 std::make_shared<Transaction>(sttxNew, reason, app);
645
646 if (tpTransNew)
647 {
648 if (!tpTransNew->getSTransaction()->isEquivalent(
649 *tpTrans->getSTransaction()))
650 {
651 tpTransNew.reset();
652 }
653 tpTrans = std::move(tpTransNew);
654 }
655 }
656 }
657 catch (std::exception&)
658 {
659 // Assume that any exceptions are related to transaction sterilization.
660 tpTrans.reset();
661 }
662
663 if (!tpTrans)
664 {
665 ret.first =
666 RPC::make_error(rpcINTERNAL, "Unable to sterilize transaction.");
667 return ret;
668 }
669 ret.second = std::move(tpTrans);
670 return ret;
671}
672
673static Json::Value
675{
676 Json::Value jvResult;
677 try
678 {
679 if (apiVersion > 1)
680 {
681 jvResult[jss::tx_json] =
682 tpTrans->getJson(JsonOptions::disable_API_prior_V2);
683 jvResult[jss::hash] = to_string(tpTrans->getID());
684 }
685 else
686 jvResult[jss::tx_json] = tpTrans->getJson(JsonOptions::none);
687
689 jvResult[jss::tx_json],
690 tpTrans->getSTransaction()->getTxnType(),
691 apiVersion);
692
693 jvResult[jss::tx_blob] =
694 strHex(tpTrans->getSTransaction()->getSerializer().peekData());
695
696 if (temUNCERTAIN != tpTrans->getResult())
697 {
698 std::string sToken;
699 std::string sHuman;
700
701 transResultInfo(tpTrans->getResult(), sToken, sHuman);
702
703 jvResult[jss::engine_result] = sToken;
704 jvResult[jss::engine_result_code] = tpTrans->getResult();
705 jvResult[jss::engine_result_message] = sHuman;
706 }
707 }
708 catch (std::exception&)
709 {
710 jvResult = RPC::make_error(
711 rpcINTERNAL, "Exception occurred during JSON handling.");
712 }
713 return jvResult;
714}
715
716} // namespace detail
717
718//------------------------------------------------------------------------------
719
720[[nodiscard]]
721static XRPAmount
722getTxFee(Application const& app, Config const& config, Json::Value tx)
723{
724 // autofilling only needed in this function so that the `STParsedJSONObject`
725 // parsing works properly it should not be modifying the actual `tx` object
726 if (!tx.isMember(jss::Fee))
727 {
728 tx[jss::Fee] = "0";
729 }
730
731 if (!tx.isMember(jss::Sequence))
732 {
733 tx[jss::Sequence] = "0";
734 }
735
736 if (!tx.isMember(jss::SigningPubKey))
737 {
738 tx[jss::SigningPubKey] = "";
739 }
740
741 if (!tx.isMember(jss::TxnSignature))
742 {
743 tx[jss::TxnSignature] = "";
744 }
745
746 if (tx.isMember(jss::Signers))
747 {
748 if (!tx[jss::Signers].isArray())
749 return config.FEES.reference_fee;
750
751 // check multi-signed signers
752 for (auto& signer : tx[jss::Signers])
753 {
754 if (!signer.isMember(jss::Signer) ||
755 !signer[jss::Signer].isObject())
756 return config.FEES.reference_fee;
757 if (!signer[jss::Signer].isMember(jss::SigningPubKey))
758 {
759 // autofill SigningPubKey
760 signer[jss::Signer][jss::SigningPubKey] = "";
761 }
762 if (!signer[jss::Signer].isMember(jss::TxnSignature))
763 {
764 // autofill TxnSignature
765 signer[jss::Signer][jss::TxnSignature] = "";
766 }
767 }
768 }
769
770 STParsedJSONObject parsed(std::string(jss::tx_json), tx);
771 if (!parsed.object.has_value())
772 {
773 return config.FEES.reference_fee;
774 }
775
776 try
777 {
778 STTx const& stTx = STTx(std::move(parsed.object.value()));
779 return calculateBaseFee(*app.openLedger().current(), stTx);
780 }
781 catch (std::exception& e)
782 {
783 return config.FEES.reference_fee;
784 }
785}
786
789 Role const role,
790 Config const& config,
791 LoadFeeTrack const& feeTrack,
792 TxQ const& txQ,
793 Application const& app,
794 Json::Value const& tx,
795 int mult,
796 int div)
797{
798 XRPAmount const feeDefault = getTxFee(app, config, tx);
799
800 auto ledger = app.openLedger().current();
801 // Administrative and identified endpoints are exempt from local fees.
802 XRPAmount const loadFee =
803 scaleFeeLoad(feeDefault, feeTrack, ledger->fees(), isUnlimited(role));
804 XRPAmount fee = loadFee;
805 {
806 auto const metrics = txQ.getMetrics(*ledger);
807 auto const baseFee = ledger->fees().base;
808 auto escalatedFee =
809 toDrops(metrics.openLedgerFeeLevel - FeeLevel64(1), baseFee) + 1;
810 fee = std::max(fee, escalatedFee);
811 }
812
813 auto const limit = mulDiv(feeDefault, mult, div);
814 if (!limit)
815 Throw<std::overflow_error>("mulDiv");
816
817 if (fee > *limit)
818 {
820 ss << "Fee of " << fee << " exceeds the requested tx limit of "
821 << *limit;
822 return RPC::make_error(rpcHIGH_FEE, ss.str());
823 }
824
825 return fee.jsonClipped();
826}
827
830 Json::Value& request,
831 Role const role,
832 bool doAutoFill,
833 Config const& config,
834 LoadFeeTrack const& feeTrack,
835 TxQ const& txQ,
836 Application const& app)
837{
838 Json::Value& tx(request[jss::tx_json]);
839 if (tx.isMember(jss::Fee))
840 return Json::Value();
841
842 if (!doAutoFill)
843 return RPC::missing_field_error("tx_json.Fee");
844
847 if (request.isMember(jss::fee_mult_max))
848 {
849 if (request[jss::fee_mult_max].isInt())
850 {
851 mult = request[jss::fee_mult_max].asInt();
852 if (mult < 0)
853 return RPC::make_error(
856 jss::fee_mult_max, "a positive integer"));
857 }
858 else
859 {
860 return RPC::make_error(
863 jss::fee_mult_max, "a positive integer"));
864 }
865 }
866 if (request.isMember(jss::fee_div_max))
867 {
868 if (request[jss::fee_div_max].isInt())
869 {
870 div = request[jss::fee_div_max].asInt();
871 if (div <= 0)
872 return RPC::make_error(
875 jss::fee_div_max, "a positive integer"));
876 }
877 else
878 {
879 return RPC::make_error(
882 jss::fee_div_max, "a positive integer"));
883 }
884 }
885
886 auto feeOrError =
887 getCurrentNetworkFee(role, config, feeTrack, txQ, app, tx, mult, div);
888 if (feeOrError.isMember(jss::error))
889 return feeOrError;
890 tx[jss::Fee] = std::move(feeOrError);
891 return Json::Value();
892}
893
894//------------------------------------------------------------------------------
895
899 Json::Value jvRequest,
900 unsigned apiVersion,
901 NetworkOPs::FailHard failType,
902 Role role,
903 std::chrono::seconds validatedLedgerAge,
904 Application& app)
905{
906 using namespace detail;
907
908 auto j = app.journal("RPCHandler");
909 JLOG(j.debug()) << "transactionSign: " << jvRequest;
910
911 // Add and amend fields based on the transaction type.
912 SigningForParams signForParams;
913 transactionPreProcessResult preprocResult = transactionPreProcessImpl(
914 jvRequest, role, signForParams, validatedLedgerAge, app);
915
916 if (!preprocResult.second)
917 return preprocResult.first;
918
920 // Make sure the STTx makes a legitimate Transaction.
922 transactionConstructImpl(preprocResult.second, ledger->rules(), app);
923
924 if (!txn.second)
925 return txn.first;
926
927 return transactionFormatResultImpl(txn.second, apiVersion);
928}
929
933 Json::Value jvRequest,
934 unsigned apiVersion,
935 NetworkOPs::FailHard failType,
936 Role role,
937 std::chrono::seconds validatedLedgerAge,
938 Application& app,
939 ProcessTransactionFn const& processTransaction)
940{
941 using namespace detail;
942
943 auto const& ledger = app.openLedger().current();
944 auto j = app.journal("RPCHandler");
945 JLOG(j.debug()) << "transactionSubmit: " << jvRequest;
946
947 // Add and amend fields based on the transaction type.
948 SigningForParams signForParams;
949 transactionPreProcessResult preprocResult = transactionPreProcessImpl(
950 jvRequest, role, signForParams, validatedLedgerAge, app);
951
952 if (!preprocResult.second)
953 return preprocResult.first;
954
955 // Make sure the STTx makes a legitimate Transaction.
957 transactionConstructImpl(preprocResult.second, ledger->rules(), app);
958
959 if (!txn.second)
960 return txn.first;
961
962 // Finally, submit the transaction.
963 try
964 {
965 // FIXME: For performance, should use asynch interface
966 processTransaction(txn.second, isUnlimited(role), true, failType);
967 }
968 catch (std::exception&)
969 {
970 return RPC::make_error(
971 rpcINTERNAL, "Exception occurred during transaction submission.");
972 }
973
974 return transactionFormatResultImpl(txn.second, apiVersion);
975}
976
977namespace detail {
978// There are a some field checks shared by transactionSignFor
979// and transactionSubmitMultiSigned. Gather them together here.
980static Json::Value
982{
983 if (!jvRequest.isMember(jss::tx_json))
984 return RPC::missing_field_error(jss::tx_json);
985
986 Json::Value const& tx_json(jvRequest[jss::tx_json]);
987
988 if (!tx_json.isObject())
989 return RPC::invalid_field_message(jss::tx_json);
990
991 // There are a couple of additional fields we need to check before
992 // we serialize. If we serialize first then we generate less useful
993 // error messages.
994 if (!tx_json.isMember(jss::Sequence))
995 return RPC::missing_field_error("tx_json.Sequence");
996
997 if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
998 return RPC::missing_field_error("tx_json.SigningPubKey");
999
1000 if (!tx_json[sfSigningPubKey.getJsonName()].asString().empty())
1001 return RPC::make_error(
1003 "When multi-signing 'tx_json.SigningPubKey' must be empty.");
1004
1005 return Json::Value();
1006}
1007
1008// Sort and validate an stSigners array.
1009//
1010// Returns a null Json::Value if there are no errors.
1011static Json::Value
1012sortAndValidateSigners(STArray& signers, AccountID const& signingForID)
1013{
1014 if (signers.empty())
1015 return RPC::make_param_error("Signers array may not be empty.");
1016
1017 // Signers must be sorted by Account.
1018 std::sort(
1019 signers.begin(),
1020 signers.end(),
1021 [](STObject const& a, STObject const& b) {
1022 return (a[sfAccount] < b[sfAccount]);
1023 });
1024
1025 // Signers may not contain any duplicates.
1026 auto const dupIter = std::adjacent_find(
1027 signers.begin(),
1028 signers.end(),
1029 [](STObject const& a, STObject const& b) {
1030 return (a[sfAccount] == b[sfAccount]);
1031 });
1032
1033 if (dupIter != signers.end())
1034 {
1036 err << "Duplicate Signers:Signer:Account entries ("
1037 << toBase58((*dupIter)[sfAccount]) << ") are not allowed.";
1038 return RPC::make_param_error(err.str());
1039 }
1040
1041 // An account may not sign for itself.
1042 if (signers.end() !=
1044 signers.begin(),
1045 signers.end(),
1046 [&signingForID](STObject const& elem) {
1047 return elem[sfAccount] == signingForID;
1048 }))
1049 {
1051 err << "A Signer may not be the transaction's Account ("
1052 << toBase58(signingForID) << ").";
1053 return RPC::make_param_error(err.str());
1054 }
1055 return {};
1056}
1057
1058} // namespace detail
1059
1063 Json::Value jvRequest,
1064 unsigned apiVersion,
1065 NetworkOPs::FailHard failType,
1066 Role role,
1067 std::chrono::seconds validatedLedgerAge,
1068 Application& app)
1069{
1070 auto const& ledger = app.openLedger().current();
1071 auto j = app.journal("RPCHandler");
1072 JLOG(j.debug()) << "transactionSignFor: " << jvRequest;
1073
1074 // Verify presence of the signer's account field.
1075 const char accountField[] = "account";
1076
1077 if (!jvRequest.isMember(accountField))
1078 return RPC::missing_field_error(accountField);
1079
1080 // Turn the signer's account into an AccountID for multi-sign.
1081 auto const signerAccountID =
1082 parseBase58<AccountID>(jvRequest[accountField].asString());
1083 if (!signerAccountID)
1084 {
1085 return RPC::make_error(
1087 }
1088
1089 if (!jvRequest.isMember(jss::tx_json))
1090 return RPC::missing_field_error(jss::tx_json);
1091
1092 {
1093 Json::Value& tx_json(jvRequest[jss::tx_json]);
1094
1095 if (!tx_json.isObject())
1096 return RPC::object_field_error(jss::tx_json);
1097
1098 // If the tx_json.SigningPubKey field is missing,
1099 // insert an empty one.
1100 if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
1101 tx_json[sfSigningPubKey.getJsonName()] = "";
1102 }
1103
1104 // When multi-signing, the "Sequence" and "SigningPubKey" fields must
1105 // be passed in by the caller.
1106 using namespace detail;
1107 {
1108 Json::Value err = checkMultiSignFields(jvRequest);
1109 if (RPC::contains_error(err))
1110 return err;
1111 }
1112
1113 // Add and amend fields based on the transaction type.
1114 SigningForParams signForParams(*signerAccountID);
1115
1116 transactionPreProcessResult preprocResult = transactionPreProcessImpl(
1117 jvRequest, role, signForParams, validatedLedgerAge, app);
1118
1119 if (!preprocResult.second)
1120 return preprocResult.first;
1121
1122 XRPL_ASSERT(
1123 signForParams.validMultiSign(),
1124 "ripple::RPC::transactionSignFor : valid multi-signature");
1125
1126 {
1127 std::shared_ptr<SLE const> account_state =
1128 ledger->read(keylet::account(*signerAccountID));
1129 // Make sure the account and secret belong together.
1130 auto const err = acctMatchesPubKey(
1131 account_state, *signerAccountID, signForParams.getPublicKey());
1132
1133 if (err != rpcSUCCESS)
1134 return rpcError(err);
1135 }
1136
1137 // Inject the newly generated signature into tx_json.Signers.
1138 auto& sttx = preprocResult.second;
1139 {
1140 // Make the signer object that we'll inject.
1141 STObject signer = STObject::makeInnerObject(sfSigner);
1142 signer[sfAccount] = *signerAccountID;
1143 signer.setFieldVL(sfTxnSignature, signForParams.getSignature());
1144 signer.setFieldVL(
1145 sfSigningPubKey, signForParams.getPublicKey().slice());
1146
1147 // If there is not yet a Signers array, make one.
1148 if (!sttx->isFieldPresent(sfSigners))
1149 sttx->setFieldArray(sfSigners, {});
1150
1151 auto& signers = sttx->peekFieldArray(sfSigners);
1152 signers.emplace_back(std::move(signer));
1153
1154 // The array must be sorted and validated.
1155 auto err = sortAndValidateSigners(signers, (*sttx)[sfAccount]);
1156 if (RPC::contains_error(err))
1157 return err;
1158 }
1159
1160 // Make sure the STTx makes a legitimate Transaction.
1162 transactionConstructImpl(sttx, ledger->rules(), app);
1163
1164 if (!txn.second)
1165 return txn.first;
1166
1167 return transactionFormatResultImpl(txn.second, apiVersion);
1168}
1169
1173 Json::Value jvRequest,
1174 unsigned apiVersion,
1175 NetworkOPs::FailHard failType,
1176 Role role,
1177 std::chrono::seconds validatedLedgerAge,
1178 Application& app,
1179 ProcessTransactionFn const& processTransaction)
1180{
1181 auto const& ledger = app.openLedger().current();
1182 auto j = app.journal("RPCHandler");
1183 JLOG(j.debug()) << "transactionSubmitMultiSigned: " << jvRequest;
1184
1185 // When multi-signing, the "Sequence" and "SigningPubKey" fields must
1186 // be passed in by the caller.
1187 using namespace detail;
1188 {
1189 Json::Value err = checkMultiSignFields(jvRequest);
1190 if (RPC::contains_error(err))
1191 return err;
1192 }
1193
1194 Json::Value& tx_json(jvRequest["tx_json"]);
1195
1196 auto [txJsonResult, srcAddressID] = checkTxJsonFields(
1197 tx_json,
1198 role,
1199 true,
1200 validatedLedgerAge,
1201 app.config(),
1202 app.getFeeTrack(),
1203 getAPIVersionNumber(jvRequest, app.config().BETA_RPC_API));
1204
1205 if (RPC::contains_error(txJsonResult))
1206 return std::move(txJsonResult);
1207
1209 ledger->read(keylet::account(srcAddressID));
1210
1211 if (!sle)
1212 {
1213 // If did not find account, error.
1214 JLOG(j.debug())
1215 << "transactionSubmitMultiSigned: Failed to find source account "
1216 << "in current ledger: " << toBase58(srcAddressID);
1217
1219 }
1220
1221 {
1222 Json::Value err = checkFee(
1223 jvRequest,
1224 role,
1225 false,
1226 app.config(),
1227 app.getFeeTrack(),
1228 app.getTxQ(),
1229 app);
1230
1231 if (RPC::contains_error(err))
1232 return err;
1233
1234 err = checkPayment(jvRequest, tx_json, srcAddressID, role, app, false);
1235
1236 if (RPC::contains_error(err))
1237 return err;
1238 }
1239
1240 // Grind through the JSON in tx_json to produce a STTx.
1242 {
1243 STParsedJSONObject parsedTx_json("tx_json", tx_json);
1244 if (!parsedTx_json.object)
1245 {
1246 Json::Value jvResult;
1247 jvResult["error"] = parsedTx_json.error["error"];
1248 jvResult["error_code"] = parsedTx_json.error["error_code"];
1249 jvResult["error_message"] = parsedTx_json.error["error_message"];
1250 return jvResult;
1251 }
1252 try
1253 {
1254 stTx =
1255 std::make_shared<STTx>(std::move(parsedTx_json.object.value()));
1256 }
1257 catch (STObject::FieldErr& err)
1258 {
1259 return RPC::make_error(rpcINVALID_PARAMS, err.what());
1260 }
1261 catch (std::exception& ex)
1262 {
1263 std::string reason(ex.what());
1264 return RPC::make_error(
1266 "Exception while serializing transaction: " + reason);
1267 }
1268 std::string reason;
1269 if (!passesLocalChecks(*stTx, reason))
1270 return RPC::make_error(rpcINVALID_PARAMS, reason);
1271 }
1272
1273 // Validate the fields in the serialized transaction.
1274 {
1275 // We now have the transaction text serialized and in the right format.
1276 // Verify the values of select fields.
1277 //
1278 // The SigningPubKey must be present but empty.
1279 if (!stTx->getFieldVL(sfSigningPubKey).empty())
1280 {
1282 err << "Invalid " << sfSigningPubKey.fieldName
1283 << " field. Field must be empty when multi-signing.";
1284 return RPC::make_error(rpcINVALID_PARAMS, err.str());
1285 }
1286
1287 // There may not be a TxnSignature field.
1288 if (stTx->isFieldPresent(sfTxnSignature))
1290
1291 // The Fee field must be in XRP and greater than zero.
1292 auto const fee = stTx->getFieldAmount(sfFee);
1293
1294 if (!isLegalNet(fee))
1295 {
1297 err << "Invalid " << sfFee.fieldName
1298 << " field. Fees must be specified in XRP.";
1299 return RPC::make_error(rpcINVALID_PARAMS, err.str());
1300 }
1301 if (fee <= STAmount{0})
1302 {
1304 err << "Invalid " << sfFee.fieldName
1305 << " field. Fees must be greater than zero.";
1306 return RPC::make_error(rpcINVALID_PARAMS, err.str());
1307 }
1308 }
1309
1310 // Verify that the Signers field is present.
1311 if (!stTx->isFieldPresent(sfSigners))
1312 return RPC::missing_field_error("tx_json.Signers");
1313
1314 // If the Signers field is present the SField guarantees it to be an array.
1315 // Get a reference to the Signers array so we can verify and sort it.
1316 auto& signers = stTx->peekFieldArray(sfSigners);
1317
1318 if (signers.empty())
1319 return RPC::make_param_error("tx_json.Signers array may not be empty.");
1320
1321 // The Signers array may only contain Signer objects.
1322 if (std::find_if_not(
1323 signers.begin(), signers.end(), [](STObject const& obj) {
1324 return (
1325 // A Signer object always contains these fields and no
1326 // others.
1327 obj.isFieldPresent(sfAccount) &&
1328 obj.isFieldPresent(sfSigningPubKey) &&
1329 obj.isFieldPresent(sfTxnSignature) && obj.getCount() == 3);
1330 }) != signers.end())
1331 {
1332 return RPC::make_param_error(
1333 "Signers array may only contain Signer entries.");
1334 }
1335
1336 // The array must be sorted and validated.
1337 auto err = sortAndValidateSigners(signers, srcAddressID);
1338 if (RPC::contains_error(err))
1339 return err;
1340
1341 // Make sure the SerializedTransaction makes a legitimate Transaction.
1343 transactionConstructImpl(stTx, ledger->rules(), app);
1344
1345 if (!txn.second)
1346 return txn.first;
1347
1348 // Finally, submit the transaction.
1349 try
1350 {
1351 // FIXME: For performance, should use asynch interface
1352 processTransaction(txn.second, isUnlimited(role), true, failType);
1353 }
1354 catch (std::exception&)
1355 {
1356 return RPC::make_error(
1357 rpcINTERNAL, "Exception occurred during transaction submission.");
1358 }
1359
1360 return transactionFormatResultImpl(txn.second, apiVersion);
1361}
1362
1363} // namespace RPC
1364} // 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
uint32_t NETWORK_ID
Definition: Config.h:163
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:795
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:860
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)