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