If you’re looking for the reference documentation on all configuration parameters, see the Backtesting Reference.
How It Works
Backtesting operates in two phases:- Transaction Fetching: Identifies all transactions to the target contract in the block range
- Transaction Validation: Replays each transaction with your assertion enabled
- trace_filter API (recommended): Single RPC call for the entire block range, detects internal calls
- Block scanning: One RPC call per block, detects only direct calls
Example
CredibleTestWithBacktesting instead of CredibleTest. The executeBacktest function returns results in a BacktestingTypes.BacktestingResults struct.
Common Configurations
Large Block Ranges (100+ blocks)
Debugging Failures
forkByTxHash: true setting replays all prior transactions to get the exact state just before execution.
This is disabled by default, since it uses significantly more RPC calls and hence is slower. It is recommended to use this setting when debugging failures for concentrated block intervals.
Quick Tests (< 20 blocks)
Testing Against a Specific Transaction
When you want to test your assertion against a specific known transaction (such as a historical exploit), setblockRange: 1 with the block number containing that transaction:
- Validating that your assertion catches known exploits
- Testing edge cases found in production
- Verifying assertion behavior on specific problematic transactions
Understanding Results
When backtesting completes, transactions are categorized into different result types to help you quickly identify issues:Result Categories
PASS - Assertion passed successfully- Transaction replayed and assertion validated without errors
- Recommended Action: None - everything is working as expected
- Transaction either called a function not monitored by your assertion, or failed to replay in the test environment
- Common causes:
- Function mismatch: Assertion monitors
batch()but transaction calledcall() - State dependencies: Transaction depends on earlier transactions in the same block
- Context requirements: Transaction requires specific block state that isn’t present when forking at block level
- Function mismatch: Assertion monitors
- Recommended Action:
- If many transactions show this status, enable
forkByTxHash: trueto fork at exact transaction state - Review to ensure your assertion is triggering on the correct function
- If many transactions show this status, enable
- Note: These are NOT assertion violations - they’re informational and indicate transactions that either aren’t relevant to your assertion or fail before the assertion is executed due to wrong configuration of the backtest
- Your assertion reverted when validating this transaction
- Most Common Causes:
- False positive: Your assertion logic incorrectly flags legitimate protocol behavior (most common)
- Gas limit exceeded: Assertion ran out of gas (300k limit)
- Assertion bug: Logic error in your assertion code
- Known exploit: If testing against a historical exploit block, this is expected behavior
- Recommended Action:
- Check if the transaction is a known exploit - if so, this confirms your assertion works correctly
- Review your assertion logic to ensure it properly handles this transaction pattern
- Check if the assertion is running out of gas and needs optimization
- Verify the transaction on a block explorer to understand what it does
- An error occurred that doesn’t fit other categories
- May indicate RPC issues, assertion bugs, or unexpected contract behavior
- Recommended Action: Check the error message and retry; if persistent, file a bug report.
Reading the Summary
At the end of each backtest run, you’ll see a summary like:Running Tests
The
--ffi flag is required to enable foreign function interface for RPC calls.Foundry Configuration
Enable FFI in your Foundry profile:Best Practices
- Start small - Test with 10-20 blocks first to verify your setup
- Use trace_filter - Set
useTraceFilter: trueif your RPC provider supports it - Keep forkByTxHash false - Enable if assertions are reverting and might be affected by txs earlier in a block
- Use paid RPC providers - For block ranges over 1,000
- Check assertion failures - Ensure
results.assertionFailures == 0 - Run before deployment - Catch false positives on real transactions
- Run manually - Exclude from CI/CD to avoid long test runs
- Backtesting Reference - Complete configuration details
- Testing Assertions - Basic testing guide
- Fuzz Testing - Test with random inputs
- Balancer V2 Rate Manipulation Exploit

