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