From 36dd69738b1b907d76132be812dfdde2dea853bc Mon Sep 17 00:00:00 2001 From: lukacan Date: Sun, 29 Sep 2024 16:26:47 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20Config=20is=20read=20at=20start?= =?UTF-8?q?=20of=20fuzzing=20session=20+=20transaction=20processing=20disp?= =?UTF-8?q?atch=20within=20the=20FuzzExecutor=20macro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + Cargo.lock | 13 +- crates/client/Cargo.toml | 1 - crates/client/src/cleaner.rs | 33 +- crates/client/src/commander.rs | 23 +- crates/client/src/config.rs | 609 ------------------ crates/client/src/lib.rs | 7 +- .../fuzz_instructions_generator.rs | 2 +- .../test_fuzz_generator.rs | 7 +- .../trident-tests/Cargo_fuzz.toml.tmpl | 1 - .../expected_fuzz_instructions.rs | 2 +- .../expected_test_fuzz.rs | 11 +- crates/fuzz/Cargo.toml | 3 + .../fuzz/derive/accounts_snapshots/src/lib.rs | 6 +- .../fuzz/derive/fuzz_deserialize/Cargo.toml | 16 - .../fuzz/derive/fuzz_deserialize/src/lib.rs | 34 - .../fuzz/derive/fuzz_test_executor/src/lib.rs | 92 +-- crates/fuzz/src/config/constants.rs | 8 + crates/fuzz/src/config/fuzz.rs | 32 + crates/fuzz/src/config/honggfuzz.rs | 229 +++++++ crates/fuzz/src/config/mod.rs | 261 ++++++++ crates/fuzz/src/fuzz_data.rs | 4 +- crates/fuzz/src/fuzz_deserialize.rs | 8 +- crates/fuzz/src/fuzz_test_executor.rs | 2 + crates/fuzz/src/ix_ops.rs | 21 +- crates/fuzz/src/lib.rs | 2 + crates/fuzz/src/snapshot.rs | 50 +- crates/fuzz/src/transaction_executor.rs | 144 +++++ .../docs/features/fuzz-instructions.md | 1 + .../arbitrary-custom-types-4/Cargo.lock | 13 +- .../arbitrary-custom-types-4/Trident.toml | 4 - .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 10 +- .../arbitrary-limit-inputs-5/Cargo.lock | 13 +- .../arbitrary-limit-inputs-5/Trident.toml | 4 - .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 10 +- examples/fuzz-tests/cpi-metaplex-7/Cargo.lock | 13 +- .../fuzz-tests/cpi-metaplex-7/Trident.toml | 4 - .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 11 +- examples/fuzz-tests/hello_world/Cargo.lock | 13 +- examples/fuzz-tests/hello_world/Trident.toml | 6 +- .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 24 +- .../incorrect-integer-arithmetic-3/Cargo.lock | 13 +- .../Trident.toml | 4 - .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 10 +- .../incorrect-ix-sequence-1/Cargo.lock | 13 +- .../incorrect-ix-sequence-1/Trident.toml | 4 - .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 10 +- examples/fuzz-tests/simple-cpi-6/Cargo.lock | 13 +- examples/fuzz-tests/simple-cpi-6/Trident.toml | 6 +- .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 11 +- .../unauthorized-access-2/Cargo.lock | 13 +- .../unauthorized-access-2/Trident.toml | 4 - .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 10 +- .../unchecked-arithmetic-0/Cargo.lock | 13 +- .../unchecked-arithmetic-0/Trident.toml | 4 - .../fuzz_tests/fuzz_0/fuzz_instructions.rs | 2 +- .../fuzz_tests/fuzz_0/test_fuzz.rs | 10 +- 65 files changed, 926 insertions(+), 978 deletions(-) delete mode 100644 crates/client/src/config.rs delete mode 100644 crates/fuzz/derive/fuzz_deserialize/Cargo.toml delete mode 100644 crates/fuzz/derive/fuzz_deserialize/src/lib.rs create mode 100644 crates/fuzz/src/config/constants.rs create mode 100644 crates/fuzz/src/config/fuzz.rs create mode 100644 crates/fuzz/src/config/honggfuzz.rs create mode 100644 crates/fuzz/src/config/mod.rs create mode 100644 crates/fuzz/src/transaction_executor.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 59ab0526e..239ee3042 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ incremented upon a breaking change and the patch version will be incremented for **Changed** +- impr/ fuzz flags are read at start of fuzzing session from Config instead of env variable and transaction dispatch was added to increase FuzzTestExecutor readability ([204](https://github.com/Ackee-Blockchain/trident/pull/204)) - impr/ allow various instructions to be generated in case of multiple programs in the Anchor workspace ([200](https://github.com/Ackee-Blockchain/trident/pull/200)) - feat/ option to add account into Fuzz Test environment with base64 data ([197](https://github.com/Ackee-Blockchain/trident/pull/197)) - impr/ instead of parsing source code and creating our IDL, read anchor IDL ([198](https://github.com/Ackee-Blockchain/trident/pull/196)) diff --git a/Cargo.lock b/Cargo.lock index 092e20598..4d1733149 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5949,7 +5949,6 @@ dependencies = [ "toml", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -5974,15 +5973,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -5997,7 +5987,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -6009,6 +6001,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml", ] [[package]] diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index 2ddf7795b..6a7f519a3 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -16,7 +16,6 @@ pretty_assertions = "1.1.0" [dependencies] # TRIDENT trident-derive-displayix = { path = "../fuzz/derive/display_ix", version = "0.0.2" } -trident-derive-fuzz-deserialize = { path = "../fuzz/derive/fuzz_deserialize", version = "0.0.2" } trident-derive-fuzz-test-executor = { path = "../fuzz/derive/fuzz_test_executor", version = "0.0.2" } trident-derive-accounts-snapshots = { path = "../fuzz/derive/accounts_snapshots", version = "0.0.1" } diff --git a/crates/client/src/cleaner.rs b/crates/client/src/cleaner.rs index e012d94aa..327ae89d8 100644 --- a/crates/client/src/cleaner.rs +++ b/crates/client/src/cleaner.rs @@ -1,7 +1,7 @@ -use crate::config::Config; +use anyhow::Context; use fehler::{throw, throws}; use std::{ - io, + env, io, path::{Path, PathBuf}, }; use thiserror::Error; @@ -15,6 +15,8 @@ pub enum Error { Io(#[from] io::Error), #[error("Cannot find the Anchor.toml file to locate the root folder")] BadWorkspace, + #[error("{0:?}")] + Anyhow(#[from] anyhow::Error), } pub struct Cleaner; @@ -31,7 +33,7 @@ impl Cleaner { } #[throws] pub async fn clean_target(&self) { - let root = match Config::discover_root() { + let root = match discover_root() { Ok(root) => root, Err(_) => throw!(Error::BadWorkspace), }; @@ -60,3 +62,28 @@ impl Cleaner { } } } + +/// Tries to find the root directory with the `Anchor.toml` file. +/// Throws an error when there is no directory with the `Anchor.toml` file +pub fn discover_root() -> Result { + let current_dir = env::current_dir()?; + let mut dir = Some(current_dir.as_path()); + while let Some(cwd) = dir { + for file in std::fs::read_dir(cwd) + .with_context(|| format!("Error reading the directory with path: {}", cwd.display()))? + { + let path = file + .with_context(|| { + format!("Error reading the directory with path: {}", cwd.display()) + })? + .path(); + if let Some(filename) = path.file_name() { + if filename.to_str() == Some(ANCHOR_TOML) { + return Ok(PathBuf::from(cwd)); + } + } + } + dir = cwd.parent(); + } + throw!(Error::BadWorkspace) +} diff --git a/crates/client/src/commander.rs b/crates/client/src/commander.rs index d43de0f54..231d78e2e 100644 --- a/crates/client/src/commander.rs +++ b/crates/client/src/commander.rs @@ -1,4 +1,3 @@ -use crate::config::Config; use fehler::{throw, throws}; use std::path::PathBuf; use std::process; @@ -9,6 +8,7 @@ use tokio::{ process::{Child, Command}, signal, }; +use trident_fuzz::config::Config; use crate::constants::*; use tokio::io::AsyncBufReadExt; @@ -86,10 +86,6 @@ impl Commander { let genesis_folder = PathBuf::from(self.root.to_string()).join("trident-genesis"); - let rustflags = std::env::var("RUSTFLAGS").unwrap_or_default(); - - let rustflags = config.get_rustflags_args(rustflags); - let mut fuzz_args = config.get_honggfuzz_args(hfuzz_run_args); // let cargo_target_dir = std::env::var("CARGO_TARGET_DIR").unwrap_or_default(); @@ -118,7 +114,7 @@ impl Commander { } } - match rustflags.contains("fuzzing_with_stats") { + match config.get_fuzzing_with_stats() { true => { // enforce keep output to be true fuzz_args.push_str("--keep_output"); @@ -127,7 +123,6 @@ impl Commander { .env("HFUZZ_RUN_ARGS", fuzz_args) .env("CARGO_TARGET_DIR", cargo_target_dir) .env("HFUZZ_WORKSPACE", hfuzz_workspace) - .env("RUSTFLAGS", rustflags) .arg("hfuzz") .arg("run") .arg(target) @@ -141,7 +136,6 @@ impl Commander { .env("HFUZZ_RUN_ARGS", fuzz_args) .env("CARGO_TARGET_DIR", cargo_target_dir) .env("HFUZZ_WORKSPACE", hfuzz_workspace) - .env("RUSTFLAGS", rustflags) .arg("hfuzz") .arg("run") .arg(target) @@ -177,11 +171,7 @@ impl Commander { let mut fuzz_args = config.get_honggfuzz_args(hfuzz_run_args); - let rustflags = std::env::var("RUSTFLAGS").unwrap_or_default(); - - let rustflags = config.get_rustflags_args(rustflags); - - match rustflags.contains("fuzzing_with_stats") { + match config.get_fuzzing_with_stats() { true => { // enforce keep output to be true fuzz_args.push_str("--keep_output"); @@ -190,7 +180,6 @@ impl Commander { .env("HFUZZ_RUN_ARGS", fuzz_args) .env("CARGO_TARGET_DIR", cargo_target_dir) .env("HFUZZ_WORKSPACE", hfuzz_workspace) - .env("RUSTFLAGS", rustflags) .arg("hfuzz") .arg("run") .arg(target) @@ -204,7 +193,6 @@ impl Commander { .env("HFUZZ_RUN_ARGS", fuzz_args) .env("CARGO_TARGET_DIR", cargo_target_dir) .env("HFUZZ_WORKSPACE", hfuzz_workspace) - .env("RUSTFLAGS", rustflags) .arg("hfuzz") .arg("run") .arg(target) @@ -336,15 +324,10 @@ impl Commander { let cargo_target_dir = std::env::var("CARGO_TARGET_DIR") .unwrap_or_else(|_| config.get_env_arg("CARGO_TARGET_DIR")); - let rustflags = std::env::var("RUSTFLAGS").unwrap_or_default(); - - let rustflags = config.get_rustflags_args(rustflags); - // using exec rather than spawn and replacing current process to avoid unflushed terminal output after ctrl+c signal std::process::Command::new("cargo") .env("GENESIS_FOLDER", genesis_folder) .env("CARGO_TARGET_DIR", cargo_target_dir) - .env("RUSTFLAGS", rustflags) .arg("hfuzz") .arg("run-debug") .arg(target) diff --git a/crates/client/src/config.rs b/crates/client/src/config.rs deleted file mode 100644 index 1e15d3baf..000000000 --- a/crates/client/src/config.rs +++ /dev/null @@ -1,609 +0,0 @@ -use anyhow::Context; -use fehler::throw; -use serde::Deserialize; -use std::{collections::HashMap, env, fs, io, path::PathBuf}; -use thiserror::Error; - -use crate::constants::*; - -#[derive(Error, Debug)] -pub enum Error { - #[error("invalid workspace")] - BadWorkspace, - #[error("{0:?}")] - Anyhow(#[from] anyhow::Error), - #[error("{0:?}")] - Io(#[from] io::Error), - #[error("{0:?}")] - Toml(#[from] toml::de::Error), -} - -#[derive(Debug, Deserialize, Clone)] -pub struct Cfg { - pub cfg_identifier: String, - pub val: bool, -} - -#[derive(Debug, Deserialize, Clone)] -pub struct Fuzz { - pub rust_flags: Vec, -} -#[derive(Default, Debug, Deserialize, Clone)] -struct _Fuzz { - #[serde(default)] - pub allow_duplicate_txs: Option, - #[serde(default)] - pub fuzzing_with_stats: Option, -} -impl From<_Fuzz> for Fuzz { - fn from(_f: _Fuzz) -> Self { - let mut _self = Self { rust_flags: vec![] }; - - // allow_duplicate_txs - let allow_duplicate_txs = _f.allow_duplicate_txs.unwrap_or(false); - - _self.rust_flags.push(Cfg { - cfg_identifier: "allow_duplicate_txs".to_string(), - val: allow_duplicate_txs, - }); - - // fuzzing_with_stats - let fuzzing_with_stats = _f.fuzzing_with_stats.unwrap_or(false); - - _self.rust_flags.push(Cfg { - cfg_identifier: "fuzzing_with_stats".to_string(), - val: fuzzing_with_stats, - }); - - _self - } -} -#[derive(Debug, Deserialize, Clone)] -pub struct HonggFuzzArg { - pub short_opt: Option, - pub long_opt: Option, - pub val: Option, -} -#[derive(Debug, Deserialize, Clone)] -pub struct HonggFuzz { - pub fuzz_args: Vec, - pub env_variables: HashMap, -} -#[derive(Default, Debug, Deserialize, Clone)] -struct _HonggFuzz { - #[serde(default)] - /// Timeout in seconds (default: 10) - /// -t - /// --timeout - pub timeout: Option, - #[serde(default)] - /// Number of fuzzing iterations (default: 0 [no limit]) - /// -N - /// --iterations - pub iterations: Option, - #[serde(default)] - /// Number of concurrent fuzzing threads (default: number of CPUs / 2) - /// -n - /// --threads - pub threads: Option, - #[serde(default)] - /// Don't close children's stdin, stdout, stderr; can be noisy - /// -Q - /// --keep_output - pub keep_output: Option, - #[serde(default)] - /// Disable ANSI console; use simple log output - /// -v - /// --verbose - pub verbose: Option, - #[serde(default)] - /// Exit upon seeing the first crash (default: false) - /// --exit_upon_crash - pub exit_upon_crash: Option, - #[serde(default)] - /// Maximal number of mutations per one run (default: 6) - /// -r - /// --mutations_per_run - pub mutations_per_run: Option, - #[serde(default)] - /// Target compilation directory, defaults to "trident-tests/fuzz_tests/fuzzing/hfuzz_target" to not clash with cargo build's default target directory. - /// CARGO_TARGET_DIR env variable - pub cargo_target_dir: Option, - #[serde(default)] - /// Honggfuzz working directory, defaults to "trident-tests/fuzz_tests/fuzzing/hfuzz_workspace". - /// HFUZZ_WORKSPACE env variable - pub hfuzz_workspace: Option, - #[serde(default)] - /// Directory where crashes are saved to (default: workspace directory) - /// --crashdir - pub crashdir: Option, - #[serde(default)] - /// Input file extension (e.g. 'swf'), (default: 'fuzz') - /// -e - /// --extension - pub extension: Option, - #[serde(default)] - /// Number of seconds this fuzzing session will last (default: 0 [no limit]) - /// --run_time - pub run_time: Option, - #[serde(default)] - /// Maximal size of files processed by the fuzzer in bytes (default: 1048576 = 1MB) - /// -F - /// --max_file_size - pub max_file_size: Option, - #[serde(default)] - /// Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames (default: false) - /// -u - /// --save_all - pub save_all: Option, -} - -impl From<_HonggFuzz> for HonggFuzz { - fn from(_f: _HonggFuzz) -> Self { - let mut _self = Self { - fuzz_args: vec![], - env_variables: HashMap::default(), - }; - - // timeout - let timeout = _f.timeout.unwrap_or(10); - _self - .fuzz_args - .push(HonggFuzzArg::new("-t", "--timeout", &timeout.to_string())); - - // iterations - let iterations = _f.iterations.unwrap_or(0); - _self.fuzz_args.push(HonggFuzzArg::new( - "-N", - "--iterations", - &iterations.to_string(), - )); - - // threads - let threads = _f.threads.unwrap_or(0); - if threads > 0 { - _self - .fuzz_args - .push(HonggFuzzArg::new("-n", "--threads", &threads.to_string())); - } - - // keep_output - let keep_output = _f.keep_output.unwrap_or(false); - if keep_output { - _self - .fuzz_args - .push(HonggFuzzArg::new("-Q", "--keep_output", "")); - } - // verbose - let verbose = _f.verbose.unwrap_or(false); - if verbose { - _self - .fuzz_args - .push(HonggFuzzArg::new("-v", "--verbose", "")); - } - - // exit_upon_crash - let exit_upon_crash = _f.exit_upon_crash.unwrap_or(false); - if exit_upon_crash { - _self - .fuzz_args - .push(HonggFuzzArg::new("", "--exit_upon_crash", "")); - } - // mutations_per_run - let mutations_per_run = _f.mutations_per_run.unwrap_or(6); - _self.fuzz_args.push(HonggFuzzArg::new( - "-r", - "--mutations_per_run", - &mutations_per_run.to_string(), - )); - // cargo_target_dir - let cargo_target_dir = _f.cargo_target_dir.unwrap_or_default(); - if !cargo_target_dir.is_empty() { - _self - .env_variables - .insert(CARGO_TARGET_DIR_ENV.to_owned(), cargo_target_dir); - } else { - _self.env_variables.insert( - CARGO_TARGET_DIR_ENV.to_owned(), - CARGO_TARGET_DIR_DEFAULT.to_owned(), - ); - } - // hfuzz_workspace - let hfuzz_workspace = _f.hfuzz_workspace.unwrap_or_default(); - if !hfuzz_workspace.is_empty() { - _self - .env_variables - .insert(HFUZZ_WORKSPACE_ENV.to_owned(), hfuzz_workspace); - } else { - _self.env_variables.insert( - HFUZZ_WORKSPACE_ENV.to_owned(), - HFUZZ_WORKSPACE_DEFAULT.to_owned(), - ); - } - // crashdir - let crash_dir = _f.crashdir.unwrap_or_default(); - if !crash_dir.is_empty() { - _self - .fuzz_args - .push(HonggFuzzArg::new("", "--crashdir", &crash_dir)); - } - // extension - let extension = _f.extension.unwrap_or_default(); - if !extension.is_empty() { - _self - .fuzz_args - .push(HonggFuzzArg::new("-e", "--extension", &extension)); - } - // run_time - let run_time = _f.run_time.unwrap_or(0); - _self - .fuzz_args - .push(HonggFuzzArg::new("", "--run_time", &run_time.to_string())); - - // max_file_size - let max_file_size = _f.max_file_size.unwrap_or(1_048_576); - _self.fuzz_args.push(HonggFuzzArg::new( - "-F", - "--max_file_size", - &max_file_size.to_string(), - )); - // save_all - let save_all = _f.save_all.unwrap_or(false); - if save_all { - _self - .fuzz_args - .push(HonggFuzzArg::new("-u", "--save_all", "")); - } - _self - } -} - -impl HonggFuzzArg { - fn new(short_opt: &str, long_opt: &str, val: &str) -> Self { - let short_opt = if short_opt.is_empty() { - None - } else { - Some(short_opt.to_owned()) - }; - let long_opt = if long_opt.is_empty() { - None - } else { - Some(long_opt.to_owned()) - }; - let val = if val.is_empty() { - None - } else { - Some(val.to_owned()) - }; - Self { - short_opt, - long_opt, - val, - } - } -} - -#[derive(Debug, Deserialize, Clone)] -pub struct Config { - pub honggfuzz: HonggFuzz, - pub fuzz: Fuzz, -} - -#[derive(Default, Debug, Deserialize, Clone)] -struct _Config { - #[serde(default)] - pub honggfuzz: Option<_HonggFuzz>, - #[serde(default)] - pub fuzz: Option<_Fuzz>, -} - -impl From<_Config> for Config { - fn from(_c: _Config) -> Self { - Self { - honggfuzz: _c.honggfuzz.unwrap_or_default().into(), - fuzz: _c.fuzz.unwrap_or_default().into(), - } - } -} - -impl Config { - pub fn new() -> Self { - let root = Config::discover_root().expect("failed to find the root folder"); - let s = fs::read_to_string(root.join(TRIDENT_TOML).as_path()) - .expect("failed to read the Trident config file"); - let _config: _Config = toml::from_str(&s).expect("failed to parse the Trident config file"); - _config.into() - } - - /// Tries to find the root directory with the `Anchor.toml` file. - /// Throws an error when there is no directory with the `Anchor.toml` file - pub fn discover_root() -> Result { - let current_dir = env::current_dir()?; - let mut dir = Some(current_dir.as_path()); - while let Some(cwd) = dir { - for file in std::fs::read_dir(cwd).with_context(|| { - format!("Error reading the directory with path: {}", cwd.display()) - })? { - let path = file - .with_context(|| { - format!("Error reading the directory with path: {}", cwd.display()) - })? - .path(); - if let Some(filename) = path.file_name() { - if filename.to_str() == Some(ANCHOR_TOML) { - return Ok(PathBuf::from(cwd)); - } - } - } - dir = cwd.parent(); - } - throw!(Error::BadWorkspace) - } - pub fn get_honggfuzz_args(&self, cli_input: String) -> String { - // Tested on a few examples, HFUZZ_RUN_ARGS give precedence to the later arguments. - // so if HFUZZ_RUN_ARGS="-t 10 -t 15" -> timeout 15s is applied. - // That means we do not need to parse the arguments from the CLI; - // thus, we can simply append them at the end, and the CLI will have precedence. - - let mut args: Vec = self - .honggfuzz - .fuzz_args - .iter() - .map(|a| { - let val = a.val.to_owned().unwrap_or("".to_string()); - if let Some(o) = &a.short_opt { - format!("{} {}", o, val) - } else if let Some(o) = &a.long_opt { - format!("{} {}", o, val) - } else { - "".to_string() - } - }) - .collect(); - args.push(cli_input); - args.join(" ") - } - pub fn get_rustflags_args(&self, cli_input: String) -> String { - let mut args: Vec = self - .fuzz - .rust_flags - .iter() - .map(|arg| { - if arg.val { - format!("--cfg {}", arg.cfg_identifier) - } else { - "".to_string() - } - }) - .collect(); - args.push(cli_input); - args.join(" ") - } - pub fn get_env_arg(&self, env_variable: &str) -> String { - let expect = format!("{env_variable} not found"); - self.honggfuzz - .env_variables - .get(env_variable) - .expect(&expect) - .to_string() - } -} - -#[cfg(test)] -mod tests { - impl Default for HonggFuzz { - fn default() -> Self { - let mut env_variables: HashMap = HashMap::default(); - env_variables.insert( - HFUZZ_WORKSPACE_ENV.to_owned(), - HFUZZ_WORKSPACE_DEFAULT.to_owned(), - ); - env_variables.insert( - CARGO_TARGET_DIR_ENV.to_owned(), - CARGO_TARGET_DIR_DEFAULT.to_owned(), - ); - Self { - fuzz_args: vec![ - HonggFuzzArg::new("-t", "--timeout", &10.to_string()), - HonggFuzzArg::new("-N", "--iterations", &0.to_string()), - HonggFuzzArg::new("-r", "--mutations_per_run", &6.to_string()), - HonggFuzzArg::new("-e", "--extension", "fuzz"), - HonggFuzzArg::new("", "--run_time", &0.to_string()), - HonggFuzzArg::new("-F", "--max_file_size", &1_048_576.to_string()), - ], - env_variables, - } - } - } - - impl Default for Fuzz { - fn default() -> Self { - let rust_flags = vec![ - Cfg { - cfg_identifier: "allow_duplicate_txs".to_string(), - val: false, - }, - Cfg { - cfg_identifier: "fuzzing_with_stats".to_string(), - val: false, - }, - ]; - - Self { rust_flags } - } - } - - use super::*; - #[test] - fn test_merge_and_precedence1() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz::default(), - }; - - let env_var_string = config.get_honggfuzz_args(String::default()); - assert_eq!( - env_var_string, - "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 " - ); - } - #[test] - fn test_merge_and_precedence2() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz::default(), - }; - - let env_var_string = config.get_honggfuzz_args("-t 0 -N10 --exit_upon_crash".to_string()); - - assert_eq!( - env_var_string, - "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 -t 0 -N10 --exit_upon_crash" - ); - } - #[test] - fn test_merge_and_precedence3() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz::default(), - }; - let env_var_string = - config.get_honggfuzz_args("-t 100 -N 5000 -Q -v --exit_upon_crash".to_string()); - assert_eq!( - env_var_string, - "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 -t 100 -N 5000 -Q -v --exit_upon_crash" - ); - } - #[test] - fn test_merge_and_precedence4() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz::default(), - }; - - let env_var_string = config.get_honggfuzz_args("-t 10 -N 500 -Q -v --exit_upon_crash -n 15 --mutations_per_run 8 --verifier -W random_dir --crashdir random_dir5 --run_time 666".to_string()); - assert_eq!( - env_var_string, - "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 -t 10 -N 500 -Q -v --exit_upon_crash -n 15 --mutations_per_run 8 --verifier -W random_dir --crashdir random_dir5 --run_time 666" - ); - } - #[test] - fn test_merge_and_precedence5() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz::default(), - }; - - let env_var_string = config.get_honggfuzz_args("-t 10 -N 500 -Q -v --exit_upon_crash -n 15 --verifier -W random_dir --crashdir random_dir5 --run_time 666".to_string()); - assert_eq!( - env_var_string, - "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 -t 10 -N 500 -Q -v --exit_upon_crash -n 15 --verifier -W random_dir --crashdir random_dir5 --run_time 666" - ); - } - #[test] - fn test_obtain_env_variables() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz::default(), - }; - - let cargo_target_dir = config.get_env_arg(CARGO_TARGET_DIR_ENV); - - assert_eq!(cargo_target_dir, CARGO_TARGET_DIR_DEFAULT); - let hfuzz_workspace = config.get_env_arg(HFUZZ_WORKSPACE_ENV); - assert_eq!(hfuzz_workspace, HFUZZ_WORKSPACE_DEFAULT); - } - #[test] - fn test_obtain_env_variables2() { - let mut config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz::default(), - }; - - config - .honggfuzz - .env_variables - .insert(CARGO_TARGET_DIR_ENV.to_owned(), "new_value_x".to_owned()); - - config - .honggfuzz - .env_variables - .insert(HFUZZ_WORKSPACE_ENV.to_owned(), "new_value_y".to_owned()); - - let cargo_target_dir = config.get_env_arg(CARGO_TARGET_DIR_ENV); - - assert_eq!(cargo_target_dir, "new_value_x"); - let hfuzz_workspace = config.get_env_arg(HFUZZ_WORKSPACE_ENV); - assert_eq!(hfuzz_workspace, "new_value_y"); - } - - #[test] - fn test_obtain_rustflags_variable1() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz::default(), - }; - - let rustflags = config.get_rustflags_args("".to_string()); - let default_rustflags = " "; - - assert_eq!(rustflags, default_rustflags); - } - #[test] - fn test_obtain_rustflags_variable2() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz { - rust_flags: vec![Cfg { - cfg_identifier: "fuzzing_with_stats".to_string(), - val: true, - }], - }, - }; - - let rustflags = config.get_rustflags_args("".to_string()); - let reference_rustflags = "--cfg fuzzing_with_stats "; - - assert_eq!(rustflags, reference_rustflags); - } - #[test] - fn test_obtain_rustflags_variable3() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz { - rust_flags: vec![ - Cfg { - cfg_identifier: "allow_duplicate_txs".to_string(), - val: true, - }, - Cfg { - cfg_identifier: "fuzzing_with_stats".to_string(), - val: false, - }, - ], - }, - }; - - let rustflags = config.get_rustflags_args("".to_string()); - let reference_rustflags = "--cfg allow_duplicate_txs "; - - assert_eq!(rustflags, reference_rustflags); - } - #[test] - fn test_obtain_rustflags_variable4() { - let config = Config { - honggfuzz: HonggFuzz::default(), - fuzz: Fuzz { - rust_flags: vec![Cfg { - cfg_identifier: "allow_duplicate_txs".to_string(), - val: true, - }], - }, - }; - - let rustflags = config.get_rustflags_args("--cfg fuzzing_with_stats".to_string()); - let reference_rustflags = "--cfg allow_duplicate_txs --cfg fuzzing_with_stats"; - - assert_eq!(rustflags, reference_rustflags); - } -} diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs index 7db5b2934..43b005e99 100644 --- a/crates/client/src/lib.rs +++ b/crates/client/src/lib.rs @@ -31,7 +31,6 @@ pub mod fuzzing { /// trident derive pub use trident_derive_displayix::DisplayIx; - pub use trident_derive_fuzz_deserialize::FuzzDeserialize; pub use trident_derive_fuzz_test_executor::FuzzTestExecutor; /// trident macros @@ -48,6 +47,7 @@ pub mod fuzzing { pub use super::temp_clone::*; /// trident methods pub use trident_fuzz::accounts_storage::*; + pub use trident_fuzz::config::Config; pub use trident_fuzz::error::*; pub use trident_fuzz::fuzz_client::FuzzClient; pub use trident_fuzz::fuzz_data::build_ix_fuzz_data; @@ -58,6 +58,7 @@ pub mod fuzzing { pub use trident_fuzz::ix_ops::IxOps; pub use trident_fuzz::program_test_client_blocking::ProgramTestClientBlocking; pub use trident_fuzz::snapshot::Snapshot; + pub use trident_fuzz::transaction_executor::TransactionExecutor; pub use std::cell::RefCell; pub use std::collections::HashMap; @@ -66,7 +67,6 @@ pub mod fuzzing { mod anchor_idl; mod cleaner; mod commander; -mod config; mod source_code_generators; mod temp_clone; mod test_generator; @@ -97,9 +97,6 @@ mod constants { pub const FUZZ_TEST: &str = "test_fuzz.rs"; pub const HFUZZ_TARGET: &str = "hfuzz_target"; pub const CARGO_TARGET_DIR_DEFAULT: &str = "trident-tests/fuzz_tests/fuzzing/hfuzz_target"; - pub const HFUZZ_WORKSPACE_DEFAULT: &str = "trident-tests/fuzz_tests/fuzzing/hfuzz_workspace"; - pub const CARGO_TARGET_DIR_ENV: &str = "CARGO_TARGET_DIR"; - pub const HFUZZ_WORKSPACE_ENV: &str = "HFUZZ_WORKSPACE"; // workspace pub const GIT_IGNORE: &str = ".gitignore"; diff --git a/crates/client/src/source_code_generators/fuzz_instructions_generator.rs b/crates/client/src/source_code_generators/fuzz_instructions_generator.rs index afd221ff3..00af19b36 100644 --- a/crates/client/src/source_code_generators/fuzz_instructions_generator.rs +++ b/crates/client/src/source_code_generators/fuzz_instructions_generator.rs @@ -35,7 +35,7 @@ pub fn generate_source_code(idls: &[Idl]) -> String { #(#all_snapshot_types)* - #[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] + #[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { #(#all_instructions),* } diff --git a/crates/client/src/source_code_generators/test_fuzz_generator.rs b/crates/client/src/source_code_generators/test_fuzz_generator.rs index 96a1795f0..a9e94eb22 100644 --- a/crates/client/src/source_code_generators/test_fuzz_generator.rs +++ b/crates/client/src/source_code_generators/test_fuzz_generator.rs @@ -21,23 +21,24 @@ pub fn generate_source_code(idl_instructions: &[Idl]) -> String { impl FuzzDataBuilder for MyFuzzData {} - fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { + fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData,config: &Config) { #(#fuzzing_programs)* let mut client = ProgramTestClientBlocking::new(&#programs_array,&[]).unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client,config); } fn main() { + let config = Config::new(); loop { fuzz_trident!(fuzz_ix: FuzzInstruction, |fuzz_data: MyFuzzData| { - fuzz_iteration(fuzz_data); + fuzz_iteration(fuzz_data,&config); }); diff --git a/crates/client/src/templates/trident-tests/Cargo_fuzz.toml.tmpl b/crates/client/src/templates/trident-tests/Cargo_fuzz.toml.tmpl index cd0687a6b..9668ad316 100644 --- a/crates/client/src/templates/trident-tests/Cargo_fuzz.toml.tmpl +++ b/crates/client/src/templates/trident-tests/Cargo_fuzz.toml.tmpl @@ -7,7 +7,6 @@ edition = "2021" # Dependencies specific to Fuzz test [dependencies] # ... your dependencies here -honggfuzz = "0.5.56" arbitrary = "1.3.0" assert_matches = "1.4.0" diff --git a/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs b/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs index 91b147a89..5c2024b33 100644 --- a/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs +++ b/crates/client/tests/expected_source_codes/expected_fuzz_instructions.rs @@ -1,7 +1,7 @@ use trident_client::fuzzing::*; type InitializeIxDummy2Snapshot<'info> = InitializeIxDummy2Alias<'info>; type InitializeIxDummyExampleSnapshot<'info> = InitializeIxDummyExampleAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { InitializeIxDummy2(InitializeIxDummy2), InitializeIxDummyExample(InitializeIxDummyExample), diff --git a/crates/client/tests/expected_source_codes/expected_test_fuzz.rs b/crates/client/tests/expected_source_codes/expected_test_fuzz.rs index 4dce8fb05..1d0368ccd 100644 --- a/crates/client/tests/expected_source_codes/expected_test_fuzz.rs +++ b/crates/client/tests/expected_source_codes/expected_test_fuzz.rs @@ -16,7 +16,10 @@ struct MyFuzzData; impl FuzzDataBuilder for MyFuzzData {} -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_dummy_2 = FuzzingProgram::new( PROGRAM_NAME_DUMMY_2, @@ -36,13 +39,15 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz ) .unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); + loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data , & config) ; }); } } diff --git a/crates/fuzz/Cargo.toml b/crates/fuzz/Cargo.toml index b754c50b8..57ec308bc 100644 --- a/crates/fuzz/Cargo.toml +++ b/crates/fuzz/Cargo.toml @@ -30,3 +30,6 @@ prettytable = "0.10.0" serde = { version = "1.0.136", default-features = false } serde_json = "1.0.72" tokio = "1" +anyhow = "1.0.45" +fehler = "1.0.0" +toml = { version = "0.5.8", features = ["preserve_order"] } diff --git a/crates/fuzz/derive/accounts_snapshots/src/lib.rs b/crates/fuzz/derive/accounts_snapshots/src/lib.rs index 6e505e9b7..8712dcb31 100644 --- a/crates/fuzz/derive/accounts_snapshots/src/lib.rs +++ b/crates/fuzz/derive/accounts_snapshots/src/lib.rs @@ -722,10 +722,10 @@ fn generate(accs: &TridentAccountsStruct) -> proc_macro2::TokenStream { #[cfg(target_os = "solana")] compile_error!("Do not use fuzzing with Production Code"); use super::*; - impl<'info> #snapshot_name<'info> { - pub fn deserialize_option( + impl<'info>trident_fuzz::fuzz_deserialize::FuzzDeserialize<'info> for #snapshot_name<'info> { + fn deserialize_option( _program_id: &anchor_lang::prelude::Pubkey, - accounts: &'info mut [Option>], + accounts: &mut &'info [Option>], ) -> core::result::Result { let mut accounts_iter = accounts.iter(); diff --git a/crates/fuzz/derive/fuzz_deserialize/Cargo.toml b/crates/fuzz/derive/fuzz_deserialize/Cargo.toml deleted file mode 100644 index f0b0a01a5..000000000 --- a/crates/fuzz/derive/fuzz_deserialize/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -rust-version = "1.60" -edition = "2021" -license-file = "../../../../LICENSE" -readme = "../../../../README.md" -description = "trident-derive-fuzz-deserialize" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = "1" diff --git a/crates/fuzz/derive/fuzz_deserialize/src/lib.rs b/crates/fuzz/derive/fuzz_deserialize/src/lib.rs deleted file mode 100644 index 3ed818dec..000000000 --- a/crates/fuzz/derive/fuzz_deserialize/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -use proc_macro::TokenStream; -use quote::{format_ident, quote}; -use syn::{parse_macro_input, Data, DeriveInput}; - -#[proc_macro_derive(FuzzDeserialize)] -pub fn fuzz_deserialize(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - - let fuzz_deser_impls = match &input.data { - Data::Enum(enum_data) => { - let fuzz_deser_impl = enum_data.variants.iter().map(|variant| { - let variant_name = &variant.ident; - let snapshot_name = format_ident!("{}Snapshot", variant_name); - quote! { - impl<'info> FuzzDeserialize<'info> for #variant_name { - type Ix = #snapshot_name<'info>; - fn deserialize_option( - &self, - _program_id: &anchor_lang::prelude::Pubkey, - accounts: &'info mut [Option>], - ) -> Result { - Self::Ix::deserialize_option(_program_id,accounts) - } - } - } - }); - - quote! { #(#fuzz_deser_impl)* } - } - _ => panic!("DisplayIx can only be derived for enums"), - }; - - TokenStream::from(fuzz_deser_impls) -} diff --git a/crates/fuzz/derive/fuzz_test_executor/src/lib.rs b/crates/fuzz/derive/fuzz_test_executor/src/lib.rs index 4f72998b0..9603a6999 100644 --- a/crates/fuzz/derive/fuzz_test_executor/src/lib.rs +++ b/crates/fuzz/derive/fuzz_test_executor/src/lib.rs @@ -13,86 +13,19 @@ pub fn fuzz_test_executor(input: TokenStream) -> TokenStream { let variant_name = &variant.ident; quote! { #enum_name::#variant_name (ix) => { - let program_id = ix.get_program_id(); - let (mut signers, metas) = ix.get_accounts(client, &mut accounts.borrow_mut()) - .map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))) - .expect("Accounts calculation expect"); - - let mut snaphot = Snapshot::new(&metas, ix); - snaphot.capture_before(client).unwrap(); - - let data = ix.get_data(client, &mut accounts.borrow_mut()) - .map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))) - .expect("Data calculation expect"); - - let ixx = Instruction { - program_id, - accounts: metas.clone(), - data: data.data(), - }; - - let mut transaction = - Transaction::new_with_payer(&[ixx], Some(&client.payer().pubkey())); - - signers.push(client.payer().clone()); - let sig: Vec<&Keypair> = signers.iter().collect(); - transaction.sign(&sig, client.get_last_blockhash()); - - let duplicate_tx = if cfg!(allow_duplicate_txs) { - None - } else { - let message_hash = transaction.message().hash(); - sent_txs.insert(message_hash, ()) - }; - - match duplicate_tx { - Some(_) => eprintln!("\x1b[1;93mWarning\x1b[0m: Skipping duplicate instruction `{}`", self.to_context_string()), - None => { - #[cfg(fuzzing_with_stats)] - let mut stats_logger = FuzzingStatistics::new(); - #[cfg(fuzzing_with_stats)] - stats_logger.increase_invoked(self.to_context_string()); - - let tx_result = client.process_transaction(transaction) - .map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))); - match tx_result { - Ok(_) => { - #[cfg(fuzzing_with_stats)] - stats_logger.increase_successful(self.to_context_string()); - - snaphot.capture_after(client).unwrap(); - let (acc_before, acc_after) = snaphot.get_snapshot(&program_id) - .map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))) - .expect("Snapshot deserialization expect"); // we want to panic if we cannot unwrap to cause a crash - - if let Err(e) = ix.check(acc_before, acc_after, data).map_err(|e| e.with_origin(Origin::Instruction(self.to_context_string()))) { - #[cfg(fuzzing_with_stats)] - { - stats_logger.increase_failed_check(self.to_context_string()); - stats_logger.output_serialized(); - } - eprintln!( - "\x1b[31mCRASH DETECTED!\x1b[0m Custom check after the {} instruction did not pass!", - self.to_context_string()); - panic!("{}", e) - } - #[cfg(fuzzing_with_stats)] - stats_logger.output_serialized(); - - }, - Err(e) => { - #[cfg(fuzzing_with_stats)] - { - stats_logger.increase_failed(self.to_context_string()); - stats_logger.output_serialized(); - } - let mut raw_accounts = snaphot.get_raw_pre_ix_accounts(); - ix.tx_error_handler(e, data, &mut raw_accounts)? - } - } - } - } + // snapshot has to live as long as ix, thus we declare it here + let mut snaphot = Snapshot::new_empty(ix); + + TransactionExecutor::process_transaction( + &self.to_context_string(), + client, + ix, + &mut snaphot, + sent_txs, + config, + accounts + )?; } } }); @@ -104,6 +37,7 @@ pub fn fuzz_test_executor(input: TokenStream) -> TokenStream { accounts: &RefCell, client: &mut impl FuzzClient, sent_txs: &mut HashMap, + config: &Config, ) -> core::result::Result<(), FuzzClientErrorWithOrigin> { match self { #(#display_match_arms)* diff --git a/crates/fuzz/src/config/constants.rs b/crates/fuzz/src/config/constants.rs new file mode 100644 index 000000000..0c67c2b09 --- /dev/null +++ b/crates/fuzz/src/config/constants.rs @@ -0,0 +1,8 @@ +// tomls +pub const TRIDENT_TOML: &str = "Trident.toml"; +pub const ANCHOR_TOML: &str = "Anchor.toml"; + +pub const CARGO_TARGET_DIR_DEFAULT: &str = "trident-tests/fuzz_tests/fuzzing/hfuzz_target"; +pub const HFUZZ_WORKSPACE_DEFAULT: &str = "trident-tests/fuzz_tests/fuzzing/hfuzz_workspace"; +pub const CARGO_TARGET_DIR_ENV: &str = "CARGO_TARGET_DIR"; +pub const HFUZZ_WORKSPACE_ENV: &str = "HFUZZ_WORKSPACE"; diff --git a/crates/fuzz/src/config/fuzz.rs b/crates/fuzz/src/config/fuzz.rs new file mode 100644 index 000000000..32a635515 --- /dev/null +++ b/crates/fuzz/src/config/fuzz.rs @@ -0,0 +1,32 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize, Clone, Default)] +pub struct Fuzz { + pub fuzzing_with_stats: bool, + pub allow_duplicate_txs: bool, +} + +#[derive(Default, Debug, Deserialize, Clone)] +pub struct _Fuzz { + #[serde(default)] + pub fuzzing_with_stats: bool, + #[serde(default)] + pub allow_duplicate_txs: bool, +} +impl From<_Fuzz> for Fuzz { + fn from(_f: _Fuzz) -> Self { + Self { + fuzzing_with_stats: _f.fuzzing_with_stats, + allow_duplicate_txs: _f.allow_duplicate_txs, + } + } +} + +impl Fuzz { + pub fn get_fuzzing_with_stats(&self) -> bool { + self.fuzzing_with_stats + } + pub fn get_allow_duplicate_txs(&self) -> bool { + self.allow_duplicate_txs + } +} diff --git a/crates/fuzz/src/config/honggfuzz.rs b/crates/fuzz/src/config/honggfuzz.rs new file mode 100644 index 000000000..edc476d54 --- /dev/null +++ b/crates/fuzz/src/config/honggfuzz.rs @@ -0,0 +1,229 @@ +use serde::Deserialize; +use std::collections::HashMap; + +use crate::config::constants::*; + +#[derive(Debug, Deserialize, Clone)] +pub struct HonggFuzzArg { + pub short_opt: Option, + pub long_opt: Option, + pub val: Option, +} +#[derive(Debug, Deserialize, Clone)] +pub struct HonggFuzz { + pub fuzz_args: Vec, + pub env_variables: HashMap, +} +#[derive(Default, Debug, Deserialize, Clone)] +pub struct _HonggFuzz { + #[serde(default)] + /// Timeout in seconds (default: 10) + /// -t + /// --timeout + pub timeout: Option, + #[serde(default)] + /// Number of fuzzing iterations (default: 0 [no limit]) + /// -N + /// --iterations + pub iterations: Option, + #[serde(default)] + /// Number of concurrent fuzzing threads (default: number of CPUs / 2) + /// -n + /// --threads + pub threads: Option, + #[serde(default)] + /// Don't close children's stdin, stdout, stderr; can be noisy + /// -Q + /// --keep_output + pub keep_output: Option, + #[serde(default)] + /// Disable ANSI console; use simple log output + /// -v + /// --verbose + pub verbose: Option, + #[serde(default)] + /// Exit upon seeing the first crash (default: false) + /// --exit_upon_crash + pub exit_upon_crash: Option, + #[serde(default)] + /// Maximal number of mutations per one run (default: 6) + /// -r + /// --mutations_per_run + pub mutations_per_run: Option, + #[serde(default)] + /// Target compilation directory, defaults to "trident-tests/fuzz_tests/fuzzing/hfuzz_target" to not clash with cargo build's default target directory. + /// CARGO_TARGET_DIR env variable + pub cargo_target_dir: Option, + #[serde(default)] + /// Honggfuzz working directory, defaults to "trident-tests/fuzz_tests/fuzzing/hfuzz_workspace". + /// HFUZZ_WORKSPACE env variable + pub hfuzz_workspace: Option, + #[serde(default)] + /// Directory where crashes are saved to (default: workspace directory) + /// --crashdir + pub crashdir: Option, + #[serde(default)] + /// Input file extension (e.g. 'swf'), (default: 'fuzz') + /// -e + /// --extension + pub extension: Option, + #[serde(default)] + /// Number of seconds this fuzzing session will last (default: 0 [no limit]) + /// --run_time + pub run_time: Option, + #[serde(default)] + /// Maximal size of files processed by the fuzzer in bytes (default: 1048576 = 1MB) + /// -F + /// --max_file_size + pub max_file_size: Option, + #[serde(default)] + /// Save all test-cases (not only the unique ones) by appending the current time-stamp to the filenames (default: false) + /// -u + /// --save_all + pub save_all: Option, +} + +impl From<_HonggFuzz> for HonggFuzz { + fn from(_f: _HonggFuzz) -> Self { + let mut _self = Self { + fuzz_args: vec![], + env_variables: HashMap::default(), + }; + + // timeout + let timeout = _f.timeout.unwrap_or(10); + _self + .fuzz_args + .push(HonggFuzzArg::new("-t", "--timeout", &timeout.to_string())); + + // iterations + let iterations = _f.iterations.unwrap_or(0); + _self.fuzz_args.push(HonggFuzzArg::new( + "-N", + "--iterations", + &iterations.to_string(), + )); + + // threads + let threads = _f.threads.unwrap_or(0); + if threads > 0 { + _self + .fuzz_args + .push(HonggFuzzArg::new("-n", "--threads", &threads.to_string())); + } + + // keep_output + let keep_output = _f.keep_output.unwrap_or(false); + if keep_output { + _self + .fuzz_args + .push(HonggFuzzArg::new("-Q", "--keep_output", "")); + } + // verbose + let verbose = _f.verbose.unwrap_or(false); + if verbose { + _self + .fuzz_args + .push(HonggFuzzArg::new("-v", "--verbose", "")); + } + + // exit_upon_crash + let exit_upon_crash = _f.exit_upon_crash.unwrap_or(false); + if exit_upon_crash { + _self + .fuzz_args + .push(HonggFuzzArg::new("", "--exit_upon_crash", "")); + } + // mutations_per_run + let mutations_per_run = _f.mutations_per_run.unwrap_or(6); + _self.fuzz_args.push(HonggFuzzArg::new( + "-r", + "--mutations_per_run", + &mutations_per_run.to_string(), + )); + // cargo_target_dir + let cargo_target_dir = _f.cargo_target_dir.unwrap_or_default(); + if !cargo_target_dir.is_empty() { + _self + .env_variables + .insert(CARGO_TARGET_DIR_ENV.to_owned(), cargo_target_dir); + } else { + _self.env_variables.insert( + CARGO_TARGET_DIR_ENV.to_owned(), + CARGO_TARGET_DIR_DEFAULT.to_owned(), + ); + } + // hfuzz_workspace + let hfuzz_workspace = _f.hfuzz_workspace.unwrap_or_default(); + if !hfuzz_workspace.is_empty() { + _self + .env_variables + .insert(HFUZZ_WORKSPACE_ENV.to_owned(), hfuzz_workspace); + } else { + _self.env_variables.insert( + HFUZZ_WORKSPACE_ENV.to_owned(), + HFUZZ_WORKSPACE_DEFAULT.to_owned(), + ); + } + // crashdir + let crash_dir = _f.crashdir.unwrap_or_default(); + if !crash_dir.is_empty() { + _self + .fuzz_args + .push(HonggFuzzArg::new("", "--crashdir", &crash_dir)); + } + // extension + let extension = _f.extension.unwrap_or_default(); + if !extension.is_empty() { + _self + .fuzz_args + .push(HonggFuzzArg::new("-e", "--extension", &extension)); + } + // run_time + let run_time = _f.run_time.unwrap_or(0); + _self + .fuzz_args + .push(HonggFuzzArg::new("", "--run_time", &run_time.to_string())); + + // max_file_size + let max_file_size = _f.max_file_size.unwrap_or(1_048_576); + _self.fuzz_args.push(HonggFuzzArg::new( + "-F", + "--max_file_size", + &max_file_size.to_string(), + )); + // save_all + let save_all = _f.save_all.unwrap_or(false); + if save_all { + _self + .fuzz_args + .push(HonggFuzzArg::new("-u", "--save_all", "")); + } + _self + } +} + +impl HonggFuzzArg { + pub(crate) fn new(short_opt: &str, long_opt: &str, val: &str) -> Self { + let short_opt = if short_opt.is_empty() { + None + } else { + Some(short_opt.to_owned()) + }; + let long_opt = if long_opt.is_empty() { + None + } else { + Some(long_opt.to_owned()) + }; + let val = if val.is_empty() { + None + } else { + Some(val.to_owned()) + }; + Self { + short_opt, + long_opt, + val, + } + } +} diff --git a/crates/fuzz/src/config/mod.rs b/crates/fuzz/src/config/mod.rs new file mode 100644 index 000000000..7eb35ba66 --- /dev/null +++ b/crates/fuzz/src/config/mod.rs @@ -0,0 +1,261 @@ +mod constants; +mod fuzz; +mod honggfuzz; + +use constants::*; +use fuzz::*; +use honggfuzz::*; + +use anyhow::Context; +use fehler::throw; +use serde::Deserialize; +use std::{env, fs, io, path::PathBuf}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("invalid workspace")] + BadWorkspace, + #[error("{0:?}")] + Anyhow(#[from] anyhow::Error), + #[error("{0:?}")] + Io(#[from] io::Error), + #[error("{0:?}")] + Toml(#[from] toml::de::Error), +} + +#[derive(Debug, Deserialize, Clone)] +pub struct Config { + pub honggfuzz: HonggFuzz, + pub fuzz: Fuzz, +} + +#[derive(Default, Debug, Deserialize, Clone)] +struct _Config { + #[serde(default)] + pub honggfuzz: Option<_HonggFuzz>, + #[serde(default)] + pub fuzz: Option<_Fuzz>, +} + +impl From<_Config> for Config { + fn from(_c: _Config) -> Self { + Self { + honggfuzz: _c.honggfuzz.unwrap_or_default().into(), + fuzz: _c.fuzz.unwrap_or_default().into(), + } + } +} + +impl Config { + pub fn new() -> Self { + let root = discover_root().expect("failed to find the root folder"); + let s = fs::read_to_string(root.join(TRIDENT_TOML).as_path()) + .expect("failed to read the Trident config file"); + let _config: _Config = toml::from_str(&s).expect("failed to parse the Trident config file"); + _config.into() + } + + pub fn get_honggfuzz_args(&self, cli_input: String) -> String { + // Tested on a few examples, HFUZZ_RUN_ARGS give precedence to the later arguments. + // so if HFUZZ_RUN_ARGS="-t 10 -t 15" -> timeout 15s is applied. + // That means we do not need to parse the arguments from the CLI; + // thus, we can simply append them at the end, and the CLI will have precedence. + + let mut args: Vec = self + .honggfuzz + .fuzz_args + .iter() + .map(|a| { + let val = a.val.to_owned().unwrap_or("".to_string()); + if let Some(o) = &a.short_opt { + format!("{} {}", o, val) + } else if let Some(o) = &a.long_opt { + format!("{} {}", o, val) + } else { + "".to_string() + } + }) + .collect(); + args.push(cli_input); + args.join(" ") + } + pub fn get_env_arg(&self, env_variable: &str) -> String { + let expect = format!("{env_variable} not found"); + self.honggfuzz + .env_variables + .get(env_variable) + .expect(&expect) + .to_string() + } + pub fn get_fuzzing_with_stats(&self) -> bool { + self.fuzz.get_fuzzing_with_stats() + } + pub fn get_allow_duplicate_txs(&self) -> bool { + self.fuzz.get_allow_duplicate_txs() + } +} + +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + +/// Tries to find the root directory with the `Anchor.toml` file. +/// Throws an error when there is no directory with the `Anchor.toml` file +pub fn discover_root() -> Result { + let current_dir = env::current_dir()?; + let mut dir = Some(current_dir.as_path()); + while let Some(cwd) = dir { + for file in std::fs::read_dir(cwd) + .with_context(|| format!("Error reading the directory with path: {}", cwd.display()))? + { + let path = file + .with_context(|| { + format!("Error reading the directory with path: {}", cwd.display()) + })? + .path(); + if let Some(filename) = path.file_name() { + if filename.to_str() == Some(ANCHOR_TOML) { + return Ok(PathBuf::from(cwd)); + } + } + } + dir = cwd.parent(); + } + throw!(Error::BadWorkspace) +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + impl Default for HonggFuzz { + fn default() -> Self { + let mut env_variables: HashMap = HashMap::default(); + env_variables.insert( + HFUZZ_WORKSPACE_ENV.to_owned(), + HFUZZ_WORKSPACE_DEFAULT.to_owned(), + ); + env_variables.insert( + CARGO_TARGET_DIR_ENV.to_owned(), + CARGO_TARGET_DIR_DEFAULT.to_owned(), + ); + Self { + fuzz_args: vec![ + HonggFuzzArg::new("-t", "--timeout", &10.to_string()), + HonggFuzzArg::new("-N", "--iterations", &0.to_string()), + HonggFuzzArg::new("-r", "--mutations_per_run", &6.to_string()), + HonggFuzzArg::new("-e", "--extension", "fuzz"), + HonggFuzzArg::new("", "--run_time", &0.to_string()), + HonggFuzzArg::new("-F", "--max_file_size", &1_048_576.to_string()), + ], + env_variables, + } + } + } + + use super::*; + #[test] + fn test_merge_and_precedence1() { + let config = Config { + honggfuzz: HonggFuzz::default(), + fuzz: Fuzz::default(), + }; + + let env_var_string = config.get_honggfuzz_args(String::default()); + assert_eq!( + env_var_string, + "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 " + ); + } + #[test] + fn test_merge_and_precedence2() { + let config = Config { + honggfuzz: HonggFuzz::default(), + fuzz: Fuzz::default(), + }; + + let env_var_string = config.get_honggfuzz_args("-t 0 -N10 --exit_upon_crash".to_string()); + + assert_eq!( + env_var_string, + "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 -t 0 -N10 --exit_upon_crash" + ); + } + #[test] + fn test_merge_and_precedence3() { + let config = Config { + honggfuzz: HonggFuzz::default(), + fuzz: Fuzz::default(), + }; + let env_var_string = + config.get_honggfuzz_args("-t 100 -N 5000 -Q -v --exit_upon_crash".to_string()); + assert_eq!( + env_var_string, + "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 -t 100 -N 5000 -Q -v --exit_upon_crash" + ); + } + #[test] + fn test_merge_and_precedence4() { + let config = Config { + honggfuzz: HonggFuzz::default(), + fuzz: Fuzz::default(), + }; + + let env_var_string = config.get_honggfuzz_args("-t 10 -N 500 -Q -v --exit_upon_crash -n 15 --mutations_per_run 8 --verifier -W random_dir --crashdir random_dir5 --run_time 666".to_string()); + assert_eq!( + env_var_string, + "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 -t 10 -N 500 -Q -v --exit_upon_crash -n 15 --mutations_per_run 8 --verifier -W random_dir --crashdir random_dir5 --run_time 666" + ); + } + #[test] + fn test_merge_and_precedence5() { + let config = Config { + honggfuzz: HonggFuzz::default(), + fuzz: Fuzz::default(), + }; + + let env_var_string = config.get_honggfuzz_args("-t 10 -N 500 -Q -v --exit_upon_crash -n 15 --verifier -W random_dir --crashdir random_dir5 --run_time 666".to_string()); + assert_eq!( + env_var_string, + "-t 10 -N 0 -r 6 -e fuzz --run_time 0 -F 1048576 -t 10 -N 500 -Q -v --exit_upon_crash -n 15 --verifier -W random_dir --crashdir random_dir5 --run_time 666" + ); + } + #[test] + fn test_obtain_env_variables() { + let config = Config { + honggfuzz: HonggFuzz::default(), + fuzz: Fuzz::default(), + }; + + let cargo_target_dir = config.get_env_arg(CARGO_TARGET_DIR_ENV); + + assert_eq!(cargo_target_dir, CARGO_TARGET_DIR_DEFAULT); + let hfuzz_workspace = config.get_env_arg(HFUZZ_WORKSPACE_ENV); + assert_eq!(hfuzz_workspace, HFUZZ_WORKSPACE_DEFAULT); + } + #[test] + fn test_obtain_env_variables2() { + let mut config = Config { + honggfuzz: HonggFuzz::default(), + fuzz: Fuzz::default(), + }; + + config + .honggfuzz + .env_variables + .insert(CARGO_TARGET_DIR_ENV.to_owned(), "new_value_x".to_owned()); + + config + .honggfuzz + .env_variables + .insert(HFUZZ_WORKSPACE_ENV.to_owned(), "new_value_y".to_owned()); + + let cargo_target_dir = config.get_env_arg(CARGO_TARGET_DIR_ENV); + + assert_eq!(cargo_target_dir, "new_value_x"); + let hfuzz_workspace = config.get_env_arg(HFUZZ_WORKSPACE_ENV); + assert_eq!(hfuzz_workspace, "new_value_y"); + } +} diff --git a/crates/fuzz/src/fuzz_data.rs b/crates/fuzz/src/fuzz_data.rs index 87eb422a2..bf96e5e62 100644 --- a/crates/fuzz/src/fuzz_data.rs +++ b/crates/fuzz/src/fuzz_data.rs @@ -11,6 +11,7 @@ use std::collections::HashMap; use std::error::Error; use std::fmt::Display; +use crate::config::Config; use crate::error::*; use crate::fuzz_client::FuzzClient; use crate::fuzz_test_executor::FuzzTestExecutor; @@ -56,6 +57,7 @@ where pub fn run_with_runtime( &self, client: &mut impl FuzzClient, + config: &Config, ) -> core::result::Result<(), Box> { // solana_logger::setup_with_default("off"); // #[cfg(fuzzing_debug)] @@ -83,7 +85,7 @@ where eprintln!("\x1b[34mCurrently processing\x1b[0m: {}", fuzz_ix); if fuzz_ix - .run_fuzzer(&self.accounts, client, &mut sent_txs) + .run_fuzzer(&self.accounts, client, &mut sent_txs, config) .is_err() { // for now skip following instructions in case of error and move to the next fuzz iteration diff --git a/crates/fuzz/src/fuzz_deserialize.rs b/crates/fuzz/src/fuzz_deserialize.rs index e38093a9f..fbc2724b9 100644 --- a/crates/fuzz/src/fuzz_deserialize.rs +++ b/crates/fuzz/src/fuzz_deserialize.rs @@ -4,13 +4,11 @@ use anchor_lang::solana_program::account_info::AccountInfo; use crate::error::FuzzingError; -pub trait FuzzDeserialize<'info> { - type Ix; +pub trait FuzzDeserialize<'info>: Sized { // TODO return also remaining accounts fn deserialize_option( - &self, _program_id: &anchor_lang::prelude::Pubkey, - accounts: &'info mut [Option>], - ) -> Result; + accounts: &mut &'info [Option>], + ) -> Result; } diff --git a/crates/fuzz/src/fuzz_test_executor.rs b/crates/fuzz/src/fuzz_test_executor.rs index 727ffab15..6f7326fe7 100644 --- a/crates/fuzz/src/fuzz_test_executor.rs +++ b/crates/fuzz/src/fuzz_test_executor.rs @@ -5,6 +5,7 @@ use anchor_lang::solana_program::hash::Hash; use std::cell::RefCell; use std::collections::HashMap; +use crate::config::Config; use crate::error::FuzzClientErrorWithOrigin; use crate::fuzz_client::FuzzClient; @@ -14,5 +15,6 @@ pub trait FuzzTestExecutor { accounts: &RefCell, client: &mut impl FuzzClient, sent_txs: &mut HashMap, + config: &Config, ) -> core::result::Result<(), FuzzClientErrorWithOrigin>; } diff --git a/crates/fuzz/src/ix_ops.rs b/crates/fuzz/src/ix_ops.rs index 2b3680e1a..983fc0557 100644 --- a/crates/fuzz/src/ix_ops.rs +++ b/crates/fuzz/src/ix_ops.rs @@ -2,7 +2,9 @@ use crate::error::*; use crate::fuzz_client::FuzzClient; +use crate::fuzz_deserialize::FuzzDeserialize; use anchor_lang::solana_program::account_info::AccountInfo; +use anchor_lang::InstructionData; use solana_sdk::instruction::AccountMeta; use solana_sdk::signature::Keypair; @@ -10,11 +12,11 @@ use solana_sdk::signature::Keypair; /// users to implement custom invariants checks and transactions error handling. pub trait IxOps<'info> { /// The data to be passed as instruction data parameter - type IxData; + type IxData: InstructionData; /// The accounts to be passed as instruction accounts type IxAccounts; /// The structure to which the instruction accounts will be deserialized - type IxSnapshot; + type IxSnapshot: FuzzDeserialize<'info>; /// Specify Program ID to which the Instruction corresponds. This is particularly helpful when using multiple /// programs in the workspace, to differentiate between possible program calls. @@ -71,15 +73,26 @@ pub trait IxOps<'info> { /// the `pre_ix_acc_infos` raw accounts to a snapshot structure, you can call: /// /// ```rust,ignore - /// self.deserialize_option(pre_ix_acc_infos) + /// self.deserialize_accounts(pre_ix_acc_infos) /// ``` #[allow(unused_variables)] fn tx_error_handler( &self, e: FuzzClientErrorWithOrigin, ix_data: Self::IxData, - pre_ix_acc_infos: &'info mut [Option>], + pre_ix_acc_infos: &mut &'info [Option>], ) -> Result<(), FuzzClientErrorWithOrigin> { Err(e) } + + /// A method implemented for each instruction variant. + /// This method calls the corresponding `deserialize_option`, which is defined + /// by deriving the `AccountsSnapshot` macro. + /// No changes are needed for this function. + fn deserialize_accounts( + &self, + accounts: &mut &'info [Option>], + ) -> Result { + Self::IxSnapshot::deserialize_option(&self.get_program_id(), accounts) + } } diff --git a/crates/fuzz/src/lib.rs b/crates/fuzz/src/lib.rs index d12aaf109..614575856 100644 --- a/crates/fuzz/src/lib.rs +++ b/crates/fuzz/src/lib.rs @@ -5,8 +5,10 @@ pub mod fuzz_stats; pub mod program_test_client_blocking; pub mod snapshot; pub type AccountId = u8; +pub mod config; pub mod fuzz_client; pub mod fuzz_deserialize; pub mod fuzz_test_executor; pub mod fuzz_trident; pub mod ix_ops; +pub mod transaction_executor; diff --git a/crates/fuzz/src/snapshot.rs b/crates/fuzz/src/snapshot.rs index 647ed59a6..94f56cff4 100644 --- a/crates/fuzz/src/snapshot.rs +++ b/crates/fuzz/src/snapshot.rs @@ -5,30 +5,49 @@ use anchor_lang::solana_program::account_info::AccountInfo; use solana_sdk::{account::Account, instruction::AccountMeta}; use crate::fuzz_client::FuzzClient; -use crate::fuzz_deserialize::FuzzDeserialize; use crate::error::*; +use crate::ix_ops::IxOps; pub struct Snapshot<'info, T> { before: Vec>, before_acc_inf: Vec>>, after: Vec>, after_acc_inf: Vec>>, - metas: &'info [AccountMeta], + metas: Vec, ix: &'info T, } impl<'info, T> Snapshot<'info, T> where - T: FuzzDeserialize<'info>, + T: IxOps<'info>, { - pub fn new(metas: &'info [AccountMeta], ix: &'info T) -> Snapshot<'info, T> { + pub fn new_empty(ix: &'info T) -> Snapshot<'info, T> { + let capacity = 0; + Self { + before: Vec::with_capacity(capacity), + before_acc_inf: Vec::with_capacity(capacity), + after: Vec::with_capacity(capacity), + after_acc_inf: Vec::with_capacity(capacity), + metas: vec![], + ix, + } + } + pub fn add_metas(&mut self, metas: &[AccountMeta]) { + let capacity = metas.len(); + self.before = Vec::with_capacity(capacity); + self.before_acc_inf = Vec::with_capacity(capacity); + self.after = Vec::with_capacity(capacity); + self.after_acc_inf = Vec::with_capacity(capacity); + self.metas = metas.to_vec(); + } + pub fn new(metas: &[AccountMeta], ix: &'info T) -> Snapshot<'info, T> { let capacity = metas.len(); Self { before: Vec::with_capacity(capacity), before_acc_inf: Vec::with_capacity(capacity), after: Vec::with_capacity(capacity), after_acc_inf: Vec::with_capacity(capacity), - metas, + metas: metas.to_vec(), ix, } } @@ -57,7 +76,7 @@ where &mut self, client: &mut impl FuzzClient, ) -> Result>, FuzzClientErrorWithOrigin> { - client.get_accounts(self.metas) + client.get_accounts(&self.metas) } fn calculate_account_info( @@ -95,15 +114,15 @@ where } } - pub fn get_raw_pre_ix_accounts(&'info mut self) -> Vec>> { + pub fn get_raw_pre_ix_accounts(&'info mut self) -> &[Option>] { Self::set_missing_accounts_to_default(&mut self.before); - Self::calculate_account_info(&mut self.before, self.metas) + self.before_acc_inf = Self::calculate_account_info(&mut self.before, &self.metas); + &self.before_acc_inf } pub fn get_snapshot( &'info mut self, - program_id: &solana_sdk::pubkey::Pubkey, - ) -> Result<(T::Ix, T::Ix), FuzzingErrorWithOrigin> { + ) -> Result<(T::IxSnapshot, T::IxSnapshot), FuzzingErrorWithOrigin> { // When user passes an account that is not initialized, the runtime will provide // a default empty account to the program. If the uninitialized account is of type // AccountInfo, Signer or UncheckedAccount, Anchor will not return an error. However @@ -114,16 +133,19 @@ where Self::set_missing_accounts_to_default(&mut self.before); Self::set_missing_accounts_to_default(&mut self.after); - self.before_acc_inf = Self::calculate_account_info(&mut self.before, self.metas); - self.after_acc_inf = Self::calculate_account_info(&mut self.after, self.metas); + self.before_acc_inf = Self::calculate_account_info(&mut self.before, &self.metas); + self.after_acc_inf = Self::calculate_account_info(&mut self.after, &self.metas); + + let mut remaining_accounts_before: &[Option>] = &self.before_acc_inf; + let mut remaining_accounts_after: &[Option>] = &self.after_acc_inf; let pre_ix = self .ix - .deserialize_option(program_id, &mut self.before_acc_inf) + .deserialize_accounts(&mut remaining_accounts_before) .map_err(|e| e.with_context(Context::Pre))?; let post_ix = self .ix - .deserialize_option(program_id, &mut self.after_acc_inf) + .deserialize_accounts(&mut remaining_accounts_after) .map_err(|e| e.with_context(Context::Post))?; Ok((pre_ix, post_ix)) } diff --git a/crates/fuzz/src/transaction_executor.rs b/crates/fuzz/src/transaction_executor.rs new file mode 100644 index 000000000..7d30f9875 --- /dev/null +++ b/crates/fuzz/src/transaction_executor.rs @@ -0,0 +1,144 @@ +use std::{cell::RefCell, collections::HashMap}; + +use anchor_lang::InstructionData; +use solana_sdk::{ + instruction::Instruction, signature::Keypair, signer::Signer, transaction::Transaction, +}; + +use crate::{ + config::Config, + error::{FuzzClientErrorWithOrigin, Origin}, + fuzz_client::FuzzClient, + fuzz_stats::FuzzingStatistics, + ix_ops::IxOps, + snapshot::Snapshot, +}; + +pub struct TransactionExecutor; + +impl TransactionExecutor { + #[allow(clippy::too_many_arguments)] + pub fn process_transaction<'info, I>( + instruction_name: &str, + client: &mut impl FuzzClient, + ix: &'info I, + snapshot: &'info mut Snapshot<'info, I>, + sent_txs: &mut HashMap, + config: &Config, + accounts: &RefCell, + ) -> core::result::Result<(), FuzzClientErrorWithOrigin> + where + I: IxOps<'info>, + { + let program_id = ix.get_program_id(); + + let (mut signers, account_metas) = ix + .get_accounts(client, &mut accounts.borrow_mut()) + .map_err(|e| e.with_origin(Origin::Instruction(instruction_name.to_owned()))) + .expect("Accounts calculation expect"); + + let data = ix + .get_data(client, &mut accounts.borrow_mut()) + .map_err(|e| e.with_origin(Origin::Instruction(instruction_name.to_owned()))) + .expect("Data calculation expect"); + + snapshot.add_metas(&account_metas); + + snapshot.capture_before(client).unwrap(); + + let ixx = Instruction { + program_id, + accounts: account_metas, + data: data.data(), + }; + + let mut transaction = Transaction::new_with_payer(&[ixx], Some(&client.payer().pubkey())); + + signers.push(client.payer().insecure_clone()); + let sig: Vec<&Keypair> = signers.iter().collect(); + transaction.sign(&sig, client.get_last_blockhash()); + + let duplicate_tx = if config.get_allow_duplicate_txs() { + None + } else { + let message_hash = transaction.message().hash(); + sent_txs.insert(message_hash, ()) + }; + + match duplicate_tx { + Some(_) => eprintln!( + "\x1b[1;93mWarning\x1b[0m: Skipping duplicate instruction `{}`", + instruction_name.to_owned() + ), + None => { + if config.get_fuzzing_with_stats() { + let mut stats_logger = FuzzingStatistics::new(); + + stats_logger.increase_invoked(instruction_name.to_owned()); + + let tx_result = client.process_transaction(transaction).map_err(|e| { + e.with_origin(Origin::Instruction(instruction_name.to_owned())) + }); + match tx_result { + Ok(_) => { + stats_logger.increase_successful(instruction_name.to_owned()); + + snapshot.capture_after(client).unwrap(); + let (acc_before, acc_after) = snapshot + .get_snapshot() + .map_err(|e| { + e.with_origin(Origin::Instruction(instruction_name.to_owned())) + }) + .expect("Snapshot deserialization expect"); // we want to panic if we cannot unwrap to cause a crash + + if let Err(e) = ix.check(acc_before, acc_after, data).map_err(|e| { + e.with_origin(Origin::Instruction(instruction_name.to_owned())) + }) { + stats_logger.increase_failed_check(instruction_name.to_owned()); + stats_logger.output_serialized(); + + eprintln!("\x1b[31mCRASH DETECTED!\x1b[0m Custom check after the {} instruction did not pass!",instruction_name.to_owned()); + panic!("{}", e) + } + stats_logger.output_serialized(); + } + Err(e) => { + stats_logger.increase_failed(instruction_name.to_owned()); + stats_logger.output_serialized(); + + let mut raw_accounts = snapshot.get_raw_pre_ix_accounts(); + ix.tx_error_handler(e, data, &mut raw_accounts)? + } + } + } else { + let tx_result = client.process_transaction(transaction).map_err(|e| { + e.with_origin(Origin::Instruction(instruction_name.to_owned())) + }); + match tx_result { + Ok(_) => { + snapshot.capture_after(client).unwrap(); + let (acc_before, acc_after) = snapshot + .get_snapshot() + .map_err(|e| { + e.with_origin(Origin::Instruction(instruction_name.to_owned())) + }) + .expect("Snapshot deserialization expect"); // we want to panic if we cannot unwrap to cause a crash + + if let Err(e) = ix.check(acc_before, acc_after, data).map_err(|e| { + e.with_origin(Origin::Instruction(instruction_name.to_owned())) + }) { + eprintln!("\x1b[31mCRASH DETECTED!\x1b[0m Custom check after the {} instruction did not pass!",instruction_name.to_owned()); + panic!("{}", e) + } + } + Err(e) => { + let mut raw_accounts = snapshot.get_raw_pre_ix_accounts(); + ix.tx_error_handler(e, data, &mut raw_accounts)? + } + } + } + } + } + Ok(()) + } +} diff --git a/documentation/docs/features/fuzz-instructions.md b/documentation/docs/features/fuzz-instructions.md index dc8302db1..590ae9513 100644 --- a/documentation/docs/features/fuzz-instructions.md +++ b/documentation/docs/features/fuzz-instructions.md @@ -32,6 +32,7 @@ Each Instruction variant has to define `IxOps` trait containing the following me - `get_accounts()` (required) - `check()` (optional) - `tx_error_handler()` (optional) +- `deserialize_accounts()` (automatically implemented) ## Get Program ID diff --git a/examples/fuzz-tests/arbitrary-custom-types-4/Cargo.lock b/examples/fuzz-tests/arbitrary-custom-types-4/Cargo.lock index 1968a626f..ba3826cc4 100644 --- a/examples/fuzz-tests/arbitrary-custom-types-4/Cargo.lock +++ b/examples/fuzz-tests/arbitrary-custom-types-4/Cargo.lock @@ -5900,7 +5900,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -5925,15 +5924,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -5948,7 +5938,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -5960,6 +5952,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/arbitrary-custom-types-4/Trident.toml b/examples/fuzz-tests/arbitrary-custom-types-4/Trident.toml index a398402c4..b976b8222 100644 --- a/examples/fuzz-tests/arbitrary-custom-types-4/Trident.toml +++ b/examples/fuzz-tests/arbitrary-custom-types-4/Trident.toml @@ -1,7 +1,3 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 diff --git a/examples/fuzz-tests/arbitrary-custom-types-4/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/arbitrary-custom-types-4/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 62bf91ca5..09026b8b5 100644 --- a/examples/fuzz-tests/arbitrary-custom-types-4/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/arbitrary-custom-types-4/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -5,7 +5,7 @@ use arbitrary_custom_types_4::trident_fuzz_initialize_snapshot::InitializeAlias; use arbitrary_custom_types_4::trident_fuzz_update_snapshot::UpdateAlias; type InitializeSnapshot<'info> = InitializeAlias<'info>; type UpdateSnapshot<'info> = UpdateAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { Initialize(Initialize), Update(Update), diff --git a/examples/fuzz-tests/arbitrary-custom-types-4/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/arbitrary-custom-types-4/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index a429af20d..6e78ed229 100644 --- a/examples/fuzz-tests/arbitrary-custom-types-4/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/arbitrary-custom-types-4/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -20,7 +20,10 @@ impl FuzzDataBuilder for MyFuzzData { } } -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_arbitrary_custom_types_4 = FuzzingProgram::new( PROGRAM_NAME_ARBITRARY_CUSTOM_TYPES_4, &PROGRAM_ID_ARBITRARY_CUSTOM_TYPES_4, @@ -30,11 +33,12 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz let mut client = ProgramTestClientBlocking::new(&[fuzzing_program_arbitrary_custom_types_4], &[]).unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } } diff --git a/examples/fuzz-tests/arbitrary-limit-inputs-5/Cargo.lock b/examples/fuzz-tests/arbitrary-limit-inputs-5/Cargo.lock index de4dde49a..ffa989dce 100644 --- a/examples/fuzz-tests/arbitrary-limit-inputs-5/Cargo.lock +++ b/examples/fuzz-tests/arbitrary-limit-inputs-5/Cargo.lock @@ -6087,7 +6087,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -6112,15 +6111,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -6135,7 +6125,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -6147,6 +6139,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/arbitrary-limit-inputs-5/Trident.toml b/examples/fuzz-tests/arbitrary-limit-inputs-5/Trident.toml index d0247eb7c..3a3b8efed 100644 --- a/examples/fuzz-tests/arbitrary-limit-inputs-5/Trident.toml +++ b/examples/fuzz-tests/arbitrary-limit-inputs-5/Trident.toml @@ -1,7 +1,3 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 diff --git a/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 9c6c2ecbf..3447f6ea8 100644 --- a/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -6,7 +6,7 @@ use arbitrary_limit_inputs_5::trident_fuzz_withdraw_unlocked_snapshot::WithdrawU type InitVestingSnapshot<'info> = InitVestingContextAlias<'info>; type WithdrawUnlockedSnapshot<'info> = WithdrawUnlockedAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { InitVesting(InitVesting), WithdrawUnlocked(WithdrawUnlocked), diff --git a/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index b8f9fa055..a4bd01709 100644 --- a/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/arbitrary-limit-inputs-5/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -27,7 +27,10 @@ impl FuzzDataBuilder for MyFuzzData { } } -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_arbitrary_limit_inputs_5 = FuzzingProgram::new( PROGRAM_NAME_ARBITRARY_LIMIT_INPUTS_5, &PROGRAM_ID_ARBITRARY_LIMIT_INPUTS_5, @@ -37,11 +40,12 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz let mut client = ProgramTestClientBlocking::new(&[fuzzing_program_arbitrary_limit_inputs_5], &[]).unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } } diff --git a/examples/fuzz-tests/cpi-metaplex-7/Cargo.lock b/examples/fuzz-tests/cpi-metaplex-7/Cargo.lock index f080a5278..c84abdc77 100644 --- a/examples/fuzz-tests/cpi-metaplex-7/Cargo.lock +++ b/examples/fuzz-tests/cpi-metaplex-7/Cargo.lock @@ -6101,7 +6101,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -6126,15 +6125,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -6149,7 +6139,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -6161,6 +6153,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/cpi-metaplex-7/Trident.toml b/examples/fuzz-tests/cpi-metaplex-7/Trident.toml index 1c4d43cba..c698c1e26 100644 --- a/examples/fuzz-tests/cpi-metaplex-7/Trident.toml +++ b/examples/fuzz-tests/cpi-metaplex-7/Trident.toml @@ -1,7 +1,3 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 diff --git a/examples/fuzz-tests/cpi-metaplex-7/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/cpi-metaplex-7/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index cae273ca7..0b54df8fd 100644 --- a/examples/fuzz-tests/cpi-metaplex-7/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/cpi-metaplex-7/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -4,7 +4,7 @@ use trident_client::fuzzing::*; use cpi_metaplex_7::trident_fuzz_initialize_snapshot::InitializeAlias; type InitializeSnapshot<'info> = InitializeAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { Initialize(Initialize), } diff --git a/examples/fuzz-tests/cpi-metaplex-7/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/cpi-metaplex-7/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 8f06e7c93..cb3d6b079 100644 --- a/examples/fuzz-tests/cpi-metaplex-7/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/cpi-metaplex-7/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -24,7 +24,10 @@ impl FuzzDataBuilder for MyFuzzData { } } -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_cpi_metaplex_7 = FuzzingProgram::new( PROGRAM_NAME_CPI_METAPLEX_7, &PROGRAM_ID_CPI_METAPLEX_7, @@ -36,11 +39,13 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz let mut client = ProgramTestClientBlocking::new(&[fuzzing_program_cpi_metaplex_7, metaplex], &[]).unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); + loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } } diff --git a/examples/fuzz-tests/hello_world/Cargo.lock b/examples/fuzz-tests/hello_world/Cargo.lock index e88ddd2cc..42131748e 100644 --- a/examples/fuzz-tests/hello_world/Cargo.lock +++ b/examples/fuzz-tests/hello_world/Cargo.lock @@ -5900,7 +5900,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -5925,15 +5924,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -5948,7 +5938,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -5960,6 +5952,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/hello_world/Trident.toml b/examples/fuzz-tests/hello_world/Trident.toml index 93edfd43b..a7811d6f9 100644 --- a/examples/fuzz-tests/hello_world/Trident.toml +++ b/examples/fuzz-tests/hello_world/Trident.toml @@ -1,7 +1,3 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 @@ -38,4 +34,4 @@ save_all = false allow_duplicate_txs = false # Trident will show statistics after the fuzzing session. This option forces use of honggfuzz parameter # `keep_output` as true in order to be able to catch fuzzer stdout. (default: false) -fuzzing_with_stats = false +fuzzing_with_stats = true diff --git a/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 9f6fad618..e9e74ac1c 100644 --- a/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -4,7 +4,7 @@ use trident_client::fuzzing::*; use hello_world::trident_fuzz_initialize_context_snapshot::InitializeContextAlias; type InitializeFnSnapshot<'info> = InitializeContextAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { InitializeFn(InitializeFn), } diff --git a/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 49763f26c..c82111546 100644 --- a/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/hello_world/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -1,3 +1,4 @@ +use fuzz_instructions::InitializeFn; use trident_client::fuzzing::*; mod fuzz_instructions; @@ -10,9 +11,23 @@ const PROGRAM_NAME_HELLO_WORLD: &str = "hello_world"; struct MyFuzzData; -impl FuzzDataBuilder for MyFuzzData {} +impl FuzzDataBuilder for MyFuzzData { + fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result> { + let init = FuzzInstruction::InitializeFn(InitializeFn::arbitrary(u)?); + Ok(vec![init]) + } + fn ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result> { + Ok(vec![]) + } + fn post_ixs(_u: &mut arbitrary::Unstructured) -> arbitrary::Result> { + Ok(vec![]) + } +} -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_hello_world = FuzzingProgram::new( PROGRAM_NAME_HELLO_WORLD, &PROGRAM_ID_HELLO_WORLD, @@ -21,11 +36,12 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz let mut client = ProgramTestClientBlocking::new(&[fuzzing_program_hello_world], &[]).unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } } diff --git a/examples/fuzz-tests/incorrect-integer-arithmetic-3/Cargo.lock b/examples/fuzz-tests/incorrect-integer-arithmetic-3/Cargo.lock index e13408527..5e8c6e226 100644 --- a/examples/fuzz-tests/incorrect-integer-arithmetic-3/Cargo.lock +++ b/examples/fuzz-tests/incorrect-integer-arithmetic-3/Cargo.lock @@ -6296,7 +6296,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -6321,15 +6320,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -6344,7 +6334,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang 0.30.1", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -6356,6 +6348,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/incorrect-integer-arithmetic-3/Trident.toml b/examples/fuzz-tests/incorrect-integer-arithmetic-3/Trident.toml index a398402c4..b976b8222 100644 --- a/examples/fuzz-tests/incorrect-integer-arithmetic-3/Trident.toml +++ b/examples/fuzz-tests/incorrect-integer-arithmetic-3/Trident.toml @@ -1,7 +1,3 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 diff --git a/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 13d976f55..ca2d59394 100644 --- a/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -6,7 +6,7 @@ use incorrect_integer_arithmetic_3::trident_fuzz_withdraw_unlocked_snapshot::Wit type InitVestingSnapshot<'info> = InitVestingAlias<'info>; type WithdrawUnlockedSnapshot<'info> = WithdrawUnlockedAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { InitVesting(InitVesting), WithdrawUnlocked(WithdrawUnlocked), diff --git a/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 78fcc12ef..2ee187e2a 100644 --- a/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/incorrect-integer-arithmetic-3/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -19,7 +19,10 @@ impl FuzzDataBuilder for MyFuzzData { } } -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_incorrect_integer_arithmetic_3 = FuzzingProgram::new( PROGRAM_NAME_INCORRECT_INTEGER_ARITHMETIC_3, &PROGRAM_ID_INCORRECT_INTEGER_ARITHMETIC_3, @@ -30,11 +33,12 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz ProgramTestClientBlocking::new(&[fuzzing_program_incorrect_integer_arithmetic_3], &[]) .unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } } diff --git a/examples/fuzz-tests/incorrect-ix-sequence-1/Cargo.lock b/examples/fuzz-tests/incorrect-ix-sequence-1/Cargo.lock index 57f244c3b..e63c31e0b 100644 --- a/examples/fuzz-tests/incorrect-ix-sequence-1/Cargo.lock +++ b/examples/fuzz-tests/incorrect-ix-sequence-1/Cargo.lock @@ -5900,7 +5900,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -5925,15 +5924,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -5948,7 +5938,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -5960,6 +5952,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/incorrect-ix-sequence-1/Trident.toml b/examples/fuzz-tests/incorrect-ix-sequence-1/Trident.toml index a398402c4..b976b8222 100644 --- a/examples/fuzz-tests/incorrect-ix-sequence-1/Trident.toml +++ b/examples/fuzz-tests/incorrect-ix-sequence-1/Trident.toml @@ -1,7 +1,3 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 diff --git a/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 56ca21150..9d06c5dc8 100644 --- a/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -11,7 +11,7 @@ type EndRegistrationsSnapshot<'info> = EndRegistrationAlias<'info>; type InitializeSnapshot<'info> = InitializeAlias<'info>; type InvestSnapshot<'info> = InvestAlias<'info>; type RegisterSnapshot<'info> = RegisterAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { EndRegistrations(EndRegistrations), Initialize(Initialize), diff --git a/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 2fc9e6636..d275d88cc 100644 --- a/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/incorrect-ix-sequence-1/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -18,7 +18,10 @@ impl FuzzDataBuilder for MyFuzzData { } } -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_incorrect_ix_sequence_1 = FuzzingProgram::new( PROGRAM_NAME_INCORRECT_IX_SEQUENCE_1, &PROGRAM_ID_INCORRECT_IX_SEQUENCE_1, @@ -28,11 +31,12 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz let mut client = ProgramTestClientBlocking::new(&[fuzzing_program_incorrect_ix_sequence_1], &[]).unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } } diff --git a/examples/fuzz-tests/simple-cpi-6/Cargo.lock b/examples/fuzz-tests/simple-cpi-6/Cargo.lock index 67ba96fa1..6bd955da0 100644 --- a/examples/fuzz-tests/simple-cpi-6/Cargo.lock +++ b/examples/fuzz-tests/simple-cpi-6/Cargo.lock @@ -5898,7 +5898,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -5923,15 +5922,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -5946,7 +5936,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -5958,6 +5950,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/simple-cpi-6/Trident.toml b/examples/fuzz-tests/simple-cpi-6/Trident.toml index 936fc1bde..2c1032328 100644 --- a/examples/fuzz-tests/simple-cpi-6/Trident.toml +++ b/examples/fuzz-tests/simple-cpi-6/Trident.toml @@ -1,12 +1,8 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 # Number of fuzzing iterations (default: 0 [no limit]) -iterations = 1000 +iterations = 100 # Number of concurrent fuzzing threads (default: 0 [number of CPUs / 2]) threads = 0 # Don't close children's stdin, stdout, stderr; can be noisy (default: false) diff --git a/examples/fuzz-tests/simple-cpi-6/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/simple-cpi-6/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 1da549488..e64ffea72 100644 --- a/examples/fuzz-tests/simple-cpi-6/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/simple-cpi-6/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -5,7 +5,7 @@ use caller::trident_fuzz_initialize_caller_snapshot::InitializeCallerAlias; type InitializeCalleeSnapshot<'info> = InitializeCalleeAlias<'info>; type InitializeCallerSnapshot<'info> = InitializeCallerAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { InitializeCallee(InitializeCallee), InitializeCaller(InitializeCaller), diff --git a/examples/fuzz-tests/simple-cpi-6/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/simple-cpi-6/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 0bc8147aa..13f02c533 100644 --- a/examples/fuzz-tests/simple-cpi-6/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/simple-cpi-6/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -28,7 +28,10 @@ impl FuzzDataBuilder for MyFuzzData { } } -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_callee = FuzzingProgram::new( PROGRAM_NAME_CALLEE, &PROGRAM_ID_CALLEE, @@ -45,11 +48,13 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz ProgramTestClientBlocking::new(&[fuzzing_program_callee, fuzzing_program_caller], &[]) .unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); + loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } } diff --git a/examples/fuzz-tests/unauthorized-access-2/Cargo.lock b/examples/fuzz-tests/unauthorized-access-2/Cargo.lock index 5fada0231..ddba59511 100644 --- a/examples/fuzz-tests/unauthorized-access-2/Cargo.lock +++ b/examples/fuzz-tests/unauthorized-access-2/Cargo.lock @@ -5891,7 +5891,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -5916,15 +5915,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -5939,7 +5929,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -5951,6 +5943,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/unauthorized-access-2/Trident.toml b/examples/fuzz-tests/unauthorized-access-2/Trident.toml index a398402c4..b976b8222 100644 --- a/examples/fuzz-tests/unauthorized-access-2/Trident.toml +++ b/examples/fuzz-tests/unauthorized-access-2/Trident.toml @@ -1,7 +1,3 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 diff --git a/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 786b6042b..5703361f0 100644 --- a/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -7,7 +7,7 @@ use unauthorized_access_2::ESCROW_SEED; type InitializeSnapshot<'info> = InitializeAlias<'info>; type WithdrawSnapshot<'info> = WithdrawAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { Initialize(Initialize), Withdraw(Withdraw), diff --git a/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 9e5c7af33..dd97c3e69 100644 --- a/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/unauthorized-access-2/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -19,7 +19,10 @@ impl FuzzDataBuilder for MyFuzzData { } } -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_unauthorized_access_2 = FuzzingProgram::new( PROGRAM_NAME_UNAUTHORIZED_ACCESS_2, &PROGRAM_ID_UNAUTHORIZED_ACCESS_2, @@ -29,11 +32,12 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz let mut client = ProgramTestClientBlocking::new(&[fuzzing_program_unauthorized_access_2], &[]).unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } } diff --git a/examples/fuzz-tests/unchecked-arithmetic-0/Cargo.lock b/examples/fuzz-tests/unchecked-arithmetic-0/Cargo.lock index fcb4b4522..fc9abca26 100644 --- a/examples/fuzz-tests/unchecked-arithmetic-0/Cargo.lock +++ b/examples/fuzz-tests/unchecked-arithmetic-0/Cargo.lock @@ -5891,7 +5891,6 @@ dependencies = [ "toml 0.5.11", "trident-derive-accounts-snapshots", "trident-derive-displayix", - "trident-derive-fuzz-deserialize", "trident-derive-fuzz-test-executor", "trident-fuzz", ] @@ -5916,15 +5915,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trident-derive-fuzz-deserialize" -version = "0.0.2" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "trident-derive-fuzz-test-executor" version = "0.0.2" @@ -5939,7 +5929,9 @@ name = "trident-fuzz" version = "0.1.0" dependencies = [ "anchor-lang", + "anyhow", "arbitrary", + "fehler", "prettytable", "regex", "serde", @@ -5951,6 +5943,7 @@ dependencies = [ "spl-token", "thiserror", "tokio", + "toml 0.5.11", ] [[package]] diff --git a/examples/fuzz-tests/unchecked-arithmetic-0/Trident.toml b/examples/fuzz-tests/unchecked-arithmetic-0/Trident.toml index d0247eb7c..3a3b8efed 100644 --- a/examples/fuzz-tests/unchecked-arithmetic-0/Trident.toml +++ b/examples/fuzz-tests/unchecked-arithmetic-0/Trident.toml @@ -1,7 +1,3 @@ -[test] -validator_startup_timeout = 15000 - - [honggfuzz] # Timeout in seconds (default: 10) timeout = 10 diff --git a/examples/fuzz-tests/unchecked-arithmetic-0/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs b/examples/fuzz-tests/unchecked-arithmetic-0/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index b0a5c667a..921b5f6ae 100644 --- a/examples/fuzz-tests/unchecked-arithmetic-0/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs +++ b/examples/fuzz-tests/unchecked-arithmetic-0/trident-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -6,7 +6,7 @@ use unchecked_arithmetic_0::trident_fuzz_update_snapshot::UpdateAlias; type InitializeSnapshot<'info> = InitializeAlias<'info>; type UpdateSnapshot<'info> = UpdateAlias<'info>; -#[derive(Arbitrary, DisplayIx, FuzzTestExecutor, FuzzDeserialize)] +#[derive(Arbitrary, DisplayIx, FuzzTestExecutor)] pub enum FuzzInstruction { Initialize(Initialize), Update(Update), diff --git a/examples/fuzz-tests/unchecked-arithmetic-0/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs b/examples/fuzz-tests/unchecked-arithmetic-0/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs index eabe55094..64518688d 100644 --- a/examples/fuzz-tests/unchecked-arithmetic-0/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs +++ b/examples/fuzz-tests/unchecked-arithmetic-0/trident-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -26,7 +26,10 @@ impl FuzzDataBuilder for MyFuzzData { } } -fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: FuzzData) { +fn fuzz_iteration + std::fmt::Display, U>( + fuzz_data: FuzzData, + config: &Config, +) { let fuzzing_program_unchecked_arithmetic_0 = FuzzingProgram::new( PROGRAM_NAME_UNCHECKED_ARITHMETIC_0, &PROGRAM_ID_UNCHECKED_ARITHMETIC_0, @@ -36,11 +39,12 @@ fn fuzz_iteration + std::fmt::Display, U>(fuzz_data: Fuzz let mut client = ProgramTestClientBlocking::new(&[fuzzing_program_unchecked_arithmetic_0], &[]).unwrap(); - let _ = fuzz_data.run_with_runtime(&mut client); + let _ = fuzz_data.run_with_runtime(&mut client, config); } fn main() { + let config = Config::new(); loop { - fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data) ; }); + fuzz_trident ! (fuzz_ix : FuzzInstruction , | fuzz_data : MyFuzzData | { fuzz_iteration (fuzz_data,&config) ; }); } }