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]] static XRPAmount
750getTxFee(Application const& app, Config const& config, Json::Value tx)
751{
752 // autofilling only needed in this function so that the `STParsedJSONObject`
753 // parsing works properly it should not be modifying the actual `tx` object
754 if (!tx.isMember(jss::Fee))
755 {
756 tx[jss::Fee] = "0";
757 }
758
759 if (!tx.isMember(jss::Sequence))
760 {
761 tx[jss::Sequence] = "0";
762 }
763
764 if (!tx.isMember(jss::SigningPubKey))
765 {
766 tx[jss::SigningPubKey] = "";
767 }
768
769 if (!tx.isMember(jss::TxnSignature))
770 {
771 tx[jss::TxnSignature] = "";
772 }
773
774 if (tx.isMember(jss::Signers))
775 {
776 if (!tx[jss::Signers].isArray())
777 return config.FEES.reference_fee;
778
779 // check multi-signed signers
780 for (auto& signer : tx[jss::Signers])
781 {
782 if (!signer.isMember(jss::Signer) ||
783 !signer[jss::Signer].isObject())
784 return config.FEES.reference_fee;
785 if (!signer[jss::Signer].isMember(jss::SigningPubKey))
786 {
787 // autofill SigningPubKey
788 signer[jss::Signer][jss::SigningPubKey] = "";
789 }
790 if (!signer[jss::Signer].isMember(jss::TxnSignature))
791 {
792 // autofill TxnSignature
793 signer[jss::Signer][jss::TxnSignature] = "";
794 }
795 }
796 }
797
798 STParsedJSONObject parsed(std::string(jss::tx_json), tx);
799 if (!parsed.object.has_value())
800 {
801 return config.FEES.reference_fee;
802 }
803
804 try
805 {
806 STTx const& stTx = STTx(std::move(parsed.object.value()));
807 return calculateBaseFee(*app.openLedger().current(), stTx);
808 }
809 catch (std::exception& e)
810 {
811 return config.FEES.reference_fee;
812 }
813}
814
817 Role const role,
818 Config const& config,
819 LoadFeeTrack const& feeTrack,
820 TxQ const& txQ,
821 Application const& app,
822 Json::Value const& tx,
823 int mult,
824 int div)
825{
826 XRPAmount const feeDefault = getTxFee(app, config, tx);
827
828 auto ledger = app.openLedger().current();
829 // Administrative and identified endpoints are exempt from local fees.
830 XRPAmount const loadFee =
831 scaleFeeLoad(feeDefault, feeTrack, ledger->fees(), isUnlimited(role));
832 XRPAmount fee = loadFee;
833 {
834 auto const metrics = txQ.getMetrics(*ledger);
835 auto const baseFee = ledger->fees().base;
836 auto escalatedFee =
837 toDrops(metrics.openLedgerFeeLevel - FeeLevel64(1), baseFee) + 1;
838 fee = std::max(fee, escalatedFee);
839 }
840
841 auto const limit = mulDiv(feeDefault, mult, div);
842 if (!limit)
843 Throw<std::overflow_error>("mulDiv");
844
845 if (fee > *limit)
846 {
848 ss << "Fee of " << fee << " exceeds the requested tx limit of "
849 << *limit;
850 return RPC::make_error(rpcHIGH_FEE, ss.str());
851 }
852
853 return fee.jsonClipped();
854}
855
858 Json::Value& request,
859 Role const role,
860 bool doAutoFill,
861 Config const& config,
862 LoadFeeTrack const& feeTrack,
863 TxQ const& txQ,
864 Application const& app)
865{
866 Json::Value& tx(request[jss::tx_json]);
867 if (tx.isMember(jss::Fee))
868 return Json::Value();
869
870 if (!doAutoFill)
871 return RPC::missing_field_error("tx_json.Fee");
872
875 if (request.isMember(jss::fee_mult_max))
876 {
877 if (request[jss::fee_mult_max].isInt())
878 {
879 mult = request[jss::fee_mult_max].asInt();
880 if (mult < 0)
881 return RPC::make_error(
884 jss::fee_mult_max, "a positive integer"));
885 }
886 else
887 {
888 return RPC::make_error(
891 jss::fee_mult_max, "a positive integer"));
892 }
893 }
894 if (request.isMember(jss::fee_div_max))
895 {
896 if (request[jss::fee_div_max].isInt())
897 {
898 div = request[jss::fee_div_max].asInt();
899 if (div <= 0)
900 return RPC::make_error(
903 jss::fee_div_max, "a positive integer"));
904 }
905 else
906 {
907 return RPC::make_error(
910 jss::fee_div_max, "a positive integer"));
911 }
912 }
913
914 auto feeOrError =
915 getCurrentNetworkFee(role, config, feeTrack, txQ, app, tx, mult, div);
916 if (feeOrError.isMember(jss::error))
917 return feeOrError;
918 tx[jss::Fee] = std::move(feeOrError);
919 return Json::Value();
920}
921
922//------------------------------------------------------------------------------
923
927 Json::Value jvRequest,
928 unsigned apiVersion,
929 NetworkOPs::FailHard failType,
930 Role role,
931 std::chrono::seconds validatedLedgerAge,
932 Application& app)
933{
934 using namespace detail;
935
936 auto j = app.journal("RPCHandler");
937 JLOG(j.debug()) << "transactionSign: " << jvRequest;
938
939 // Add and amend fields based on the transaction type.
940 SigningForParams signForParams;
941 transactionPreProcessResult preprocResult = transactionPreProcessImpl(
942 jvRequest, role, signForParams, validatedLedgerAge, app);
943
944 if (!preprocResult.second)
945 return preprocResult.first;
946
948 // Make sure the STTx makes a legitimate Transaction.
950 transactionConstructImpl(preprocResult.second, ledger->rules(), app);
951
952 if (!txn.second)
953 return txn.first;
954
955 return transactionFormatResultImpl(txn.second, apiVersion);
956}
957
961 Json::Value jvRequest,
962 unsigned apiVersion,
963 NetworkOPs::FailHard failType,
964 Role role,
965 std::chrono::seconds validatedLedgerAge,
966 Application& app,
967 ProcessTransactionFn const& processTransaction)
968{
969 using namespace detail;
970
971 auto const& ledger = app.openLedger().current();
972 auto j = app.journal("RPCHandler");
973 JLOG(j.debug()) << "transactionSubmit: " << jvRequest;
974
975 // Add and amend fields based on the transaction type.
976 SigningForParams signForParams;
977 transactionPreProcessResult preprocResult = transactionPreProcessImpl(
978 jvRequest, role, signForParams, validatedLedgerAge, app);
979
980 if (!preprocResult.second)
981 return preprocResult.first;
982
983 // Make sure the STTx makes a legitimate Transaction.
985 transactionConstructImpl(preprocResult.second, ledger->rules(), app);
986
987 if (!txn.second)
988 return txn.first;
989
990 // Finally, submit the transaction.
991 try
992 {
993 // FIXME: For performance, should use asynch interface
994 processTransaction(txn.second, isUnlimited(role), true, failType);
995 }
996 catch (std::exception&)
997 {
998 return RPC::make_error(
999 rpcINTERNAL, "Exception occurred during transaction submission.");
1000 }
1001
1002 return transactionFormatResultImpl(txn.second, apiVersion);
1003}
1004
1005namespace detail {
1006// There are a some field checks shared by transactionSignFor
1007// and transactionSubmitMultiSigned. Gather them together here.
1008static Json::Value
1010{
1011 if (!jvRequest.isMember(jss::tx_json))
1012 return RPC::missing_field_error(jss::tx_json);
1013
1014 Json::Value const& tx_json(jvRequest[jss::tx_json]);
1015
1016 if (!tx_json.isObject())
1017 return RPC::invalid_field_message(jss::tx_json);
1018
1019 // There are a couple of additional fields we need to check before
1020 // we serialize. If we serialize first then we generate less useful
1021 // error messages.
1022 if (!tx_json.isMember(jss::Sequence))
1023 return RPC::missing_field_error("tx_json.Sequence");
1024
1025 if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
1026 return RPC::missing_field_error("tx_json.SigningPubKey");
1027
1028 if (!tx_json[sfSigningPubKey.getJsonName()].asString().empty())
1029 return RPC::make_error(
1031 "When multi-signing 'tx_json.SigningPubKey' must be empty.");
1032
1033 return Json::Value();
1034}
1035
1036// Sort and validate an stSigners array.
1037//
1038// Returns a null Json::Value if there are no errors.
1039static Json::Value
1040sortAndValidateSigners(STArray& signers, AccountID const& signingForID)
1041{
1042 if (signers.empty())
1043 return RPC::make_param_error("Signers array may not be empty.");
1044
1045 // Signers must be sorted by Account.
1046 std::sort(
1047 signers.begin(),
1048 signers.end(),
1049 [](STObject const& a, STObject const& b) {
1050 return (a[sfAccount] < b[sfAccount]);
1051 });
1052
1053 // Signers may not contain any duplicates.
1054 auto const dupIter = std::adjacent_find(
1055 signers.begin(),
1056 signers.end(),
1057 [](STObject const& a, STObject const& b) {
1058 return (a[sfAccount] == b[sfAccount]);
1059 });
1060
1061 if (dupIter != signers.end())
1062 {
1064 err << "Duplicate Signers:Signer:Account entries ("
1065 << toBase58((*dupIter)[sfAccount]) << ") are not allowed.";
1066 return RPC::make_param_error(err.str());
1067 }
1068
1069 // An account may not sign for itself.
1070 if (signers.end() !=
1072 signers.begin(),
1073 signers.end(),
1074 [&signingForID](STObject const& elem) {
1075 return elem[sfAccount] == signingForID;
1076 }))
1077 {
1079 err << "A Signer may not be the transaction's Account ("
1080 << toBase58(signingForID) << ").";
1081 return RPC::make_param_error(err.str());
1082 }
1083 return {};
1084}
1085
1086} // namespace detail
1087
1091 Json::Value jvRequest,
1092 unsigned apiVersion,
1093 NetworkOPs::FailHard failType,
1094 Role role,
1095 std::chrono::seconds validatedLedgerAge,
1096 Application& app)
1097{
1098 auto const& ledger = app.openLedger().current();
1099 auto j = app.journal("RPCHandler");
1100 JLOG(j.debug()) << "transactionSignFor: " << jvRequest;
1101
1102 // Verify presence of the signer's account field.
1103 char const accountField[] = "account";
1104
1105 if (!jvRequest.isMember(accountField))
1106 return RPC::missing_field_error(accountField);
1107
1108 // Turn the signer's account into an AccountID for multi-sign.
1109 auto const signerAccountID =
1110 parseBase58<AccountID>(jvRequest[accountField].asString());
1111 if (!signerAccountID)
1112 {
1113 return RPC::make_error(
1115 }
1116
1117 if (!jvRequest.isMember(jss::tx_json))
1118 return RPC::missing_field_error(jss::tx_json);
1119
1120 {
1121 Json::Value& tx_json(jvRequest[jss::tx_json]);
1122
1123 if (!tx_json.isObject())
1124 return RPC::object_field_error(jss::tx_json);
1125
1126 // If the tx_json.SigningPubKey field is missing,
1127 // insert an empty one.
1128 if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
1129 tx_json[sfSigningPubKey.getJsonName()] = "";
1130 }
1131
1132 // When multi-signing, the "Sequence" and "SigningPubKey" fields must
1133 // be passed in by the caller.
1134 using namespace detail;
1135 {
1136 Json::Value err = checkMultiSignFields(jvRequest);
1137 if (RPC::contains_error(err))
1138 return err;
1139 }
1140
1141 // Add and amend fields based on the transaction type.
1142 SigningForParams signForParams(*signerAccountID);
1143
1144 transactionPreProcessResult preprocResult = transactionPreProcessImpl(
1145 jvRequest, role, signForParams, validatedLedgerAge, app);
1146
1147 if (!preprocResult.second)
1148 return preprocResult.first;
1149
1150 XRPL_ASSERT(
1151 signForParams.validMultiSign(),
1152 "ripple::RPC::transactionSignFor : valid multi-signature");
1153
1154 {
1155 std::shared_ptr<SLE const> account_state =
1156 ledger->read(keylet::account(*signerAccountID));
1157 // Make sure the account and secret belong together.
1158 auto const err = acctMatchesPubKey(
1159 account_state, *signerAccountID, signForParams.getPublicKey());
1160
1161 if (err != rpcSUCCESS)
1162 return rpcError(err);
1163 }
1164
1165 // Inject the newly generated signature into tx_json.Signers.
1166 auto& sttx = preprocResult.second;
1167 {
1168 // Make the signer object that we'll inject.
1169 STObject signer = STObject::makeInnerObject(sfSigner);
1170 signer[sfAccount] = *signerAccountID;
1171 signer.setFieldVL(sfTxnSignature, signForParams.getSignature());
1172 signer.setFieldVL(
1173 sfSigningPubKey, signForParams.getPublicKey().slice());
1174
1175 // If there is not yet a Signers array, make one.
1176 if (!sttx->isFieldPresent(sfSigners))
1177 sttx->setFieldArray(sfSigners, {});
1178
1179 auto& signers = sttx->peekFieldArray(sfSigners);
1180 signers.emplace_back(std::move(signer));
1181
1182 // The array must be sorted and validated.
1183 auto err = sortAndValidateSigners(signers, (*sttx)[sfAccount]);
1184 if (RPC::contains_error(err))
1185 return err;
1186 }
1187
1188 // Make sure the STTx makes a legitimate Transaction.
1190 transactionConstructImpl(sttx, ledger->rules(), app);
1191
1192 if (!txn.second)
1193 return txn.first;
1194
1195 return transactionFormatResultImpl(txn.second, apiVersion);
1196}
1197
1201 Json::Value jvRequest,
1202 unsigned apiVersion,
1203 NetworkOPs::FailHard failType,
1204 Role role,
1205 std::chrono::seconds validatedLedgerAge,
1206 Application& app,
1207 ProcessTransactionFn const& processTransaction)
1208{
1209 auto const& ledger = app.openLedger().current();
1210 auto j = app.journal("RPCHandler");
1211 JLOG(j.debug()) << "transactionSubmitMultiSigned: " << jvRequest;
1212
1213 // When multi-signing, the "Sequence" and "SigningPubKey" fields must
1214 // be passed in by the caller.
1215 using namespace detail;
1216 {
1217 Json::Value err = checkMultiSignFields(jvRequest);
1218 if (RPC::contains_error(err))
1219 return err;
1220 }
1221
1222 Json::Value& tx_json(jvRequest["tx_json"]);
1223
1224 auto [txJsonResult, srcAddressID] = checkTxJsonFields(
1225 tx_json,
1226 role,
1227 true,
1228 validatedLedgerAge,
1229 app.config(),
1230 app.getFeeTrack(),
1231 getAPIVersionNumber(jvRequest, app.config().BETA_RPC_API));
1232
1233 if (RPC::contains_error(txJsonResult))
1234 return std::move(txJsonResult);
1235
1237 ledger->read(keylet::account(srcAddressID));
1238
1239 if (!sle)
1240 {
1241 // If did not find account, error.
1242 JLOG(j.debug())
1243 << "transactionSubmitMultiSigned: Failed to find source account "
1244 << "in current ledger: " << toBase58(srcAddressID);
1245
1247 }
1248
1249 {
1250 Json::Value err = checkFee(
1251 jvRequest,
1252 role,
1253 false,
1254 app.config(),
1255 app.getFeeTrack(),
1256 app.getTxQ(),
1257 app);
1258
1259 if (RPC::contains_error(err))
1260 return err;
1261
1262 err = checkPayment(jvRequest, tx_json, srcAddressID, role, app, false);
1263
1264 if (RPC::contains_error(err))
1265 return err;
1266 }
1267
1268 // Grind through the JSON in tx_json to produce a STTx.
1270 {
1271 STParsedJSONObject parsedTx_json("tx_json", tx_json);
1272 if (!parsedTx_json.object)
1273 {
1274 Json::Value jvResult;
1275 jvResult["error"] = parsedTx_json.error["error"];
1276 jvResult["error_code"] = parsedTx_json.error["error_code"];
1277 jvResult["error_message"] = parsedTx_json.error["error_message"];
1278 return jvResult;
1279 }
1280 try
1281 {
1282 stTx =
1283 std::make_shared<STTx>(std::move(parsedTx_json.object.value()));
1284 }
1285 catch (STObject::FieldErr& err)
1286 {
1287 return RPC::make_error(rpcINVALID_PARAMS, err.what());
1288 }
1289 catch (std::exception& ex)
1290 {
1291 std::string reason(ex.what());
1292 return RPC::make_error(
1294 "Exception while serializing transaction: " + reason);
1295 }
1296 std::string reason;
1297 if (!passesLocalChecks(*stTx, reason))
1298 return RPC::make_error(rpcINVALID_PARAMS, reason);
1299 }
1300
1301 // Validate the fields in the serialized transaction.
1302 {
1303 // We now have the transaction text serialized and in the right format.
1304 // Verify the values of select fields.
1305 //
1306 // The SigningPubKey must be present but empty.
1307 if (!stTx->getFieldVL(sfSigningPubKey).empty())
1308 {
1310 err << "Invalid " << sfSigningPubKey.fieldName
1311 << " field. Field must be empty when multi-signing.";
1312 return RPC::make_error(rpcINVALID_PARAMS, err.str());
1313 }
1314
1315 // There may not be a TxnSignature field.
1316 if (stTx->isFieldPresent(sfTxnSignature))
1318
1319 // The Fee field must be in XRP and greater than zero.
1320 auto const fee = stTx->getFieldAmount(sfFee);
1321
1322 if (!isLegalNet(fee))
1323 {
1325 err << "Invalid " << sfFee.fieldName
1326 << " field. Fees must be specified in XRP.";
1327 return RPC::make_error(rpcINVALID_PARAMS, err.str());
1328 }
1329 if (fee <= STAmount{0})
1330 {
1332 err << "Invalid " << sfFee.fieldName
1333 << " field. Fees must be greater than zero.";
1334 return RPC::make_error(rpcINVALID_PARAMS, err.str());
1335 }
1336 }
1337
1338 // Verify that the Signers field is present.
1339 if (!stTx->isFieldPresent(sfSigners))
1340 return RPC::missing_field_error("tx_json.Signers");
1341
1342 // If the Signers field is present the SField guarantees it to be an array.
1343 // Get a reference to the Signers array so we can verify and sort it.
1344 auto& signers = stTx->peekFieldArray(sfSigners);
1345
1346 if (signers.empty())
1347 return RPC::make_param_error("tx_json.Signers array may not be empty.");
1348
1349 // The Signers array may only contain Signer objects.
1350 if (std::find_if_not(
1351 signers.begin(), signers.end(), [](STObject const& obj) {
1352 return (
1353 // A Signer object always contains these fields and no
1354 // others.
1355 obj.isFieldPresent(sfAccount) &&
1356 obj.isFieldPresent(sfSigningPubKey) &&
1357 obj.isFieldPresent(sfTxnSignature) && obj.getCount() == 3);
1358 }) != signers.end())
1359 {
1360 return RPC::make_param_error(
1361 "Signers array may only contain Signer entries.");
1362 }
1363
1364 // The array must be sorted and validated.
1365 auto err = sortAndValidateSigners(signers, srcAddressID);
1366 if (RPC::contains_error(err))
1367 return err;
1368
1369 // Make sure the SerializedTransaction makes a legitimate Transaction.
1371 transactionConstructImpl(stTx, ledger->rules(), app);
1372
1373 if (!txn.second)
1374 return txn.first;
1375
1376 // Finally, submit the transaction.
1377 try
1378 {
1379 // FIXME: For performance, should use asynch interface
1380 processTransaction(txn.second, isUnlimited(role), true, failType);
1381 }
1382 catch (std::exception&)
1383 {
1384 return RPC::make_error(
1385 rpcINTERNAL, "Exception occurred during transaction submission.");
1386 }
1387
1388 return transactionFormatResultImpl(txn.second, apiVersion);
1389}
1390
1391} // namespace RPC
1392} // 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(char const *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(char const *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: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: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.
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: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)