1use alloy_primitives::U256;
4use foundry_compilers::utils::canonicalized;
5use serde::{Deserialize, Serialize};
6use std::path::PathBuf;
7
8#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
10pub struct FuzzConfig {
11 pub runs: u32,
13 pub fail_on_revert: bool,
15 pub max_test_rejects: u32,
18 pub seed: Option<U256>,
20 #[serde(flatten)]
22 pub dictionary: FuzzDictionaryConfig,
23 pub gas_report_samples: u32,
25 #[serde(flatten)]
27 pub corpus: FuzzCorpusConfig,
28 pub failure_persist_dir: Option<PathBuf>,
30 pub show_logs: bool,
32 pub timeout: Option<u32>,
34}
35
36impl Default for FuzzConfig {
37 fn default() -> Self {
38 Self {
39 runs: 256,
40 fail_on_revert: true,
41 max_test_rejects: 65536,
42 seed: None,
43 dictionary: FuzzDictionaryConfig::default(),
44 gas_report_samples: 256,
45 corpus: FuzzCorpusConfig::default(),
46 failure_persist_dir: None,
47 show_logs: false,
48 timeout: None,
49 }
50 }
51}
52
53impl FuzzConfig {
54 pub fn new(cache_dir: PathBuf) -> Self {
56 Self { failure_persist_dir: Some(cache_dir), ..Default::default() }
57 }
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
62pub struct FuzzDictionaryConfig {
63 #[serde(deserialize_with = "crate::deserialize_stringified_percent")]
65 pub dictionary_weight: u32,
66 pub include_storage: bool,
68 pub include_push_bytes: bool,
70 #[serde(
75 deserialize_with = "crate::deserialize_usize_or_max",
76 serialize_with = "crate::serialize_usize_or_max"
77 )]
78 pub max_fuzz_dictionary_addresses: usize,
79 #[serde(
82 deserialize_with = "crate::deserialize_usize_or_max",
83 serialize_with = "crate::serialize_usize_or_max"
84 )]
85 pub max_fuzz_dictionary_values: usize,
86 #[serde(
90 deserialize_with = "crate::deserialize_usize_or_max",
91 serialize_with = "crate::serialize_usize_or_max"
92 )]
93 pub max_fuzz_dictionary_literals: usize,
94}
95
96impl Default for FuzzDictionaryConfig {
97 fn default() -> Self {
98 const MB: usize = 1024 * 1024;
99
100 Self {
101 dictionary_weight: 40,
102 include_storage: true,
103 include_push_bytes: true,
104 max_fuzz_dictionary_addresses: 300 * MB / 20,
105 max_fuzz_dictionary_values: 300 * MB / 32,
106 max_fuzz_dictionary_literals: 200 * MB / 32,
107 }
108 }
109}
110
111#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
112pub struct FuzzCorpusConfig {
113 pub corpus_dir: Option<PathBuf>,
116 pub corpus_gzip: bool,
118 pub corpus_min_mutations: usize,
121 pub corpus_min_size: usize,
123 pub show_edge_coverage: bool,
125}
126
127impl FuzzCorpusConfig {
128 pub fn with_test(&mut self, contract: &str, test: &str) {
129 if let Some(corpus_dir) = &self.corpus_dir {
130 self.corpus_dir = Some(canonicalized(corpus_dir.join(contract).join(test)));
131 }
132 }
133
134 pub fn collect_edge_coverage(&self) -> bool {
136 self.corpus_dir.is_some() || self.show_edge_coverage
137 }
138
139 pub fn is_coverage_guided(&self) -> bool {
141 self.corpus_dir.is_some()
142 }
143}
144
145impl Default for FuzzCorpusConfig {
146 fn default() -> Self {
147 Self {
148 corpus_dir: None,
149 corpus_gzip: true,
150 corpus_min_mutations: 5,
151 corpus_min_size: 0,
152 show_edge_coverage: false,
153 }
154 }
155}