foundry_config/
invariant.rs

1//! Configuration for invariant testing
2
3use crate::fuzz::FuzzDictionaryConfig;
4use serde::{Deserialize, Serialize};
5use std::path::PathBuf;
6
7/// Contains for invariant testing
8#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
9pub struct InvariantConfig {
10    /// The number of runs that must execute for each invariant test group.
11    pub runs: u32,
12    /// The number of calls executed to attempt to break invariants in one run.
13    pub depth: u32,
14    /// Fails the invariant fuzzing if a revert occurs
15    pub fail_on_revert: bool,
16    /// Allows overriding an unsafe external call when running invariant tests. eg. reentrancy
17    /// checks
18    pub call_override: bool,
19    /// The fuzz dictionary configuration
20    #[serde(flatten)]
21    pub dictionary: FuzzDictionaryConfig,
22    /// The maximum number of attempts to shrink the sequence
23    pub shrink_run_limit: u32,
24    /// The maximum number of rejects via `vm.assume` which can be encountered during a single
25    /// invariant run.
26    pub max_assume_rejects: u32,
27    /// Number of runs to execute and include in the gas report.
28    pub gas_report_samples: u32,
29    /// Path where invariant corpus is stored, enables coverage guided fuzzing and edge coverage
30    /// metrics.
31    pub corpus_dir: Option<PathBuf>,
32    /// Whether corpus to use gzip file compression and decompression.
33    pub corpus_gzip: bool,
34    // Number of corpus mutations until marked as eligible to be flushed from memory.
35    pub corpus_min_mutations: usize,
36    // Number of corpus that won't be evicted from memory.
37    pub corpus_min_size: usize,
38    /// Path where invariant failures are recorded and replayed.
39    pub failure_persist_dir: Option<PathBuf>,
40    /// Whether to collect and display fuzzed selectors metrics.
41    pub show_metrics: bool,
42    /// Optional timeout (in seconds) for each invariant test.
43    pub timeout: Option<u32>,
44    /// Display counterexample as solidity calls.
45    pub show_solidity: bool,
46    /// Whether to collect and display edge coverage metrics.
47    pub show_edge_coverage: bool,
48}
49
50impl Default for InvariantConfig {
51    fn default() -> Self {
52        Self {
53            runs: 256,
54            depth: 500,
55            fail_on_revert: false,
56            call_override: false,
57            dictionary: FuzzDictionaryConfig { dictionary_weight: 80, ..Default::default() },
58            shrink_run_limit: 5000,
59            max_assume_rejects: 65536,
60            gas_report_samples: 256,
61            corpus_dir: None,
62            corpus_gzip: true,
63            corpus_min_mutations: 5,
64            corpus_min_size: 0,
65            failure_persist_dir: None,
66            show_metrics: true,
67            timeout: None,
68            show_solidity: false,
69            show_edge_coverage: false,
70        }
71    }
72}
73
74impl InvariantConfig {
75    /// Creates invariant configuration to write failures in `{PROJECT_ROOT}/cache/fuzz` dir.
76    pub fn new(cache_dir: PathBuf) -> Self {
77        Self {
78            runs: 256,
79            depth: 500,
80            fail_on_revert: false,
81            call_override: false,
82            dictionary: FuzzDictionaryConfig { dictionary_weight: 80, ..Default::default() },
83            shrink_run_limit: 5000,
84            max_assume_rejects: 65536,
85            gas_report_samples: 256,
86            corpus_dir: None,
87            corpus_gzip: true,
88            corpus_min_mutations: 5,
89            corpus_min_size: 0,
90            failure_persist_dir: Some(cache_dir),
91            show_metrics: true,
92            timeout: None,
93            show_solidity: false,
94            show_edge_coverage: false,
95        }
96    }
97}