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