Skip to content

Commit

Permalink
fixup fuzzer
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidn committed Sep 24, 2024
1 parent 6cb546e commit 4d57ab5
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 74 deletions.
31 changes: 12 additions & 19 deletions crates/chia-consensus/fuzz/fuzz_targets/solution-generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use chia_consensus::gen::solution_generator::{calculate_generator_length, soluti
use chia_protocol::{Coin, CoinSpend};
use chia_traits::Streamable;
use clvmr::{
serde::{node_from_bytes, node_to_bytes},
serde::{node_from_bytes_backrefs, node_to_bytes},
Allocator,
};
use libfuzzer_sys::fuzz_target;
Expand All @@ -13,7 +13,7 @@ fuzz_target!(|data: &[u8]| {
let mut spends = Vec::<CoinSpend>::new();
let mut generator_input = Vec::<(Coin, Vec<u8>, Vec<u8>)>::new();
let mut data = Cursor::new(data);
let mut discrepancy: usize = 0;
let mut discrepancy: i64 = 0;
let mut a = Allocator::new();
while let Ok(spend) = CoinSpend::parse::<false>(&mut data) {
spends.push(spend.clone());
Expand All @@ -23,30 +23,23 @@ fuzz_target!(|data: &[u8]| {
spend.solution.to_vec(),
));
// Check if puzzle or solution are atoms which can represented in a smaller form
let node = node_from_bytes(&mut a, spend.puzzle_reveal.as_ref()).expect("node");
if node.is_atom() {
let puz = node_to_bytes(&a, node).expect("bytes");
discrepancy += spend.puzzle_reveal.as_ref().len() - puz.len();
}
let node = node_from_bytes(&mut a, spend.solution.as_ref()).expect("node");
if node.is_atom() {
let sol = node_to_bytes(&a, node).expect("bytes");
discrepancy += spend.solution.as_ref().len() - sol.len();
}
let node = node_from_bytes_backrefs(&mut a, spend.puzzle_reveal.as_ref()).expect("node");
let puz = node_to_bytes(&a, node).expect("bytes");
discrepancy += spend.puzzle_reveal.as_ref().len() as i64 - puz.len() as i64;
let node = node_from_bytes_backrefs(&mut a, spend.solution.as_ref()).expect("node");
let sol = node_to_bytes(&a, node).expect("bytes");
discrepancy += spend.solution.as_ref().len() as i64 - sol.len() as i64;
}
if spends.is_empty() {
return;
}
let Ok(result) = solution_generator(generator_input) else {
return;
};

if result.len() != calculate_generator_length(spends.clone()) - discrepancy {
let result = solution_generator(generator_input).expect("solution_generator");
if result.len() as i64 != calculate_generator_length(spends.clone()) as i64 - discrepancy {
panic!("Debug spends: {:?}", spends);
}

assert_eq!(
result.len(),
calculate_generator_length(spends) - discrepancy
result.len() as i64,
calculate_generator_length(spends) as i64 - discrepancy
);
});
69 changes: 14 additions & 55 deletions crates/chia-consensus/src/gen/solution_generator.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use chia_protocol::Coin;
use chia_protocol::CoinSpend;
use clvmr::allocator::{Allocator, NodePtr};
use clvmr::serde::{
node_from_bytes, node_from_bytes_backrefs, node_to_bytes, node_to_bytes_backrefs,
};
use clvmr::serde::{node_from_bytes_backrefs, node_to_bytes, node_to_bytes_backrefs};
use std::io;

// the tuple has the Coin, puzzle-reveal and solution
Expand Down Expand Up @@ -42,42 +40,6 @@ where
Ok(quote)
}

// the tuple has the Coin, puzzle-reveal and solution
fn build_generator_no_backrefs<BufRef, I>(a: &mut Allocator, spends: I) -> io::Result<NodePtr>
where
BufRef: AsRef<[u8]>,
I: IntoIterator<Item = (Coin, BufRef, BufRef)>,
{
// the generator we produce here is just a quoted list. Nothing fancy.
// Its format is as follows:
// (q . ( ( ( parent-id puzzle-reveal amount solution ) ... ) ) )

let mut spend_list = a.nil();
for s in spends {
let item = a.nil();
// solution
let solution = node_from_bytes(a, s.2.as_ref())?;
let item = a.new_pair(solution, item)?;
// amount
let amount = a.new_number(s.0.amount.into())?;
let item = a.new_pair(amount, item)?;
// puzzle reveal
let puzzle = node_from_bytes(a, s.1.as_ref())?;
let item = a.new_pair(puzzle, item)?;
// parent-id
let parent_id = a.new_atom(&s.0.parent_coin_info)?;
let item = a.new_pair(parent_id, item)?;

spend_list = a.new_pair(item, spend_list)?;
}

// the list of spends is the first (and only) item in an outer list
spend_list = a.new_pair(spend_list, a.nil())?;

let quote = a.new_pair(a.one(), spend_list)?;
Ok(quote)
}

fn clvm_bytes_len(val: u64) -> usize {
if val < 0x80 {
1
Expand Down Expand Up @@ -127,7 +89,7 @@ where
I: IntoIterator<Item = (Coin, BufRef, BufRef)>,
{
let mut a = Allocator::new();
let generator = build_generator_no_backrefs(&mut a, spends)?;
let generator = build_generator(&mut a, spends)?;
node_to_bytes(&a, generator)
}

Expand All @@ -145,6 +107,7 @@ where
mod tests {
use super::*;
use chia_protocol::Program;
use chia_traits::Streamable;
use clvmr::{run_program, ChiaDialect};
use hex_literal::hex;
use rstest::rstest;
Expand Down Expand Up @@ -371,7 +334,7 @@ mod tests {
let mut spends: Vec<(Coin, &[u8], &[u8])> = Vec::new();
let mut coin_spends = Vec::<CoinSpend>::new();
let mut a = Allocator::new();
let mut discrepancy: usize = 0;
let mut discrepancy: i64 = 0;

let coin: Coin = Coin::new(
hex!("ccd5bb71183532bff220ba46c268991a00000000000000000000000000036840").into(),
Expand All @@ -381,24 +344,20 @@ mod tests {
spends.push((coin, puzzle, solution));
coin_spends.push(CoinSpend {
coin,
puzzle_reveal: Program::from(puzzle),
solution: Program::from(solution),
puzzle_reveal: Program::from_bytes(puzzle).expect("puzzle_reveal"),
solution: Program::from_bytes(solution).expect("solution"),
});
let node = node_from_bytes(&mut a, puzzle).expect("atom");
if node.is_atom() {
let puz = node_to_bytes(&a, node).expect("bytes");
discrepancy = puzzle.len() - puz.len();
}
let node = node_from_bytes(&mut a, solution).expect("atom");
if node.is_atom() {
let sol = node_to_bytes(&a, node).expect("bytes");
discrepancy = solution.len() - sol.len();
}
let node = node_from_bytes_backrefs(&mut a, puzzle).expect("puzzle");
let puz = node_to_bytes(&a, node).expect("bytes");
discrepancy += puzzle.len() as i64 - puz.len() as i64;
let node = node_from_bytes_backrefs(&mut a, solution).expect("solution");
let sol = node_to_bytes(&a, node).expect("bytes");
discrepancy += solution.len() as i64 - sol.len() as i64;
let result = solution_generator(spends.clone()).expect("solution_generator");

assert_eq!(
result.len(),
calculate_generator_length(&coin_spends) - discrepancy
result.len() as i64,
calculate_generator_length(&coin_spends) as i64 - discrepancy
);
}

Expand Down

0 comments on commit 4d57ab5

Please sign in to comment.