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