mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-22 06:40:53 +00:00
Merge remote-tracking branch 'origin/develop' into FN-36-credential_pins_pseudo_account
# Conflicts: # src/test/app/lending/LoanBroker_test.cpp
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -198,7 +199,10 @@ dirLink(
|
||||
* if withdrawing to self.
|
||||
* - If withdrawing to self, succeed.
|
||||
* - If not, checks if the receiver requires deposit authorization, and if
|
||||
* the sender has it.
|
||||
* the sender has it (account-based or credential-based).
|
||||
* - Expects any credentials passed in to already exist in the ledger, and
|
||||
* returns an internal error otherwise. Validate them beforehand with
|
||||
* credentials::valid().
|
||||
* - Checks that the receiver will not exceed the limit (IOU trustline limit
|
||||
* or MPT MaximumAmount).
|
||||
*/
|
||||
@@ -209,7 +213,8 @@ canWithdraw(
|
||||
AccountID const& to,
|
||||
SLE::const_ref toSle,
|
||||
STAmount const& amount,
|
||||
bool hasDestinationTag);
|
||||
bool hasDestinationTag,
|
||||
std::optional<std::vector<uint256>> const& credentialIDs = std::nullopt);
|
||||
|
||||
/**
|
||||
* Checks that can withdraw funds from an object to itself or a destination.
|
||||
@@ -222,7 +227,10 @@ canWithdraw(
|
||||
* if withdrawing to self.
|
||||
* - If withdrawing to self, succeed.
|
||||
* - If not, checks if the receiver requires deposit authorization, and if
|
||||
* the sender has it.
|
||||
* the sender has it (account-based or credential-based).
|
||||
* - Expects any credentials passed in to already exist in the ledger, and
|
||||
* returns an internal error otherwise. Validate them beforehand with
|
||||
* credentials::valid().
|
||||
* - Checks that the receiver will not exceed the limit (IOU trustline limit
|
||||
* or MPT MaximumAmount).
|
||||
*/
|
||||
@@ -232,20 +240,25 @@ canWithdraw(
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
STAmount const& amount,
|
||||
bool hasDestinationTag);
|
||||
bool hasDestinationTag,
|
||||
std::optional<std::vector<uint256>> const& credentialIDs = std::nullopt);
|
||||
|
||||
/**
|
||||
* Checks that can withdraw funds from an object to itself or a destination.
|
||||
*
|
||||
* The receiver may be either the submitting account (sfAccount) or a different
|
||||
* destination account (sfDestination).
|
||||
* destination account (sfDestination). Credentials, if any, are taken from the
|
||||
* transaction's sfCredentialIDs field.
|
||||
*
|
||||
* - Checks that the receiver account exists.
|
||||
* - If the receiver requires a destination tag, check that one exists, even
|
||||
* if withdrawing to self.
|
||||
* - If withdrawing to self, succeed.
|
||||
* - If not, checks if the receiver requires deposit authorization, and if
|
||||
* the sender has it.
|
||||
* the sender has it (account-based or credential-based).
|
||||
* - Expects any credentials in sfCredentialIDs to already exist in the
|
||||
* ledger, and returns an internal error otherwise. Validate them
|
||||
* beforehand with credentials::valid().
|
||||
* - Checks that the receiver will not exceed the limit (IOU trustline limit
|
||||
* or MPT MaximumAmount).
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
@@ -21,6 +22,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
@@ -58,6 +60,42 @@ canApplyToBrokerCover(
|
||||
bool
|
||||
checkLendingProtocolDependencies(Rules const& rules, STTx const& tx);
|
||||
|
||||
/**
|
||||
* The accounts and asset that LoanManage::defaultLoan's fixCleanup3_4_0
|
||||
* freeze/lock exemption applies to.
|
||||
*
|
||||
* `defaultLoan` moves funds from the LoanBroker pseudo-account to the Vault
|
||||
* pseudo-account via `accountSend`. Since neither is the vault asset's
|
||||
* issuer, this is a third-party transfer that transits through the issuer in
|
||||
* two hops (broker -> issuer, issuer -> vault; see
|
||||
* `directSendNoLimitIOU`/`directSendNoLimitMPT`), so the exemption must cover
|
||||
* both the issuer/broker and issuer/vault pairs, not a direct broker/vault
|
||||
* pair. `asset` scopes it further to the vault's own currency/MPT issuance,
|
||||
* so an unrelated one the same accounts happen to hold is still protected.
|
||||
*/
|
||||
struct LoanDefaultFreezeExemptAccounts
|
||||
{
|
||||
AccountID issuer;
|
||||
AccountID broker;
|
||||
AccountID vault;
|
||||
Asset asset;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves the accounts and asset a LoanManage default transaction is
|
||||
* exempt from freeze/lock for.
|
||||
*
|
||||
* @param view Ledger view used to resolve the Loan -> LoanBroker -> Vault
|
||||
* chain.
|
||||
* @param tx The transaction under invariant review.
|
||||
* @return The exempt accounts and asset if `tx` is a `ttLOAN_MANAGE`
|
||||
* transaction with the `tfLoanDefault` flag set, `fixCleanup3_4_0` is
|
||||
* enabled, and the loan/broker/vault objects it references can all be
|
||||
* resolved; `std::nullopt` otherwise.
|
||||
*/
|
||||
[[nodiscard]] std::optional<LoanDefaultFreezeExemptAccounts>
|
||||
getLoanDefaultFreezeExemptAccounts(ReadView const& view, STTx const& tx);
|
||||
|
||||
static constexpr std::uint32_t kSecondsInYear = 365 * 24 * 60 * 60;
|
||||
|
||||
Number
|
||||
|
||||
@@ -921,6 +921,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
{sfDestination, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfCredentialIDs, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction claws back tokens from a vault. */
|
||||
@@ -1004,6 +1005,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
{sfDestination, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfCredentialIDs, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction claws back First Loss Capital from a Loan Broker to
|
||||
|
||||
@@ -121,6 +121,32 @@ public:
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDestinationTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfCredentialIDs (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VECTOR256::type::value_type>
|
||||
getCredentialIDs() const
|
||||
{
|
||||
if (hasCredentialIDs())
|
||||
{
|
||||
return this->tx_->at(sfCredentialIDs);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfCredentialIDs is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasCredentialIDs() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfCredentialIDs);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -214,6 +240,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfCredentialIDs (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
LoanBrokerCoverWithdrawBuilder&
|
||||
setCredentialIDs(std::decay_t<typename SF_VECTOR256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfCredentialIDs] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the LoanBrokerCoverWithdraw wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
|
||||
@@ -121,6 +121,32 @@ public:
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDestinationTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfCredentialIDs (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VECTOR256::type::value_type>
|
||||
getCredentialIDs() const
|
||||
{
|
||||
if (hasCredentialIDs())
|
||||
{
|
||||
return this->tx_->at(sfCredentialIDs);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfCredentialIDs is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasCredentialIDs() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfCredentialIDs);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -214,6 +240,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfCredentialIDs (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
VaultWithdrawBuilder&
|
||||
setCredentialIDs(std::decay_t<typename SF_VECTOR256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfCredentialIDs] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the VaultWithdraw wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -130,16 +129,6 @@ public:
|
||||
view_->rawDestroyXRP(fee);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all invariant checkers one by one.
|
||||
*
|
||||
* @param result the result generated by processing this transaction.
|
||||
* @param fee the fee charged for this transaction
|
||||
* @return the result code that should be returned for this transaction.
|
||||
*/
|
||||
TER
|
||||
checkInvariants(TER const result, XRPAmount const fee);
|
||||
|
||||
ApplyViewContext
|
||||
getApplyViewContext()
|
||||
{
|
||||
@@ -150,13 +139,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static TER
|
||||
failInvariantCheck(TER const result);
|
||||
|
||||
template <std::size_t... Is>
|
||||
TER
|
||||
checkInvariantsHelper(TER const result, XRPAmount const fee, std::index_sequence<Is...>);
|
||||
|
||||
OpenView& base_;
|
||||
ApplyFlags flags_;
|
||||
std::optional<ApplyViewImpl> view_;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/applySteps.h>
|
||||
#include <xrpl/tx/invariants/InvariantRunner.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -147,7 +148,7 @@ struct FeePayer
|
||||
FeePayerType type{FeePayerType::Account};
|
||||
};
|
||||
|
||||
class Transactor
|
||||
class Transactor : public TxInvariantCheck
|
||||
{
|
||||
protected:
|
||||
ApplyContext& ctx_;
|
||||
@@ -158,7 +159,7 @@ protected:
|
||||
XRPAmount preFeeBalance_{}; // Balance before fees.
|
||||
|
||||
public:
|
||||
virtual ~Transactor() = default;
|
||||
~Transactor() override = default;
|
||||
Transactor(Transactor const&) = delete;
|
||||
Transactor&
|
||||
operator=(Transactor const&) = delete;
|
||||
@@ -183,20 +184,50 @@ public:
|
||||
return ctx_.view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Which invariant layers to check.
|
||||
*
|
||||
* Full runs the protocol invariants plus the transaction-specific
|
||||
* check. This is always the scope of the initial pass, even when the
|
||||
* tentative TER is a tec: a bug or exploit could still mutate ledger
|
||||
* state, so transaction-specific invariants must run for failed
|
||||
* transactions too.
|
||||
*
|
||||
* ProtocolOnly runs only the protocol invariants and is used
|
||||
* exclusively for the second invariant pass that follows a
|
||||
* fee-claim reset — specifically, the reset that
|
||||
* Transactor::operator() performs when the initial invariant pass
|
||||
* returns tecINVARIANT_FAILED, rolling the transaction's effects back
|
||||
* to a fee-claim-only state. In that reduced state the
|
||||
* transaction-specific post-conditions no longer apply, but the
|
||||
* protocol invariants must still hold against the fee claim itself.
|
||||
* ProtocolOnly is not intended for other context discards (e.g. the
|
||||
* reset used to handle tecOVERSIZE/tecKILLED/etc. in
|
||||
* processPersistentChanges, or the ctx_.discard() done under
|
||||
* TapFailHard); those paths do not re-run invariants at all.
|
||||
*/
|
||||
enum class InvariantScope { Full, ProtocolOnly };
|
||||
|
||||
/**
|
||||
* Check all invariants for the current transaction.
|
||||
*
|
||||
* Runs transaction-specific invariants first (visitInvariantEntry +
|
||||
* finalizeInvariants), then protocol-level invariants. Both layers
|
||||
* always run; the worst failure code is returned.
|
||||
* Delegates to the free xrpl::checkInvariants runner. When @p scope is
|
||||
* InvariantScope::Full, this transactor is passed so both layers
|
||||
* share a single walk of the modified ledger entries. A failure in
|
||||
* either layer fails the transaction the same way: tecINVARIANT_FAILED
|
||||
* on the first pass, which the caller may respond to by rolling the
|
||||
* transaction back to a fee-claim state and re-invoking this with
|
||||
* InvariantScope::ProtocolOnly; a failure on that post-reset pass
|
||||
* escalates to tefINVARIANT_FAILED.
|
||||
*
|
||||
* @param result the tentative TER from transaction processing.
|
||||
* @param fee the fee consumed by the transaction.
|
||||
* @param scope which invariant layers to check.
|
||||
*
|
||||
* @return the final TER after all invariant checks.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkInvariants(TER result, XRPAmount fee);
|
||||
checkInvariants(TER result, XRPAmount fee, InvariantScope scope);
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/*
|
||||
@@ -538,20 +569,30 @@ private:
|
||||
preflightUniversal(PreflightContext const& ctx);
|
||||
|
||||
/**
|
||||
* Check transaction-specific invariants only.
|
||||
*
|
||||
* Walks every modified ledger entry via visitInvariantEntry, then
|
||||
* calls finalizeInvariants on the derived transactor. Returns
|
||||
* tecINVARIANT_FAILED if any transaction invariant is violated.
|
||||
*
|
||||
* @param result the tentative TER from transaction processing.
|
||||
* @param fee the fee consumed by the transaction.
|
||||
*
|
||||
* @return the original result if all invariants pass, or
|
||||
* tecINVARIANT_FAILED otherwise.
|
||||
* Bridges the two-phase TxInvariantCheck interface to this transactor's
|
||||
* visitInvariantEntry/finalizeInvariants hooks. Declared private (rather
|
||||
* than protected, like the hooks they forward to) so that neither this
|
||||
* transactor nor any subclass can call them directly through a
|
||||
* Transactor& — only through the TxInvariantCheck& that the free
|
||||
* xrpl::checkInvariants runner holds, which is where the two-phase
|
||||
* ordering is enforced.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkTransactionInvariants(TER result, XRPAmount fee);
|
||||
void
|
||||
visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) final
|
||||
{
|
||||
visitInvariantEntry(isDelete, before, after);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalize(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) final
|
||||
{
|
||||
return finalizeInvariants(tx, result, fee, view, j);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
@@ -11,6 +12,7 @@
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -70,7 +72,8 @@ private:
|
||||
STTx const& tx,
|
||||
beast::Journal const& j,
|
||||
bool enforce,
|
||||
bool fixOverrideFreeze);
|
||||
bool fixOverrideFreeze,
|
||||
std::optional<LoanDefaultFreezeExemptAccounts> const& loanDefaultAccounts);
|
||||
|
||||
static bool
|
||||
validateFrozenState(
|
||||
@@ -80,7 +83,8 @@ private:
|
||||
beast::Journal const& j,
|
||||
bool enforce,
|
||||
bool globalFreeze,
|
||||
bool fixOverrideFreeze);
|
||||
bool fixOverrideFreeze,
|
||||
std::optional<LoanDefaultFreezeExemptAccounts> const& loanDefaultAccounts);
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
140
include/xrpl/tx/invariants/InvariantRunner.h
Normal file
140
include/xrpl/tx/invariants/InvariantRunner.h
Normal file
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Runtime interface for a transaction-specific invariant check.
|
||||
*
|
||||
* The free checkInvariants runner drives two layers of checks over a single
|
||||
* walk of the modified ledger entries:
|
||||
*
|
||||
* - Protocol checks are the concrete types in InvariantChecks, held in a
|
||||
* std::tuple and dispatched statically by a compile-time fold (no
|
||||
* virtual calls). They are duck-typed against the two-phase contract
|
||||
* described below; see InvariantChecker_PROTOTYPE in InvariantCheck.h.
|
||||
* - The transaction-specific check is injected at runtime through this
|
||||
* interface, so the runner can call it without depending on the concrete
|
||||
* transactor type. Transactor implements this interface directly (see
|
||||
* Transactor.h) so that the interface's access can stay narrower than
|
||||
* Transactor's own public surface: calling through a TxInvariantCheck&
|
||||
* (all the runner ever holds) is public, but calling through a
|
||||
* Transactor& is not, since Transactor overrides these as private
|
||||
* (forwarding to its own protected visitInvariantEntry/finalizeInvariants).
|
||||
*
|
||||
* Both layers honour the same two-phase protocol:
|
||||
*
|
||||
* Phase 1 — state collection (visitEntry). Called once for each ledger
|
||||
* entry created, modified, or deleted by the transaction. Implementations
|
||||
* accumulate whatever state they need to evaluate their post-conditions.
|
||||
* Must not throw.
|
||||
*
|
||||
* Phase 2 — condition evaluation (finalize). Called once after every
|
||||
* modified entry has been visited. Returns true if all post-conditions
|
||||
* hold, false to fail the transaction.
|
||||
*
|
||||
* Rule: invariants must run regardless of transaction result. finalize
|
||||
* MUST perform meaningful checks even when the transaction has failed
|
||||
* (when result is not tesSUCCESS). A bug or exploit could cause a failed
|
||||
* transaction to mutate ledger state in unexpected ways; invariants are the
|
||||
* last line of defense.
|
||||
*
|
||||
* The typical pattern: an invariant that expects a domain-specific state
|
||||
* change (e.g. a Vault being created) should expect that change only when
|
||||
* the transaction succeeded. A failed VaultCreate must not have created a
|
||||
* Vault.
|
||||
*
|
||||
* Rule: privilege-gated checks apply to failed transactions too. Failed
|
||||
* transactions carry no privileges. Any privilege-gated assertion must
|
||||
* therefore also be enforced for failed transactions.
|
||||
*/
|
||||
class TxInvariantCheck
|
||||
{
|
||||
public:
|
||||
virtual ~TxInvariantCheck() = default;
|
||||
|
||||
/**
|
||||
* @brief Called for each ledger entry modified by the transaction.
|
||||
*
|
||||
* @param isDelete true if the SLE is being deleted.
|
||||
* @param before the entry's state before the transaction (nullptr for
|
||||
* newly created entries).
|
||||
* @param after the entry's state after the transaction. For deletions
|
||||
* this is the SLE being erased; use @p isDelete rather than
|
||||
* a null @p after to detect deletions. @p after is
|
||||
* never null.
|
||||
*/
|
||||
virtual void
|
||||
visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) = 0;
|
||||
|
||||
/**
|
||||
* @brief Called after all entries have been visited.
|
||||
*
|
||||
* @param tx the transaction being applied.
|
||||
* @param result the tentative TER result of the transaction.
|
||||
* @param fee the fee consumed by the transaction.
|
||||
* @param view read-only view of the ledger after the transaction.
|
||||
* @param j journal for logging invariant failures.
|
||||
* @return true if all invariants hold; false to fail with
|
||||
* tecINVARIANT_FAILED / tefINVARIANT_FAILED.
|
||||
*/
|
||||
[[nodiscard]] virtual bool
|
||||
finalize(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Run all protocol invariant checks plus the transaction-specific check
|
||||
* in a single pass over the modified entries.
|
||||
*
|
||||
* Both layers share one walk of the modified-entry set: @p txCheck's
|
||||
* visitEntry accumulates state on the same traversal that drives the
|
||||
* protocol checkers, then both layers' finalize run on the complete state.
|
||||
*
|
||||
* Any failure (a finalize returning false or an exception anywhere in the
|
||||
* check) returns failInvariantCheck(result). On the first pass that yields
|
||||
* tecINVARIANT_FAILED, which the transactor treats as a signal to roll the
|
||||
* transaction's effects back to a fee-claim-only state and re-run this
|
||||
* runner against the reduced state (see Transactor::InvariantScope). If
|
||||
* that second pass also fails, the result escalates to tefINVARIANT_FAILED,
|
||||
* which excludes the transaction from the ledger entirely.
|
||||
*
|
||||
* The whole traversal — both layers' visitEntry calls and both layers'
|
||||
* finalize calls — runs under a single try/catch. There is no per-layer
|
||||
* isolation: an exception anywhere aborts the remaining traversal and
|
||||
* finalize calls and fails the transaction.
|
||||
*
|
||||
* @param ctx the apply context for the current transaction.
|
||||
* @param result the tentative TER from transaction processing.
|
||||
* @param fee the fee consumed by the transaction.
|
||||
* @param txCheck the transaction-specific invariant check.
|
||||
* @return the final TER after all invariant checks.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkInvariants(
|
||||
ApplyContext& ctx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
std::optional<std::reference_wrapper<TxInvariantCheck>> txCheck);
|
||||
|
||||
[[nodiscard]] inline TER
|
||||
checkInvariants(ApplyContext& ctx, TER result, XRPAmount fee)
|
||||
{
|
||||
return checkInvariants(ctx, result, fee, std::nullopt);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -20,6 +20,9 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user