Introduce fuzz tests for core (#844)

This PR introduces fuzz tests and address #592
This commit is contained in:
Alexey Miroshkin 2018-03-22 17:53:47 +01:00 committed by Ignotus Peverell
parent 4b639cae5c
commit eb226beea8
7 changed files with 184 additions and 0 deletions

4
core/fuzz/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
target
corpus
artifacts

34
core/fuzz/Cargo.toml Normal file
View file

@ -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"

35
core/fuzz/README.md Normal file
View file

@ -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.

View file

@ -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<block::Block, ser::Error> = ser::deserialize(&mut d);
});

View file

@ -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<block::CompactBlock, ser::Error> = ser::deserialize(&mut d);
});

View file

@ -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<transaction::Transaction, ser::Error> = ser::deserialize(&mut d);
});

75
core/fuzz/src/main.rs Normal file
View file

@ -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<W: ser::Writeable>(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()
}