xrpld
Loading...
Searching...
No Matches
xrpl::InvariantChecker_PROTOTYPE Class Reference

Prototype for invariant check implementations. More...

#include <InvariantCheck.h>

Public Member Functions

 InvariantChecker_PROTOTYPE ()=default
void visitEntry (bool isDelete, SLE::const_ref before, SLE::const_ref after)
 called for each ledger entry in the current transaction.
bool finalize (STTx const &tx, TER const tec, XRPAmount const fee, ReadView const &view, beast::Journal const &j)
 called after all ledger entries have been visited to determine the final status of the check.

Detailed Description

Prototype for invariant check implementations.

THIS CLASS DOES NOT EXIST - or rather it exists in documentation only to communicate the interface required of any invariant checker. Any invariant check implementation should implement the public methods documented here.

Rules for implementing finalize

Invariants must run regardless of transaction result

An invariant's finalize method MUST perform meaningful checks even when the transaction has failed (i.e., !isTesSuccess(tec)). The following pattern is almost certainly wrong and must never be used:

// WRONG: skipping all checks on failure defeats the purpose of invariants
if (!isTesSuccess(tec))
return true;
bool isTesSuccess(TER x) noexcept
Definition TER.h:676

The entire purpose of invariants is to detect and prevent the impossible. A bug or exploit could cause a failed transaction to mutate ledger state in unexpected ways. Invariants are the last line of defense against such scenarios.

In general: an invariant that expects a domain-specific state change to occur (e.g., a new object being created) should only expect that change when the transaction succeeded. A failed VaultCreate must not have created a Vault. A failed LoanSet must not have created a Loan.

Also be aware that failed transactions, regardless of type, carry no Privileges. Any privilege-gated checks must therefore also be applied to failed transactions.

Definition at line 66 of file InvariantCheck.h.

Constructor & Destructor Documentation

◆ InvariantChecker_PROTOTYPE()

xrpl::InvariantChecker_PROTOTYPE::InvariantChecker_PROTOTYPE ( )
explicitdefault

Member Function Documentation

◆ visitEntry()

void xrpl::InvariantChecker_PROTOTYPE::visitEntry ( bool isDelete,
SLE::const_ref before,
SLE::const_ref after )

called for each ledger entry in the current transaction.

Parameters
isDeletetrue if the SLE is being deleted.
beforeledger entry before modification by the transaction. before will be null if the entry is new.
afterledger entry after modification by the transaction. Always non-null. When deleting, after may differ from before. Whether that is important is up to the individual invariant check.
Note
after IS NEVER NULL. isDelete is the only correct way to check for deletions. Do not make logic or branching decisions on whether on after is set, because it will always be set. Treat a null after as a programming error (with XRPL_ASSERT). An invariant MAY check for null defensively, if it makes more sense, but an assertion is preferred for new invariants.

◆ finalize()

bool xrpl::InvariantChecker_PROTOTYPE::finalize ( STTx const & tx,
TER const tec,
XRPAmount const fee,
ReadView const & view,
beast::Journal const & j )

called after all ledger entries have been visited to determine the final status of the check.

This method MUST perform meaningful checks even when tec indicates a failed transaction. See the class-level documentation for the rules governing how failed transactions must be handled.

Parameters
txthe transaction being applied
tecthe current TER result of the transaction
feethe fee actually charged for this transaction
viewa ReadView of the ledger being modified
jjournal for logging
Returns
true if check passes, false if it fails