681 lines
15 KiB
Rust
681 lines
15 KiB
Rust
use cached_tree_hash::{merkleize::merkleize, *};
|
|
use ethereum_types::H256 as Hash256;
|
|
use int_to_bytes::int_to_bytes32;
|
|
use tree_hash_derive::{CachedTreeHash, TreeHash};
|
|
|
|
#[test]
|
|
fn modifications() {
|
|
let n = 2048;
|
|
|
|
let vec: Vec<Hash256> = (0..n).map(|_| Hash256::random()).collect();
|
|
|
|
let mut cache = TreeHashCache::new(&vec, 0).unwrap();
|
|
cache.update(&vec).unwrap();
|
|
|
|
let modifications = cache.chunk_modified.iter().filter(|b| **b).count();
|
|
|
|
assert_eq!(modifications, 0);
|
|
|
|
let mut modified_vec = vec.clone();
|
|
modified_vec[n - 1] = Hash256::random();
|
|
|
|
cache.update(&modified_vec).unwrap();
|
|
|
|
let modifications = cache.chunk_modified.iter().filter(|b| **b).count();
|
|
|
|
assert_eq!(modifications, n.trailing_zeros() as usize + 2);
|
|
}
|
|
|
|
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
|
|
pub struct NestedStruct {
|
|
pub a: u64,
|
|
pub b: Inner,
|
|
}
|
|
|
|
fn test_routine<T>(original: T, modified: Vec<T>)
|
|
where
|
|
T: CachedTreeHash<T> + std::fmt::Debug,
|
|
{
|
|
let mut hasher = CachedTreeHasher::new(&original).unwrap();
|
|
|
|
let standard_root = original.tree_hash_root();
|
|
let cached_root = hasher.tree_hash_root().unwrap();
|
|
assert_eq!(standard_root, cached_root, "Initial cache build failed.");
|
|
|
|
for (i, modified) in modified.iter().enumerate() {
|
|
println!("-- Start of modification {} --", i);
|
|
|
|
// Update the existing hasher.
|
|
hasher
|
|
.update(modified)
|
|
.expect(&format!("Modification {}", i));
|
|
|
|
// Create a new hasher from the "modified" struct.
|
|
let modified_hasher = CachedTreeHasher::new(modified).unwrap();
|
|
|
|
assert_eq!(
|
|
hasher.cache.chunk_modified.len(),
|
|
modified_hasher.cache.chunk_modified.len(),
|
|
"Number of chunks is different"
|
|
);
|
|
|
|
assert_eq!(
|
|
hasher.cache.cache.len(),
|
|
modified_hasher.cache.cache.len(),
|
|
"Number of bytes is different"
|
|
);
|
|
|
|
assert_eq!(
|
|
hasher.cache.cache, modified_hasher.cache.cache,
|
|
"Bytes are different"
|
|
);
|
|
|
|
assert_eq!(
|
|
hasher.cache.schemas.len(),
|
|
modified_hasher.cache.schemas.len(),
|
|
"Number of schemas is different"
|
|
);
|
|
|
|
assert_eq!(
|
|
hasher.cache.schemas, modified_hasher.cache.schemas,
|
|
"Schemas are different"
|
|
);
|
|
|
|
// Test the root generated by the updated hasher matches a non-cached tree hash root.
|
|
let standard_root = modified.tree_hash_root();
|
|
let cached_root = hasher
|
|
.tree_hash_root()
|
|
.expect(&format!("Modification {}", i));
|
|
assert_eq!(
|
|
standard_root, cached_root,
|
|
"Modification {} failed. \n Cache: {:?}",
|
|
i, hasher
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested_struct() {
|
|
let original = NestedStruct {
|
|
a: 42,
|
|
b: Inner {
|
|
a: 12,
|
|
b: 13,
|
|
c: 14,
|
|
d: 15,
|
|
},
|
|
};
|
|
let modified = vec![NestedStruct {
|
|
a: 99,
|
|
..original.clone()
|
|
}];
|
|
|
|
test_routine(original, modified);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inner() {
|
|
let original = Inner {
|
|
a: 12,
|
|
b: 13,
|
|
c: 14,
|
|
d: 15,
|
|
};
|
|
|
|
let modified = vec![Inner {
|
|
a: 99,
|
|
..original.clone()
|
|
}];
|
|
|
|
test_routine(original, modified);
|
|
}
|
|
|
|
#[test]
|
|
fn test_vec_of_hash256() {
|
|
let n = 16;
|
|
|
|
let original: Vec<Hash256> = (0..n).map(|_| Hash256::random()).collect();
|
|
|
|
let modified: Vec<Vec<Hash256>> = vec![
|
|
original[..].to_vec(),
|
|
original[0..n / 2].to_vec(),
|
|
vec![],
|
|
original[0..1].to_vec(),
|
|
original[0..3].to_vec(),
|
|
original[0..n - 12].to_vec(),
|
|
];
|
|
|
|
test_routine(original, modified);
|
|
}
|
|
|
|
#[test]
|
|
fn test_vec_of_u64() {
|
|
let original: Vec<u64> = vec![1, 2, 3, 4, 5];
|
|
|
|
let modified: Vec<Vec<u64>> = vec![
|
|
vec![1, 2, 3, 4, 42],
|
|
vec![1, 2, 3, 4],
|
|
vec![],
|
|
vec![42; 2_usize.pow(4)],
|
|
vec![],
|
|
vec![],
|
|
vec![1, 2, 3, 4, 42],
|
|
vec![1, 2, 3],
|
|
vec![1],
|
|
];
|
|
|
|
test_routine(original, modified);
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested_list_of_u64() {
|
|
let original: Vec<Vec<u64>> = vec![vec![42]];
|
|
|
|
let modified = vec![
|
|
vec![vec![1]],
|
|
vec![vec![1], vec![2]],
|
|
vec![vec![1], vec![3], vec![4]],
|
|
vec![],
|
|
vec![vec![1], vec![3], vec![4]],
|
|
vec![],
|
|
vec![vec![1, 2], vec![3], vec![4, 5, 6, 7, 8]],
|
|
vec![],
|
|
vec![vec![1], vec![2], vec![3]],
|
|
vec![vec![1, 2, 3, 4, 5, 6], vec![1, 2, 3, 4, 5, 6, 7]],
|
|
vec![vec![], vec![], vec![]],
|
|
vec![vec![0, 0, 0], vec![0], vec![0]],
|
|
];
|
|
|
|
test_routine(original, modified);
|
|
}
|
|
|
|
#[test]
|
|
fn test_shrinking_vec_of_vec() {
|
|
let original: Vec<Vec<u64>> = vec![vec![1], vec![2], vec![3], vec![4], vec![5]];
|
|
let modified: Vec<Vec<u64>> = original[0..3].to_vec();
|
|
|
|
let new_hasher = CachedTreeHasher::new(&modified).unwrap();
|
|
|
|
let mut modified_hasher = CachedTreeHasher::new(&original).unwrap();
|
|
modified_hasher.update(&modified).unwrap();
|
|
|
|
assert_eq!(
|
|
new_hasher.cache.schemas.len(),
|
|
modified_hasher.cache.schemas.len(),
|
|
"Schema count is different"
|
|
);
|
|
|
|
assert_eq!(
|
|
new_hasher.cache.chunk_modified.len(),
|
|
modified_hasher.cache.chunk_modified.len(),
|
|
"Chunk count is different"
|
|
);
|
|
}
|
|
|
|
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
|
|
pub struct StructWithVec {
|
|
pub a: u64,
|
|
pub b: Inner,
|
|
pub c: Vec<u64>,
|
|
}
|
|
|
|
#[test]
|
|
fn test_struct_with_vec() {
|
|
let original = StructWithVec {
|
|
a: 42,
|
|
b: Inner {
|
|
a: 12,
|
|
b: 13,
|
|
c: 14,
|
|
d: 15,
|
|
},
|
|
c: vec![1, 2, 3, 4, 5],
|
|
};
|
|
|
|
let modified = vec![
|
|
StructWithVec {
|
|
a: 99,
|
|
..original.clone()
|
|
},
|
|
StructWithVec {
|
|
a: 100,
|
|
..original.clone()
|
|
},
|
|
StructWithVec {
|
|
c: vec![1, 2, 3, 4, 5],
|
|
..original.clone()
|
|
},
|
|
StructWithVec {
|
|
c: vec![1, 3, 4, 5, 6],
|
|
..original.clone()
|
|
},
|
|
StructWithVec {
|
|
c: vec![1, 3, 4, 5, 6, 7, 8, 9],
|
|
..original.clone()
|
|
},
|
|
StructWithVec {
|
|
c: vec![1, 3, 4, 5],
|
|
..original.clone()
|
|
},
|
|
StructWithVec {
|
|
b: Inner {
|
|
a: u64::max_value(),
|
|
b: u64::max_value(),
|
|
c: u64::max_value(),
|
|
d: u64::max_value(),
|
|
},
|
|
c: vec![],
|
|
..original.clone()
|
|
},
|
|
StructWithVec {
|
|
b: Inner {
|
|
a: 0,
|
|
b: 1,
|
|
c: 2,
|
|
d: 3,
|
|
},
|
|
..original.clone()
|
|
},
|
|
];
|
|
|
|
test_routine(original, modified);
|
|
}
|
|
|
|
#[test]
|
|
fn test_vec_of_struct_with_vec() {
|
|
let a = StructWithVec {
|
|
a: 42,
|
|
b: Inner {
|
|
a: 12,
|
|
b: 13,
|
|
c: 14,
|
|
d: 15,
|
|
},
|
|
c: vec![1, 2, 3, 4, 5],
|
|
};
|
|
let b = StructWithVec {
|
|
c: vec![],
|
|
..a.clone()
|
|
};
|
|
let c = StructWithVec {
|
|
b: Inner {
|
|
a: 99,
|
|
b: 100,
|
|
c: 101,
|
|
d: 102,
|
|
},
|
|
..a.clone()
|
|
};
|
|
let d = StructWithVec { a: 0, ..a.clone() };
|
|
|
|
let original: Vec<StructWithVec> = vec![a.clone(), c.clone()];
|
|
|
|
let modified = vec![
|
|
vec![a.clone(), c.clone()],
|
|
vec![],
|
|
vec![a.clone(), b.clone(), c.clone(), d.clone()],
|
|
vec![b.clone(), a.clone(), c.clone(), d.clone()],
|
|
vec![],
|
|
vec![a.clone()],
|
|
vec![],
|
|
vec![a.clone(), b.clone(), c.clone(), d.clone()],
|
|
];
|
|
|
|
test_routine(original, modified);
|
|
}
|
|
|
|
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
|
|
pub struct StructWithVecOfStructs {
|
|
pub a: u64,
|
|
pub b: Inner,
|
|
pub c: Vec<Inner>,
|
|
}
|
|
|
|
fn get_inners() -> Vec<Inner> {
|
|
vec![
|
|
Inner {
|
|
a: 12,
|
|
b: 13,
|
|
c: 14,
|
|
d: 15,
|
|
},
|
|
Inner {
|
|
a: 99,
|
|
b: 100,
|
|
c: 101,
|
|
d: 102,
|
|
},
|
|
Inner {
|
|
a: 255,
|
|
b: 256,
|
|
c: 257,
|
|
d: 0,
|
|
},
|
|
Inner {
|
|
a: 1000,
|
|
b: 2000,
|
|
c: 3000,
|
|
d: 0,
|
|
},
|
|
Inner {
|
|
a: 0,
|
|
b: 0,
|
|
c: 0,
|
|
d: 0,
|
|
},
|
|
]
|
|
}
|
|
|
|
fn get_struct_with_vec_of_structs() -> Vec<StructWithVecOfStructs> {
|
|
let inner_a = Inner {
|
|
a: 12,
|
|
b: 13,
|
|
c: 14,
|
|
d: 15,
|
|
};
|
|
|
|
let inner_b = Inner {
|
|
a: 99,
|
|
b: 100,
|
|
c: 101,
|
|
d: 102,
|
|
};
|
|
|
|
let inner_c = Inner {
|
|
a: 255,
|
|
b: 256,
|
|
c: 257,
|
|
d: 0,
|
|
};
|
|
|
|
let a = StructWithVecOfStructs {
|
|
a: 42,
|
|
b: inner_a.clone(),
|
|
c: vec![inner_a.clone(), inner_b.clone(), inner_c.clone()],
|
|
};
|
|
|
|
let b = StructWithVecOfStructs {
|
|
c: vec![],
|
|
..a.clone()
|
|
};
|
|
|
|
let c = StructWithVecOfStructs {
|
|
a: 800,
|
|
..a.clone()
|
|
};
|
|
|
|
let d = StructWithVecOfStructs {
|
|
b: inner_c.clone(),
|
|
..a.clone()
|
|
};
|
|
|
|
let e = StructWithVecOfStructs {
|
|
c: vec![inner_a.clone(), inner_b.clone()],
|
|
..a.clone()
|
|
};
|
|
|
|
let f = StructWithVecOfStructs {
|
|
c: vec![inner_a.clone()],
|
|
..a.clone()
|
|
};
|
|
|
|
vec![a, b, c, d, e, f]
|
|
}
|
|
|
|
#[test]
|
|
fn test_struct_with_vec_of_structs() {
|
|
let variants = get_struct_with_vec_of_structs();
|
|
|
|
test_routine(variants[0].clone(), variants.clone());
|
|
test_routine(variants[1].clone(), variants.clone());
|
|
test_routine(variants[2].clone(), variants.clone());
|
|
test_routine(variants[3].clone(), variants.clone());
|
|
test_routine(variants[4].clone(), variants.clone());
|
|
test_routine(variants[5].clone(), variants.clone());
|
|
}
|
|
|
|
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
|
|
pub struct StructWithVecOfStructWithVecOfStructs {
|
|
pub a: Vec<StructWithVecOfStructs>,
|
|
pub b: u64,
|
|
}
|
|
|
|
#[test]
|
|
fn test_struct_with_vec_of_struct_with_vec_of_structs() {
|
|
let structs = get_struct_with_vec_of_structs();
|
|
|
|
let variants = vec![
|
|
StructWithVecOfStructWithVecOfStructs {
|
|
a: structs[..].to_vec(),
|
|
b: 99,
|
|
},
|
|
StructWithVecOfStructWithVecOfStructs { a: vec![], b: 99 },
|
|
StructWithVecOfStructWithVecOfStructs {
|
|
a: structs[0..2].to_vec(),
|
|
b: 99,
|
|
},
|
|
StructWithVecOfStructWithVecOfStructs {
|
|
a: structs[0..2].to_vec(),
|
|
b: 100,
|
|
},
|
|
StructWithVecOfStructWithVecOfStructs {
|
|
a: structs[0..1].to_vec(),
|
|
b: 100,
|
|
},
|
|
StructWithVecOfStructWithVecOfStructs {
|
|
a: structs[0..4].to_vec(),
|
|
b: 100,
|
|
},
|
|
StructWithVecOfStructWithVecOfStructs {
|
|
a: structs[0..5].to_vec(),
|
|
b: 8,
|
|
},
|
|
];
|
|
|
|
for v in &variants {
|
|
test_routine(v.clone(), variants.clone());
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
|
|
pub struct StructWithTwoVecs {
|
|
pub a: Vec<Inner>,
|
|
pub b: Vec<Inner>,
|
|
}
|
|
|
|
fn get_struct_with_two_vecs() -> Vec<StructWithTwoVecs> {
|
|
let inners = get_inners();
|
|
|
|
vec![
|
|
StructWithTwoVecs {
|
|
a: inners[..].to_vec(),
|
|
b: inners[..].to_vec(),
|
|
},
|
|
StructWithTwoVecs {
|
|
a: inners[0..1].to_vec(),
|
|
b: inners[..].to_vec(),
|
|
},
|
|
StructWithTwoVecs {
|
|
a: inners[0..1].to_vec(),
|
|
b: inners[0..2].to_vec(),
|
|
},
|
|
StructWithTwoVecs {
|
|
a: inners[0..4].to_vec(),
|
|
b: inners[0..2].to_vec(),
|
|
},
|
|
StructWithTwoVecs {
|
|
a: vec![],
|
|
b: inners[..].to_vec(),
|
|
},
|
|
StructWithTwoVecs {
|
|
a: inners[..].to_vec(),
|
|
b: vec![],
|
|
},
|
|
StructWithTwoVecs {
|
|
a: inners[0..3].to_vec(),
|
|
b: inners[0..1].to_vec(),
|
|
},
|
|
]
|
|
}
|
|
|
|
#[test]
|
|
fn test_struct_with_two_vecs() {
|
|
let variants = get_struct_with_two_vecs();
|
|
|
|
for v in &variants {
|
|
test_routine(v.clone(), variants.clone());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_vec_of_struct_with_two_vecs() {
|
|
let structs = get_struct_with_two_vecs();
|
|
|
|
let variants = vec![
|
|
structs[0..].to_vec(),
|
|
structs[0..2].to_vec(),
|
|
structs[2..3].to_vec(),
|
|
vec![],
|
|
structs[2..4].to_vec(),
|
|
];
|
|
|
|
test_routine(variants[0].clone(), vec![variants[2].clone()]);
|
|
|
|
for v in &variants {
|
|
test_routine(v.clone(), variants.clone());
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
|
|
pub struct U64AndTwoStructs {
|
|
pub a: u64,
|
|
pub b: Inner,
|
|
pub c: Inner,
|
|
}
|
|
|
|
#[test]
|
|
fn test_u64_and_two_structs() {
|
|
let inners = get_inners();
|
|
|
|
let variants = vec![
|
|
U64AndTwoStructs {
|
|
a: 99,
|
|
b: inners[0].clone(),
|
|
c: inners[1].clone(),
|
|
},
|
|
U64AndTwoStructs {
|
|
a: 10,
|
|
b: inners[2].clone(),
|
|
c: inners[3].clone(),
|
|
},
|
|
U64AndTwoStructs {
|
|
a: 0,
|
|
b: inners[1].clone(),
|
|
c: inners[1].clone(),
|
|
},
|
|
U64AndTwoStructs {
|
|
a: 0,
|
|
b: inners[1].clone(),
|
|
c: inners[1].clone(),
|
|
},
|
|
];
|
|
|
|
for v in &variants {
|
|
test_routine(v.clone(), variants.clone());
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
|
|
pub struct Inner {
|
|
pub a: u64,
|
|
pub b: u64,
|
|
pub c: u64,
|
|
pub d: u64,
|
|
}
|
|
|
|
fn generic_test(index: usize) {
|
|
let inner = Inner {
|
|
a: 1,
|
|
b: 2,
|
|
c: 3,
|
|
d: 4,
|
|
};
|
|
|
|
let mut cache = TreeHashCache::new(&inner, 0).unwrap();
|
|
|
|
let changed_inner = match index {
|
|
0 => Inner {
|
|
a: 42,
|
|
..inner.clone()
|
|
},
|
|
1 => Inner {
|
|
b: 42,
|
|
..inner.clone()
|
|
},
|
|
2 => Inner {
|
|
c: 42,
|
|
..inner.clone()
|
|
},
|
|
3 => Inner {
|
|
d: 42,
|
|
..inner.clone()
|
|
},
|
|
_ => panic!("bad index"),
|
|
};
|
|
|
|
changed_inner.update_tree_hash_cache(&mut cache).unwrap();
|
|
|
|
let data1 = int_to_bytes32(1);
|
|
let data2 = int_to_bytes32(2);
|
|
let data3 = int_to_bytes32(3);
|
|
let data4 = int_to_bytes32(4);
|
|
|
|
let mut data = vec![data1, data2, data3, data4];
|
|
|
|
data[index] = int_to_bytes32(42);
|
|
|
|
let expected = merkleize(join(data));
|
|
|
|
let cache_bytes: Vec<u8> = cache.into();
|
|
|
|
assert_eq!(expected, cache_bytes);
|
|
}
|
|
|
|
#[test]
|
|
fn cached_hash_on_inner() {
|
|
generic_test(0);
|
|
generic_test(1);
|
|
generic_test(2);
|
|
generic_test(3);
|
|
}
|
|
|
|
#[test]
|
|
fn inner_builds() {
|
|
let data1 = int_to_bytes32(1);
|
|
let data2 = int_to_bytes32(2);
|
|
let data3 = int_to_bytes32(3);
|
|
let data4 = int_to_bytes32(4);
|
|
|
|
let data = join(vec![data1, data2, data3, data4]);
|
|
let expected = merkleize(data);
|
|
|
|
let inner = Inner {
|
|
a: 1,
|
|
b: 2,
|
|
c: 3,
|
|
d: 4,
|
|
};
|
|
|
|
let cache: Vec<u8> = TreeHashCache::new(&inner, 0).unwrap().into();
|
|
|
|
assert_eq!(expected, cache);
|
|
}
|
|
|
|
fn join(many: Vec<Vec<u8>>) -> Vec<u8> {
|
|
let mut all = vec![];
|
|
for one in many {
|
|
all.extend_from_slice(&mut one.clone())
|
|
}
|
|
all
|
|
}
|