Backtesting runs your assertions against actual historical transactions from a specified block range. This helps ensure your assertions work correctly with real transaction patterns and don’t trigger false positives on legitimate protocol operations.Documentation Index
Fetch the complete documentation index at: https://docs.phylax.systems/llms.txt
Use this file to discover all available pages before exploring further.
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 using trace APIs (with automatic fallback)
- Transaction Validation: Replays each transaction with your assertion enabled
Example
CredibleTestWithBacktesting instead of CredibleTest. The executeBacktest function returns results in a BacktestingTypes.BacktestingResults struct.
Common Configurations
Standard Configuration
Testing Against a Specific Block
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
Testing a Single Transaction by Hash
For debugging false positives or validating against a specific transaction, useexecuteBacktestForTransaction:
- Debugging potential false positives reported during staging (see Testing Strategy)
- Quick validation of assertion behavior on a specific transaction
- Investigating incidents without needing to know the block number
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 called a function not monitored by your assertion (function selector didn’t match)
- This is normal behavior - your assertion only triggers on specific function calls
- Recommended Action: None required, unless you expected this transaction to trigger your assertion
- Note: These are NOT assertion violations - they indicate transactions that aren’t relevant to your assertion
- Transaction failed to replay before the assertion could execute
- Common causes:
- State dependencies: Transaction depends on specific state that isn’t present
- Context requirements: Transaction requires specific block context
- Insufficient funds: Sender balance changed between original execution and replay
- Recommended Action: Check the error message for details; this usually indicates an environmental issue rather than an assertion problem
- Note: These are NOT assertion violations
- 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 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
- Debug with single transactions - Use
executeBacktestForTransactionto investigate specific failures
- Backtesting Reference - Complete configuration details
- Testing Assertions - Basic testing guide
- Fuzz Testing - Test with random inputs
- Troubleshooting - Common errors and solutions
- Balancer V2 Rate Manipulation Exploit

