diff --git a/crates/cli/src/command/build.rs b/crates/cli/src/command/build.rs index 68b159f84..be90f1342 100644 --- a/crates/cli/src/command/build.rs +++ b/crates/cli/src/command/build.rs @@ -8,5 +8,5 @@ pub async fn build(root: String) { commander.create_program_client_crate().await?; commander.build_programs().await?; commander.generate_program_client_deps().await?; - commander.generate_program_client_lib_rs().await?; + commander.generate_program_client_lib_rs(None).await?; } diff --git a/crates/cli/src/command/fuzz.rs b/crates/cli/src/command/fuzz.rs index aab548e86..a81d69272 100644 --- a/crates/cli/src/command/fuzz.rs +++ b/crates/cli/src/command/fuzz.rs @@ -1,17 +1,8 @@ -use std::{ - env, - path::{Path, PathBuf}, - process, -}; - use anyhow::{bail, Context, Error, Result}; use clap::Subcommand; use fehler::throws; -use trdelnik_client::Commander; - -pub const TESTS_WORKSPACE: &str = "trdelnik-tests"; -pub const HFUZZ_WORKSPACE: &str = "hfuzz_workspace"; +use trdelnik_client::{Commander, TestGenerator}; #[derive(Subcommand)] #[allow(non_camel_case_types)] @@ -31,6 +22,7 @@ pub enum FuzzCommand { /// Path to the crash file crash_file_path: String, }, + Add, } #[throws] @@ -55,26 +47,7 @@ pub async fn fuzz(root: Option, subcmd: FuzzCommand) { with_exit_code, } => { if with_exit_code { - // Parse the HFUZZ run arguments to find out if the crash folder and crash files extension was modified. - let hfuzz_run_args = env::var("HFUZZ_RUN_ARGS").unwrap_or_default(); - let (crash_dir, ext) = get_crash_dir_and_ext(&root, &target, &hfuzz_run_args); - - if let Ok(crash_files) = get_crash_files(&crash_dir, &ext) { - if !crash_files.is_empty() { - println!("Error: The crash directory {} already contains crash files from previous runs. \n\nTo run Trdelnik fuzzer with exit code, you must either (backup and) remove the old crash files or alternatively change the crash folder using for example the --crashdir option and the HFUZZ_RUN_ARGS env variable such as:\nHFUZZ_RUN_ARGS=\"--crashdir ./new_crash_dir\"", crash_dir.to_string_lossy()); - process::exit(1); - } - } - commander.run_fuzzer(target).await?; - if let Ok(crash_files) = get_crash_files(&crash_dir, &ext) { - if !crash_files.is_empty() { - println!( - "The crash directory {} contains new fuzz test crashes. Exiting!", - crash_dir.to_string_lossy() - ); - process::exit(1); - } - } + commander.run_fuzzer_with_exit_code(target).await?; } else { commander.run_fuzzer(target).await?; } @@ -85,6 +58,11 @@ pub async fn fuzz(root: Option, subcmd: FuzzCommand) { } => { commander.run_fuzzer_debug(target, crash_file_path).await?; } + + FuzzCommand::Add => { + let generator = TestGenerator::new(); + generator.add_new_fuzz_test().await?; + } }; } @@ -114,229 +92,3 @@ fn _discover() -> Result> { Ok(None) } - -fn get_crash_dir_and_ext(root: &str, target: &str, hfuzz_run_args: &str) -> (PathBuf, String) { - // FIXME: we split by whitespace without respecting escaping or quotes - same approach as honggfuzz-rs so there is no point to fix it here before the upstream is fixed - let hfuzz_run_args = hfuzz_run_args.split_whitespace(); - - let extension = - get_cmd_option_value(hfuzz_run_args.clone(), "-e", "--ext").unwrap_or("fuzz".to_string()); - - let crash_dir = get_cmd_option_value(hfuzz_run_args.clone(), "", "--cr") - .or_else(|| get_cmd_option_value(hfuzz_run_args.clone(), "-W", "--w")); - - let crash_path = if let Some(dir) = crash_dir { - Path::new(root).join(TESTS_WORKSPACE).join(dir) - } else { - Path::new(root) - .join(TESTS_WORKSPACE) - .join(HFUZZ_WORKSPACE) - .join(target) - }; - - (crash_path, extension) -} - -fn get_cmd_option_value<'a>( - hfuzz_run_args: impl Iterator, - short_opt: &str, - long_opt: &str, -) -> Option { - let mut args_iter = hfuzz_run_args; - let mut value: Option = None; - - // ensure short option starts with one dash and long option with two dashes - let short_opt = format!("-{}", short_opt.trim_start_matches('-')); - let long_opt = format!("--{}", long_opt.trim_start_matches('-')); - - while let Some(arg) = args_iter.next() { - match arg.strip_prefix(&short_opt) { - Some(val) if short_opt.len() > 1 => { - if !val.is_empty() { - // -ecrash for crash extension with no space - value = Some(val.to_string()); - } else if let Some(next_arg) = args_iter.next() { - // -e crash for crash extension with space - value = Some(next_arg.to_string()); - } else { - value = None; - } - } - _ => { - if arg.starts_with(&long_opt) && long_opt.len() > 2 { - value = args_iter.next().map(|a| a.to_string()); - } - } - } - } - - value -} - -fn get_crash_files( - dir: &PathBuf, - extension: &str, -) -> Result, Box> { - let paths = std::fs::read_dir(dir)? - // Filter out all those directory entries which couldn't be read - .filter_map(|res| res.ok()) - // Map the directory entries to paths - .map(|dir_entry| dir_entry.path()) - // Filter out all paths with extensions other than `extension` - .filter_map(|path| { - if path.extension().map_or(false, |ext| ext == extension) { - Some(path) - } else { - None - } - }) - .collect::>(); - Ok(paths) -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_cmd_options_parsing() { - let mut command = String::from("-Q -v --extension fuzz"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, Some("fuzz".to_string())); - - command = String::from("-Q --extension fuzz -v"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, Some("fuzz".to_string())); - - command = String::from("-Q -e fuzz -v"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, Some("fuzz".to_string())); - - command = String::from("-Q --extension fuzz -v --extension "); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, None); - - command = String::from("-Q --extension fuzz -v -e "); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, None); - - let mut command = String::from("--extension buzz -e fuzz"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, Some("fuzz".to_string())); - - command = String::from("-Q -v -e fuzz"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, Some("fuzz".to_string())); - - command = String::from("-Q -v -efuzz"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, Some("fuzz".to_string())); - - command = String::from("-Q -v --ext fuzz"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, Some("fuzz".to_string())); - - command = String::from("-Q -v --extfuzz"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, None); - - command = String::from("-Q -v --workspace"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", "--ext"); - assert_eq!(extension, None); - - command = String::from("-Q -v -e"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "", "--ext"); - assert_eq!(extension, None); - - command = String::from("-Q -v --ext fuzz"); - let args = command.split_whitespace(); - - let extension = get_cmd_option_value(args, "-e", ""); - assert_eq!(extension, None); - } - - #[test] - fn test_get_crash_dir_and_ext() { - let root = "/home/fuzz"; - let target = "target"; - let default_crash_path = Path::new(root) - .join(TESTS_WORKSPACE) - .join(HFUZZ_WORKSPACE) - .join(target); - - let (crash_dir, ext) = get_crash_dir_and_ext(root, target, ""); - - assert_eq!(crash_dir, default_crash_path); - assert_eq!(&ext, "fuzz"); - - let (crash_dir, ext) = get_crash_dir_and_ext(root, target, "-Q -e"); - - assert_eq!(crash_dir, default_crash_path); - assert_eq!(&ext, "fuzz"); - - let (crash_dir, ext) = get_crash_dir_and_ext(root, target, "-Q -e crash"); - - assert_eq!(crash_dir, default_crash_path); - assert_eq!(&ext, "crash"); - - // test absolute path - let (crash_dir, ext) = get_crash_dir_and_ext(root, target, "-Q -W /home/crash -e crash"); - - let expected_crash_path = Path::new("/home/crash"); - assert_eq!(crash_dir, expected_crash_path); - assert_eq!(&ext, "crash"); - - // test absolute path - let (crash_dir, ext) = - get_crash_dir_and_ext(root, target, "-Q --crash /home/crash -e crash"); - - let expected_crash_path = Path::new("/home/crash"); - assert_eq!(crash_dir, expected_crash_path); - assert_eq!(&ext, "crash"); - - // test relative path - let (crash_dir, ext) = get_crash_dir_and_ext(root, target, "-Q -W ../crash -e crash"); - - let expected_crash_path = Path::new(root).join(TESTS_WORKSPACE).join("../crash"); - assert_eq!(crash_dir, expected_crash_path); - assert_eq!(&ext, "crash"); - - // test relative path - let (crash_dir, ext) = get_crash_dir_and_ext(root, target, "-Q --crash ../crash -e crash"); - - let expected_crash_path = Path::new(root).join(TESTS_WORKSPACE).join("../crash"); - assert_eq!(crash_dir, expected_crash_path); - assert_eq!(&ext, "crash"); - - // crash directory has precedence before workspace - let (crash_dir, ext) = - get_crash_dir_and_ext(root, target, "-Q --crash ../crash -W /workspace -e crash"); - - let expected_crash_path = Path::new(root).join(TESTS_WORKSPACE).join("../crash"); - assert_eq!(crash_dir, expected_crash_path); - assert_eq!(&ext, "crash"); - } -} diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index d1232d822..0d1102d5e 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -60,3 +60,4 @@ shellexpand = { workspace = true } trdelnik-derive-displayix = { path = "./derive/display_ix" } trdelnik-derive-fuzz-deserialize = { path = "./derive/fuzz_deserialize" } trdelnik-derive-fuzz-test-executor = { path = "./derive/fuzz_test_executor" } +pathdiff="0.2.1" diff --git a/crates/client/src/cleaner.rs b/crates/client/src/cleaner.rs index ff7533388..562171915 100644 --- a/crates/client/src/cleaner.rs +++ b/crates/client/src/cleaner.rs @@ -45,13 +45,17 @@ impl Cleaner { async fn clean_hfuzz_target(&self, root: &PathBuf) { let hfuzz_target_path = Path::new(root) .join(crate::test_generator::TESTS_WORKSPACE) + .join(crate::test_generator::FUZZ_TEST_DIRECTORY) + .join(crate::test_generator::FUZZING) .join(crate::test_generator::HFUZZ_TARGET); if hfuzz_target_path.exists() { fs::remove_dir_all(hfuzz_target_path).await?; } else { println!( - "skipping {}/{} directory: not found", + "skipping {}/{}/{}/{} directory: not found", crate::test_generator::TESTS_WORKSPACE, + crate::test_generator::FUZZ_TEST_DIRECTORY, + crate::test_generator::FUZZING, crate::test_generator::HFUZZ_TARGET ) } diff --git a/crates/client/src/commander.rs b/crates/client/src/commander.rs index 68170bf30..7fc1f43e2 100644 --- a/crates/client/src/commander.rs +++ b/crates/client/src/commander.rs @@ -6,7 +6,6 @@ use crate::{ idl::{self, Idl}, program_client_generator, test_generator::FUZZ_INSTRUCTIONS_FILE_NAME, - test_generator::TESTS_WORKSPACE, Client, }; use cargo_metadata::{MetadataCommand, Package}; @@ -14,6 +13,8 @@ use fehler::{throw, throws}; use futures::future::try_join_all; use log::debug; use solana_sdk::signer::keypair::Keypair; +use std::path::PathBuf; +use std::process; use std::{ borrow::Cow, io, iter, os::unix::process::CommandExt, path::Path, process::Stdio, string::FromUtf8Error, @@ -26,7 +27,9 @@ use tokio::{ signal, }; -pub static PROGRAM_CLIENT_DIRECTORY: &str = ".program_client"; +pub const PROGRAM_CLIENT_DIRECTORY: &str = ".program_client"; +pub const CARGO_TARGET_DIR_DEFAULT: &str = "trdelnik-tests/fuzz_tests/fuzzing/hfuzz_target"; +pub const HFUZZ_WORKSPACE_DEFAULT: &str = "trdelnik-tests/fuzz_tests/fuzzing/hfuzz_workspace"; #[derive(Error, Debug)] pub enum Error { @@ -145,6 +148,7 @@ impl Commander { pub async fn run_tests(&self) { let success = Command::new("cargo") .arg("test") + .args(["--package", "poc_tests"]) .arg("--") .arg("--nocapture") .spawn()? @@ -155,22 +159,37 @@ impl Commander { throw!(Error::TestingFailed); } } - /// Runs fuzzer on the given target. + /// Runs fuzzer on the given target with exit code option. #[throws] - pub async fn run_fuzzer(&self, target: String) { + pub async fn run_fuzzer_with_exit_code(&self, target: String) { let config = Config::new(); let hfuzz_run_args = std::env::var("HFUZZ_RUN_ARGS").unwrap_or_default(); + + let cargo_target_dir = + std::env::var("CARGO_TARGET_DIR").unwrap_or(CARGO_TARGET_DIR_DEFAULT.to_string()); + + // we read the workspace from the env variable , if not explicitly set, set it to + // the default directory + let hfuzz_workspace = + std::env::var("HFUZZ_WORKSPACE").unwrap_or(HFUZZ_WORKSPACE_DEFAULT.to_string()); + let fuzz_args = config.get_fuzz_args(hfuzz_run_args); - let cur_dir = Path::new(&self.root.to_string()).join(TESTS_WORKSPACE); - if !cur_dir.try_exists()? { - throw!(Error::NotInitialized); + let (crash_dir, ext) = + get_crash_dir_and_ext(&self.root, &target, &fuzz_args, &hfuzz_workspace); + + if let Ok(crash_files) = get_crash_files(&crash_dir, &ext) { + if !crash_files.is_empty() { + println!("Error: The crash directory {} already contains crash files from previous runs. \n\nTo run Trdelnik fuzzer with exit code, you must either (backup and) remove the old crash files or alternatively change the crash folder using for example the --crashdir option and the HFUZZ_RUN_ARGS env variable such as:\nHFUZZ_RUN_ARGS=\"--crashdir ./new_crash_dir\"", crash_dir.to_string_lossy()); + process::exit(1); + } } let mut child = Command::new("cargo") .env("HFUZZ_RUN_ARGS", fuzz_args) - .current_dir(cur_dir) + .env("CARGO_TARGET_DIR", cargo_target_dir) + .env("HFUZZ_WORKSPACE", hfuzz_workspace) .arg("hfuzz") .arg("run") .arg(target) @@ -188,26 +207,70 @@ impl Commander { tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; }, } + + if let Ok(crash_files) = get_crash_files(&crash_dir, &ext) { + if !crash_files.is_empty() { + println!( + "The crash directory {} contains new fuzz test crashes. Exiting!", + crash_dir.to_string_lossy() + ); + process::exit(1); + } + } } /// Runs fuzzer on the given target. #[throws] - pub async fn run_fuzzer_debug(&self, target: String, crash_file_path: String) { - let cur_dir = Path::new(&self.root.to_string()).join(TESTS_WORKSPACE); - let crash_file = std::env::current_dir()?.join(crash_file_path); + pub async fn run_fuzzer(&self, target: String) { + let config = Config::new(); + + let hfuzz_run_args = std::env::var("HFUZZ_RUN_ARGS").unwrap_or_default(); + let cargo_target_dir = + std::env::var("CARGO_TARGET_DIR").unwrap_or(CARGO_TARGET_DIR_DEFAULT.to_string()); + let hfuzz_workspace = + std::env::var("HFUZZ_WORKSPACE").unwrap_or(HFUZZ_WORKSPACE_DEFAULT.to_string()); + + let fuzz_args = config.get_fuzz_args(hfuzz_run_args); + + let mut child = Command::new("cargo") + .env("HFUZZ_RUN_ARGS", fuzz_args) + .env("CARGO_TARGET_DIR", cargo_target_dir) + .env("HFUZZ_WORKSPACE", hfuzz_workspace) + .arg("hfuzz") + .arg("run") + .arg(target) + .spawn()?; - if !cur_dir.try_exists()? { - throw!(Error::NotInitialized); + tokio::select! { + res = child.wait() => + match res { + Ok(status) => if !status.success() { + println!("Honggfuzz exited with an error!"); + }, + Err(_) => throw!(Error::FuzzingFailed), + }, + _ = signal::ctrl_c() => { + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + }, } + } + + /// Runs fuzzer on the given target. + #[throws] + pub async fn run_fuzzer_debug(&self, target: String, crash_file_path: String) { + let crash_file = std::path::Path::new(&self.root as &str).join(crash_file_path); if !crash_file.try_exists()? { println!("The crash file {:?} not found!", crash_file); throw!(Error::CrashFileNotFound); } + let cargo_target_dir = + std::env::var("CARGO_TARGET_DIR").unwrap_or(CARGO_TARGET_DIR_DEFAULT.to_string()); + // using exec rather than spawn and replacing current process to avoid unflushed terminal output after ctrl+c signal std::process::Command::new("cargo") - .current_dir(cur_dir) + .env("CARGO_TARGET_DIR", cargo_target_dir) .arg("hfuzz") .arg("run-debug") .arg(target) @@ -327,7 +390,7 @@ impl Commander { /// /// It's used internally by the [`#[trdelnik_test]`](trdelnik_test::trdelnik_test) macro. #[throws] - pub async fn generate_program_client_lib_rs(&self) { + pub async fn generate_program_client_lib_rs(&self, new_fuzz_test_dir: Option) { let program_idls_codes = self.program_packages().map(|package| async move { let name = package.name; let output = Command::new("cargo") @@ -367,30 +430,26 @@ impl Commander { let program_client = program_client_generator::generate_source_code(&idl, &use_tokens); let program_client = Self::format_program_code(&program_client).await?; - let program_fuzzer = fuzzer::fuzzer_generator::generate_source_code(&idl); - let program_fuzzer = Self::format_program_code(&program_fuzzer).await?; - - let fuzzer_snapshots = - generate_snapshots_code(codes_libs_pairs).map_err(Error::ReadProgramCodeFailed)?; - let fuzzer_snapshots = Self::format_program_code(&fuzzer_snapshots).await?; - // TODO do not overwrite files if they already exist to keep user changes let rust_file_path = Path::new(self.root.as_ref()) .join(PROGRAM_CLIENT_DIRECTORY) .join("src/lib.rs"); fs::write(rust_file_path, &program_client).await?; - let rust_file_path = Path::new(self.root.as_ref()) - .join(TESTS_WORKSPACE) - .join("src/") - .join(FUZZ_INSTRUCTIONS_FILE_NAME); - fs::write(rust_file_path, &program_fuzzer).await?; + if let Some(fuzz_test_dir) = new_fuzz_test_dir { + let program_fuzzer = fuzzer::fuzzer_generator::generate_source_code(&idl); + let program_fuzzer = Self::format_program_code(&program_fuzzer).await?; - let rust_file_path = Path::new(self.root.as_ref()) - .join(TESTS_WORKSPACE) - .join("src/") - .join(ACCOUNTS_SNAPSHOTS_FILE_NAME); - fs::write(rust_file_path, &fuzzer_snapshots).await?; + let fuzzer_snapshots = + generate_snapshots_code(codes_libs_pairs).map_err(Error::ReadProgramCodeFailed)?; + let fuzzer_snapshots = Self::format_program_code(&fuzzer_snapshots).await?; + + let rust_file_path = fuzz_test_dir.join(FUZZ_INSTRUCTIONS_FILE_NAME); + fs::write(rust_file_path, &program_fuzzer).await?; + + let rust_file_path = fuzz_test_dir.join(ACCOUNTS_SNAPSHOTS_FILE_NAME); + fs::write(rust_file_path, &fuzzer_snapshots).await?; + } } /// Formats program code. @@ -476,3 +535,307 @@ impl Default for Commander { Self::new() } } + +fn get_crash_dir_and_ext( + root: &str, + target: &str, + hfuzz_run_args: &str, + hfuzz_workspace: &str, +) -> (PathBuf, String) { + // FIXME: we split by whitespace without respecting escaping or quotes - same approach as honggfuzz-rs so there is no point to fix it here before the upstream is fixed + let hfuzz_run_args = hfuzz_run_args.split_whitespace(); + + let extension = + get_cmd_option_value(hfuzz_run_args.clone(), "-e", "--ext").unwrap_or("fuzz".to_string()); + + // If we run fuzzer like: + // HFUZZ_WORKSPACE="./new_hfuzz_workspace" HFUZZ_RUN_ARGS="--crashdir ./new_crash_dir -W ./new_workspace" cargo hfuzz run + // The structure will be as follows: + // ./new_hfuzz_workspace - will contain inputs + // ./new_crash_dir - will contain crashes + // ./new_workspace - will contain report + // So finally , we have to give precedence: + // --crashdir > --workspace > HFUZZ_WORKSPACE + let crash_dir = get_cmd_option_value(hfuzz_run_args.clone(), "", "--cr") + .or_else(|| get_cmd_option_value(hfuzz_run_args.clone(), "-W", "--w")); + + let crash_path = if let Some(dir) = crash_dir { + // INFO If path is absolute, it replaces the current path. + std::path::Path::new(root).join(dir) + } else { + std::path::Path::new(hfuzz_workspace).join(target) + }; + + (crash_path, extension) +} + +fn get_cmd_option_value<'a>( + hfuzz_run_args: impl Iterator, + short_opt: &str, + long_opt: &str, +) -> Option { + let mut args_iter = hfuzz_run_args; + let mut value: Option = None; + + // ensure short option starts with one dash and long option with two dashes + let short_opt = format!("-{}", short_opt.trim_start_matches('-')); + let long_opt = format!("--{}", long_opt.trim_start_matches('-')); + + while let Some(arg) = args_iter.next() { + match arg.strip_prefix(&short_opt) { + Some(val) if short_opt.len() > 1 => { + if !val.is_empty() { + // -ecrash for crash extension with no space + value = Some(val.to_string()); + } else if let Some(next_arg) = args_iter.next() { + // -e crash for crash extension with space + value = Some(next_arg.to_string()); + } else { + value = None; + } + } + _ => { + if arg.starts_with(&long_opt) && long_opt.len() > 2 { + value = args_iter.next().map(|a| a.to_string()); + } + } + } + } + + value +} + +fn get_crash_files( + dir: &PathBuf, + extension: &str, +) -> Result, Box> { + let paths = std::fs::read_dir(dir)? + // Filter out all those directory entries which couldn't be read + .filter_map(|res| res.ok()) + // Map the directory entries to paths + .map(|dir_entry| dir_entry.path()) + // Filter out all paths with extensions other than `extension` + .filter_map(|path| { + if path.extension().map_or(false, |ext| ext == extension) { + Some(path) + } else { + None + } + }) + .collect::>(); + Ok(paths) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_cmd_options_parsing() { + let mut command = String::from("-Q -v --extension fuzz"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, Some("fuzz".to_string())); + + command = String::from("-Q --extension fuzz -v"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, Some("fuzz".to_string())); + + command = String::from("-Q -e fuzz -v"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, Some("fuzz".to_string())); + + command = String::from("-Q --extension fuzz -v --extension "); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, None); + + command = String::from("-Q --extension fuzz -v -e "); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, None); + + let mut command = String::from("--extension buzz -e fuzz"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, Some("fuzz".to_string())); + + command = String::from("-Q -v -e fuzz"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, Some("fuzz".to_string())); + + command = String::from("-Q -v -efuzz"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, Some("fuzz".to_string())); + + command = String::from("-Q -v --ext fuzz"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, Some("fuzz".to_string())); + + command = String::from("-Q -v --extfuzz"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, None); + + command = String::from("-Q -v --workspace"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", "--ext"); + assert_eq!(extension, None); + + command = String::from("-Q -v -e"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "", "--ext"); + assert_eq!(extension, None); + + command = String::from("-Q -v --ext fuzz"); + let args = command.split_whitespace(); + + let extension = get_cmd_option_value(args, "-e", ""); + assert_eq!(extension, None); + } + + #[test] + fn test_get_crash_dir_and_ext() { + pub const TARGET: &str = "fuzz_0"; + pub const TEST_CRASH_PATH: &str = "/home/fuzz/test-crash-path"; + + const ROOT: &str = "/home/fuzz/"; + + let default_crash_path = std::path::Path::new(HFUZZ_WORKSPACE_DEFAULT).join(TARGET); + let env_specified_crash_path = std::path::Path::new(TEST_CRASH_PATH).join(TARGET); + + // this is default behavior + let (crash_dir, ext) = get_crash_dir_and_ext(ROOT, TARGET, "", HFUZZ_WORKSPACE_DEFAULT); + + assert_eq!(crash_dir, default_crash_path); + assert_eq!(&ext, "fuzz"); + + // behavior where path is specified within env variable HFUZZ_WORKSPACE, but not within -W HFUZZ_RUN_ARGS + let (crash_dir, ext) = get_crash_dir_and_ext(ROOT, TARGET, "-Q -e", TEST_CRASH_PATH); + + assert_eq!(crash_dir, env_specified_crash_path); + assert_eq!(&ext, "fuzz"); + + // behavior as above + let (crash_dir, ext) = get_crash_dir_and_ext(ROOT, TARGET, "-Q -e crash", TEST_CRASH_PATH); + + assert_eq!(crash_dir, env_specified_crash_path); + assert_eq!(&ext, "crash"); + + // test absolute path + // HFUZZ_WORKSPACE has default value however -W is set + let (crash_dir, ext) = get_crash_dir_and_ext( + ROOT, + TARGET, + "-Q -W /home/crash -e crash", + HFUZZ_WORKSPACE_DEFAULT, + ); + + let expected_crash_path = std::path::Path::new("/home/crash"); + assert_eq!(crash_dir, expected_crash_path); + assert_eq!(&ext, "crash"); + + // test absolute path + // HFUZZ_WORKSPACE is set and -W is also set + let (crash_dir, ext) = get_crash_dir_and_ext( + ROOT, + TARGET, + "-Q --crash /home/crash -e crash", + TEST_CRASH_PATH, + ); + let expected_crash_path = std::path::Path::new("/home/crash"); + assert_eq!(crash_dir, expected_crash_path); + assert_eq!(&ext, "crash"); + + // test absolute path + // HFUZZ_WORKSPACE is set and -W is also set + let (crash_dir, ext) = get_crash_dir_and_ext( + ROOT, + TARGET, + "-Q --crash /home/crash/foo/bar/dead/beef -e crash", + TEST_CRASH_PATH, + ); + + let expected_crash_path = std::path::Path::new("/home/crash/foo/bar/dead/beef"); + assert_eq!(crash_dir, expected_crash_path); + assert_eq!(&ext, "crash"); + + // test relative path + // HFUZZ_WORKSPACE is set and -W is also set, this time with relative path + let (crash_dir, ext) = + get_crash_dir_and_ext(ROOT, TARGET, "-Q -W ../crash -e crash", TEST_CRASH_PATH); + + let expected_crash_path = std::path::Path::new(ROOT).join("../crash"); + assert_eq!(crash_dir, expected_crash_path); + assert_eq!(&ext, "crash"); + + // test relative path + // HFUZZ_WORKSPACE is set and -W is also set, this time with relative path + let (crash_dir, ext) = get_crash_dir_and_ext( + ROOT, + TARGET, + "-Q -W ../../dead/beef/crash -e crash", + TEST_CRASH_PATH, + ); + + let expected_crash_path = std::path::Path::new(ROOT).join("../../dead/beef/crash"); + assert_eq!(crash_dir, expected_crash_path); + assert_eq!(&ext, "crash"); + + // test relative path + let (crash_dir, ext) = get_crash_dir_and_ext( + ROOT, + TARGET, + "-Q --crash ../crash -e crash", + HFUZZ_WORKSPACE_DEFAULT, + ); + + let expected_crash_path = std::path::Path::new(ROOT).join("../crash"); + assert_eq!(crash_dir, expected_crash_path); + assert_eq!(&ext, "crash"); + + // crash directory has precedence before workspace option , which have precedence before + // HFUZZ_WORKSPACE + let (crash_dir, ext) = get_crash_dir_and_ext( + ROOT, + TARGET, + "-Q --crash ../bitcoin/to/the/moon -W /workspace -e crash", + TEST_CRASH_PATH, + ); + + let expected_crash_path = std::path::Path::new(ROOT).join("../bitcoin/to/the/moon"); + assert_eq!(crash_dir, expected_crash_path); + assert_eq!(&ext, "crash"); + + // crash directory has precedence before workspace HFUZZ_WORKSPACE + let (crash_dir, ext) = get_crash_dir_and_ext( + ROOT, + TARGET, + "-Q --crash /home/crashes/we/like/solana -e crash", + TEST_CRASH_PATH, + ); + + // If path is specified as absolute, the join will replace whole path. + let expected_crash_path = std::path::Path::new("/home/crashes/we/like/solana"); + + // let expected_crash_path = root.join("/home/crashes/we/like/solana"); + assert_eq!(crash_dir, expected_crash_path); + assert_eq!(&ext, "crash"); + } +} diff --git a/crates/client/src/reader.rs b/crates/client/src/reader.rs index d0854d0b0..42f85124c 100644 --- a/crates/client/src/reader.rs +++ b/crates/client/src/reader.rs @@ -28,7 +28,9 @@ pub struct Reader { impl Reader { /// Creates a new `Reader` instance with the default root `"../../"`. pub fn new() -> Self { - Self { root: "../".into() } + Self { + root: "../../".into(), + } } /// Creates a new `Reader` instance with the provided `root`. diff --git a/crates/client/src/templates/trdelnik-tests/Cargo.toml.tmpl b/crates/client/src/templates/trdelnik-tests/Cargo.toml.tmpl deleted file mode 100644 index fd0ab9e4b..000000000 --- a/crates/client/src/templates/trdelnik-tests/Cargo.toml.tmpl +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "trdelnik-tests" -version = "0.1.0" -description = "Created with Trdelnik" -edition = "2021" - -[dependencies] -trdelnik-client = "0.5.0" -program_client = { path = "../.program_client" } - -[dev-dependencies] -fehler = "1.0.0" -rstest = "0.12.0" diff --git a/crates/client/src/templates/trdelnik-tests/Cargo_fuzz.toml.tmpl b/crates/client/src/templates/trdelnik-tests/Cargo_fuzz.toml.tmpl new file mode 100644 index 000000000..cbe01b234 --- /dev/null +++ b/crates/client/src/templates/trdelnik-tests/Cargo_fuzz.toml.tmpl @@ -0,0 +1,20 @@ +[package] +name = "fuzz_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" + +# Dependencies specific to Fuzz test +[dependencies] +# ... your dependencies here +honggfuzz = "0.5.55" +arbitrary = "1.3.0" +assert_matches = "1.4.0" + + +[dependencies.trdelnik-client] +version = "0.5.0" +features=["fuzzing"] + +[dependencies.program_client] +path = "../../.program_client" diff --git a/examples/turnstile/trdelnik-tests/Cargo.toml b/crates/client/src/templates/trdelnik-tests/Cargo_poc.toml.tmpl similarity index 53% rename from examples/turnstile/trdelnik-tests/Cargo.toml rename to crates/client/src/templates/trdelnik-tests/Cargo_poc.toml.tmpl index b5a67f867..d3a97b23b 100644 --- a/examples/turnstile/trdelnik-tests/Cargo.toml +++ b/crates/client/src/templates/trdelnik-tests/Cargo_poc.toml.tmpl @@ -1,18 +1,19 @@ [package] -name = "trdelnik-tests" +name = "poc_tests" version = "0.1.0" description = "Created with Trdelnik" edition = "2021" -[dev-dependencies] -fehler = "1.0.0" -rstest = "0.12.0" [dev-dependencies.trdelnik-client] -path = "../../../crates/client" +version = "0.5.0" + [dev-dependencies.program_client] -path = "../.program_client" +path = "../../.program_client" -[dev-dependencies.turnstile] -path = "../programs/turnstile" + +[dependencies] +assert_matches = "1.4.0" +fehler = "1.0.0" +rstest = "0.12.0" diff --git a/crates/client/src/templates/trdelnik-tests/fuzz_target.rs b/crates/client/src/templates/trdelnik-tests/test_fuzz.rs similarity index 91% rename from crates/client/src/templates/trdelnik-tests/fuzz_target.rs rename to crates/client/src/templates/trdelnik-tests/test_fuzz.rs index a269fb122..62e4d4826 100644 --- a/crates/client/src/templates/trdelnik-tests/fuzz_target.rs +++ b/crates/client/src/templates/trdelnik-tests/test_fuzz.rs @@ -1,4 +1,6 @@ use trdelnik_client::{fuzz_trd, fuzzing::*}; +mod accounts_snapshots; +mod fuzz_instructions; const PROGRAM_NAME: &str = "###PROGRAM_NAME###"; diff --git a/crates/client/src/test_generator.rs b/crates/client/src/test_generator.rs index ef56ce2c4..860b9b391 100644 --- a/crates/client/src/test_generator.rs +++ b/crates/client/src/test_generator.rs @@ -12,21 +12,20 @@ use std::{ use std::{fs::File, io::prelude::*}; use thiserror::Error; use tokio::fs; -use toml::{ - value::{Map, Table}, - Value, -}; +use toml::{value::Table, Value}; pub(crate) const TESTS_WORKSPACE: &str = "trdelnik-tests"; -const TESTS_DIRECTORY: &str = "tests"; -const FUZZ_DIRECTORY: &str = "src/bin"; const TESTS_FILE_NAME: &str = "test.rs"; -const FUZZ_TEST_FILE_NAME: &str = "fuzz_target.rs"; -pub(crate) const FUZZ_LIB_FILE_NAME: &str = "lib.rs"; pub(crate) const FUZZ_INSTRUCTIONS_FILE_NAME: &str = "fuzz_instructions.rs"; pub(crate) const ACCOUNTS_SNAPSHOTS_FILE_NAME: &str = "accounts_snapshots.rs"; pub(crate) const HFUZZ_TARGET: &str = "hfuzz_target"; +pub const FUZZ_TEST_DIRECTORY: &str = "fuzz_tests"; +pub const FUZZ_TEST: &str = "test_fuzz.rs"; +pub const POC_TEST_DIRECTORY: &str = "poc_tests"; +pub const TESTS: &str = "tests"; +pub const FUZZING: &str = "fuzzing"; + #[derive(Error, Debug)] pub enum Error { #[error("cannot parse Cargo.toml")] @@ -92,7 +91,7 @@ impl TestGenerator { /// It fails when: /// - there is not a root directory (no `Anchor.toml` file) #[throws] - pub async fn generate(&self, skip_fuzzer: bool) { + pub async fn generate(&self, _skip_fuzzer: bool) { let root = match Config::discover_root() { Ok(root) => root, Err(_) => throw!(Error::BadWorkspace), @@ -101,20 +100,43 @@ impl TestGenerator { let commander = Commander::with_root(root_path); commander.create_program_client_crate().await?; self.generate_test_files(&root).await?; - if !skip_fuzzer { - self.generate_fuzz_test_files(&root).await?; - self.update_gitignore(&root, "hfuzz_target")?; - } - self.update_workspace(&root).await?; - self.build_program_client(&commander).await?; + self.update_workspace(&root, "trdelnik-tests/poc_tests") + .await?; + let new_fuzz_test_dir = self.generate_fuzz_test_files(&root).await?; + self.build_program_client(&commander, new_fuzz_test_dir) + .await?; + self.update_gitignore( + &root, + &format!("{TESTS_WORKSPACE}/{FUZZ_TEST_DIRECTORY}/{FUZZING}/{HFUZZ_TARGET}"), + )?; + } + + #[throws] + pub async fn add_new_fuzz_test(&self) { + let root = match Config::discover_root() { + Ok(root) => root, + Err(_) => throw!(Error::BadWorkspace), + }; + let new_fuzz_test_dir = self.generate_fuzz_test_files(&root).await?; + + let root_path = root.to_str().unwrap().to_string(); + let commander = Commander::with_root(root_path); + self.build_program_client(&commander, new_fuzz_test_dir) + .await?; + self.update_gitignore( + &root, + &format!("{TESTS_WORKSPACE}/{FUZZ_TEST_DIRECTORY}/{FUZZING}/{HFUZZ_TARGET}"), + )?; } /// Builds and generates programs for `program_client` module #[throws] - async fn build_program_client(&self, commander: &Commander) { + async fn build_program_client(&self, commander: &Commander, new_fuzz_test_dir: PathBuf) { commander.build_programs().await?; commander.generate_program_client_deps().await?; - commander.generate_program_client_lib_rs().await?; + commander + .generate_program_client_lib_rs(Some(new_fuzz_test_dir)) + .await?; } /// Creates the `trdelnik-tests` workspace with `tests` directory and empty `test.rs` file @@ -122,23 +144,28 @@ impl TestGenerator { /// template located in `client/src/templates` #[throws] async fn generate_test_files(&self, root: &Path) { - let workspace_path = root.join(TESTS_WORKSPACE); - self.create_directory(&workspace_path, TESTS_WORKSPACE) - .await?; + let workspace_path = root + .join(TESTS_WORKSPACE) + .join(POC_TEST_DIRECTORY) + .join(TESTS); + + self.create_directory_all(&workspace_path, TESTS).await?; + + let test_path = workspace_path.join(TESTS_FILE_NAME); - let tests_path = workspace_path.join(TESTS_DIRECTORY); - self.create_directory(&tests_path, TESTS_DIRECTORY).await?; - let test_path = tests_path.join(TESTS_FILE_NAME); let test_content = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), "/src/templates/trdelnik-tests/test.rs" )); + let program_libs = self.get_program_lib_names(root).await?; + let program_name = if let Some(name) = program_libs.first() { name } else { throw!(Error::NoProgramsFound) }; + let test_content = test_content.replace("###PROGRAM_NAME###", program_name); let use_instructions = format!("use program_client::{}_instruction::*;\n", program_name); let template = format!("{use_instructions}{test_content}"); @@ -146,14 +173,21 @@ impl TestGenerator { self.create_file(&test_path, TESTS_FILE_NAME, &template) .await?; - let cargo_toml_path = workspace_path.join(CARGO_TOML); + let cargo_toml_path = root + .join(TESTS_WORKSPACE) + .join(POC_TEST_DIRECTORY) + .join(CARGO_TOML); + let cargo_toml_content = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), - "/src/templates/trdelnik-tests/Cargo.toml.tmpl" + "/src/templates/trdelnik-tests/Cargo_poc.toml.tmpl" )); + self.create_file(&cargo_toml_path, CARGO_TOML, cargo_toml_content) .await?; - self.add_program_deps(root, &cargo_toml_path).await?; + + let cargo_toml_dir = root.join(TESTS_WORKSPACE).join(POC_TEST_DIRECTORY); + self.add_program_deps(root, &cargo_toml_dir).await?; let trdelnik_toml_path = root.join(TRDELNIK_TOML); let trdelnik_toml_content = include_str!(concat!( @@ -166,26 +200,53 @@ impl TestGenerator { /// Creates the `trdelnik-tests` workspace with `src/bin` directory and empty `fuzz_target.rs` file #[throws] - async fn generate_fuzz_test_files(&self, root: &Path) { - let fuzzer_path = root.join(TESTS_WORKSPACE).join(FUZZ_DIRECTORY); - self.create_directory_all(&fuzzer_path, FUZZ_DIRECTORY) + async fn generate_fuzz_test_files(&self, root: &Path) -> PathBuf { + let fuzz_dir_path = root.join(TESTS_WORKSPACE).join(FUZZ_TEST_DIRECTORY); + let fuzz_tests_manifest_path = fuzz_dir_path.join(CARGO_TOML); + + self.create_directory_all(&fuzz_dir_path, FUZZ_TEST_DIRECTORY) .await?; let libs = self.get_program_lib_names(root).await?; - // create fuzz test template - let fuzzer_test_path = fuzzer_path.join(FUZZ_TEST_FILE_NAME); + let fuzz_id = if fuzz_dir_path.read_dir()?.next().is_none() { + 0 + } else { + let mut directories: Vec<_> = fuzz_dir_path + .read_dir() + .unwrap() + .map(|r| r.unwrap()) + .collect(); + + // INFO discard known entries created by framework, everything else + // created by user will be taken as fuzz test. + directories.retain(|x| x.file_name() != "fuzzing"); + directories.retain(|x| x.file_name() != "Cargo.toml"); + + directories.len() + }; + + let new_fuzz_test = format!("fuzz_{fuzz_id}"); + let new_fuzz_test_dir = fuzz_dir_path.join(&new_fuzz_test); + let new_bin_target = format!("{new_fuzz_test}/test_fuzz.rs"); + + self.create_directory(&new_fuzz_test_dir, &new_fuzz_test) + .await?; + + let fuzz_test_path = new_fuzz_test_dir.join(FUZZ_TEST); + let fuzz_test_content = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), - "/src/templates/trdelnik-tests/fuzz_target.rs" + "/src/templates/trdelnik-tests/test_fuzz.rs" )) .to_string(); + // create fuzz target file let fuzz_test_content = if let Some(lib) = libs.first() { let use_entry = format!("use {}::entry;\n", lib); let use_instructions = format!("use program_client::{}_instruction::*;\n", lib); let use_fuzz_instructions = format!( - "use trdelnik_tests::fuzz_instructions::{}_fuzz_instructions::FuzzInstruction;\n", + "use fuzz_instructions::{}_fuzz_instructions::FuzzInstruction;\n", lib ); let template = @@ -195,23 +256,11 @@ impl TestGenerator { throw!(Error::NoProgramsFound) }; - self.create_file(&fuzzer_test_path, FUZZ_TEST_FILE_NAME, &fuzz_test_content) - .await?; - - // create ./trdelnik-tests/src/lib.rs file - let fuzz_lib_content = "pub mod fuzz_instructions;\npub mod accounts_snapshots;"; - let fuzz_lib_path = root - .join(TESTS_WORKSPACE) - .join("src") - .join(FUZZ_LIB_FILE_NAME); - self.create_file(&fuzz_lib_path, FUZZ_LIB_FILE_NAME, fuzz_lib_content) + self.create_file(&fuzz_test_path, FUZZ_TEST, &fuzz_test_content) .await?; // create fuzz instructions file - let fuzz_instructions_path = root - .join(TESTS_WORKSPACE) - .join("src") - .join(FUZZ_INSTRUCTIONS_FILE_NAME); + let fuzz_instructions_path = new_fuzz_test_dir.join(FUZZ_INSTRUCTIONS_FILE_NAME); let fuzz_instructions_content = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), "/src/templates/trdelnik-tests/fuzz_instructions.rs" @@ -223,11 +272,8 @@ impl TestGenerator { ) .await?; - // create accounts_snapshots file - let accounts_snapshots_path = root - .join(TESTS_WORKSPACE) - .join("src") - .join(ACCOUNTS_SNAPSHOTS_FILE_NAME); + // // create accounts_snapshots file + let accounts_snapshots_path = new_fuzz_test_dir.join(ACCOUNTS_SNAPSHOTS_FILE_NAME); let accounts_snapshots_content = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), "/src/templates/trdelnik-tests/accounts_snapshots.rs" @@ -239,10 +285,21 @@ impl TestGenerator { ) .await?; - let workspace_path = root.join(TESTS_WORKSPACE); - let cargo_toml_path = workspace_path.join(CARGO_TOML); - self.add_feature_to_dep(root, &cargo_toml_path, "trdelnik-client", "fuzzing") + let cargo_toml_content = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/templates/trdelnik-tests/Cargo_fuzz.toml.tmpl" + )); + + self.create_file(&fuzz_tests_manifest_path, CARGO_TOML, cargo_toml_content) + .await?; + + self.add_bin_target(&fuzz_tests_manifest_path, &new_fuzz_test, &new_bin_target) + .await?; + self.add_program_deps(root, &fuzz_dir_path).await?; + + self.update_workspace(&root.to_path_buf(), "trdelnik-tests/fuzz_tests") .await?; + new_fuzz_test_dir } /// Creates a new file with a given content on the specified `path` and `name` @@ -299,10 +356,10 @@ impl TestGenerator { /// Adds `trdelnik-tests` workspace to the `root`'s `Cargo.toml` workspace members if needed. #[throws] - async fn update_workspace(&self, root: &PathBuf) { + async fn update_workspace(&self, root: &PathBuf, new_member: &str) { let cargo = Path::new(&root).join(CARGO_TOML); let mut content: Value = fs::read_to_string(&cargo).await?.parse()?; - let test_workspace_value = Value::String(String::from(TESTS_WORKSPACE)); + let test_workspace_value = Value::String(String::from(new_member)); let members = content .as_table_mut() .ok_or(Error::CannotParseCargoToml)? @@ -347,13 +404,45 @@ impl TestGenerator { } } + #[throws] + async fn add_bin_target(&self, cargo_path: &PathBuf, name: &str, path: &str) { + // Read the existing Cargo.toml file + let cargo_toml_content = fs::read_to_string(cargo_path).await?; + let mut cargo_toml: Value = cargo_toml_content.parse()?; + + // Create a new bin table + let mut bin_table = Table::new(); + bin_table.insert("name".to_string(), Value::String(name.to_string())); + bin_table.insert("path".to_string(), Value::String(path.to_string())); + + // Add the new [[bin]] section to the [[bin]] array + if let Some(bin_array) = cargo_toml.as_table_mut().and_then(|t| t.get_mut("bin")) { + if let Value::Array(bin_array) = bin_array { + bin_array.push(Value::Table(bin_table)); + } + } else { + // If there is no existing [[bin]] array, create one + let bin_array = Value::Array(vec![Value::Table(bin_table)]); + cargo_toml + .as_table_mut() + .unwrap() + .insert("bin".to_string(), bin_array); + } + + // Write the updated Cargo.toml file + fs::write(cargo_path, cargo_toml.to_string()).await?; + } + /// Adds programs to Cargo.toml as a dependencies to be able to be used in tests and fuzz targets #[throws] - async fn add_program_deps(&self, root: &Path, cargo_toml_path: &Path) { - let programs = self.get_programs(root).await?; + async fn add_program_deps(&self, root: &Path, cargo_toml_dir: &Path) { + let cargo_toml_path = cargo_toml_dir.join("Cargo.toml"); + let programs = self + .get_programs(root, &cargo_toml_dir.to_path_buf()) + .await?; if !programs.is_empty() { println!("Adding programs to Cargo.toml ..."); - let mut content: Value = fs::read_to_string(cargo_toml_path).await?.parse()?; + let mut content: Value = fs::read_to_string(&cargo_toml_path).await?.parse()?; let dev_deps = content .get_mut("dependencies") .and_then(Value::as_table_mut) @@ -364,66 +453,14 @@ impl TestGenerator { dev_deps.entry(name).or_insert(value); } } - fs::write(cargo_toml_path, content.to_string()).await?; + fs::write(&cargo_toml_path, content.to_string()).await?; } else { println!("Skipping adding programs to Cargo.toml ..."); } } - /// Adds programs to Cargo.toml as a dev dependencies to be able to be used in tests - #[throws] - async fn add_feature_to_dep( - &self, - root: &Path, - cargo_toml_path: &Path, - dependency: &str, - feature: &str, - ) { - let rel_path = cargo_toml_path - .strip_prefix(root) - .unwrap_or(Path::new("Cargo.toml")) - .to_string_lossy() - .to_string(); - println!("Adding feature {feature} to dependency {dependency} in {rel_path} ..."); - let mut content: Value = fs::read_to_string(cargo_toml_path).await?.parse()?; - let deps = content - .get_mut("dependencies") - .and_then(Value::as_table_mut) - .ok_or(Error::CannotParseCargoToml)?; - - let values = deps - .get_mut(dependency) - .and_then(|f| { - if f.is_table() { - f.as_table_mut() - } else if f.is_str() { - // if the value is only a string with version such as dependency = 0.0, create a new table with that version - let version = f.as_str().unwrap(); - let mut map = Map::new(); - let _ = map.insert("version".to_string(), Value::String(version.to_string())); - let t = Value::Table(map); - *f = t.to_owned(); - f.as_table_mut() - } else { - None - } - }) - .ok_or(Error::CannotParseCargoToml)?; - - let fuzzing = Value::String(feature.to_string()); - let value = Value::Array(vec![fuzzing.clone()]); - let features = values.entry("features").or_insert(value); - if let Some(features) = features.as_array_mut() { - if !features.iter().any(|f| *f == fuzzing) { - features.push(fuzzing); - }; - } - - fs::write(cargo_toml_path, content.to_string()).await?; - } - /// Scans `programs` directory and returns a list of `toml::Value` programs and their paths. - async fn get_programs(&self, root: &Path) -> Result, Error> { + async fn get_programs(&self, root: &Path, cargo_dir: &PathBuf) -> Result, Error> { let programs = root.join("programs"); if !programs.exists() { println!("Programs folder does not exist."); @@ -434,12 +471,10 @@ impl TestGenerator { let programs = std::fs::read_dir(programs)?; for program in programs { let file = program?; - let file_name = file.file_name(); if file.path().is_dir() { let path = file.path().join(CARGO_TOML); if path.exists() { - let name = file_name.to_str().unwrap(); - let dependency = self.get_program_dep(&path, name).await?; + let dependency = self.get_program_dep(&path, cargo_dir).await?; program_names.push(dependency); } } @@ -478,7 +513,10 @@ impl TestGenerator { /// Gets the program name from `/Cargo.toml` and returns a `toml::Value` program dependency. #[throws] - async fn get_program_dep<'a>(&self, dir: &Path, dir_name: &'a str) -> Value { + async fn get_program_dep<'a>(&self, dir: &Path, cargo_dir: &PathBuf) -> Value { + let manifest_path = dir.parent().unwrap(); + let relative_path = pathdiff::diff_paths(manifest_path, cargo_dir).unwrap(); + let content: Value = fs::read_to_string(&dir).await?.parse()?; let name = content .get("package") @@ -486,8 +524,12 @@ impl TestGenerator { .and_then(|table| table.get("name")) .and_then(Value::as_str) .ok_or(Error::CannotParseCargoToml)?; - format!("{name} = {{ path = \"../programs/{dir_name}\" }}") - .parse() - .unwrap() + format!( + r#"{} = {{ path = "{}" }}"#, + name, + relative_path.to_str().unwrap() + ) + .parse() + .unwrap() } } diff --git a/examples/escrow/.gitignore b/examples/escrow/.gitignore index d243ecc13..187f6d490 100644 --- a/examples/escrow/.gitignore +++ b/examples/escrow/.gitignore @@ -5,3 +5,4 @@ target **/*.rs.bk node_modules test-ledger +hfuzz_target diff --git a/examples/escrow/.program_client/src/lib.rs b/examples/escrow/.program_client/src/lib.rs index 8724e0388..741b0b16f 100644 --- a/examples/escrow/.program_client/src/lib.rs +++ b/examples/escrow/.program_client/src/lib.rs @@ -1,4 +1,4 @@ -// DO NOT EDIT - automatically generated file +// DO NOT EDIT - automatically generated file (except `use` statements inside the `*_instruction` module pub mod escrow_instruction { use trdelnik_client::*; pub static PROGRAM_ID: Pubkey = Pubkey::new_from_array([ @@ -10,15 +10,15 @@ pub mod escrow_instruction { client: &Client, i_initializer_amount: u64, i_taker_amount: u64, - a_initializer: anchor_lang::solana_program::pubkey::Pubkey, - a_initializer_deposit_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_initializer_receive_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_escrow_account: anchor_lang::solana_program::pubkey::Pubkey, - a_system_program: anchor_lang::solana_program::pubkey::Pubkey, - a_token_program: anchor_lang::solana_program::pubkey::Pubkey, + a_initializer: Pubkey, + a_initializer_deposit_token_account: Pubkey, + a_initializer_receive_token_account: Pubkey, + a_escrow_account: Pubkey, + a_system_program: Pubkey, + a_token_program: Pubkey, signers: impl IntoIterator + Send + 'static, ) -> Result { - Ok(client + client .send_instruction( PROGRAM_ID, escrow::instruction::InitializeEscrow { @@ -35,17 +35,17 @@ pub mod escrow_instruction { }, signers, ) - .await?) + .await } pub fn initialize_escrow_ix( i_initializer_amount: u64, i_taker_amount: u64, - a_initializer: anchor_lang::solana_program::pubkey::Pubkey, - a_initializer_deposit_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_initializer_receive_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_escrow_account: anchor_lang::solana_program::pubkey::Pubkey, - a_system_program: anchor_lang::solana_program::pubkey::Pubkey, - a_token_program: anchor_lang::solana_program::pubkey::Pubkey, + a_initializer: Pubkey, + a_initializer_deposit_token_account: Pubkey, + a_initializer_receive_token_account: Pubkey, + a_escrow_account: Pubkey, + a_system_program: Pubkey, + a_token_program: Pubkey, ) -> Instruction { Instruction { program_id: PROGRAM_ID, @@ -67,14 +67,14 @@ pub mod escrow_instruction { } pub async fn cancel_escrow( client: &Client, - a_initializer: anchor_lang::solana_program::pubkey::Pubkey, - a_pda_deposit_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_pda_account: anchor_lang::solana_program::pubkey::Pubkey, - a_escrow_account: anchor_lang::solana_program::pubkey::Pubkey, - a_token_program: anchor_lang::solana_program::pubkey::Pubkey, + a_initializer: Pubkey, + a_pda_deposit_token_account: Pubkey, + a_pda_account: Pubkey, + a_escrow_account: Pubkey, + a_token_program: Pubkey, signers: impl IntoIterator + Send + 'static, ) -> Result { - Ok(client + client .send_instruction( PROGRAM_ID, escrow::instruction::CancelEscrow {}, @@ -87,14 +87,14 @@ pub mod escrow_instruction { }, signers, ) - .await?) + .await } pub fn cancel_escrow_ix( - a_initializer: anchor_lang::solana_program::pubkey::Pubkey, - a_pda_deposit_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_pda_account: anchor_lang::solana_program::pubkey::Pubkey, - a_escrow_account: anchor_lang::solana_program::pubkey::Pubkey, - a_token_program: anchor_lang::solana_program::pubkey::Pubkey, + a_initializer: Pubkey, + a_pda_deposit_token_account: Pubkey, + a_pda_account: Pubkey, + a_escrow_account: Pubkey, + a_token_program: Pubkey, ) -> Instruction { Instruction { program_id: PROGRAM_ID, @@ -111,18 +111,18 @@ pub mod escrow_instruction { } pub async fn exchange( client: &Client, - a_taker: anchor_lang::solana_program::pubkey::Pubkey, - a_taker_deposit_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_taker_receive_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_pda_deposit_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_initializer_receive_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_initializer_main_account: anchor_lang::solana_program::pubkey::Pubkey, - a_escrow_account: anchor_lang::solana_program::pubkey::Pubkey, - a_pda_account: anchor_lang::solana_program::pubkey::Pubkey, - a_token_program: anchor_lang::solana_program::pubkey::Pubkey, + a_taker: Pubkey, + a_taker_deposit_token_account: Pubkey, + a_taker_receive_token_account: Pubkey, + a_pda_deposit_token_account: Pubkey, + a_initializer_receive_token_account: Pubkey, + a_initializer_main_account: Pubkey, + a_escrow_account: Pubkey, + a_pda_account: Pubkey, + a_token_program: Pubkey, signers: impl IntoIterator + Send + 'static, ) -> Result { - Ok(client + client .send_instruction( PROGRAM_ID, escrow::instruction::Exchange {}, @@ -139,18 +139,18 @@ pub mod escrow_instruction { }, signers, ) - .await?) + .await } pub fn exchange_ix( - a_taker: anchor_lang::solana_program::pubkey::Pubkey, - a_taker_deposit_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_taker_receive_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_pda_deposit_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_initializer_receive_token_account: anchor_lang::solana_program::pubkey::Pubkey, - a_initializer_main_account: anchor_lang::solana_program::pubkey::Pubkey, - a_escrow_account: anchor_lang::solana_program::pubkey::Pubkey, - a_pda_account: anchor_lang::solana_program::pubkey::Pubkey, - a_token_program: anchor_lang::solana_program::pubkey::Pubkey, + a_taker: Pubkey, + a_taker_deposit_token_account: Pubkey, + a_taker_receive_token_account: Pubkey, + a_pda_deposit_token_account: Pubkey, + a_initializer_receive_token_account: Pubkey, + a_initializer_main_account: Pubkey, + a_escrow_account: Pubkey, + a_pda_account: Pubkey, + a_token_program: Pubkey, ) -> Instruction { Instruction { program_id: PROGRAM_ID, diff --git a/examples/escrow/Cargo.toml b/examples/escrow/Cargo.toml index fbe457ec4..bd2c6b660 100644 --- a/examples/escrow/Cargo.toml +++ b/examples/escrow/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["programs/*", "trdelnik-tests"] +members = ["programs/*", "trdelnik-tests/poc_tests"] diff --git a/examples/escrow/Trdelnik.toml b/examples/escrow/Trdelnik.toml index e69de29bb..023cf8a3e 100644 --- a/examples/escrow/Trdelnik.toml +++ b/examples/escrow/Trdelnik.toml @@ -0,0 +1,11 @@ +[test] +validator_startup_timeout = 15000 + + +# set for default values +[fuzz] +timeout = 10 +iterations = 0 +keep_output = false +verbose = false +exit_upon_crash = false diff --git a/examples/escrow/trdelnik-tests/Cargo.toml b/examples/escrow/trdelnik-tests/poc_tests/Cargo.toml similarity index 54% rename from examples/escrow/trdelnik-tests/Cargo.toml rename to examples/escrow/trdelnik-tests/poc_tests/Cargo.toml index 0c3a7e5af..0eb31c5da 100644 --- a/examples/escrow/trdelnik-tests/Cargo.toml +++ b/examples/escrow/trdelnik-tests/poc_tests/Cargo.toml @@ -1,19 +1,21 @@ [package] -name = "trdelnik-tests" +name = "poc_tests" version = "0.1.0" description = "Created with Trdelnik" edition = "2021" -[dev-dependencies] +[dev-dependencies.trdelnik-client] +path = "../../../../crates/client" + +[dev-dependencies.program_client] +path = "../../.program_client" + +[dependencies] +assert_matches = "1.4.0" fehler = "1.0.0" rstest = "0.12.0" anchor-spl = "0.28.0" -[dev-dependencies.trdelnik-client] -path = "../../../crates/client" - -[dev-dependencies.program_client] -path = "../.program_client" -[dev-dependencies.escrow] -path = "../programs/escrow" +[dependencies.escrow] +path = "../../programs/escrow" diff --git a/examples/escrow/trdelnik-tests/tests/test.rs b/examples/escrow/trdelnik-tests/poc_tests/tests/test.rs similarity index 100% rename from examples/escrow/trdelnik-tests/tests/test.rs rename to examples/escrow/trdelnik-tests/poc_tests/tests/test.rs diff --git a/examples/fuzz_example0/.gitignore b/examples/fuzz_example0/.gitignore index bf9f05784..81caf3a30 100644 --- a/examples/fuzz_example0/.gitignore +++ b/examples/fuzz_example0/.gitignore @@ -6,4 +6,4 @@ target node_modules test-ledger .yarn -trdelnik-tests/hfuzz_target +trdelnik-tests/fuzz_tests/fuzzing/hfuzz_target diff --git a/examples/fuzz_example0/Cargo.lock b/examples/fuzz_example0/Cargo.lock index 2d697eb51..c1501bdd3 100644 --- a/examples/fuzz_example0/Cargo.lock +++ b/examples/fuzz_example0/Cargo.lock @@ -540,9 +540,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.75" +version = "0.1.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" +checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.33", @@ -1024,15 +1024,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -1777,12 +1777,24 @@ dependencies = [ ] [[package]] -name = "fuzzer" +name = "fuzz_example0" version = "0.1.0" dependencies = [ "anchor-lang", ] +[[package]] +name = "fuzz_tests" +version = "0.1.0" +dependencies = [ + "arbitrary", + "assert_matches", + "fuzz_example0", + "honggfuzz", + "program_client", + "trdelnik-client", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1855,9 +1867,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" dependencies = [ "bytes", "fnv", @@ -2610,11 +2622,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.7.1", + "num_enum_derive 0.7.2", ] [[package]] @@ -2631,11 +2643,11 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 2.0.1", + "proc-macro-crate 3.0.0", "proc-macro2 1.0.66", "quote 1.0.33", "syn 2.0.29", @@ -2766,6 +2778,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pbkdf2" version = "0.4.0" @@ -2863,6 +2881,18 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "poc_tests" +version = "0.1.0" +dependencies = [ + "assert_matches", + "fehler", + "fuzz_example0", + "program_client", + "rstest 0.12.0", + "trdelnik-client", +] + [[package]] name = "polyval" version = "0.5.3" @@ -2920,12 +2950,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" dependencies = [ - "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.21.0", ] [[package]] @@ -2974,7 +3003,7 @@ dependencies = [ name = "program_client" version = "0.1.0" dependencies = [ - "fuzzer", + "fuzz_example0", "trdelnik-client", ] @@ -5038,7 +5067,7 @@ dependencies = [ "bytemuck", "num-derive 0.4.1", "num-traits", - "num_enum 0.7.1", + "num_enum 0.7.2", "solana-program", "solana-zk-token-sdk", "spl-memo", @@ -5272,9 +5301,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -5522,9 +5551,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" [[package]] name = "toml_edit" @@ -5539,9 +5568,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ "indexmap 2.1.0", "toml_datetime", @@ -5628,6 +5657,7 @@ dependencies = [ "honggfuzz", "lazy_static", "log", + "pathdiff", "proc-macro2 1.0.66", "quinn-proto", "quote 1.0.33", @@ -5692,17 +5722,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trdelnik-tests" -version = "0.1.0" -dependencies = [ - "fehler", - "fuzzer", - "program_client", - "rstest 0.12.0", - "trdelnik-client", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -6057,15 +6076,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -6084,21 +6094,6 @@ dependencies = [ "windows-targets 0.52.0", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.48.5" @@ -6257,9 +6252,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.31" +version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" dependencies = [ "memchr", ] diff --git a/examples/fuzz_example0/Cargo.toml b/examples/fuzz_example0/Cargo.toml index 0f494a20f..f85805661 100644 --- a/examples/fuzz_example0/Cargo.toml +++ b/examples/fuzz_example0/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["programs/*", "trdelnik-tests"] +members = ["programs/*", "trdelnik-tests/poc_tests", "trdelnik-tests/fuzz_tests"] [profile.release] overflow-checks = true lto = "fat" diff --git a/examples/fuzz_example0/trdelnik-tests/Cargo.toml b/examples/fuzz_example0/trdelnik-tests/Cargo.toml deleted file mode 100644 index ea88f1524..000000000 --- a/examples/fuzz_example0/trdelnik-tests/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "trdelnik-tests" -version = "0.1.0" -description = "Created with Trdelnik" -edition = "2021" -[dependencies.trdelnik-client] -path = "../../../crates/client" -features = ["fuzzing"] - -[dependencies.program_client] -path = "../.program_client" - -[dependencies.fuzz_example0] -path = "../programs/fuzz_example0" - -[dev-dependencies] -fehler = "1.0.0" -rstest = "0.12.0" diff --git a/examples/fuzz_example0/trdelnik-tests/fuzz_tests/Cargo.toml b/examples/fuzz_example0/trdelnik-tests/fuzz_tests/Cargo.toml new file mode 100644 index 000000000..cd43d51f5 --- /dev/null +++ b/examples/fuzz_example0/trdelnik-tests/fuzz_tests/Cargo.toml @@ -0,0 +1,24 @@ +[[bin]] +name = "fuzz_0" +path = "fuzz_0/test_fuzz.rs" + +[package] +name = "fuzz_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" + +[dependencies] +honggfuzz = "0.5.55" +arbitrary = "1.3.0" +assert_matches = "1.4.0" + +[dependencies.trdelnik-client] +path = "../../../../crates/client" +features = ["fuzzing"] + +[dependencies.program_client] +path = "../../.program_client" + +[dependencies.fuzz_example0] +path = "../../programs/fuzz_example0" diff --git a/examples/fuzz_example0/trdelnik-tests/src/accounts_snapshots.rs b/examples/fuzz_example0/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs similarity index 100% rename from examples/fuzz_example0/trdelnik-tests/src/accounts_snapshots.rs rename to examples/fuzz_example0/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs diff --git a/examples/fuzz_example0/trdelnik-tests/src/fuzz_instructions.rs b/examples/fuzz_example0/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs similarity index 100% rename from examples/fuzz_example0/trdelnik-tests/src/fuzz_instructions.rs rename to examples/fuzz_example0/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs diff --git a/examples/fuzz_example0/trdelnik-tests/src/bin/fuzz_target.rs b/examples/fuzz_example0/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs similarity index 81% rename from examples/fuzz_example0/trdelnik-tests/src/bin/fuzz_target.rs rename to examples/fuzz_example0/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs index a60632c3d..003556cb7 100644 --- a/examples/fuzz_example0/trdelnik-tests/src/bin/fuzz_target.rs +++ b/examples/fuzz_example0/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -1,8 +1,9 @@ use fuzz_example0::entry; +use fuzz_instructions::fuzz_example0_fuzz_instructions::{FuzzInstruction, Initialize}; use program_client::fuzz_example0_instruction::*; use trdelnik_client::{fuzz_trd, fuzzing::*}; -use trdelnik_tests::fuzz_instructions::fuzz_example0_fuzz_instructions::FuzzInstruction; -use trdelnik_tests::fuzz_instructions::fuzz_example0_fuzz_instructions::Initialize; +mod accounts_snapshots; +mod fuzz_instructions; const PROGRAM_NAME: &str = "fuzz_example0"; diff --git a/examples/fuzz_example0/trdelnik-tests/hfuzz_workspace/fuzz_target/overflow_crash.fuzz b/examples/fuzz_example0/trdelnik-tests/hfuzz_workspace/fuzz_target/overflow_crash.fuzz deleted file mode 100644 index 38a4c82a7..000000000 Binary files a/examples/fuzz_example0/trdelnik-tests/hfuzz_workspace/fuzz_target/overflow_crash.fuzz and /dev/null differ diff --git a/examples/fuzz_example0/trdelnik-tests/poc_tests/Cargo.toml b/examples/fuzz_example0/trdelnik-tests/poc_tests/Cargo.toml new file mode 100644 index 000000000..d82cb595d --- /dev/null +++ b/examples/fuzz_example0/trdelnik-tests/poc_tests/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "poc_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" +[dev-dependencies.trdelnik-client] +path = "../../../../crates/client" + + +[dev-dependencies.program_client] +path = "../../.program_client" + +[dependencies] +assert_matches = "1.4.0" +fehler = "1.0.0" +rstest = "0.12.0" + +[dependencies.fuzz_example0] +path = "../../programs/fuzz_example0" diff --git a/examples/fuzz_example0/trdelnik-tests/tests/test.rs b/examples/fuzz_example0/trdelnik-tests/poc_tests/tests/test.rs similarity index 100% rename from examples/fuzz_example0/trdelnik-tests/tests/test.rs rename to examples/fuzz_example0/trdelnik-tests/poc_tests/tests/test.rs diff --git a/examples/fuzz_example0/trdelnik-tests/src/lib.rs b/examples/fuzz_example0/trdelnik-tests/src/lib.rs deleted file mode 100644 index 3edf590b0..000000000 --- a/examples/fuzz_example0/trdelnik-tests/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod fuzz_instructions; -pub mod accounts_snapshots; \ No newline at end of file diff --git a/examples/fuzz_example1/.gitignore b/examples/fuzz_example1/.gitignore index bf9f05784..81caf3a30 100644 --- a/examples/fuzz_example1/.gitignore +++ b/examples/fuzz_example1/.gitignore @@ -6,4 +6,4 @@ target node_modules test-ledger .yarn -trdelnik-tests/hfuzz_target +trdelnik-tests/fuzz_tests/fuzzing/hfuzz_target diff --git a/examples/fuzz_example1/Cargo.lock b/examples/fuzz_example1/Cargo.lock index 74bf04447..71bcdf335 100644 --- a/examples/fuzz_example1/Cargo.lock +++ b/examples/fuzz_example1/Cargo.lock @@ -1025,15 +1025,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -1783,6 +1783,18 @@ dependencies = [ "anchor-lang", ] +[[package]] +name = "fuzz_tests" +version = "0.1.0" +dependencies = [ + "arbitrary", + "assert_matches", + "fuzz_example1", + "honggfuzz", + "program_client", + "trdelnik-client", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1855,9 +1867,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" dependencies = [ "bytes", "fnv", @@ -2610,11 +2622,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.7.1", + "num_enum_derive 0.7.2", ] [[package]] @@ -2631,11 +2643,11 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 2.0.1", + "proc-macro-crate 3.0.0", "proc-macro2 1.0.71", "quote 1.0.33", "syn 2.0.42", @@ -2766,6 +2778,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pbkdf2" version = "0.4.0" @@ -2863,6 +2881,18 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "poc_tests" +version = "0.1.0" +dependencies = [ + "assert_matches", + "fehler", + "fuzz_example1", + "program_client", + "rstest 0.12.0", + "trdelnik-client", +] + [[package]] name = "polyval" version = "0.5.3" @@ -2920,12 +2950,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" dependencies = [ - "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.21.0", ] [[package]] @@ -5027,7 +5056,7 @@ dependencies = [ "bytemuck", "num-derive 0.4.1", "num-traits", - "num_enum 0.7.1", + "num_enum 0.7.2", "solana-program", "solana-zk-token-sdk", "spl-memo", @@ -5261,9 +5290,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -5511,9 +5540,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" [[package]] name = "toml_edit" @@ -5528,9 +5557,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ "indexmap 2.1.0", "toml_datetime", @@ -5617,6 +5646,7 @@ dependencies = [ "honggfuzz", "lazy_static", "log", + "pathdiff", "proc-macro2 1.0.71", "quinn-proto", "quote 1.0.33", @@ -5681,17 +5711,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trdelnik-tests" -version = "0.1.0" -dependencies = [ - "fehler", - "fuzz_example1", - "program_client", - "rstest 0.12.0", - "trdelnik-client", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -6046,15 +6065,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -6073,21 +6083,6 @@ dependencies = [ "windows-targets 0.52.0", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.48.5" @@ -6246,9 +6241,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.31" +version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" dependencies = [ "memchr", ] diff --git a/examples/fuzz_example1/Cargo.toml b/examples/fuzz_example1/Cargo.toml index 0f494a20f..f85805661 100644 --- a/examples/fuzz_example1/Cargo.toml +++ b/examples/fuzz_example1/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["programs/*", "trdelnik-tests"] +members = ["programs/*", "trdelnik-tests/poc_tests", "trdelnik-tests/fuzz_tests"] [profile.release] overflow-checks = true lto = "fat" diff --git a/examples/fuzz_example1/trdelnik-tests/Cargo.toml b/examples/fuzz_example1/trdelnik-tests/Cargo.toml deleted file mode 100644 index e69d082d4..000000000 --- a/examples/fuzz_example1/trdelnik-tests/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "trdelnik-tests" -version = "0.1.0" -description = "Created with Trdelnik" -edition = "2021" -[dependencies.trdelnik-client] -version = "0.5.0" -path = "../../../crates/client" -features = ["fuzzing"] - -[dependencies.program_client] -path = "../.program_client" - -[dependencies.fuzz_example1] -path = "../programs/fuzz_example1" - -[dev-dependencies] -fehler = "1.0.0" -rstest = "0.12.0" diff --git a/examples/fuzz_example1/trdelnik-tests/fuzz_tests/Cargo.toml b/examples/fuzz_example1/trdelnik-tests/fuzz_tests/Cargo.toml new file mode 100644 index 000000000..d78158052 --- /dev/null +++ b/examples/fuzz_example1/trdelnik-tests/fuzz_tests/Cargo.toml @@ -0,0 +1,24 @@ +[[bin]] +name = "fuzz_0" +path = "fuzz_0/test_fuzz.rs" + +[package] +name = "fuzz_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" + +[dependencies] +honggfuzz = "0.5.55" +arbitrary = "1.3.0" +assert_matches = "1.4.0" + +[dependencies.trdelnik-client] +path = "../../../../crates/client" +features = ["fuzzing"] + +[dependencies.program_client] +path = "../../.program_client" + +[dependencies.fuzz_example1] +path = "../../programs/fuzz_example1" diff --git a/examples/fuzz_example1/trdelnik-tests/src/accounts_snapshots.rs b/examples/fuzz_example1/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs similarity index 87% rename from examples/fuzz_example1/trdelnik-tests/src/accounts_snapshots.rs rename to examples/fuzz_example1/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs index 9b7282d92..13621236e 100644 --- a/examples/fuzz_example1/trdelnik-tests/src/accounts_snapshots.rs +++ b/examples/fuzz_example1/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs @@ -1,4 +1,4 @@ -use fuzz_example1::state::{State, Project}; +use fuzz_example1::state::{Project, State}; use trdelnik_client::anchor_lang::solana_program::instruction::AccountMeta; use trdelnik_client::anchor_lang::{self, prelude::*}; use trdelnik_client::fuzzing::{get_account_infos_option, FuzzingError}; @@ -36,19 +36,19 @@ impl<'info> InitializeSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::signer::Signer::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let state: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let system_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); Ok(Self { author, state, @@ -69,25 +69,25 @@ impl<'info> RegisterSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::signer::Signer::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let project: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let state: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let system_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); Ok(Self { project_author, project, @@ -109,13 +109,13 @@ impl<'info> EndRegistrationsSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::signer::Signer::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let state: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); Ok(Self { author, state }) } } @@ -132,25 +132,25 @@ impl<'info> InvestSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::signer::Signer::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let project: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let state: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let system_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); Ok(Self { investor, project, diff --git a/examples/fuzz_example1/trdelnik-tests/src/fuzz_instructions.rs b/examples/fuzz_example1/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs similarity index 100% rename from examples/fuzz_example1/trdelnik-tests/src/fuzz_instructions.rs rename to examples/fuzz_example1/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs diff --git a/examples/fuzz_example1/trdelnik-tests/src/bin/fuzz_target.rs b/examples/fuzz_example1/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs similarity index 85% rename from examples/fuzz_example1/trdelnik-tests/src/bin/fuzz_target.rs rename to examples/fuzz_example1/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 5db7ca3cb..fa15905cd 100644 --- a/examples/fuzz_example1/trdelnik-tests/src/bin/fuzz_target.rs +++ b/examples/fuzz_example1/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -1,9 +1,9 @@ use fuzz_example1::entry; +use fuzz_instructions::fuzz_example1_fuzz_instructions::{FuzzInstruction, Initialize}; use program_client::fuzz_example1_instruction::*; use trdelnik_client::{fuzz_trd, fuzzing::*}; -use trdelnik_tests::fuzz_instructions::fuzz_example1_fuzz_instructions::{ - FuzzInstruction, Initialize, -}; +mod accounts_snapshots; +mod fuzz_instructions; const PROGRAM_NAME: &str = "fuzz_example1"; diff --git a/examples/fuzz_example1/trdelnik-tests/hfuzz_workspace/fuzz_target/register_check.fuzz b/examples/fuzz_example1/trdelnik-tests/hfuzz_workspace/fuzz_target/register_check.fuzz deleted file mode 100644 index e48d4d2eb..000000000 Binary files a/examples/fuzz_example1/trdelnik-tests/hfuzz_workspace/fuzz_target/register_check.fuzz and /dev/null differ diff --git a/examples/fuzz_example1/trdelnik-tests/poc_tests/Cargo.toml b/examples/fuzz_example1/trdelnik-tests/poc_tests/Cargo.toml new file mode 100644 index 000000000..3a67ed741 --- /dev/null +++ b/examples/fuzz_example1/trdelnik-tests/poc_tests/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "poc_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" +[dev-dependencies.trdelnik-client] +path = "../../../../crates/client" + + +[dev-dependencies.program_client] +path = "../../.program_client" + +[dependencies] +assert_matches = "1.4.0" +fehler = "1.0.0" +rstest = "0.12.0" + +[dependencies.fuzz_example1] +path = "../../programs/fuzz_example1" diff --git a/examples/fuzz_example1/trdelnik-tests/tests/test.rs b/examples/fuzz_example1/trdelnik-tests/poc_tests/tests/test.rs similarity index 100% rename from examples/fuzz_example1/trdelnik-tests/tests/test.rs rename to examples/fuzz_example1/trdelnik-tests/poc_tests/tests/test.rs diff --git a/examples/fuzz_example1/trdelnik-tests/src/lib.rs b/examples/fuzz_example1/trdelnik-tests/src/lib.rs deleted file mode 100644 index 3edf590b0..000000000 --- a/examples/fuzz_example1/trdelnik-tests/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod fuzz_instructions; -pub mod accounts_snapshots; \ No newline at end of file diff --git a/examples/fuzz_example2/.gitignore b/examples/fuzz_example2/.gitignore new file mode 100644 index 000000000..81caf3a30 --- /dev/null +++ b/examples/fuzz_example2/.gitignore @@ -0,0 +1,9 @@ + +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn +trdelnik-tests/fuzz_tests/fuzzing/hfuzz_target diff --git a/examples/fuzz_example2/Cargo.lock b/examples/fuzz_example2/Cargo.lock index e08831f92..75c7ff0f9 100644 --- a/examples/fuzz_example2/Cargo.lock +++ b/examples/fuzz_example2/Cargo.lock @@ -1025,15 +1025,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -1104,11 +1104,10 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if", "crossbeam-utils", ] @@ -1782,6 +1781,18 @@ dependencies = [ "anchor-lang", ] +[[package]] +name = "fuzz_tests" +version = "0.1.0" +dependencies = [ + "arbitrary", + "assert_matches", + "fuzz_example2", + "honggfuzz", + "program_client", + "trdelnik-client", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1854,9 +1865,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" dependencies = [ "bytes", "fnv", @@ -2609,11 +2620,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.7.1", + "num_enum_derive 0.7.2", ] [[package]] @@ -2630,11 +2641,11 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 2.0.1", + "proc-macro-crate 3.0.0", "proc-macro2 1.0.71", "quote 1.0.33", "syn 2.0.43", @@ -2765,6 +2776,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pbkdf2" version = "0.4.0" @@ -2862,6 +2879,18 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "poc_tests" +version = "0.1.0" +dependencies = [ + "assert_matches", + "fehler", + "fuzz_example2", + "program_client", + "rstest 0.12.0", + "trdelnik-client", +] + [[package]] name = "polyval" version = "0.5.3" @@ -2919,12 +2948,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" dependencies = [ - "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.21.0", ] [[package]] @@ -5026,7 +5054,7 @@ dependencies = [ "bytemuck", "num-derive 0.4.1", "num-traits", - "num_enum 0.7.1", + "num_enum 0.7.2", "solana-program", "solana-zk-token-sdk", "spl-memo", @@ -5260,9 +5288,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -5510,9 +5538,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" [[package]] name = "toml_edit" @@ -5527,9 +5555,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ "indexmap 2.1.0", "toml_datetime", @@ -5616,6 +5644,7 @@ dependencies = [ "honggfuzz", "lazy_static", "log", + "pathdiff", "proc-macro2 1.0.71", "quinn-proto", "quote 1.0.33", @@ -5680,17 +5709,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trdelnik-tests" -version = "0.1.0" -dependencies = [ - "fehler", - "fuzz_example2", - "program_client", - "rstest 0.12.0", - "trdelnik-client", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -6045,15 +6063,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -6072,21 +6081,6 @@ dependencies = [ "windows-targets 0.52.0", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.48.5" @@ -6245,9 +6239,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.31" +version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" dependencies = [ "memchr", ] diff --git a/examples/fuzz_example2/Cargo.toml b/examples/fuzz_example2/Cargo.toml index 0f494a20f..f85805661 100644 --- a/examples/fuzz_example2/Cargo.toml +++ b/examples/fuzz_example2/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["programs/*", "trdelnik-tests"] +members = ["programs/*", "trdelnik-tests/poc_tests", "trdelnik-tests/fuzz_tests"] [profile.release] overflow-checks = true lto = "fat" diff --git a/examples/fuzz_example2/trdelnik-tests/Cargo.toml b/examples/fuzz_example2/trdelnik-tests/Cargo.toml deleted file mode 100644 index bb1caecf8..000000000 --- a/examples/fuzz_example2/trdelnik-tests/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "trdelnik-tests" -version = "0.1.0" -description = "Created with Trdelnik" -edition = "2021" -[dependencies.trdelnik-client] -path = "../../../crates/client" -features = ["fuzzing"] - -[dependencies.program_client] -path = "../.program_client" - -[dependencies.fuzz_example2] -path = "../programs/fuzz_example2" - -[dev-dependencies] -fehler = "1.0.0" -rstest = "0.12.0" diff --git a/examples/fuzz_example2/trdelnik-tests/fuzz_tests/Cargo.toml b/examples/fuzz_example2/trdelnik-tests/fuzz_tests/Cargo.toml new file mode 100644 index 000000000..c5c7cfe3f --- /dev/null +++ b/examples/fuzz_example2/trdelnik-tests/fuzz_tests/Cargo.toml @@ -0,0 +1,24 @@ +[[bin]] +name = "fuzz_0" +path = "fuzz_0/test_fuzz.rs" + +[package] +name = "fuzz_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" + +[dependencies] +honggfuzz = "0.5.55" +arbitrary = "1.3.0" +assert_matches = "1.4.0" + +[dependencies.trdelnik-client] +path = "../../../../crates/client" +features = ["fuzzing"] + +[dependencies.program_client] +path = "../../.program_client" + +[dependencies.fuzz_example2] +path = "../../programs/fuzz_example2" diff --git a/examples/fuzz_example2/trdelnik-tests/src/accounts_snapshots.rs b/examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs similarity index 88% rename from examples/fuzz_example2/trdelnik-tests/src/accounts_snapshots.rs rename to examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs index d40fa1a22..10a9fd85d 100644 --- a/examples/fuzz_example2/trdelnik-tests/src/accounts_snapshots.rs +++ b/examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs @@ -25,19 +25,19 @@ impl<'info> InitializeSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::signer::Signer::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let escrow: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let system_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); Ok(Self { author, escrow, @@ -58,19 +58,19 @@ impl<'info> WithdrawSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::signer::Signer::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let escrow: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let system_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); Ok(Self { receiver, escrow, diff --git a/examples/fuzz_example2/trdelnik-tests/src/fuzz_instructions.rs b/examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs similarity index 98% rename from examples/fuzz_example2/trdelnik-tests/src/fuzz_instructions.rs rename to examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs index 1ff8c8f38..6a387070e 100644 --- a/examples/fuzz_example2/trdelnik-tests/src/fuzz_instructions.rs +++ b/examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs @@ -133,7 +133,7 @@ pub mod fuzz_example2_fuzz_instructions { &self, pre_ix: Self::IxSnapshot, post_ix: Self::IxSnapshot, - ix_data: Self::IxData, + _ix_data: Self::IxData, ) -> Result<(), &'static str> { if let Some(escrow_pre) = pre_ix.escrow { // we can unwrap the receiver account because it has to be initialized before the instruction @@ -159,7 +159,7 @@ pub mod fuzz_example2_fuzz_instructions { #[derive(Default)] pub struct FuzzAccounts { receiver: AccountsStorage, - system_program: AccountsStorage, + // system_program: AccountsStorage, author: AccountsStorage, escrow: AccountsStorage, } diff --git a/examples/fuzz_example2/trdelnik-tests/src/bin/fuzz_target.rs b/examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs similarity index 82% rename from examples/fuzz_example2/trdelnik-tests/src/bin/fuzz_target.rs rename to examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 244ce511f..5c84c753b 100644 --- a/examples/fuzz_example2/trdelnik-tests/src/bin/fuzz_target.rs +++ b/examples/fuzz_example2/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -1,15 +1,14 @@ use fuzz_example2::entry; +use fuzz_instructions::fuzz_example2_fuzz_instructions::{FuzzInstruction, Initialize}; use program_client::fuzz_example2_instruction::*; use trdelnik_client::{fuzz_trd, fuzzing::*}; -use trdelnik_tests::fuzz_instructions::fuzz_example2_fuzz_instructions::{ - FuzzInstruction, Initialize, -}; +mod accounts_snapshots; +mod fuzz_instructions; const PROGRAM_NAME: &str = "fuzz_example2"; struct MyFuzzData; -// impl FuzzDataBuilder for MyFuzzData {} impl FuzzDataBuilder for MyFuzzData { fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result> { let init_ix = FuzzInstruction::Initialize(Initialize::arbitrary(u)?); diff --git a/examples/fuzz_example2/trdelnik-tests/hfuzz_workspace/fuzz_target/withdraw_check.fuzz b/examples/fuzz_example2/trdelnik-tests/hfuzz_workspace/fuzz_target/withdraw_check.fuzz deleted file mode 100644 index 4d4964871..000000000 Binary files a/examples/fuzz_example2/trdelnik-tests/hfuzz_workspace/fuzz_target/withdraw_check.fuzz and /dev/null differ diff --git a/examples/fuzz_example2/trdelnik-tests/poc_tests/Cargo.toml b/examples/fuzz_example2/trdelnik-tests/poc_tests/Cargo.toml new file mode 100644 index 000000000..34de3cc7f --- /dev/null +++ b/examples/fuzz_example2/trdelnik-tests/poc_tests/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "poc_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" +[dev-dependencies.trdelnik-client] +path = "../../../../crates/client" + + +[dev-dependencies.program_client] +path = "../../.program_client" + +[dependencies] +assert_matches = "1.4.0" +fehler = "1.0.0" +rstest = "0.12.0" + +[dependencies.fuzz_example2] +path = "../../programs/fuzz_example2" diff --git a/examples/fuzz_example2/trdelnik-tests/tests/test.rs b/examples/fuzz_example2/trdelnik-tests/poc_tests/tests/test.rs similarity index 100% rename from examples/fuzz_example2/trdelnik-tests/tests/test.rs rename to examples/fuzz_example2/trdelnik-tests/poc_tests/tests/test.rs diff --git a/examples/fuzz_example2/trdelnik-tests/src/lib.rs b/examples/fuzz_example2/trdelnik-tests/src/lib.rs deleted file mode 100644 index 3edf590b0..000000000 --- a/examples/fuzz_example2/trdelnik-tests/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod fuzz_instructions; -pub mod accounts_snapshots; \ No newline at end of file diff --git a/examples/fuzz_example3/.gitignore b/examples/fuzz_example3/.gitignore index bf9f05784..81caf3a30 100644 --- a/examples/fuzz_example3/.gitignore +++ b/examples/fuzz_example3/.gitignore @@ -6,4 +6,4 @@ target node_modules test-ledger .yarn -trdelnik-tests/hfuzz_target +trdelnik-tests/fuzz_tests/fuzzing/hfuzz_target diff --git a/examples/fuzz_example3/Cargo.lock b/examples/fuzz_example3/Cargo.lock index ecfc98d20..4c383bc84 100644 --- a/examples/fuzz_example3/Cargo.lock +++ b/examples/fuzz_example3/Cargo.lock @@ -1038,15 +1038,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -1117,11 +1117,10 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if", "crossbeam-utils", ] @@ -1797,6 +1796,19 @@ dependencies = [ "anchor-spl", ] +[[package]] +name = "fuzz_tests" +version = "0.1.0" +dependencies = [ + "anchor-spl", + "arbitrary", + "assert_matches", + "fuzz_example3", + "honggfuzz", + "program_client", + "trdelnik-client", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1869,9 +1881,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" dependencies = [ "bytes", "fnv", @@ -2633,11 +2645,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.7.1", + "num_enum_derive 0.7.2", ] [[package]] @@ -2666,9 +2678,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.73", @@ -2801,6 +2813,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pbkdf2" version = "0.4.0" @@ -2898,6 +2916,18 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "poc_tests" +version = "0.1.0" +dependencies = [ + "assert_matches", + "fehler", + "fuzz_example3", + "program_client", + "rstest 0.12.0", + "trdelnik-client", +] + [[package]] name = "polyval" version = "0.5.3" @@ -5110,7 +5140,7 @@ dependencies = [ "bytemuck", "num-derive 0.4.1", "num-traits", - "num_enum 0.7.1", + "num_enum 0.7.2", "solana-program", "solana-zk-token-sdk", "spl-memo 4.0.0", @@ -5689,6 +5719,7 @@ dependencies = [ "honggfuzz", "lazy_static", "log", + "pathdiff", "proc-macro2 1.0.73", "quinn-proto", "quote 1.0.34", @@ -5753,18 +5784,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "trdelnik-tests" -version = "0.1.0" -dependencies = [ - "anchor-spl", - "fehler", - "fuzz_example3", - "program_client", - "rstest 0.12.0", - "trdelnik-client", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -6119,15 +6138,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -6146,21 +6156,6 @@ dependencies = [ "windows-targets 0.52.0", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.48.5" diff --git a/examples/fuzz_example3/Cargo.toml b/examples/fuzz_example3/Cargo.toml index 0f494a20f..f85805661 100644 --- a/examples/fuzz_example3/Cargo.toml +++ b/examples/fuzz_example3/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["programs/*", "trdelnik-tests"] +members = ["programs/*", "trdelnik-tests/poc_tests", "trdelnik-tests/fuzz_tests"] [profile.release] overflow-checks = true lto = "fat" diff --git a/examples/fuzz_example3/trdelnik-tests/Cargo.toml b/examples/fuzz_example3/trdelnik-tests/Cargo.toml deleted file mode 100644 index 71d12ff36..000000000 --- a/examples/fuzz_example3/trdelnik-tests/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "trdelnik-tests" -version = "0.1.0" -description = "Created with Trdelnik" -edition = "2021" -[dependencies.trdelnik-client] -path = "../../../crates/client" -features = ["fuzzing"] - -[dependencies.program_client] -path = "../.program_client" - -[dependencies.fuzz_example3] -path = "../programs/fuzz_example3" - -[dev-dependencies] -fehler = "1.0.0" -rstest = "0.12.0" - -[dependencies] -anchor-spl = "0.28.0" diff --git a/examples/fuzz_example3/trdelnik-tests/fuzz_tests/Cargo.toml b/examples/fuzz_example3/trdelnik-tests/fuzz_tests/Cargo.toml new file mode 100644 index 000000000..4b957e7a4 --- /dev/null +++ b/examples/fuzz_example3/trdelnik-tests/fuzz_tests/Cargo.toml @@ -0,0 +1,25 @@ +[[bin]] +name = "fuzz_0" +path = "fuzz_0/test_fuzz.rs" + +[package] +name = "fuzz_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" + +[dependencies] +honggfuzz = "0.5.55" +arbitrary = "1.3.0" +assert_matches = "1.4.0" +anchor-spl = "0.28.0" + +[dependencies.trdelnik-client] +path = "../../../../crates/client" +features = ["fuzzing"] + +[dependencies.program_client] +path = "../../.program_client" + +[dependencies.fuzz_example3] +path = "../../programs/fuzz_example3" diff --git a/examples/fuzz_example3/trdelnik-tests/src/accounts_snapshots.rs b/examples/fuzz_example3/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs similarity index 86% rename from examples/fuzz_example3/trdelnik-tests/src/accounts_snapshots.rs rename to examples/fuzz_example3/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs index 3d649a35e..921e87cad 100644 --- a/examples/fuzz_example3/trdelnik-tests/src/accounts_snapshots.rs +++ b/examples/fuzz_example3/trdelnik-tests/fuzz_tests/fuzz_0/accounts_snapshots.rs @@ -1,6 +1,5 @@ -use anchor_spl::token::{Mint, Token, TokenAccount}; +use anchor_spl::token::{TokenAccount, Token, Mint}; use fuzz_example3::state::Escrow; - use trdelnik_client::anchor_lang::solana_program::instruction::AccountMeta; use trdelnik_client::anchor_lang::{self, prelude::*}; use trdelnik_client::fuzzing::{get_account_infos_option, FuzzingError}; @@ -36,45 +35,45 @@ impl<'info> InitVestingSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::signer::Signer::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let sender_token_account: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let escrow: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let escrow_token_account: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let mint: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let token_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let system_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); Ok(Self { sender, sender_token_account, @@ -99,27 +98,27 @@ impl<'info> WithdrawUnlockedSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::signer::Signer::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let recipient_token_account: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let escrow: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let escrow_token_account: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let escrow_pda_authority = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)?; @@ -128,19 +127,19 @@ impl<'info> WithdrawUnlockedSnapshot<'info> { .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::account::Account::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let token_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); let system_program: Option> = accounts_iter .next() .ok_or(FuzzingError::NotEnoughAccounts)? .map(|acc| anchor_lang::accounts::program::Program::try_from(&acc)) .transpose() - .map_err(|_| FuzzingError::CannotDeserializeAccount)?; + .unwrap_or(None); Ok(Self { recipient, recipient_token_account, diff --git a/examples/fuzz_example3/trdelnik-tests/src/fuzz_instructions.rs b/examples/fuzz_example3/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs similarity index 100% rename from examples/fuzz_example3/trdelnik-tests/src/fuzz_instructions.rs rename to examples/fuzz_example3/trdelnik-tests/fuzz_tests/fuzz_0/fuzz_instructions.rs diff --git a/examples/fuzz_example3/trdelnik-tests/src/bin/fuzz_target.rs b/examples/fuzz_example3/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs similarity index 82% rename from examples/fuzz_example3/trdelnik-tests/src/bin/fuzz_target.rs rename to examples/fuzz_example3/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs index 9f93d834e..074c1bd02 100644 --- a/examples/fuzz_example3/trdelnik-tests/src/bin/fuzz_target.rs +++ b/examples/fuzz_example3/trdelnik-tests/fuzz_tests/fuzz_0/test_fuzz.rs @@ -1,15 +1,14 @@ use fuzz_example3::entry; +use fuzz_instructions::fuzz_example3_fuzz_instructions::{FuzzInstruction, InitVesting}; use program_client::fuzz_example3_instruction::*; use trdelnik_client::{fuzz_trd, fuzzing::*}; -use trdelnik_tests::fuzz_instructions::fuzz_example3_fuzz_instructions::{ - FuzzInstruction, InitVesting, -}; +mod accounts_snapshots; +mod fuzz_instructions; const PROGRAM_NAME: &str = "fuzz_example3"; struct MyFuzzData; -// impl FuzzDataBuilder for MyFuzzData {} impl FuzzDataBuilder for MyFuzzData { fn pre_ixs(u: &mut arbitrary::Unstructured) -> arbitrary::Result> { let init_ix = FuzzInstruction::InitVesting(InitVesting::arbitrary(u)?); diff --git a/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/can_withdraw_less.fuzz b/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/can_withdraw_less.fuzz deleted file mode 100644 index c6631c976..000000000 Binary files a/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/can_withdraw_less.fuzz and /dev/null differ diff --git a/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/can_withdraw_more.fuzz b/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/can_withdraw_more.fuzz deleted file mode 100644 index 79ed97182..000000000 Binary files a/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/can_withdraw_more.fuzz and /dev/null differ diff --git a/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/cannot_withdraw_any.fuzz b/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/cannot_withdraw_any.fuzz deleted file mode 100644 index 5361e2ca9..000000000 Binary files a/examples/fuzz_example3/trdelnik-tests/hfuzz_workspace/fuzz_target/cannot_withdraw_any.fuzz and /dev/null differ diff --git a/examples/fuzz_example3/trdelnik-tests/poc_tests/Cargo.toml b/examples/fuzz_example3/trdelnik-tests/poc_tests/Cargo.toml new file mode 100644 index 000000000..d648d7925 --- /dev/null +++ b/examples/fuzz_example3/trdelnik-tests/poc_tests/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "poc_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" +[dev-dependencies.trdelnik-client] +path = "../../../../crates/client" + + +[dev-dependencies.program_client] +path = "../../.program_client" + +[dependencies] +assert_matches = "1.4.0" +fehler = "1.0.0" +rstest = "0.12.0" + +[dependencies.fuzz_example3] +path = "../../programs/fuzz_example3" diff --git a/examples/fuzz_example3/trdelnik-tests/tests/test.rs b/examples/fuzz_example3/trdelnik-tests/poc_tests/tests/test.rs similarity index 100% rename from examples/fuzz_example3/trdelnik-tests/tests/test.rs rename to examples/fuzz_example3/trdelnik-tests/poc_tests/tests/test.rs diff --git a/examples/fuzz_example3/trdelnik-tests/src/lib.rs b/examples/fuzz_example3/trdelnik-tests/src/lib.rs deleted file mode 100644 index 3edf590b0..000000000 --- a/examples/fuzz_example3/trdelnik-tests/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod fuzz_instructions; -pub mod accounts_snapshots; \ No newline at end of file diff --git a/examples/turnstile/.gitignore b/examples/turnstile/.gitignore index 92c9568be..5faebabe1 100644 --- a/examples/turnstile/.gitignore +++ b/examples/turnstile/.gitignore @@ -8,3 +8,4 @@ node_modules __pycache__ test-ledger mocked_state +hfuzz_target diff --git a/examples/turnstile/.program_client/src/lib.rs b/examples/turnstile/.program_client/src/lib.rs index a945c54ce..abbc63d1e 100644 --- a/examples/turnstile/.program_client/src/lib.rs +++ b/examples/turnstile/.program_client/src/lib.rs @@ -8,12 +8,12 @@ pub mod turnstile_instruction { ]); pub async fn initialize( client: &Client, - a_state: anchor_lang::solana_program::pubkey::Pubkey, - a_user: anchor_lang::solana_program::pubkey::Pubkey, - a_system_program: anchor_lang::solana_program::pubkey::Pubkey, + a_state: Pubkey, + a_user: Pubkey, + a_system_program: Pubkey, signers: impl IntoIterator + Send + 'static, ) -> Result { - Ok(client + client .send_instruction( PROGRAM_ID, turnstile::instruction::Initialize {}, @@ -24,13 +24,9 @@ pub mod turnstile_instruction { }, signers, ) - .await?) + .await } - pub fn initialize_ix( - a_state: anchor_lang::solana_program::pubkey::Pubkey, - a_user: anchor_lang::solana_program::pubkey::Pubkey, - a_system_program: anchor_lang::solana_program::pubkey::Pubkey, - ) -> Instruction { + pub fn initialize_ix(a_state: Pubkey, a_user: Pubkey, a_system_program: Pubkey) -> Instruction { Instruction { program_id: PROGRAM_ID, data: turnstile::instruction::Initialize {}.data(), @@ -45,10 +41,10 @@ pub mod turnstile_instruction { pub async fn coin( client: &Client, i_dummy_arg: String, - a_state: anchor_lang::solana_program::pubkey::Pubkey, + a_state: Pubkey, signers: impl IntoIterator + Send + 'static, ) -> Result { - Ok(client + client .send_instruction( PROGRAM_ID, turnstile::instruction::Coin { @@ -57,12 +53,9 @@ pub mod turnstile_instruction { turnstile::accounts::UpdateState { state: a_state }, signers, ) - .await?) + .await } - pub fn coin_ix( - i_dummy_arg: String, - a_state: anchor_lang::solana_program::pubkey::Pubkey, - ) -> Instruction { + pub fn coin_ix(i_dummy_arg: String, a_state: Pubkey) -> Instruction { Instruction { program_id: PROGRAM_ID, data: turnstile::instruction::Coin { @@ -74,19 +67,19 @@ pub mod turnstile_instruction { } pub async fn push( client: &Client, - a_state: anchor_lang::solana_program::pubkey::Pubkey, + a_state: Pubkey, signers: impl IntoIterator + Send + 'static, ) -> Result { - Ok(client + client .send_instruction( PROGRAM_ID, turnstile::instruction::Push {}, turnstile::accounts::UpdateState { state: a_state }, signers, ) - .await?) + .await } - pub fn push_ix(a_state: anchor_lang::solana_program::pubkey::Pubkey) -> Instruction { + pub fn push_ix(a_state: Pubkey) -> Instruction { Instruction { program_id: PROGRAM_ID, data: turnstile::instruction::Push {}.data(), diff --git a/examples/turnstile/Cargo.toml b/examples/turnstile/Cargo.toml index fbe457ec4..bd2c6b660 100644 --- a/examples/turnstile/Cargo.toml +++ b/examples/turnstile/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["programs/*", "trdelnik-tests"] +members = ["programs/*", "trdelnik-tests/poc_tests"] diff --git a/examples/turnstile/Trdelnik.toml b/examples/turnstile/Trdelnik.toml index 0428ca653..023cf8a3e 100644 --- a/examples/turnstile/Trdelnik.toml +++ b/examples/turnstile/Trdelnik.toml @@ -1,2 +1,11 @@ [test] validator_startup_timeout = 15000 + + +# set for default values +[fuzz] +timeout = 10 +iterations = 0 +keep_output = false +verbose = false +exit_upon_crash = false diff --git a/examples/turnstile/trdelnik-tests/poc_tests/Cargo.toml b/examples/turnstile/trdelnik-tests/poc_tests/Cargo.toml new file mode 100644 index 000000000..4ec98821c --- /dev/null +++ b/examples/turnstile/trdelnik-tests/poc_tests/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "poc_tests" +version = "0.1.0" +description = "Created with Trdelnik" +edition = "2021" +[dev-dependencies.trdelnik-client] +path = "../../../../crates/client" + +[dev-dependencies.program_client] +path = "../../.program_client" + +[dependencies] +assert_matches = "1.4.0" +fehler = "1.0.0" +rstest = "0.12.0" + +[dependencies.turnstile] +path = "../../programs/turnstile" diff --git a/examples/turnstile/trdelnik-tests/tests/test.rs b/examples/turnstile/trdelnik-tests/poc_tests/tests/test.rs similarity index 100% rename from examples/turnstile/trdelnik-tests/tests/test.rs rename to examples/turnstile/trdelnik-tests/poc_tests/tests/test.rs