#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { class ServiceRegistry; class STTx; class TxQ; struct ApplyResult { TER ter; bool applied; std::optional metadata; ApplyResult(TER t, bool a, std::optional m = std::nullopt) : ter(t), applied(a), metadata(std::move(m)) { } }; /** * Return true if the transaction can claim a fee (tec), * and the `ApplyFlags` do not allow soft failures. */ inline bool isTecClaimHardFail(TER ter, ApplyFlags flags) { return isTecClaim(ter) && ((flags & TapRetry) == 0u); } /** * Class describing the consequences to the account * of applying a transaction if the transaction consumes * the maximum XRP allowed. */ class TxConsequences { public: /** * Describes how the transaction affects subsequent * transactions */ enum class Category { /** * Moves currency around, creates offers, etc. */ Normal = 0, /** * Affects the ability of subsequent transactions * to claim a fee. Eg. `SetRegularKey` */ Blocker }; private: /** * Describes how the transaction affects subsequent * transactions */ bool isBlocker_; /** * Transaction fee */ XRPAmount fee_; /** * Does NOT include the fee. */ XRPAmount potentialSpend_; /** * SeqProxy of transaction. */ SeqProxy seqProx_; /** * Number of sequences consumed. */ std::uint32_t sequencesConsumed_; public: // Constructor if preflight returns a value other than tesSUCCESS. // Asserts if tesSUCCESS is passed. explicit TxConsequences(NotTEC pfResult); /** * Constructor if the STTx has no notable consequences for the TxQ. */ explicit TxConsequences(STTx const& tx); /** * Constructor for a blocker. */ TxConsequences(STTx const& tx, Category category); /** * Constructor for an STTx that may consume more XRP than the fee. */ TxConsequences(STTx const& tx, XRPAmount potentialSpend); /** * Constructor for an STTx that consumes more than the usual sequences. */ TxConsequences(STTx const& tx, std::uint32_t sequencesConsumed); /** * Copy constructor */ TxConsequences(TxConsequences const&) = default; /** * Copy assignment operator */ TxConsequences& operator=(TxConsequences const&) = default; /** * Move constructor */ TxConsequences(TxConsequences&&) = default; /** * Move assignment operator */ TxConsequences& operator=(TxConsequences&&) = default; /** * Fee */ [[nodiscard]] XRPAmount fee() const { return fee_; } /** * Potential Spend */ [[nodiscard]] XRPAmount const& potentialSpend() const { return potentialSpend_; } /** * SeqProxy */ [[nodiscard]] SeqProxy seqProxy() const { return seqProx_; } /** * Sequences consumed */ [[nodiscard]] std::uint32_t sequencesConsumed() const { return sequencesConsumed_; } /** * Returns true if the transaction is a blocker. */ [[nodiscard]] bool isBlocker() const { return isBlocker_; } // Return the SeqProxy that would follow this. [[nodiscard]] SeqProxy followingSeq() const { SeqProxy following = seqProx_; following.advanceBy(sequencesConsumed()); return following; } }; /** * Describes the results of the `preflight` check * * @note All members are const to make it more difficult * to "fake" a result without calling `preflight`. * @see preflight, preclaim, doApply, apply */ struct PreflightResult { public: /** * From the input - the transaction */ STTx const& tx; /** * From the input - the batch identifier, if part of a batch */ std::optional const parentBatchId; /** * From the input - the rules */ Rules const rules; /** * Consequences of the transaction */ TxConsequences const consequences; /** * From the input - the flags */ ApplyFlags const flags; /** * From the input - the journal */ beast::Journal const j; /** * Intermediate transaction result */ NotTEC const ter; /** * Constructor */ template PreflightResult(Context const& ctx, std::pair const& result) : tx(ctx.tx) , parentBatchId(ctx.parentBatchId) , rules(ctx.rules) , consequences(result.second) , flags(ctx.flags) , j(ctx.j) , ter(result.first) { } PreflightResult(PreflightResult const&) = default; /** * Deleted copy assignment operator */ PreflightResult& operator=(PreflightResult const&) = delete; }; /** * Describes the results of the `preclaim` check * * @note All members are const to make it more difficult * to "fake" a result without calling `preclaim`. * @see preflight, preclaim, doApply, apply */ struct PreclaimResult { public: /** * From the input - the ledger view */ ReadView const& view; /** * From the input - the transaction */ STTx const& tx; /** * From the input - the batch identifier, if part of a batch */ std::optional const parentBatchId; /** * From the input - the flags */ ApplyFlags const flags; /** * From the input - the journal */ beast::Journal const j; /** * Intermediate transaction result */ TER const ter; /** * Success flag - whether the transaction is likely to * claim a fee */ bool const likelyToClaimFee{}; /** * Constructor */ template PreclaimResult(Context const& ctx, TER ter) : view(ctx.view) , tx(ctx.tx) , parentBatchId(ctx.parentBatchId) , flags(ctx.flags) , j(ctx.j) , ter(ter) , likelyToClaimFee(isTesSuccess(ter) || isTecClaimHardFail(ter, flags)) { } PreclaimResult(PreclaimResult const&) = default; /** * Deleted copy assignment operator */ PreclaimResult& operator=(PreclaimResult const&) = delete; }; /** * Gate a transaction based on static information. * * The transaction is checked against all possible * validity constraints that do not require a ledger. * * @param app The current running `Application`. * @param rules The `Rules` in effect at the time of the check. * @param tx The transaction to be checked. * @param flags `ApplyFlags` describing processing options. * @param j A journal. * * @see PreflightResult, preclaim, doApply, apply * * @return A `PreflightResult` object containing, among * other things, the `TER` code. */ /** @{ */ PreflightResult preflight( ServiceRegistry& registry, Rules const& rules, STTx const& tx, ApplyFlags flags, beast::Journal j); PreflightResult preflight( ServiceRegistry& registry, Rules const& rules, uint256 const& parentBatchId, STTx const& tx, ApplyFlags flags, beast::Journal j); /** @} */ /** * Gate a transaction based on static ledger information. * * The transaction is checked against all possible * validity constraints that DO require a ledger. * * If preclaim succeeds, then the transaction is very * likely to claim a fee. This will determine if the * transaction is safe to relay without being applied * to the open ledger. * * "Succeeds" in this case is defined as returning a * `tes` or `tec`, since both lead to claiming a fee. * * @pre The transaction has been checked * and validated using `preflight` * * @param preflightResult The result of a previous * call to `preflight` for the transaction. * @param app The current running `Application`. * @param view The open ledger that the transaction * will attempt to be applied to. * * @see PreclaimResult, preflight, doApply, apply * * @return A `PreclaimResult` object containing, among * other things the `TER` code and the base fee value for * this transaction. */ PreclaimResult preclaim(PreflightResult const& preflightResult, ServiceRegistry& registry, OpenView const& view); /** * Compute only the expected base fee for a transaction. * * Base fees are transaction specific, so any calculation * needing them must get the base fee for each transaction. * * No validation is done or implied by this function. * * Caller is responsible for handling any exceptions. * Since none should be thrown, that will usually * mean terminating. * * @param view The current open ledger. * @param tx The transaction to be checked. * * @return The base fee. */ XRPAmount calculateBaseFee(ReadView const& view, STTx const& tx); /** * Return the minimum fee that an "ordinary" transaction would pay. * * When computing the FeeLevel for a transaction the TxQ sometimes needs * the know what an "ordinary" or reference transaction would be required * to pay. * * @param view The current open ledger. * @param tx The transaction so the correct multisigner count is used. * * @return The base fee in XRPAmount. */ XRPAmount calculateDefaultBaseFee(ReadView const& view, STTx const& tx); /** * Apply a prechecked transaction to an OpenView. * * @pre The transaction has been checked * and validated using `preflight` and `preclaim` * * @param preclaimResult The result of a previous * call to `preclaim` for the transaction. * @param registry The service registry. * @param view The open ledger that the transaction * will attempt to be applied to. * * @see preflight, preclaim, apply * * @return A pair with the `TER` and a `bool` indicating * whether or not the transaction was applied. */ ApplyResult doApply(PreclaimResult const& preclaimResult, ServiceRegistry& registry, OpenView& view); } // namespace xrpl