From 18a62a5df3407f9995561b368c1476cf3054d60a Mon Sep 17 00:00:00 2001 From: Davidson Souza Date: Thu, 8 Sep 2022 11:03:55 -0300 Subject: [PATCH] use serde_json for tests instead of manual parsing --- Cargo.lock | 50 +++++++++++++++++++++ Cargo.toml | 3 +- src/accumulator/proof.rs | 75 ++++++++++++++++--------------- src/accumulator/stump.rs | 95 ++++++++++++++++++++++------------------ 4 files changed, 142 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00f9877..27ef26e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,12 +97,31 @@ version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +[[package]] +name = "proc-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rustreexo" version = "0.1.0" dependencies = [ "bitcoin", "bitcoin_hashes", + "serde", "serde_json", "sha2", ] @@ -136,6 +155,20 @@ name = "serde" version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "serde_json" @@ -159,12 +192,29 @@ dependencies = [ "digest", ] +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "typenum" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index bea14e3..67fbc69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ bitcoin_hashes = "0.7.6" sha2 = "0.10.2" [dev-dependencies] -serde_json="1.0.81" \ No newline at end of file +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.81" \ No newline at end of file diff --git a/src/accumulator/proof.rs b/src/accumulator/proof.rs index f5c71b0..dceeaab 100644 --- a/src/accumulator/proof.rs +++ b/src/accumulator/proof.rs @@ -142,6 +142,7 @@ impl Proof { pub fn targets(&self) -> usize { self.targets.len() } + /// This function computes a set of roots from a proof. /// If some target's hashes are null, then it computes the roots after /// those targets are deleted. In this context null means [sha256::Hash::default]. @@ -240,6 +241,7 @@ impl Proof { Ok((nodes, calculated_root_hashes)) } + fn sorted_push( nodes: &mut Vec<(u64, bitcoin_hashes::sha256::Hash)>, to_add: (u64, bitcoin_hashes::sha256::Hash), @@ -251,13 +253,22 @@ impl Proof { #[cfg(test)] mod tests { - use std::{str::FromStr, vec}; + use std::str::FromStr; use bitcoin_hashes::{sha256, Hash, HashEngine}; + use serde::Deserialize; use super::Proof; use crate::accumulator::stump::Stump; - + #[derive(Deserialize)] + struct TestCase { + numleaves: usize, + roots: Vec, + targets: Vec, + target_preimages: Vec, + proofhashes: Vec, + expected: bool, + } fn hash_from_u8(value: u8) -> bitcoin_hashes::sha256::Hash { let mut engine = bitcoin_hashes::sha256::Hash::engine(); @@ -347,48 +358,36 @@ mod tests { } } fn run_single_case(case: &serde_json::Value) { - let mut s = Stump::new(); - - let roots = case["roots"].as_array().expect("Missing roots"); - for root in roots { - s.roots - .push(bitcoin_hashes::sha256::Hash::from_str(root.as_str().unwrap()).unwrap()); - } - s.leafs = case["numleaves"].as_u64().expect("Missing leafs count"); - - let json_targets = case["targets"].as_array().expect("Missing targets"); - let json_proof_hashes = case["proofhashes"].as_array().expect("Missing proofhashes"); - let json_del_values = case["target_preimages"].as_array(); - - let mut targets = vec![]; - let mut del_hashes = vec![]; - let mut proof_hashes = vec![]; + let case = serde_json::from_value::(case.clone()).expect("Invalid test case"); + let roots = case + .roots + .into_iter() + .map(|root| sha256::Hash::from_str(root.as_str()).expect("Test case hash is valid")) + .collect(); - for i in json_targets { - targets.push(i.as_u64().unwrap()); - } + let s = Stump { + leafs: case.numleaves as u64, + roots, + }; - if let Some(values) = json_del_values { - for i in values.iter() { - let value = i.as_u64().unwrap(); - del_hashes.push(hash_from_u8(value as u8)); - } - } else { - for i in targets.iter() { - del_hashes.push(hash_from_u8(*i as u8)); - } - } + let targets = case.targets; + let del_hashes = case + .target_preimages + .into_iter() + .map(|target| hash_from_u8(target)) + .collect(); - for i in json_proof_hashes { - proof_hashes.push(bitcoin_hashes::sha256::Hash::from_str(i.as_str().unwrap()).unwrap()); - } + let proof_hashes = case + .proofhashes + .into_iter() + .map(|hash| sha256::Hash::from_str(hash.as_str()).expect("Test case hash is valid")) + .collect(); let p = Proof::new(targets, proof_hashes); - let expected = case["expected"].as_bool().unwrap(); + let expected = case.expected; - if let Ok(res) = p.verify(&del_hashes, &s) { - assert!(expected == res); - } + let res = p.verify(&del_hashes, &s); + assert!(Ok(expected) == res); } #[test] diff --git a/src/accumulator/stump.rs b/src/accumulator/stump.rs index e8b6b70..d5f8c68 100644 --- a/src/accumulator/stump.rs +++ b/src/accumulator/stump.rs @@ -152,14 +152,21 @@ impl Stump { #[cfg(test)] mod test { - use crate::{ - accumulator::proof::Proof, get_hash_array_from_obj, get_json_field, get_u64_array_from_obj, - }; + use crate::accumulator::proof::Proof; use super::Stump; use bitcoin_hashes::{hex::ToHex, sha256, Hash, HashEngine}; + use serde::Deserialize; use std::{str::FromStr, vec}; + #[derive(Debug, Deserialize)] + struct TestCase { + leaf_preimages: Vec, + target_values: Option>, + expected_roots: Vec, + proofhashes: Option>, + } + #[test] // Make a few simple tests about stump creation fn test_stump() { @@ -176,53 +183,53 @@ mod test { sha256::Hash::from_engine(engine) } - fn run_case_with_deletion(case: &serde_json::Value) { - let leafs = get_json_field!("leaf_preimages", case); - let target_values = get_json_field!("target_values", case); - let roots = get_json_field!("expected_roots", case); - let proof_hashes = get_json_field!("proofhashes", case); + fn run_case_with_deletion(case: TestCase) { + let leaf_hashes = case + .leaf_preimages + .into_iter() + .map(|leaf| hash_from_u8(leaf)) + .collect(); - let leafs = get_u64_array_from_obj!(leafs); - let target_values = get_u64_array_from_obj!(target_values); - let roots = get_hash_array_from_obj!(roots); - let proof_hashes = get_hash_array_from_obj!(proof_hashes); + let target_hashes = case + .target_values + .clone() + .unwrap() + .into_iter() + .map(|target| hash_from_u8(target as u8)) + .collect(); - let mut leaf_hashes = vec![]; - for i in leafs.iter() { - leaf_hashes.push(hash_from_u8(*i as u8)); - } + let proof_hashes = case + .proofhashes + .unwrap_or_default() + .into_iter() + .map(|hash| sha256::Hash::from_str(hash.as_str()).expect("Test case hashes are valid")) + .collect(); - let mut target_hashes = vec![]; - for i in target_values.iter() { - target_hashes.push(hash_from_u8(*i as u8)); - } + let proof = Proof::new(case.target_values.unwrap(), proof_hashes); - let proof = Proof::new(target_values, proof_hashes); + let roots = case + .expected_roots + .into_iter() + .map(|hash| sha256::Hash::from_str(hash.as_str()).expect("Test case hashes are valid")) + .collect::>(); let stump = Stump::new() .modify(&leaf_hashes, &vec![], &Proof::default()) .expect("This stump is valid"); - let stump = stump.modify(&vec![], &target_hashes, &proof).unwrap(); assert_eq!(stump.roots, roots); } - fn run_single_addition_case(case: &serde_json::Value) { + fn run_single_addition_case(case: TestCase) { let s = Stump::new(); - let test_values = case["leaf_preimages"] - .as_array() - .expect("Test data is missing"); - - let roots = case["expected_roots"] - .as_array() - .expect("Fail reading roots for this case"); + let test_values = case.leaf_preimages; + let roots = case.expected_roots; - let mut hashes = vec![]; - - for i in test_values { - hashes.push(hash_from_u8(i.as_u64().unwrap() as u8)); - } + let hashes = test_values + .iter() + .map(|value| hash_from_u8(*value)) + .collect(); let s = s .modify(&hashes, &vec![], &Proof::default()) @@ -231,7 +238,7 @@ mod test { assert_eq!(s.leafs, hashes.len() as u64); for i in 0..roots.len() { - assert_eq!(roots[i].as_str().unwrap(), s.roots[i].to_hex()); + assert_eq!(roots[i].as_str(), s.roots[i].to_hex()); } } @@ -268,18 +275,22 @@ mod test { #[test] fn run_test_cases() { + #[derive(Deserialize)] + struct TestsJSON { + insertion_tests: Vec, + deletion_tests: Vec, + } + let contents = std::fs::read_to_string("test_values/test_cases.json") .expect("Something went wrong reading the file"); - let values: serde_json::Value = - serde_json::from_str(contents.as_str()).expect("JSON deserialization error"); - let insertion_tests = values["insertion_tests"].as_array().unwrap(); - let deletion_tests = values["deletion_tests"].as_array().unwrap(); + let tests = serde_json::from_str::(contents.as_str()) + .expect("JSON deserialization error"); - for i in insertion_tests { + for i in tests.insertion_tests { run_single_addition_case(i); } - for i in deletion_tests { + for i in tests.deletion_tests { run_case_with_deletion(i); } }