xrpld
Loading...
Searching...
No Matches
STTx.cpp
1#include <xrpl/protocol/STTx.h>
2
3#include <xrpl/basics/Blob.h>
4#include <xrpl/basics/Slice.h>
5#include <xrpl/basics/StringUtilities.h>
6#include <xrpl/basics/base_uint.h>
7#include <xrpl/basics/contract.h>
8#include <xrpl/basics/safe_cast.h>
9#include <xrpl/basics/strHex.h>
10#include <xrpl/beast/utility/Zero.h>
11#include <xrpl/beast/utility/instrumentation.h>
12#include <xrpl/json/json_value.h>
13#include <xrpl/protocol/AccountID.h>
14#include <xrpl/protocol/Batch.h>
15#include <xrpl/protocol/HashPrefix.h>
16#include <xrpl/protocol/MPTIssue.h>
17#include <xrpl/protocol/Protocol.h>
18#include <xrpl/protocol/PublicKey.h>
19#include <xrpl/protocol/Rules.h>
20#include <xrpl/protocol/SField.h>
21#include <xrpl/protocol/SOTemplate.h>
22#include <xrpl/protocol/STAccount.h>
23#include <xrpl/protocol/STAmount.h>
24#include <xrpl/protocol/STArray.h>
25#include <xrpl/protocol/STBase.h>
26#include <xrpl/protocol/STObject.h>
27#include <xrpl/protocol/SecretKey.h>
28#include <xrpl/protocol/SeqProxy.h>
29#include <xrpl/protocol/Serializer.h>
30#include <xrpl/protocol/Sign.h>
31#include <xrpl/protocol/TxFlags.h>
32#include <xrpl/protocol/TxFormats.h>
33#include <xrpl/protocol/jss.h>
34
35#include <boost/container/flat_set.hpp>
36
37#include <array>
38#include <cstddef>
39#include <cstdint>
40#include <exception>
41#include <expected>
42#include <format>
43#include <functional>
44#include <memory>
45#include <optional>
46#include <stdexcept>
47#include <string>
48#include <string_view>
49#include <type_traits>
50#include <utility>
51#include <vector>
52
53namespace xrpl {
54
55static auto
57{
58 auto format = TxFormats::getInstance().findByType(type);
59
60 if (format == nullptr)
61 {
63 "Invalid transaction type " +
65 }
66
67 return format;
68}
69
71 : STObject(std::move(object)), txType_(safeCast<TxType>(getFieldU16(sfTransactionType)))
72{
73 applyTemplate(getTxFormat(txType_)->getSOTemplate()); // may throw
76}
77
78STTx::STTx(SerialIter& sit) : STObject(sfTransaction)
79{
80 int const length = sit.getBytesLeft();
81
82 if ((length < kTxMinSizeBytes) || (length > kTxMaxSizeBytes))
83 Throw<std::runtime_error>("Transaction length invalid");
84
85 if (set(sit))
86 Throw<std::runtime_error>("Transaction contains an object terminator");
87
88 txType_ = safeCast<TxType>(getFieldU16(sfTransactionType));
89
90 applyTemplate(getTxFormat(txType_)->getSOTemplate()); // May throw
93}
94
95STTx::STTx(TxType type, std::function<void(STObject&)> assembler) : STObject(sfTransaction)
96{
97 auto format = getTxFormat(type);
98
99 set(format->getSOTemplate());
100 setFieldU16(sfTransactionType, format->getType());
101
102 assembler(*this);
103
104 // txType_ must be read after the object is assembled, so this cannot be a
105 // member initializer.
106 // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
107 txType_ = safeCast<TxType>(getFieldU16(sfTransactionType));
108
109 if (txType_ != type)
110 logicError("Transaction type was mutated during assembly");
111
114}
115
116STBase*
117STTx::copy(std::size_t n, void* buf) const
118{
119 return emplace(n, buf, *this);
120}
121
122STBase*
124{
125 return emplace(n, buf, std::move(*this));
126}
127
128// STObject functions.
131{
132 return STI_TRANSACTION;
133}
134
137{
138 std::string ret = "\"";
139 ret += to_string(getTransactionID());
140 ret += "\" = {";
141 ret += STObject::getFullText();
142 ret += "}";
143 return ret;
144}
145
146boost::container::flat_set<AccountID>
148{
149 boost::container::flat_set<AccountID> list;
150
151 for (auto const& it : *this)
152 {
153 if (auto sacc = dynamic_cast<STAccount const*>(&it))
154 {
155 XRPL_ASSERT(!sacc->isDefault(), "xrpl::STTx::getMentionedAccounts : account is set");
156 if (!sacc->isDefault())
157 list.insert(sacc->value());
158 }
159 else if (auto samt = dynamic_cast<STAmount const*>(&it))
160 {
161 auto const& issuer = samt->getIssuer();
162 if (!isXRP(issuer))
163 list.insert(issuer);
164 }
165 }
166
167 return list;
168}
169
170static Blob
172{
173 Serializer s;
176 return s.getData();
177}
178
184
185Blob
187{
188 try
189 {
190 return sigObject.getFieldVL(sfTxnSignature);
191 }
192 catch (std::exception const&)
193 {
194 return Blob();
195 }
196}
197
200{
201 std::uint32_t const seq{getFieldU32(sfSequence)};
202 if (seq != 0)
203 return SeqProxy::rawSequence(seq);
204
205 std::optional<std::uint32_t> const ticketSeq{at(~sfTicketSequence)};
206 if (!ticketSeq)
207 {
208 // No TicketSequence specified. Return the Sequence, whatever it is.
209 return SeqProxy::rawSequence(seq);
210 }
211
212 return SeqProxy::rawTicket(*ticketSeq);
213}
214
215void
217 PublicKey const& publicKey,
218 SecretKey const& secretKey,
220{
221 auto const data = getSigningData(*this);
222
223 auto const sig = xrpl::sign(publicKey, secretKey, makeSlice(data));
224
225 if (signatureTarget)
226 {
227 auto& target = peekFieldObject(*signatureTarget);
228 target.setFieldVL(sfTxnSignature, sig);
229 }
230 else
231 {
232 setFieldVL(sfTxnSignature, sig);
233 }
235}
236
237std::expected<void, std::string>
238STTx::checkSign(Rules const& rules, STObject const& sigObject) const
239{
240 try
241 {
242 // Determine whether we're single- or multi-signing by looking
243 // at the SigningPubKey. If it's empty we must be
244 // multi-signing. Otherwise we're single-signing.
245
246 Blob const& signingPubKey = sigObject.getFieldVL(sfSigningPubKey);
247 return signingPubKey.empty() ? checkMultiSign(rules, sigObject)
248 : checkSingleSign(sigObject);
249 }
250 catch (...)
251 {
252 return std::unexpected("Internal signature check failure.");
253 }
254}
255
256std::expected<void, std::string>
257STTx::checkSign(Rules const& rules) const
258{
259 if (auto const ret = checkSign(rules, *this); !ret)
260 return ret;
261
262 if (isFieldPresent(sfCounterpartySignature))
263 {
264 auto const counterSig = getFieldObject(sfCounterpartySignature);
265 if (auto const ret = checkSign(rules, counterSig); !ret)
266 return std::unexpected("Counterparty: " + ret.error());
267 }
268
269 if (isFieldPresent(sfSponsorSignature))
270 {
271 auto const sponsorSignatureObj = getFieldObject(sfSponsorSignature);
272 if (auto const ret = checkSign(rules, sponsorSignatureObj); !ret)
273 return std::unexpected("Sponsor: " + ret.error());
274 }
275
276 // Verify batch signer signatures here so they are cached with the rest
277 // of signature checking.
278 if (isFieldPresent(sfBatchSigners))
279 {
280 if (auto const ret = checkBatchSign(rules); !ret)
281 return ret;
282 }
283 return {};
284}
285
286std::expected<void, std::string>
287STTx::checkBatchSign(Rules const& rules) const
288{
289 try
290 {
291 if (getTxnType() != ttBATCH)
292 {
293 // LCOV_EXCL_START
294 UNREACHABLE("STTx::checkBatchSign : not a batch transaction");
295 return std::unexpected("Not a batch transaction.");
296 // LCOV_EXCL_STOP
297 }
298 if (!isFieldPresent(sfBatchSigners))
299 return std::unexpected("Missing BatchSigners field."); // LCOV_EXCL_LINE
300 STArray const& signers{getFieldArray(sfBatchSigners)};
301 // Bound signature verification to the protocol cap. This runs in
302 // checkValidity (via checkSign) at relay / submit time, BEFORE preflight
303 // and passesLocalChecks enforce the cap. Without this guard a malicious
304 // peer could put an oversized sfBatchSigners array in a 1 MB blob and
305 // force one signature verification per entry before any of those checks
306 // (or the fee charge) runs.
307 if (signers.size() > kMaxBatchSigners)
308 return std::unexpected("BatchSigners array exceeds max entries.");
309 // Defensive.
310 if (!batchTxns_)
311 {
312 // LCOV_EXCL_START
313 UNREACHABLE("STTx::checkBatchSign : batch transactions not built");
314 return std::unexpected("Missing inner transactions.");
315 // LCOV_EXCL_STOP
316 }
317 auto const txIds = getBatchTransactionIDs();
318 for (auto const& signer : signers)
319 {
320 Blob const& signingPubKey = signer.getFieldVL(sfSigningPubKey);
321 auto const result = signingPubKey.empty() ? checkBatchMultiSign(signer, rules, txIds)
322 : checkBatchSingleSign(signer, txIds);
323
324 if (!result)
325 return result;
326 }
327 return {};
328 }
329 catch (std::exception const& e)
330 {
331 // LCOV_EXCL_START
332 return std::unexpected(std::string("Internal batch signature check failure: ") + e.what());
333 // LCOV_EXCL_STOP
334 }
335}
336
339{
342 ret[jss::hash] = to_string(getTransactionID());
343 return ret;
344}
345
347STTx::getJson(JsonOptions options, bool binary) const
348{
349 bool const v1 = !(options & JsonOptions::Values::DisableApiPriorV2);
350
351 if (binary)
352 {
354 std::string const dataBin = strHex(s.peekData());
355
356 if (v1)
357 {
359 ret[jss::tx] = dataBin;
360 ret[jss::hash] = to_string(getTransactionID());
361 return ret;
362 }
363
364 return json::Value{dataBin};
365 }
366
368 if (v1)
369 ret[jss::hash] = to_string(getTransactionID());
370
371 return ret;
372}
373
374std::string const&
376{
377 static std::string const kSql =
378 "INSERT OR REPLACE INTO Transactions "
379 "(TransID, TransType, FromAcct, FromSeq, LedgerSeq, Status, RawTxn, "
380 "TxnMeta)"
381 " VALUES ";
382
383 return kSql;
384}
385
387STTx::getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) const
388{
389 Serializer s;
390 add(s);
391 return getMetaSQL(s, inLedger, TxnSql::Validated, escapedMetaData);
392}
393
394// VFALCO This could be a free function elsewhere
397 Serializer rawTxn,
398 std::uint32_t inLedger,
399 TxnSql status,
400 std::string const& escapedMetaData) const
401{
402 std::string rTxn = sqlBlobLiteral(rawTxn.peekData());
403
405 XRPL_ASSERT(format, "xrpl::STTx::getMetaSQL : non-null type format");
406
407 return std::format(
408 "('{}', '{}', '{}', '{}', '{}', '{}', {}, {})",
410 format->getName(),
411 toBase58(getAccountID(sfAccount)),
412 getFieldU32(sfSequence),
413 inLedger,
414 safeCast<char>(status),
415 rTxn,
416 escapedMetaData);
417}
418
419static std::expected<void, std::string>
420singleSignHelper(STObject const& sigObject, Slice const& data)
421{
422 // We don't allow both a non-empty sfSigningPubKey and an sfSigners.
423 // That would allow the transaction to be signed two ways. So if both
424 // fields are present the signature is invalid.
425 if (sigObject.isFieldPresent(sfSigners))
426 return std::unexpected("Cannot both single- and multi-sign.");
427
428 bool validSig = false;
429 try
430 {
431 auto const spk = sigObject.getFieldVL(sfSigningPubKey);
432 if (publicKeyType(makeSlice(spk)))
433 {
434 Blob const signature = sigObject.getFieldVL(sfTxnSignature);
435 validSig = verify(PublicKey(makeSlice(spk)), data, makeSlice(signature));
436 }
437 }
438 catch (std::exception const&)
439 {
440 validSig = false;
441 }
442
443 if (!validSig)
444 return std::unexpected("Invalid signature.");
445
446 return {};
447}
448
449std::expected<void, std::string>
450STTx::checkSingleSign(STObject const& sigObject) const
451{
452 auto const data = getSigningData(*this);
453 return singleSignHelper(sigObject, makeSlice(data));
454}
455
456std::expected<void, std::string>
457STTx::checkBatchSingleSign(STObject const& batchSigner, std::vector<uint256> const& txIds) const
458{
459 XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::checkBatchSingleSign : batch transaction");
460 Serializer msg;
461 serializeBatch(msg, getAccountID(sfAccount), getSeqProxy().value(), getFlags(), txIds);
462 finishMultiSigningData(batchSigner.getAccountID(sfAccount), msg);
463 return singleSignHelper(batchSigner, msg.slice());
464}
465
466std::expected<void, std::string>
468 STObject const& sigObject,
469 std::optional<AccountID> txnAccountID,
470 std::function<Serializer(AccountID const&)> makeMsg,
471 Rules const& rules)
472{
473 // Make sure the MultiSigners are present. Otherwise they are not
474 // attempting multi-signing and we just have a bad SigningPubKey.
475 if (!sigObject.isFieldPresent(sfSigners))
476 return std::unexpected("Empty SigningPubKey.");
477
478 // We don't allow both an sfSigners and an sfTxnSignature. Both fields
479 // being present would indicate that the transaction is signed both ways.
480 if (sigObject.isFieldPresent(sfTxnSignature))
481 return std::unexpected("Cannot both single- and multi-sign.");
482
483 STArray const& signers{sigObject.getFieldArray(sfSigners)};
484
485 // There are well known bounds that the number of signers must be within.
486 if (signers.size() < STTx::kMinMultiSigners || signers.size() > STTx::kMaxMultiSigners)
487 return std::unexpected("Invalid Signers array size.");
488
489 // Signers must be in sorted order by AccountID.
490 AccountID lastAccountID(beast::kZero);
491
492 for (auto const& signer : signers)
493 {
494 auto const accountID = signer.getAccountID(sfAccount);
495
496 // The account owner may not usually multisign for themselves.
497 // If they can, txnAccountID will be unseated, which is not equal to any
498 // value.
499 if (txnAccountID == accountID)
500 return std::unexpected("Invalid multisigner.");
501
502 // No duplicate signers allowed.
503 if (lastAccountID == accountID)
504 return std::unexpected("Duplicate Signers not allowed.");
505
506 // Accounts must be in order by account ID. No duplicates allowed.
507 if (lastAccountID > accountID)
508 return std::unexpected("Unsorted Signers array.");
509
510 // The next signature must be greater than this one.
511 lastAccountID = accountID;
512
513 // Verify the signature.
514 bool validSig = false;
516 try
517 {
518 auto spk = signer.getFieldVL(sfSigningPubKey);
519 if (publicKeyType(makeSlice(spk)))
520 {
521 Blob const signature = signer.getFieldVL(sfTxnSignature);
522 validSig = verify(
523 PublicKey(makeSlice(spk)), makeMsg(accountID).slice(), makeSlice(signature));
524 }
525 }
526 catch (std::exception const& e)
527 {
528 // We assume any problem lies with the signature.
529 validSig = false;
530 errorWhat = e.what();
531 }
532 if (!validSig)
533 {
534 return std::unexpected(
535 std::string("Invalid signature on account ") + toBase58(accountID) +
536 (errorWhat ? ": " + *errorWhat : "") + ".");
537 }
538 }
539 // All signatures verified.
540 return {};
541}
542
543std::expected<void, std::string>
545 STObject const& batchSigner,
546 Rules const& rules,
547 std::vector<uint256> const& txIds) const
548{
549 XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::checkBatchMultiSign : batch transaction");
550 // We can ease the computational load inside the loop a bit by
551 // pre-constructing part of the data that we hash. Fill a Serializer
552 // with the stuff that stays constant from signature to signature.
553 auto const batchSignerAccount = batchSigner.getAccountID(sfAccount);
554 Serializer dataStart;
555 serializeBatch(dataStart, getAccountID(sfAccount), getSeqProxy().value(), getFlags(), txIds);
556 dataStart.addBitString(batchSignerAccount);
557 return multiSignHelper(
558 batchSigner,
559 batchSignerAccount,
560 [&dataStart](AccountID const& accountID) -> Serializer {
561 Serializer s = dataStart;
562 finishMultiSigningData(accountID, s);
563 return s;
564 },
565 rules);
566}
567
568std::expected<void, std::string>
569STTx::checkMultiSign(Rules const& rules, STObject const& sigObject) const
570{
571 // Used inside the loop in multiSignHelper to enforce that
572 // the account owner may not multisign for themselves.
573 // For delegated transactions sfDelegate is the account whose signer list is checked,
574 // the delegate account itself can not be among the signers.
575 auto const txnAccountID =
576 &sigObject != this ? std::nullopt : std::optional<AccountID>(getInitiator());
577
578 // We can ease the computational load inside the loop a bit by
579 // pre-constructing part of the data that we hash. Fill a Serializer
580 // with the stuff that stays constant from signature to signature.
581 Serializer dataStart = startMultiSigningData(*this);
582 return multiSignHelper(
583 sigObject,
584 txnAccountID,
585 [&dataStart](AccountID const& accountID) -> Serializer {
586 Serializer s = dataStart;
587 finishMultiSigningData(accountID, s);
588 return s;
589 },
590 rules);
591}
592
593void
595{
596 // Precondition: the template must have been applied first, so the fields
597 // (including sfRawTransactions) are canonical before the inner txns are
598 // hashed. The constructors call this immediately after applying the
599 // template; isFree() being false confirms a template is set.
600 XRPL_ASSERT(!isFree(), "STTx::buildBatchTxns : template applied");
601 if (getTxnType() != ttBATCH)
602 return;
603 // A Batch always seats its inner transactions here, so every downstream
604 // consumer can rely on them. sfRawTransactions is required by the format
605 // (applyTemplate rejects a Batch without it); this guards a future change
606 // that made it optional.
607 if (!isFieldPresent(sfRawTransactions))
608 {
609 // LCOV_EXCL_START
610 UNREACHABLE("STTx::buildBatchTxns : missing RawTransactions");
611 Throw<std::runtime_error>("Batch has no RawTransactions.");
612 // LCOV_EXCL_STOP
613 }
614
615 auto const& raw = getFieldArray(sfRawTransactions);
616 if (raw.size() > kMaxBatchTxCount)
617 Throw<std::runtime_error>("Batch has too many inner transactions.");
618
619 // Build and validate each inner as an STTx once. A malformed inner throws;
620 // a nested batch is rejected before building it (a batch cannot contain a
621 // batch, and building one would recurse).
622 auto& txns = batchTxns_.emplace();
623 txns.reserve(raw.size());
624 for (STObject const& rb : raw)
625 {
626 if (rb.getFieldU16(sfTransactionType) == ttBATCH)
627 Throw<std::runtime_error>("Batch inner transaction cannot be a Batch.");
628
629 txns.push_back(std::make_shared<STTx const>(STObject{rb}));
630 }
631}
632
635{
636 auto const& txns = getBatchTransactions();
638 ids.reserve(txns.size());
639 for (auto const& stx : txns)
640 ids.push_back(stx->getTransactionID());
641 return ids;
642}
643
646{
647 XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::getBatchTransactions : batch transaction");
648 XRPL_ASSERT(batchTxns_.has_value(), "STTx::getBatchTransactions : batch transactions built");
649 XRPL_ASSERT(
650 batchTxns_->size() == getFieldArray(sfRawTransactions).size(),
651 "STTx::getBatchTransactions : batch transactions size mismatch");
652 return *batchTxns_;
653}
654
657{
658 // If sfDelegate is present, the delegate account is the initiator
659 // note: if a delegate is specified, its authorization to act on behalf of the account is
660 // enforced in `Transactor::invokeCheckPermission`
661 // cryptographic signature validity is checked separately (e.g., in `Transactor::checkSign`)
662 if (isFieldPresent(sfDelegate))
663 return getAccountID(sfDelegate);
664
665 // Default initiator
666 return getAccountID(sfAccount);
667}
668
671{
672 if (isFieldPresent(sfSponsor) && ((getFieldU32(sfSponsorFlags) & spfSponsorFee) != 0u))
673 return at(sfSponsor);
674
675 return getInitiator();
676}
677
678//------------------------------------------------------------------------------
679
680static bool
681isMemoOkay(STObject const& st, std::string& reason)
682{
683 if (!st.isFieldPresent(sfMemos))
684 return true;
685
686 auto const& memos = st.getFieldArray(sfMemos);
687
688 // The number 2048 is a preallocation hint, not a hard limit
689 // to avoid allocate/copy/free's
690 Serializer s(2048);
691 memos.add(s);
692
693 // FIXME move the memo limit into a config tunable
694 if (s.getDataLength() > 1024)
695 {
696 reason = "The memo exceeds the maximum allowed size.";
697 return false;
698 }
699
700 for (auto const& memo : memos)
701 {
702 auto memoObj = dynamic_cast<STObject const*>(&memo);
703
704 if ((memoObj == nullptr) || (memoObj->getFName() != sfMemo))
705 {
706 reason = "A memo array may contain only Memo objects.";
707 return false;
708 }
709
710 for (auto const& memoElement : *memoObj)
711 {
712 auto const& name = memoElement.getFName();
713
714 if (name != sfMemoType && name != sfMemoData && name != sfMemoFormat)
715 {
716 reason =
717 "A memo may contain only MemoType, MemoData or "
718 "MemoFormat fields.";
719 return false;
720 }
721
722 // The raw data is stored as hex-octets, which we want to decode.
723 auto optData = strUnHex(memoElement.getText());
724
725 if (!optData)
726 {
727 reason =
728 "The MemoType, MemoData and MemoFormat fields may "
729 "only contain hex-encoded data.";
730 return false;
731 }
732
733 if (name == sfMemoData)
734 continue;
735
736 // The only allowed characters for MemoType and MemoFormat are the
737 // characters allowed in URLs per RFC 3986: alphanumerics and the
738 // following symbols: -._~:/?#[]@!$&'()*+,;=%
739 static constexpr std::array<char, 256> const kAllowedSymbols = []() {
741
742 std::string_view const symbols(
743 "0123456789"
744 "-._~:/?#[]@!$&'()*+,;=%"
745 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
746 "abcdefghijklmnopqrstuvwxyz");
747
748 for (unsigned char const c : symbols)
749 a[c] = 1;
750 return a;
751 }();
752
753 for (unsigned char const c : *optData)
754 {
755 if (kAllowedSymbols[c] == 0)
756 {
757 reason =
758 "The MemoType and MemoFormat fields may only "
759 "contain characters that are allowed in URLs "
760 "under RFC 3986.";
761 return false;
762 }
763 }
764 }
765 }
766
767 return true;
768}
769
770// Ensure all account fields are 160-bits
771static bool
773{
774 for (int i = 0; i < st.getCount(); ++i)
775 {
776 auto t = dynamic_cast<STAccount const*>(st.peekAtPIndex(i));
777 if ((t != nullptr) && t->isDefault())
778 return false;
779 }
780
781 return true;
782}
783
784static bool
786{
787 auto const txType = tx[~sfTransactionType];
788 if (!txType)
789 return false;
790 if (auto const* item = TxFormats::getInstance().findByType(safeCast<TxType>(*txType)))
791 {
792 for (auto const& e : item->getSOTemplate())
793 {
794 if (tx.isFieldPresent(e.sField()) && e.supportMPT() != SoeMptNone)
795 {
796 if (auto const& field = tx.peekAtField(e.sField());
797 (field.getSType() == STI_AMOUNT &&
798 safeDowncast<STAmount const&>(field).holds<MPTIssue>()) ||
799 (field.getSType() == STI_ISSUE &&
800 safeDowncast<STIssue const&>(field).holds<MPTIssue>()))
801 {
802 if (e.supportMPT() != SoeMptSupported)
803 return true;
804 }
805 }
806 }
807 }
808 return false;
809}
810
811static bool
813{
814 XRPL_ASSERT(
815 tx.getTxnType() == ttBATCH || !tx.isFieldPresent(sfRawTransactions),
816 "xrpl::isBatchRawTransactionOkay : raw transactions only on batch");
817
818 if (tx.getTxnType() != ttBATCH)
819 return true;
820
821 if (!tx.isFieldPresent(sfRawTransactions))
822 {
823 // LCOV_EXCL_START
824 reason = "Batch transactions must contain raw transactions.";
825 return false;
826 // LCOV_EXCL_STOP
827 }
828
829 if (tx.isFieldPresent(sfBatchSigners) &&
830 tx.getFieldArray(sfBatchSigners).size() > kMaxBatchSigners)
831 {
832 reason = "BatchSigners array exceeds max entries.";
833 return false;
834 }
835
836 // Inner structure (type, template, no nesting, count) is validated when the
837 // batch STTx is constructed; here we only run each inner's local checks.
838 for (auto const& inner : tx.getBatchTransactions())
839 {
840 if (!passesLocalChecks(*inner, reason))
841 return false;
842 }
843 return true;
844}
845
846bool
848{
849 if (!isMemoOkay(tx, reason))
850 return false;
851
852 if (!isAccountFieldOkay(tx))
853 {
854 reason = "An account field is invalid.";
855 return false;
856 }
857
858 if (isPseudoTx(tx))
859 {
860 reason = "Cannot submit pseudo transactions.";
861 return false;
862 }
863
864 if (invalidMPTAmountInTx(tx))
865 {
866 reason = "Amount can not be MPT.";
867 return false;
868 }
869
870 if (!isBatchRawTransactionOkay(tx, reason))
871 return false;
872
873 return true;
874}
875
877sterilize(STTx const& stx)
878{
879 Serializer s;
880 stx.add(s);
881 SerialIter sit(s.slice());
883}
884
885bool
887{
888 auto const t = tx[~sfTransactionType];
889
890 if (!t)
891 return false;
892
893 auto const tt = safeCast<TxType>(*t);
894
895 return tt == ttAMENDMENT || tt == ttFEE || tt == ttUNL_MODIFY;
896}
897
898} // namespace xrpl
Represents a JSON value.
Definition json_value.h:117
UInt size() const
Number of values in array or object.
Item const * findByType(KeyType type) const
Retrieve a format based on its type.
A public key.
Definition PublicKey.h:53
Rules controlling protocol behavior.
Definition Rules.h:40
size_type size() const
Definition STArray.h:248
A type which can be exported to a well known binary format.
Definition STBase.h:129
static STBase * emplace(std::size_t n, void *buf, T &&val)
Definition STBase.h:226
bool isFree() const
Definition STObject.h:988
T::value_type at(TypedField< T > const &f) const
Get the value of a field.
Definition STObject.h:1078
STBase const * peekAtPIndex(int offset) const
Definition STObject.h:1037
Blob getFieldVL(SField const &field) const
Definition STObject.cpp:649
void addWithoutSigningFields(Serializer &s) const
Definition STObject.h:994
std::uint32_t getFieldU32(SField const &field) const
Definition STObject.cpp:601
void setFieldVL(SField const &field, Blob const &)
Definition STObject.cpp:791
void applyTemplate(SOTemplate const &type)
Definition STObject.cpp:158
uint256 getHash(HashPrefix prefix) const
Definition STObject.cpp:375
std::string getFullText() const override
Definition STObject.cpp:295
STArray const & getFieldArray(SField const &field) const
Definition STObject.cpp:688
STObject & peekFieldObject(SField const &field)
Definition STObject.cpp:475
json::Value getJson(JsonOptions=JsonOptions::Values::None) const override
Definition STObject.cpp:845
void add(Serializer &s) const override
Definition STObject.cpp:123
Serializer getSerializer() const
Definition STObject.h:1003
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:464
STObject(STObject const &)=default
int getCount() const
Definition STObject.h:1019
void setFieldU16(SField const &field, std::uint16_t)
Definition STObject.cpp:737
STBase const & peekAtField(SField const &field) const
Definition STObject.cpp:409
void set(SOTemplate const &)
Definition STObject.cpp:138
uint256 getSigningHash(HashPrefix prefix) const
Definition STObject.cpp:384
STObject getFieldObject(SField const &field) const
Definition STObject.cpp:678
AccountID getAccountID(SField const &field) const
Definition STObject.cpp:643
std::uint16_t getFieldU16(SField const &field) const
Definition STObject.cpp:595
std::uint32_t getFlags() const
Definition STObject.cpp:517
std::string getFullText() const override
Definition STTx.cpp:136
STBase * move(std::size_t n, void *buf) override
Definition STTx.cpp:123
Blob getSignature() const
Definition STTx.h:79
std::string getMetaSQL(std::uint32_t inLedger, std::string const &escapedMetaData) const
Definition STTx.cpp:387
uint256 tid_
Definition STTx.h:42
std::optional< std::vector< std::shared_ptr< STTx const > > > batchTxns_
Definition STTx.h:197
std::expected< void, std::string > checkBatchSign(Rules const &rules) const
Definition STTx.cpp:287
static std::string const & getMetaSQLInsertReplaceHeader()
Definition STTx.cpp:375
std::vector< uint256 > getBatchTransactionIDs() const
The IDs of the inner transactions of a Batch.
Definition STTx.cpp:634
std::expected< void, std::string > checkBatchMultiSign(STObject const &batchSigner, Rules const &rules, std::vector< uint256 > const &txIds) const
Definition STTx.cpp:544
static constexpr std::size_t kMinMultiSigners
Definition STTx.h:46
SeqProxy getSeqProxy() const
Definition STTx.cpp:199
std::expected< void, std::string > checkSign(Rules const &rules) const
Check the signature.
Definition STTx.cpp:257
std::expected< void, std::string > checkBatchSingleSign(STObject const &batchSigner, std::vector< uint256 > const &txIds) const
Definition STTx.cpp:457
STBase * copy(std::size_t n, void *buf) const override
Definition STTx.cpp:117
STTx()=delete
static constexpr std::size_t kMaxMultiSigners
Definition STTx.h:47
std::expected< void, std::string > checkSingleSign(STObject const &sigObject) const
Definition STTx.cpp:450
std::expected< void, std::string > checkMultiSign(Rules const &rules, STObject const &sigObject) const
Definition STTx.cpp:569
void buildBatchTxns()
Definition STTx.cpp:594
TxType getTxnType() const
Definition STTx.h:226
AccountID getFeePayerID() const
Definition STTx.cpp:670
uint256 getSigningHash() const
Definition STTx.cpp:180
TxType txType_
Definition STTx.h:43
json::Value getJson(JsonOptions options) const override
Definition STTx.cpp:338
AccountID getInitiator() const
The account responsible for the authorization: the delegate when sfDelegate is present,...
Definition STTx.cpp:656
uint256 getTransactionID() const
Definition STTx.h:238
SerializedTypeID getSType() const override
Definition STTx.cpp:130
boost::container::flat_set< AccountID > getMentionedAccounts() const
Definition STTx.cpp:147
void sign(PublicKey const &publicKey, SecretKey const &secretKey, std::optional< std::reference_wrapper< SField const > > signatureTarget={})
Definition STTx.cpp:216
std::vector< std::shared_ptr< STTx const > > const & getBatchTransactions() const
The inner transactions of a Batch, built and validated at construction.
Definition STTx.cpp:645
A secret key.
Definition SecretKey.h:24
A type that represents either a sequence value or a ticket value.
Definition SeqProxy.h:37
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition SeqProxy.h:62
static constexpr SeqProxy rawTicket(std::uint32_t v)
Factory function to return a ticket-based SeqProxy.
Definition SeqProxy.h:74
int getBytesLeft() const noexcept
Definition Serializer.h:340
Blob const & peekData() const
Definition Serializer.h:177
int addBitString(BaseUInt< Bits, Tag > const &v)
Definition Serializer.h:106
Slice slice() const noexcept
Definition Serializer.h:45
Blob getData() const
Definition Serializer.h:182
int getDataLength() const
Definition Serializer.h:193
An immutable linear range of bytes.
Definition Slice.h:28
static TxFormats const & getInstance()
Definition TxFormats.cpp:60
T empty(T... args)
T format(T... args)
T make_shared(T... args)
constexpr Zero kZero
Definition Zero.h:30
@ Object
object value (collection of name/value pairs).
Definition json_value.h:29
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr FlagValue spfSponsorFee
Definition TxFlags.h:459
Serializer startMultiSigningData(STObject const &obj)
Break the multi-signing hash computation into 2 parts for optimization.
constexpr std::size_t kMaxBatchSigners
The maximum number of batch signers.
Definition Protocol.h:448
Dest safeDowncast(Src *s) noexcept
Definition safe_cast.h:84
TxType
Transaction type identifiers.
Definition TxFormats.h:45
bool isXRP(AccountID const &c)
Definition AccountID.h:84
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:13
constexpr std::size_t kMaxBatchTxCount
The maximum number of transactions that can be in a batch.
Definition Protocol.h:443
constexpr std::size_t kTxMinSizeBytes
Protocol specific constants.
Definition Protocol.h:32
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
static bool isBatchRawTransactionOkay(STTx const &tx, std::string &reason)
Definition STTx.cpp:812
static bool isMemoOkay(STObject const &st, std::string &reason)
Definition STTx.cpp:681
constexpr Dest safeCast(Src s) noexcept
Definition safe_cast.h:21
static auto getTxFormat(TxType type)
Definition STTx.cpp:56
TxnSql
Definition STTx.h:31
@ Validated
Definition STTx.h:35
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
void logicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
static bool isAccountFieldOkay(STObject const &st)
Definition STTx.cpp:772
bool passesLocalChecks(STTx const &tx, std::string &)
Definition STTx.cpp:847
Slice makeSlice(std::array< T, N > const &a)
Definition Slice.h:228
void finishMultiSigningData(AccountID const &signingID, Serializer &s)
Definition Sign.h:73
static std::expected< void, std::string > singleSignHelper(STObject const &sigObject, Slice const &data)
Definition STTx.cpp:420
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
SerializedTypeID
Definition SField.h:94
static bool invalidMPTAmountInTx(STObject const &tx)
Definition STTx.cpp:785
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:34
@ TxSign
inner transaction to sign
Definition HashPrefix.h:64
@ TransactionId
transaction plus signature to give transaction ID
Definition HashPrefix.h:39
std::string sqlBlobLiteral(Blob const &blob)
Format arbitrary binary data as an SQLite "blob literal".
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
static Blob getSigningData(STTx const &that)
Definition STTx.cpp:171
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:11
@ SoeMptNone
Definition SOTemplate.h:34
@ SoeMptSupported
Definition SOTemplate.h:34
std::shared_ptr< STTx const > sterilize(STTx const &stx)
Sterilize a transaction.
Definition STTx.cpp:877
void serializeBatch(Serializer &msg, AccountID const &outerAccount, std::uint32_t outerSeqValue, std::uint32_t const &flags, std::vector< uint256 > const &txids)
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition STTx.cpp:886
BaseUInt< 256 > uint256
Definition base_uint.h:580
std::expected< void, std::string > multiSignHelper(STObject const &sigObject, std::optional< AccountID > txnAccountID, std::function< Serializer(AccountID const &)> makeMsg, Rules const &rules)
Definition STTx.cpp:467
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:52
constexpr std::size_t kTxMaxSizeBytes
Largest legal byte size of a transaction.
Definition Protocol.h:37
T push_back(T... args)
T ref(T... args)
T reserve(T... args)
Note, should be treated as flags that can be | and &.
Definition STBase.h:22
T to_string(T... args)
T unexpected(T... args)
T what(T... args)