phylaxsystems avatar

backtesting-assertions

Runs Credible Layer assertion backtests against historical transactions. Use when validating asserti

作者 phylaxsystems|オープンソース

Backtesting Assertions

Use Credible Layer backtesting to replay historical transactions with assertions enabled.

When to Use

  • You want to validate assertions against real mainnet transactions.
  • You are testing a known exploit block or incident transaction.
  • You need to confirm triggers match real protocol entrypoints.

When NOT to Use

  • You only need unit or fuzz tests. Use testing-assertions.
  • You are designing invariants or triggers. Use designing-assertions.
  • You only need Solidity implementation details. Use implementing-assertions.

Quick Start

  1. Place backtest files in assertions/test/backtest/ (e.g., VaultAssertion.backtest.t.sol).
  2. Create a test that inherits CredibleTestWithBacktesting.
  3. Configure BacktestingConfig with target contract, block range, and assertion selector.
  4. Call executeBacktest and assert failures are zero.
  5. Run with the backtest profile: FOUNDRY_PROFILE=assertions-backtest pcl test (or use --ffi flag).

See pcl-assertion-workflow for the full profile configuration with ffi = true.

Workflow

  • Pick a target contract (the assertion adopter address).
  • Choose endBlock and blockRange.
  • Verify RPC env vars; skip or fallback when missing.
  • Prefer useTraceFilter = true to detect internal calls; fall back to block scanning if your RPC lacks trace_filter.
  • For large ranges, use a paid RPC to avoid rate limits; useTraceFilter reduces calls.
  • Use forkByTxHash = true only when debugging state-dependent failures.
  • Use blockRange = 1 for a specific known exploit tx.
  • If your invariant is keyed by calldata, verify the exact input shape for the API being used. ph.callinputAt returns raw calldata including the selector.
  • Interpret results: PASS, NEEDS_REVIEW (selector mismatch or replay failure), ASSERTION_FAIL (often false positives or gas), UNKNOWN_ERROR (RPC or unexpected).
  • If many NEEDS_REVIEW, the selector/target does not match or you need forkByTxHash.

Rationalizations to Reject

  • "We only need unit tests." Backtesting catches real-world call patterns.
  • "Trace filter is optional." Without it you miss internal calls.
  • "forkByTxHash everywhere." It is slow and RPC-heavy; use it for debugging only.
  • "RPC isn't needed." Backtesting requires a working RPC and FFI.

References

backtesting-assertions - Claude Code・Cursor 対応の AIエージェント Skill | Agent Skills