1pub mod fuzzer;
14pub mod mutator;
15pub use fuzzer::Fuzzer;
16pub mod crash;
17pub mod executor;
18pub mod invariant;
19
20use rand::Rng;
21use serde::{Deserialize, Serialize};
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub struct FuzzAccount {
26 pub key: String,
28 pub data: Vec<u8>,
30 pub owner: String,
32 pub lamports: u64,
34 pub rent_epoch: u64,
36 pub is_writable: bool,
38 pub is_signer: bool,
40 pub seeds: Option<Vec<Vec<u8>>>,
42}
43
44impl Default for FuzzAccount {
45 fn default() -> Self {
46 Self {
47 key: String::new(),
48 data: vec![0u8; 32],
49 owner: "11111111111111111111111111111111".to_string(),
50 lamports: 1_000_000,
51 rent_epoch: u64::MAX,
52 is_writable: true,
53 is_signer: false,
54 seeds: None,
55 }
56 }
57}
58
59impl FuzzAccount {
60 pub fn random(rng: &mut impl Rng) -> Self {
61 let data_len: usize = rng.gen_range(1..=1024);
62 let mut data = vec![0u8; data_len];
63 rng.fill(&mut data[..]);
64
65 Self {
66 key: bs58_encode(&random_bytes(rng, 32)),
67 data,
68 owner: bs58_encode(&random_bytes(rng, 32)),
69 lamports: rng.gen_range(1..10_000_000),
70 rent_epoch: u64::MAX,
71 is_writable: rng.gen_bool(0.8),
72 is_signer: rng.gen_bool(0.1),
73 seeds: if rng.gen_bool(0.3) {
74 Some(vec![random_bytes(rng, 16)])
75 } else {
76 None
77 },
78 }
79 }
80
81 pub fn is_rent_exempt(&self) -> bool {
83 let min_lamports = self.data.len() as u64 * 3480 * 2; self.lamports >= min_lamports && self.rent_epoch != 0
88 }
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct FuzzAction {
95 pub ix_discriminator: [u8; 8],
97 pub ix_name: String,
99 pub program_id: String,
101 pub accounts: Vec<FuzzAccount>,
103 pub ix_data: Vec<u8>,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct FuzzActionSequence {
111 pub actions: Vec<FuzzAction>,
112 pub initial_accounts: Vec<FuzzAccount>,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct CoverageBitmap {
119 pub edges: Vec<u8>,
121 pub covered_edges: usize,
123}
124
125impl Default for CoverageBitmap {
126 fn default() -> Self {
127 Self::new()
128 }
129}
130
131impl CoverageBitmap {
132 pub fn new() -> Self {
133 Self {
134 edges: vec![0u8; 65536],
135 covered_edges: 0,
136 }
137 }
138
139 pub fn record_edge(&mut self, prev: usize, cur: usize) -> bool {
141 let idx = (prev ^ cur) % self.edges.len();
142 let was_zero = self.edges[idx] == 0;
143 if self.edges[idx] < u8::MAX {
144 self.edges[idx] = self.edges[idx].saturating_add(1);
145 }
146 if was_zero && self.edges[idx] > 0 {
147 self.covered_edges += 1;
148 }
149 was_zero }
151
152 pub fn has_new_coverage(&self, global: &CoverageBitmap) -> bool {
154 self.edges
155 .iter()
156 .zip(global.edges.iter())
157 .any(|(a, b)| a > b)
158 }
159
160 pub fn merge(&mut self, global: &CoverageBitmap) {
162 for (a, b) in self.edges.iter_mut().zip(global.edges.iter()) {
163 *a = a.saturating_add(*b);
164 }
165 }
166}
167
168fn random_bytes(rng: &mut impl Rng, len: usize) -> Vec<u8> {
170 (0..len).map(|_| rng.gen()).collect()
171}
172
173pub fn bs58_encode(data: &[u8]) -> String {
175 const ALPHABET: &[u8] = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
176 let mut result = String::new();
177 let mut num = 0u128;
178 let mut count = 0;
179 for &byte in data {
180 num = num * 256 + byte as u128;
181 count += 1;
182 if count >= 16 {
183 while num > 0 {
184 result.push(ALPHABET[(num % 58) as usize] as char);
185 num /= 58;
186 }
187 count = 0;
188 }
189 }
190 if result.is_empty() && data.is_empty() {
191 result.push('1');
192 }
193 result
194}