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}