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 &.