20#include <xrpl/basics/Blob.h>
21#include <xrpl/basics/Expected.h>
22#include <xrpl/basics/Log.h>
23#include <xrpl/basics/Slice.h>
24#include <xrpl/basics/StringUtilities.h>
25#include <xrpl/basics/base_uint.h>
26#include <xrpl/basics/contract.h>
27#include <xrpl/basics/safe_cast.h>
28#include <xrpl/basics/strHex.h>
29#include <xrpl/beast/utility/Zero.h>
30#include <xrpl/beast/utility/instrumentation.h>
31#include <xrpl/json/json_value.h>
32#include <xrpl/protocol/AccountID.h>
33#include <xrpl/protocol/Batch.h>
34#include <xrpl/protocol/HashPrefix.h>
35#include <xrpl/protocol/MPTIssue.h>
36#include <xrpl/protocol/Protocol.h>
37#include <xrpl/protocol/PublicKey.h>
38#include <xrpl/protocol/Rules.h>
39#include <xrpl/protocol/SField.h>
40#include <xrpl/protocol/SOTemplate.h>
41#include <xrpl/protocol/STAccount.h>
42#include <xrpl/protocol/STAmount.h>
43#include <xrpl/protocol/STArray.h>
44#include <xrpl/protocol/STBase.h>
45#include <xrpl/protocol/STObject.h>
46#include <xrpl/protocol/STTx.h>
47#include <xrpl/protocol/STVector256.h>
48#include <xrpl/protocol/SecretKey.h>
49#include <xrpl/protocol/SeqProxy.h>
50#include <xrpl/protocol/Serializer.h>
51#include <xrpl/protocol/Sign.h>
52#include <xrpl/protocol/TxFlags.h>
53#include <xrpl/protocol/TxFormats.h>
54#include <xrpl/protocol/jss.h>
56#include <boost/container/flat_set.hpp>
57#include <boost/format/format_fwd.hpp>
58#include <boost/format/free_funcs.hpp>
80 if (format ==
nullptr)
82 Throw<std::runtime_error>(
83 "Invalid transaction type " +
102 Throw<std::runtime_error>(
"Transaction length invalid");
105 Throw<std::runtime_error>(
"Transaction contains an object terminator");
118 set(format->getSOTemplate());
126 LogicError(
"Transaction type was mutated during assembly");
140 return emplace(n, buf, std::move(*
this));
147 return STI_TRANSACTION;
161boost::container::flat_set<AccountID>
164 boost::container::flat_set<AccountID> list;
166 for (
auto const& it : *
this)
168 if (
auto sacc =
dynamic_cast<STAccount const*
>(&it))
172 "ripple::STTx::getMentionedAccounts : account is set");
173 if (!sacc->isDefault())
174 list.insert(sacc->value());
176 else if (
auto samt =
dynamic_cast<STAmount const*
>(&it))
178 auto const& issuer = samt->getIssuer();
249 target.setFieldVL(sfTxnSignature, sig);
270 Blob const& signingPubKey = sigObject.
getFieldVL(sfSigningPubKey);
271 return signingPubKey.
empty()
278 return Unexpected(
"Internal signature check failure.");
284 Rules const& rules)
const
286 if (
auto const ret =
checkSign(requireCanonicalSig, rules, *
this); !ret)
304 Rules const& rules)
const
310 "STTx::checkBatchSign : not a batch transaction");
313 JLOG(
debugLog().fatal()) <<
"not a batch transaction";
314 return Unexpected(
"Not a batch transaction.");
317 for (
auto const& signer : signers)
319 Blob const& signingPubKey = signer.getFieldVL(sfSigningPubKey);
320 auto const result = signingPubKey.
empty()
332 <<
"Batch signature check failed: " << e.
what();
334 return Unexpected(
"Internal batch signature check failure.");
359 ret[jss::tx] = dataBin;
378 "INSERT OR REPLACE INTO Transactions "
379 "(TransID, TransType, FromAcct, FromSeq, LedgerSeq, Status, RawTxn, "
403 static boost::format bfTrans(
404 "('%s', '%s', '%s', '%d', '%d', '%c', %s, %s)");
408 XRPL_ASSERT(format,
"ripple::STTx::getMetaSQL : non-null type format");
413 getFieldU32(sfSequence) % inLedger % status % rTxn % escapedMetaData);
426 return Unexpected(
"Cannot both single- and multi-sign.");
428 bool validSig =
false;
431 auto const spk = sigObject.
getFieldVL(sfSigningPubKey);
453Expected<void, std::string>
492 return Unexpected(
"Cannot both single- and multi-sign.");
499 return Unexpected(
"Invalid Signers array size.");
504 for (
auto const& signer : signers)
506 auto const accountID = signer.getAccountID(sfAccount);
511 if (txnAccountID == accountID)
515 if (lastAccountID == accountID)
516 return Unexpected(
"Duplicate Signers not allowed.");
519 if (lastAccountID > accountID)
523 lastAccountID = accountID;
526 bool validSig =
false;
530 auto spk = signer.getFieldVL(sfSigningPubKey);
533 Blob const signature = signer.getFieldVL(sfTxnSignature);
536 makeMsg(accountID).slice(),
545 errorWhat = e.
what();
556Expected<void, std::string>
560 Rules const& rules)
const
593 auto const txnAccountID = &sigObject !=
this
633 "STTx::getBatchTransactionIDs : not a batch transaction");
636 "STTx::getBatchTransactionIDs : empty raw transactions");
649 "STTx::getBatchTransactionIDs : batch transaction IDs size mismatch");
671 reason =
"The memo exceeds the maximum allowed size.";
675 for (
auto const& memo : memos)
677 auto memoObj =
dynamic_cast<STObject const*
>(&memo);
679 if (!memoObj || (memoObj->getFName() != sfMemo))
681 reason =
"A memo array may contain only Memo objects.";
685 for (
auto const& memoElement : *memoObj)
687 auto const& name = memoElement.getFName();
689 if (name != sfMemoType && name != sfMemoData &&
690 name != sfMemoFormat)
693 "A memo may contain only MemoType, MemoData or "
694 "MemoFormat fields.";
699 auto optData =
strUnHex(memoElement.getText());
704 "The MemoType, MemoData and MemoFormat fields may "
705 "only contain hex-encoded data.";
709 if (name == sfMemoData)
720 "-._~:/?#[]@!$&'()*+,;=%"
721 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
722 "abcdefghijklmnopqrstuvwxyz");
724 for (
unsigned char c : symbols)
729 for (
unsigned char c : *optData)
731 if (!allowedSymbols[c])
734 "The MemoType and MemoFormat fields may only "
735 "contain characters that are allowed in URLs "
750 for (
int i = 0; i < st.
getCount(); ++i)
753 if (t && t->isDefault())
763 auto const txType = tx[~sfTransactionType];
766 if (
auto const* item =
769 for (
auto const& e : item->getSOTemplate())
773 if (
auto const& field = tx.
peekAtField(e.sField());
774 (field.getSType() == STI_AMOUNT &&
775 static_cast<STAmount const&
>(field).holds<MPTIssue>()) ||
776 (field.getSType() == STI_ISSUE &&
777 static_cast<STIssue const&
>(field).holds<MPTIssue>()))
797 reason =
"Batch Signers array exceeds max entries.";
804 reason =
"Raw Transactions array exceeds max entries.";
812 safe_cast<TxType>(raw.getFieldU16(sfTransactionType));
815 reason =
"Raw Transactions may not contain batch transactions.";
819 raw.applyTemplate(
getTxFormat(tt)->getSOTemplate());
838 reason =
"An account field is invalid.";
844 reason =
"Cannot submit pseudo transactions.";
850 reason =
"Amount can not be MPT.";
872 auto const t = tx[~sfTransactionType];
877 auto const tt = safe_cast<TxType>(*t);
879 return tt == ttAMENDMENT || tt == ttFEE || tt == ttUNL_MODIFY;
Rules controlling protocol behavior.
A type which can be exported to a well known binary format.
static STBase * emplace(std::size_t n, void *buf, T &&val)
void applyTemplate(SOTemplate const &type)
Blob getFieldVL(SField const &field) const
AccountID getAccountID(SField const &field) const
STArray const & getFieldArray(SField const &field) const
STBase const * peekAtPIndex(int offset) const
std::uint16_t getFieldU16(SField const &field) const
std::uint32_t getFieldU32(SField const &field) const
STObject & peekFieldObject(SField const &field)
void setFieldU16(SField const &field, std::uint16_t)
Serializer getSerializer() const
void set(SOTemplate const &)
void add(Serializer &s) const override
uint256 getSigningHash(HashPrefix prefix) const
T::value_type operator[](TypedField< T > const &f) const
Get the value of a field.
uint256 getHash(HashPrefix prefix) const
std::string getFullText() const override
bool isFieldPresent(SField const &field) const
Json::Value getJson(JsonOptions=JsonOptions::none) const override
STBase const & peekAtField(SField const &field) const
void addWithoutSigningFields(Serializer &s) const
void setFieldVL(SField const &field, Blob const &)
std::uint32_t getFlags() const
boost::container::flat_set< AccountID > getMentionedAccounts() const
uint256 getSigningHash() const
static std::string const & getMetaSQLInsertReplaceHeader()
std::vector< uint256 > batchTxnIds_
Expected< void, std::string > checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig, STObject const &sigObject) const
SeqProxy getSeqProxy() const
Json::Value getJson(JsonOptions options) const override
Expected< void, std::string > checkBatchSingleSign(STObject const &batchSigner, RequireFullyCanonicalSig requireCanonicalSig) const
std::vector< uint256 > const & getBatchTransactionIDs() const
Retrieves a batch of transaction IDs from the STTx.
STBase * move(std::size_t n, void *buf) override
static std::size_t const minMultiSigners
Expected< void, std::string > checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const &rules) const
Check the signature.
static std::size_t maxMultiSigners(Rules const *rules=0)
Expected< void, std::string > checkBatchMultiSign(STObject const &batchSigner, RequireFullyCanonicalSig requireCanonicalSig, Rules const &rules) const
Blob getSignature() const
std::uint32_t getSeqValue() const
Returns the first non-zero value of (Sequence, TicketSequence).
void sign(PublicKey const &publicKey, SecretKey const &secretKey, std::optional< std::reference_wrapper< SField const > > signatureTarget={})
TxType getTxnType() const
std::string getMetaSQL(std::uint32_t inLedger, std::string const &escapedMetaData) const
uint256 getTransactionID() const
Expected< void, std::string > checkMultiSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const &rules, STObject const &sigObject) const
SerializedTypeID getSType() const override
std::string getFullText() const override
Expected< void, std::string > checkBatchSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const &rules) const
STBase * copy(std::size_t n, void *buf) const override
A type that represents either a sequence value or a ticket value.
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
constexpr std::uint32_t value() const
int getBytesLeft() const noexcept
Slice slice() const noexcept
Blob const & peekData() const
int getDataLength() const
An immutable linear range of bytes.
@ objectValue
object value (collection of name/value pairs).
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::shared_ptr< STTx const > sterilize(STTx const &stx)
Sterilize a transaction.
bool isXRP(AccountID const &c)
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
static bool isAccountFieldOkay(STObject const &st)
void finishMultiSigningData(AccountID const &signingID, Serializer &s)
TxType
Transaction type identifiers.
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Serializer startMultiSigningData(STObject const &obj)
Break the multi-signing hash computation into 2 parts for optimization.
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical=true) noexcept
Verify a signature on a message.
static bool isMemoOkay(STObject const &st, std::string &reason)
static bool isRawTransactionOkay(STObject const &st, std::string &reason)
void serializeBatch(Serializer &msg, std::uint32_t const &flags, std::vector< uint256 > const &txids)
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safe_cast(Src s) noexcept
std::size_t constexpr txMinSizeBytes
Protocol specific constants.
static auto getTxFormat(TxType type)
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
static bool invalidMPTAmountInTx(STObject const &tx)
std::string sqlBlobLiteral(Blob const &blob)
Format arbitrary binary data as an SQLite "blob literal".
std::string strHex(FwdIt begin, FwdIt end)
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)
beast::Journal debugLog()
Returns a debug journal.
std::vector< unsigned char > Blob
Storage for linear binary data.
static Blob getSigningData(STTx const &that)
bool passesLocalChecks(STObject const &st, std::string &)
std::size_t constexpr txMaxSizeBytes
Largest legal byte size of a transaction.
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t tfFullyCanonicalSig
Transaction flags.
Expected< void, std::string > multiSignHelper(STObject const &sigObject, std::optional< AccountID > txnAccountID, bool const fullyCanonical, std::function< Serializer(AccountID const &)> makeMsg, Rules const &rules)
@ txSign
inner transaction to sign
@ transactionID
transaction plus signature to give transaction ID
std::size_t constexpr maxBatchTxCount
The maximum number of transactions that can be in a batch.
static Expected< void, std::string > singleSignHelper(STObject const &sigObject, Slice const &data, bool const fullyCanonical)
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Note, should be treated as flags that can be | and &.