Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
initial (failing) quickcheck
Browse files Browse the repository at this point in the history
  • Loading branch information
NikVolf committed Nov 9, 2019
1 parent deb8314 commit eb343db
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 3 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions core/client/db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ header_metadata = { package = "substrate-header-metadata", path = "../header-met
substrate-keyring = { path = "../../keyring" }
test-client = { package = "substrate-test-runtime-client", path = "../../test-runtime/client" }
env_logger = "0.7.0"
quickcheck = "0.8"

[features]
default = []
Expand Down
96 changes: 93 additions & 3 deletions core/client/db/src/storage_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -779,9 +779,11 @@ mod tests {
}

#[cfg(test)]
mod quickcheck {
mod qc {
use std::collections::{HashMap, hash_map::Entry};

use quickcheck::{quickcheck, TestResult, Arbitrary};

use super::*;
use sr_primitives::testing::{H256, Block as RawBlock, ExtrinsicWrapper};
use state_machine::backend::InMemory;
Expand All @@ -793,12 +795,57 @@ mod quickcheck {

type KeyMap = HashMap<Vec<u8>, Option<Vec<u8>>>;

#[derive(Debug, Clone)]
enum Action {
Next { hash: H256, changes: KeySet },
Fork { depth: usize, hash: H256, changes: KeySet },
Reorg { depth: usize, hash: H256 },
}

impl Arbitrary for Action {
fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
let path = gen.next_u32() as u8;
let mut buf = [0u8; 32];

match path {
0..=200 => {
gen.fill_bytes(&mut buf[..]);
Action::Next {
hash: H256::from(&buf),
changes: {
let mut set = Vec::new();
for _ in 0..gen.next_u32()/(16*256*256*256) {
set.push((vec![gen.next_u32() as u8], Some(vec![gen.next_u32() as u8])));
}
set
}
}
},
200..=250 => {
gen.fill_bytes(&mut buf[..]);
Action::Fork {
hash: H256::from(&buf),
depth: ((gen.next_u32() as u8) / 64) as usize,
changes: {
let mut set = Vec::new();
for _ in 0..gen.next_u32()/(4*256*256*256) {
set.push((vec![gen.next_u32() as u8], Some(vec![gen.next_u32() as u8])));
}
set
}
}
}
_ => {
gen.fill_bytes(&mut buf[..]);
Action::Reorg {
hash: H256::from(&buf),
depth: ((gen.next_u32() as u8) / 64) as usize,
}
}
}
}
}

struct Mutator {
shared: SharedCache<Block, Blake2Hasher>,
canon: Vec<(H256, H256, KeyMap)>,
Expand All @@ -807,8 +854,6 @@ mod quickcheck {

impl Mutator {
fn new_empty() -> Self {
let root_parent = H256::from(&[0u8; 32]);

let shared = new_shared_cache::<Block, Blake2Hasher>(256*1024, (0,1));

Self {
Expand All @@ -826,10 +871,22 @@ mod quickcheck {
)
}

fn canon_head_state(&self) -> CachingState<Blake2Hasher, InMemory<Blake2Hasher>, Block> {
self.head_state(self.canon.last().expect("Expected to be one commit").0)
}

fn head_storage(&self) -> &KeyMap {
&self.canon.last().expect("Expected to be one commit").2
}

fn mutate_static(&mut self, action: Action) -> CachingState<Blake2Hasher, InMemory<Blake2Hasher>, Block> {
self.mutate(action).expect("Expected to provide only valid actions to the mutate_static")
}

fn canon_len(&self) -> usize {
return self.canon.len();
}

fn mutate(&mut self, action: Action) -> Result<CachingState<Blake2Hasher, InMemory<Blake2Hasher>, Block>, ()> {
let state = match action {
Action::Next { hash, changes } => {
Expand Down Expand Up @@ -1011,4 +1068,37 @@ mod quickcheck {
mutator.mutate_static(Action::Reorg { depth: 3, hash: h3b });
assert!(mutator.head_state(h3a).storage(&key).unwrap().is_none());
}

fn is_head_match(mutator: &Mutator) -> bool {
let head_state = mutator.canon_head_state();
for (key, val) in mutator.head_storage().iter() {
if head_state.storage(key).unwrap() != *val {
return false;
}
}
true
}

#[test]
fn retract() {

}

quickcheck! {
fn head_complete(actions: Vec<Action>) -> TestResult {
let mut mutator = Mutator::new_empty();

for action in actions.into_iter() {
if let Err(_) = mutator.mutate(action) {
return TestResult::discard();
}
}

if mutator.canon_len() == 0 {
return TestResult::discard();
}

TestResult::from_bool(is_head_match(&mutator))
}
}
}

0 comments on commit eb343db

Please sign in to comment.