From eb226beea8a18f6bab201bccd1ad5c9c8f4d7de5 Mon Sep 17 00:00:00 2001 From: Alexey Miroshkin Date: Thu, 22 Mar 2018 17:53:47 +0100 Subject: [PATCH] Introduce fuzz tests for core (#844) This PR introduces fuzz tests and address #592 --- core/fuzz/.gitignore | 4 ++ core/fuzz/Cargo.toml | 34 +++++++++ core/fuzz/README.md | 35 +++++++++ core/fuzz/fuzz_targets/block_read.rs | 12 ++++ core/fuzz/fuzz_targets/compact_block_read.rs | 12 ++++ core/fuzz/fuzz_targets/transaction_read.rs | 12 ++++ core/fuzz/src/main.rs | 75 ++++++++++++++++++++ 7 files changed, 184 insertions(+) create mode 100644 core/fuzz/.gitignore create mode 100644 core/fuzz/Cargo.toml create mode 100644 core/fuzz/README.md create mode 100644 core/fuzz/fuzz_targets/block_read.rs create mode 100644 core/fuzz/fuzz_targets/compact_block_read.rs create mode 100644 core/fuzz/fuzz_targets/transaction_read.rs create mode 100644 core/fuzz/src/main.rs diff --git a/core/fuzz/.gitignore b/core/fuzz/.gitignore new file mode 100644 index 000000000..572e03bdf --- /dev/null +++ b/core/fuzz/.gitignore @@ -0,0 +1,4 @@ + +target +corpus +artifacts diff --git a/core/fuzz/Cargo.toml b/core/fuzz/Cargo.toml new file mode 100644 index 000000000..0b930fb1f --- /dev/null +++ b/core/fuzz/Cargo.toml @@ -0,0 +1,34 @@ + +[package] +name = "grin_core-fuzz" +version = "0.0.1" +authors = ["Automatically generated"] +publish = false + +[package.metadata] +cargo-fuzz = true + +[dependencies] +grin_core = { path = ".."} +grin_keychain = { path = "../../keychain"} +libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" } + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "transaction_read" +path = "fuzz_targets/transaction_read.rs" + +[[bin]] +name = "gen-corpus" +path = "src/main.rs" + +[[bin]] +name = "block_read" +path = "fuzz_targets/block_read.rs" + +[[bin]] +name = "compact_block_read" +path = "fuzz_targets/compact_block_read.rs" diff --git a/core/fuzz/README.md b/core/fuzz/README.md new file mode 100644 index 000000000..6046ce661 --- /dev/null +++ b/core/fuzz/README.md @@ -0,0 +1,35 @@ +# Fuzz testing + +## Installation +Cargo-fuzz (https://github.com/rust-fuzz/cargo-fuzz) has been used. +To install it: + +``` +cargo install cargo-fuzz +``` + +## Pattern generation for corpus +This step is optional, libFuzz will generate random patterns to populate +corpus (in folder `corpus`). However we can genearete more meaningful pattern +e.g. use serialized form of a real block or transaction. To generate them: + +``` +cd fuzz + +cargo run --bin gen-corpus +``` + +## Run tests +Fuzz test is basically infinite test, run it for some period of time then +stop if no failures are found. +To run the tests make sure youre in folder `core` otherwise you may get +some misleading errors, then run one of the following tests: +``` +cargo fuzz run tx_read + +cargo fuzz run block_read + +cargo fuzz run compact_block_read + +``` +Check `fuzz/Cargo.toml` for the full list of targets. diff --git a/core/fuzz/fuzz_targets/block_read.rs b/core/fuzz/fuzz_targets/block_read.rs new file mode 100644 index 000000000..23186ac22 --- /dev/null +++ b/core/fuzz/fuzz_targets/block_read.rs @@ -0,0 +1,12 @@ +#![no_main] +extern crate grin_core; +#[macro_use] +extern crate libfuzzer_sys; + +use grin_core::ser; +use grin_core::core::block; + +fuzz_target!(|data: &[u8]| { + let mut d = data.clone(); + let _t: Result = ser::deserialize(&mut d); +}); diff --git a/core/fuzz/fuzz_targets/compact_block_read.rs b/core/fuzz/fuzz_targets/compact_block_read.rs new file mode 100644 index 000000000..8e503c546 --- /dev/null +++ b/core/fuzz/fuzz_targets/compact_block_read.rs @@ -0,0 +1,12 @@ +#![no_main] +extern crate grin_core; +#[macro_use] +extern crate libfuzzer_sys; + +use grin_core::ser; +use grin_core::core::block; + +fuzz_target!(|data: &[u8]| { + let mut d = data.clone(); + let _t: Result = ser::deserialize(&mut d); +}); diff --git a/core/fuzz/fuzz_targets/transaction_read.rs b/core/fuzz/fuzz_targets/transaction_read.rs new file mode 100644 index 000000000..acc4927f2 --- /dev/null +++ b/core/fuzz/fuzz_targets/transaction_read.rs @@ -0,0 +1,12 @@ +#![no_main] +extern crate grin_core; +#[macro_use] +extern crate libfuzzer_sys; + +use grin_core::ser; +use grin_core::core::transaction; + +fuzz_target!(|data: &[u8]| { + let mut d = data.clone(); + let _t: Result = ser::deserialize(&mut d); +}); diff --git a/core/fuzz/src/main.rs b/core/fuzz/src/main.rs new file mode 100644 index 000000000..e36974275 --- /dev/null +++ b/core/fuzz/src/main.rs @@ -0,0 +1,75 @@ +extern crate grin_core; +extern crate grin_keychain; + +use std::path::Path; +use std::fs::{self, File}; +use grin_core::ser; +use grin_core::core::{Block, BlockHeader, CompactBlock, Transaction}; +use grin_core::core::target::Difficulty; + +use grin_core::core::build::{input, output, transaction_with_offset, with_fee}; +use grin_keychain::keychain::Keychain; + +fn main() { + generate("transaction_read", &tx()).unwrap(); + generate("block_read", &block()).unwrap(); + generate("compact_block_read", &compact_block()).unwrap(); +} + +fn generate(target: &str, obj: W) -> Result<(), ser::Error> { + let dir_path = Path::new("corpus").join(target); + if !dir_path.is_dir() { + fs::create_dir(&dir_path).map_err(|e| ser::Error::IOErr(e))?; + } + + let pattern_path = dir_path.join("pattern"); + if !pattern_path.exists() { + let mut file = File::create(&pattern_path).map_err(|e| ser::Error::IOErr(e))?; + ser::serialize(&mut file, &obj) + } else { + Ok(()) + } +} + +fn block() -> Block { + let keychain = Keychain::from_random_seed().unwrap(); + let key_id = keychain.derive_key_id(1).unwrap(); + + let mut tx1 = tx(); + let mut tx2 = tx(); + + Block::new( + &BlockHeader::default(), + vec![&mut tx1, &mut tx2], + &keychain, + &key_id, + Difficulty::one(), + ).unwrap() +} + +fn compact_block() -> CompactBlock { + CompactBlock { + header: BlockHeader::default(), + nonce: 1, + out_full: vec![], + kern_full: vec![], + kern_ids: vec![], + } +} + +fn tx() -> Transaction { + let keychain = Keychain::from_random_seed().unwrap(); + let key_id1 = keychain.derive_key_id(1).unwrap(); + let key_id2 = keychain.derive_key_id(2).unwrap(); + let key_id3 = keychain.derive_key_id(3).unwrap(); + + transaction_with_offset( + vec![ + input(10, key_id1), + input(11, key_id2), + output(19, key_id3), + with_fee(2), + ], + &keychain, + ).unwrap() +}