mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-12 15:02:32 +00:00
Signed-off-by: JCW <a1q123456@users.noreply.github.com> Co-authored-by: Bart <bthomee@users.noreply.github.com>
458 lines
12 KiB
C++
458 lines
12 KiB
C++
#pragma once
|
|
|
|
#include <xrpl/protocol/SField.h>
|
|
#include <xrpl/protocol/STAccount.h>
|
|
#include <xrpl/protocol/STArray.h>
|
|
#include <xrpl/protocol/STObject.h>
|
|
#include <xrpl/protocol/STTx.h>
|
|
#include <xrpl/protocol/TxFormats.h>
|
|
#include <xrpl/protocol_autogen/STObjectValidation.h>
|
|
#include <xrpl/protocol_autogen/Utils.h>
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
|
|
namespace xrpl::transactions {
|
|
|
|
/**
|
|
* @brief Base class for all transaction wrapper types.
|
|
*
|
|
* Provides type-safe read-only accessors for common transaction fields.
|
|
* This is an immutable wrapper around STTx. Use the corresponding Builder classes
|
|
* to construct new transactions.
|
|
*/
|
|
class TransactionBase
|
|
{
|
|
public:
|
|
/**
|
|
* @brief Construct a transaction wrapper from an existing STTx object.
|
|
* @param tx The underlying transaction object to wrap
|
|
*/
|
|
explicit TransactionBase(std::shared_ptr<STTx const> tx) : tx_(std::move(tx))
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @brief Validate the transaction
|
|
* @return true if validation passes, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
validate(std::string& reason) const
|
|
{
|
|
if (!protocol_autogen::validateSTObject(
|
|
*tx_, TxFormats::getInstance().findByType(tx_->getTxnType())->getSOTemplate()))
|
|
{
|
|
// LCOV_EXCL_START
|
|
reason = "Transaction failed schema validation";
|
|
return false;
|
|
// LCOV_EXCL_STOP
|
|
}
|
|
|
|
// Pseudo transactions are not submitted to the network
|
|
if (isPseudoTx(*tx_))
|
|
{
|
|
return true;
|
|
}
|
|
return passesLocalChecks(*tx_, reason);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the transaction type.
|
|
* @return The type of this transaction
|
|
*/
|
|
[[nodiscard]]
|
|
xrpl::TxType
|
|
getTransactionType() const
|
|
{
|
|
return tx_->getTxnType();
|
|
}
|
|
|
|
/**
|
|
* @brief Get the account initiating the transaction (sfAccount).
|
|
*
|
|
* This field is REQUIRED for all transactions.
|
|
* @return The account ID of the transaction sender
|
|
*/
|
|
[[nodiscard]]
|
|
AccountID
|
|
getAccount() const
|
|
{
|
|
return tx_->at(sfAccount);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the sequence number of the transaction (sfSequence).
|
|
*
|
|
* This field is REQUIRED for all transactions.
|
|
* @return The sequence number
|
|
*/
|
|
[[nodiscard]]
|
|
std::uint32_t
|
|
getSequence() const
|
|
{
|
|
return tx_->at(sfSequence);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the transaction fee (sfFee).
|
|
*
|
|
* This field is REQUIRED for all transactions.
|
|
* @return The fee amount
|
|
*/
|
|
[[nodiscard]]
|
|
STAmount
|
|
getFee() const
|
|
{
|
|
return tx_->at(sfFee);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the signing public key (sfSigningPubKey).
|
|
*
|
|
* This field is REQUIRED for all transactions.
|
|
* @return The public key used for signing as a blob
|
|
*/
|
|
[[nodiscard]]
|
|
Blob
|
|
getSigningPubKey() const
|
|
{
|
|
return tx_->getFieldVL(sfSigningPubKey);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the transaction flags (sfFlags).
|
|
*
|
|
* This field is OPTIONAL.
|
|
* @return The flags value if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<uint32_t>
|
|
getFlags() const
|
|
{
|
|
if (tx_->isFieldPresent(sfFlags))
|
|
return tx_->at(sfFlags);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has flags set.
|
|
* @return true if sfFlags is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasFlags() const
|
|
{
|
|
return tx_->isFieldPresent(sfFlags);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the source tag (sfSourceTag).
|
|
*
|
|
* This field is OPTIONAL and used to identify the source of a payment.
|
|
* @return The source tag value if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<uint32_t>
|
|
getSourceTag() const
|
|
{
|
|
if (tx_->isFieldPresent(sfSourceTag))
|
|
return tx_->at(sfSourceTag);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has a source tag.
|
|
* @return true if sfSourceTag is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasSourceTag() const
|
|
{
|
|
return tx_->isFieldPresent(sfSourceTag);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the previous transaction ID (sfPreviousTxnID).
|
|
*
|
|
* This field is OPTIONAL and used for transaction chaining.
|
|
* @return The previous transaction ID if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<uint256>
|
|
getPreviousTxnID() const
|
|
{
|
|
if (tx_->isFieldPresent(sfPreviousTxnID))
|
|
return tx_->at(sfPreviousTxnID);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has a previous transaction ID.
|
|
* @return true if sfPreviousTxnID is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasPreviousTxnID() const
|
|
{
|
|
return tx_->isFieldPresent(sfPreviousTxnID);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the last ledger sequence (sfLastLedgerSequence).
|
|
*
|
|
* This field is OPTIONAL and specifies the latest ledger sequence
|
|
* in which this transaction can be included.
|
|
* @return The last ledger sequence if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<uint32_t>
|
|
getLastLedgerSequence() const
|
|
{
|
|
if (tx_->isFieldPresent(sfLastLedgerSequence))
|
|
return tx_->at(sfLastLedgerSequence);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has a last ledger sequence.
|
|
* @return true if sfLastLedgerSequence is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasLastLedgerSequence() const
|
|
{
|
|
return tx_->isFieldPresent(sfLastLedgerSequence);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the account transaction ID (sfAccountTxnID).
|
|
*
|
|
* This field is OPTIONAL and used to track transaction sequences.
|
|
* @return The account transaction ID if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<uint256>
|
|
getAccountTxnID() const
|
|
{
|
|
if (tx_->isFieldPresent(sfAccountTxnID))
|
|
return tx_->at(sfAccountTxnID);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has an account transaction ID.
|
|
* @return true if sfAccountTxnID is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasAccountTxnID() const
|
|
{
|
|
return tx_->isFieldPresent(sfAccountTxnID);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the operation limit (sfOperationLimit).
|
|
*
|
|
* This field is OPTIONAL and limits the number of operations in a transaction.
|
|
* @return The operation limit if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<uint32_t>
|
|
getOperationLimit() const
|
|
{
|
|
if (tx_->isFieldPresent(sfOperationLimit))
|
|
return tx_->at(sfOperationLimit);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has an operation limit.
|
|
* @return true if sfOperationLimit is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasOperationLimit() const
|
|
{
|
|
return tx_->isFieldPresent(sfOperationLimit);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the memos array (sfMemos).
|
|
*
|
|
* This field is OPTIONAL and contains arbitrary data attached to the transaction.
|
|
* @note This is an untyped field (STArray).
|
|
* @return A reference wrapper to the memos array if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<std::reference_wrapper<STArray const>>
|
|
getMemos() const
|
|
{
|
|
if (tx_->isFieldPresent(sfMemos))
|
|
return tx_->getFieldArray(sfMemos);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has memos.
|
|
* @return true if sfMemos is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasMemos() const
|
|
{
|
|
return tx_->isFieldPresent(sfMemos);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the ticket sequence (sfTicketSequence).
|
|
*
|
|
* This field is OPTIONAL and used when consuming a ticket instead of a sequence number.
|
|
* @return The ticket sequence if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<uint32_t>
|
|
getTicketSequence() const
|
|
{
|
|
if (tx_->isFieldPresent(sfTicketSequence))
|
|
return tx_->at(sfTicketSequence);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has a ticket sequence.
|
|
* @return true if sfTicketSequence is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasTicketSequence() const
|
|
{
|
|
return tx_->isFieldPresent(sfTicketSequence);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the transaction signature (sfTxnSignature).
|
|
*
|
|
* This field is OPTIONAL and contains the signature for single-signed transactions.
|
|
* @return The transaction signature as a blob if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<Blob>
|
|
getTxnSignature() const
|
|
{
|
|
if (tx_->isFieldPresent(sfTxnSignature))
|
|
return tx_->getFieldVL(sfTxnSignature);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has a transaction signature.
|
|
* @return true if sfTxnSignature is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasTxnSignature() const
|
|
{
|
|
return tx_->isFieldPresent(sfTxnSignature);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the signers array (sfSigners).
|
|
*
|
|
* This field is OPTIONAL and contains the list of signers for multi-signed transactions.
|
|
* @note This is an untyped field (STArray).
|
|
* @return A reference wrapper to the signers array if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<std::reference_wrapper<STArray const>>
|
|
getSigners() const
|
|
{
|
|
if (tx_->isFieldPresent(sfSigners))
|
|
return tx_->getFieldArray(sfSigners);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has signers.
|
|
* @return true if sfSigners is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasSigners() const
|
|
{
|
|
return tx_->isFieldPresent(sfSigners);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the network ID (sfNetworkID).
|
|
*
|
|
* This field is OPTIONAL and identifies the network this transaction is intended for.
|
|
* @return The network ID if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<uint32_t>
|
|
getNetworkID() const
|
|
{
|
|
if (tx_->isFieldPresent(sfNetworkID))
|
|
return tx_->at(sfNetworkID);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has a network ID.
|
|
* @return true if sfNetworkID is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasNetworkID() const
|
|
{
|
|
return tx_->isFieldPresent(sfNetworkID);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the delegate account (sfDelegate).
|
|
*
|
|
* This field is OPTIONAL and specifies a delegate account for the transaction.
|
|
* @return The delegate account ID if present, std::nullopt otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
std::optional<AccountID>
|
|
getDelegate() const
|
|
{
|
|
if (tx_->isFieldPresent(sfDelegate))
|
|
return tx_->at(sfDelegate);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* @brief Check if the transaction has a delegate account.
|
|
* @return true if sfDelegate is present, false otherwise
|
|
*/
|
|
[[nodiscard]]
|
|
bool
|
|
hasDelegate() const
|
|
{
|
|
return tx_->isFieldPresent(sfDelegate);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the underlying STTx object.
|
|
*
|
|
* Provides direct access to the wrapped transaction object for cases
|
|
* where the type-safe accessors are insufficient.
|
|
* @return A constant reference to the underlying STTx object
|
|
*/
|
|
[[nodiscard]]
|
|
std::shared_ptr<STTx const>
|
|
getSTTx() const
|
|
{
|
|
return tx_;
|
|
}
|
|
|
|
protected:
|
|
/** @brief The underlying transaction object being wrapped. */
|
|
std::shared_ptr<STTx const> tx_;
|
|
};
|
|
|
|
} // namespace xrpl::transactions
|