#[cfg(not(feature = "std"))]
use hashbrown::{HashMap, HashSet};
use sha2::Sha256;
#[cfg(feature = "std")]
use std::collections::{HashMap, HashSet};
use alloc::vec;
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
use core::{fmt::Debug, ops::Bound};
use proptest::{
collection::{btree_map, vec},
prelude::*,
sample,
};
use crate::proof::definition::UpdateMerkleProof;
use crate::SimpleHasher;
use crate::{
mock::MockTreeStore,
node_type::LeafNode,
storage::Node,
types::{
proof::{SparseMerkleInternalNode, SparseMerkleRangeProof},
Version, PRE_GENESIS_VERSION,
},
Bytes32Ext, JellyfishMerkleIterator, JellyfishMerkleTree, KeyHash, OwnedValue, RootHash,
ValueHash, SPARSE_MERKLE_PLACEHOLDER_HASH,
};
pub fn plus_one(key: KeyHash) -> KeyHash {
assert_ne!(key, KeyHash([0xff; 32]));
let mut buf = key.0;
for i in (0..32).rev() {
if buf[i] == 255 {
buf[i] = 0;
} else {
buf[i] += 1;
break;
}
}
KeyHash(buf)
}
pub fn init_mock_db<H: SimpleHasher>(
kvs: &HashMap<KeyHash, OwnedValue>,
) -> (MockTreeStore, Version) {
assert!(!kvs.is_empty());
let db = MockTreeStore::default();
let tree = JellyfishMerkleTree::<_, H>::new(&db);
for (i, (key, value)) in kvs.clone().into_iter().enumerate() {
let (_root_hash, write_batch) = tree
.put_value_set(vec![(key, Some(value))], i as Version)
.unwrap();
db.write_tree_update_batch(write_batch).unwrap();
}
(db, (kvs.len() - 1) as Version)
}
pub fn init_mock_db_with_deletions_afterwards<H: SimpleHasher>(
kvs: &HashMap<KeyHash, OwnedValue>,
deletions: Vec<KeyHash>,
) -> (MockTreeStore, Version) {
assert!(!kvs.is_empty());
let db = MockTreeStore::default();
let tree = JellyfishMerkleTree::<_, H>::new(&db);
for (i, (key, value)) in kvs.clone().into_iter().enumerate() {
let (_root_hash, write_batch) = tree
.put_value_set(vec![(key, Some(value))], i as Version)
.unwrap();
db.write_tree_update_batch(write_batch).unwrap();
}
let after_insertions_version = kvs.len();
for (i, key) in deletions.iter().enumerate() {
let (_root_hash, write_batch) = tree
.put_value_set(
vec![(*key, None)],
(after_insertions_version + i) as Version,
)
.unwrap();
db.write_tree_update_batch(write_batch).unwrap();
}
(db, (kvs.len() + deletions.len() - 1) as Version)
}
fn init_mock_db_versioned<H: SimpleHasher>(
operations_by_version: Vec<Vec<(KeyHash, Vec<u8>)>>,
with_proof: bool,
) -> (
MockTreeStore,
Version,
Option<
Vec<(
RootHash,
UpdateMerkleProof<H>,
Vec<(KeyHash, Option<Vec<u8>>)>,
)>,
>,
) {
assert!(!operations_by_version.is_empty());
let db = MockTreeStore::default();
let tree = JellyfishMerkleTree::<_, H>::new(&db);
let mut roots_proofs: Option<
Vec<(
RootHash,
UpdateMerkleProof<H>,
Vec<(KeyHash, Option<Vec<u8>>)>,
)>,
> = if with_proof { Some(Vec::new()) } else { None };
if operations_by_version
.iter()
.any(|operations| !operations.is_empty())
{
let mut next_version = 0;
for operations in operations_by_version.into_iter() {
let operations = operations
.into_iter()
.map(|(key, value)| (key, Some(value)));
let (root_hash, proof_opt, write_batch) = if with_proof {
let (root, proof, batch) = tree
.put_value_set_with_proof(
operations.clone(),
next_version as Version,
)
.unwrap();
(root, Some(proof), batch)
} else {
let (root, batch) = tree
.put_value_set(
operations.clone(),
next_version as Version,
)
.unwrap();
(root, None, batch)
};
db.write_tree_update_batch(write_batch).unwrap();
roots_proofs
.as_mut()
.map(|proofs| proofs.push((root_hash, proof_opt.unwrap(), operations.collect())));
next_version += 1;
}
(db, next_version - 1 as Version, roots_proofs)
} else {
(db, PRE_GENESIS_VERSION, roots_proofs)
}
}
fn init_mock_db_versioned_with_deletions<H: SimpleHasher>(
operations_by_version: Vec<Vec<(KeyHash, Option<Vec<u8>>)>>,
with_proof: bool,
) -> (
MockTreeStore,
Version,
Option<
Vec<(
RootHash,
UpdateMerkleProof<H>,
Vec<(KeyHash, Option<Vec<u8>>)>,
)>,
>,
) {
assert!(!operations_by_version.is_empty());
let db = MockTreeStore::default();
let tree = JellyfishMerkleTree::<_, H>::new(&db);
let mut roots_proofs = if with_proof { Some(Vec::new()) } else { None };
if operations_by_version
.iter()
.any(|operations| !operations.is_empty())
{
let mut next_version = 0;
for operations in operations_by_version.into_iter() {
let (root_hash, proof_opt, write_batch) = if with_proof {
let (root_hash, proof, write_batch) = tree
.put_value_set_with_proof(operations.clone(), next_version as Version)
.unwrap();
(root_hash, Some(proof), write_batch)
} else {
let (root_hash, write_batch) = tree
.put_value_set(operations.clone(), next_version as Version)
.unwrap();
(root_hash, None, write_batch)
};
db.write_tree_update_batch(write_batch).unwrap();
roots_proofs
.as_mut()
.map(|proofs| proofs.push((root_hash, proof_opt.unwrap(), operations)));
next_version += 1;
}
(db, next_version - 1 as Version, roots_proofs)
} else {
(db, PRE_GENESIS_VERSION, roots_proofs)
}
}
pub fn arb_existent_kvs_and_nonexistent_keys(
num_kvs: usize,
num_non_existing_keys: usize,
) -> impl Strategy<Value = (HashMap<KeyHash, OwnedValue>, Vec<KeyHash>)> {
btree_map(any::<KeyHash>(), any::<OwnedValue>(), 1..num_kvs)
.prop_flat_map(move |kvs| {
let kvs_clone = kvs.clone();
(
Just(kvs),
vec(
any::<KeyHash>().prop_filter(
"Make sure these keys do not exist in the tree.",
move |key| !kvs_clone.contains_key(key),
),
num_non_existing_keys,
),
)
})
.prop_map(|(map, v)| (map.into_iter().collect(), v))
}
pub fn arb_existent_kvs_and_deletions_and_nonexistent_keys(
num_kvs: usize,
num_non_existing_keys: usize,
) -> impl Strategy<Value = (HashMap<KeyHash, OwnedValue>, Vec<KeyHash>, Vec<KeyHash>)> {
btree_map(any::<KeyHash>(), any::<OwnedValue>(), 1..num_kvs)
.prop_flat_map(move |kvs| {
let kvs_clone = kvs.clone();
let keys: Vec<_> = kvs.keys().cloned().collect();
let keys_count = keys.len();
(
Just(kvs),
sample::subsequence(keys, 0..keys_count),
vec(
any::<KeyHash>().prop_filter(
"Make sure these keys do not exist in the tree.",
move |key| !kvs_clone.contains_key(key),
),
num_non_existing_keys,
),
)
})
.prop_map(|(map, v1, v2)| (map.into_iter().collect(), v1, v2))
}
pub fn arb_interleaved_insertions_and_deletions<H: SimpleHasher>(
num_keys: usize,
num_values: usize,
num_insertions: usize,
num_deletions: usize,
) -> impl Strategy<Value = Vec<(KeyHash, Option<OwnedValue>)>> {
(
Just(
(0..num_keys)
.map(|n| KeyHash::with::<H>(n.to_le_bytes()))
.collect::<Vec<_>>(),
)
.prop_shuffle(),
(1..=num_values).prop_map(|end| {
(0..end)
.map(|i| {
let mut value = i.to_le_bytes().to_vec();
while let Some(byte) = value.last() {
if *byte != 0 {
break;
}
value.pop();
}
value
})
.collect::<Vec<_>>()
}),
)
.prop_flat_map(move |(keys, values)| {
vec(
(sample::select(keys), sample::select(values).prop_map(Some)),
1..num_insertions,
)
.prop_flat_map(move |insertions| {
let deletions = sample::subsequence(
insertions
.iter()
.map(|(key, _)| (*key, None))
.collect::<Vec<_>>(),
0..num_deletions.min(insertions.len()),
);
(Just(insertions), deletions)
})
.prop_flat_map(move |(insertions, deletions)| {
let mut insertions_and_deletions = insertions;
insertions_and_deletions.extend(deletions);
Just(insertions_and_deletions).prop_shuffle()
})
})
}
pub fn arb_partitions<T>(
num_partitions: usize,
values: Vec<T>,
) -> impl Strategy<Value = Vec<Vec<T>>>
where
T: Debug + Clone,
{
assert_ne!(
num_partitions, 0,
"cannot partition a vector into 0 partitions"
);
let indices = sample::subsequence(
(0..=values.len()).collect::<Vec<_>>(),
num_partitions.min(values.len()) - 1,
);
indices.prop_map(move |indices| {
let mut partitions = Vec::with_capacity(num_partitions);
let mut start = 0;
for end in indices {
if end - start > 0 {
partitions.push(values[start..end].to_vec());
} else {
partitions.push(vec![]);
}
start = end;
}
let remainder = values[start..].to_vec();
partitions.push(remainder);
partitions
})
}
pub fn test_get_with_proof<H: SimpleHasher>(
(existent_kvs, nonexistent_keys): (HashMap<KeyHash, OwnedValue>, Vec<KeyHash>),
) {
let (db, version) = init_mock_db::<H>(&existent_kvs);
let tree = JellyfishMerkleTree::<_, H>::new(&db);
test_existent_keys_impl(&tree, version, &existent_kvs);
test_nonexistent_keys_impl(&tree, version, &nonexistent_keys);
}
pub fn test_get_with_proof_with_deletions<H: SimpleHasher>(
(mut existent_kvs, deletions, mut nonexistent_keys): (
HashMap<KeyHash, OwnedValue>,
Vec<KeyHash>,
Vec<KeyHash>,
),
) {
let (db, version) =
init_mock_db_with_deletions_afterwards::<H>(&existent_kvs, deletions.clone());
let tree = JellyfishMerkleTree::<_, H>::new(&db);
for key in deletions {
existent_kvs.remove(&key);
nonexistent_keys.push(key);
}
test_existent_keys_impl(&tree, version, &existent_kvs);
test_nonexistent_keys_impl(&tree, version, &nonexistent_keys);
}
pub fn test_clairvoyant_construction_matches_interleaved_construction<H: SimpleHasher>(
operations_by_version: Vec<Vec<(KeyHash, Option<OwnedValue>)>>,
) {
let mut expected_final = HashMap::new();
for (version, operations) in operations_by_version.iter().enumerate() {
for (key, value) in operations {
if let Some(value) = value {
expected_final.insert(*key, (version, value.clone()));
} else {
expected_final.remove(key);
}
}
}
let mut clairvoyant_operations_by_version = Vec::new();
for (version, operations) in operations_by_version.iter().enumerate() {
let mut clairvoyant_operations = Vec::new();
for (key, value) in operations {
if let Some((expected_version, _)) = expected_final.get(key) {
if let Some(value) = value {
if version == *expected_version {
clairvoyant_operations.push((*key, value.clone()));
}
}
}
}
clairvoyant_operations_by_version.push(clairvoyant_operations);
}
let (db_without_deletions, version_without_deletions, _) =
init_mock_db_versioned::<H>(clairvoyant_operations_by_version, false);
let tree_without_deletions = JellyfishMerkleTree::<_, H>::new(&db_without_deletions);
let root_hash_without_deletions =
tree_without_deletions.get_root_hash(version_without_deletions);
let (db_with_deletions, version_with_deletions, _) =
init_mock_db_versioned_with_deletions::<H>(operations_by_version, false);
let tree_with_deletions = JellyfishMerkleTree::<_, H>::new(&db_with_deletions);
let root_hash_with_deletions = tree_with_deletions.get_root_hash(version_with_deletions);
match (
version_without_deletions == PRE_GENESIS_VERSION,
version_with_deletions == PRE_GENESIS_VERSION,
) {
(false, false) => {
assert_eq!(
root_hash_without_deletions.unwrap(),
root_hash_with_deletions.unwrap(),
"root hashes mismatch"
);
}
(true, true) => {
assert!(root_hash_without_deletions.is_err());
assert!(root_hash_with_deletions.is_err());
}
(true, false) => {
assert!(root_hash_without_deletions.is_err());
assert_eq!(
root_hash_with_deletions.unwrap(),
RootHash(Node::Null.hash::<H>())
);
}
(false, true) => {
assert!(root_hash_with_deletions.is_err());
assert_eq!(
root_hash_without_deletions.unwrap(),
RootHash(Node::Null.hash::<H>())
);
}
}
let iter_without_deletions = if version_without_deletions != PRE_GENESIS_VERSION {
JellyfishMerkleIterator::new(
Arc::new(db_without_deletions),
version_without_deletions,
KeyHash([0u8; 32]),
)
.unwrap()
.collect::<Result<Vec<_>, _>>()
.unwrap()
} else {
vec![]
};
let iter_with_deletions = if version_with_deletions != PRE_GENESIS_VERSION {
JellyfishMerkleIterator::new(
Arc::new(db_with_deletions),
version_with_deletions,
KeyHash([0u8; 32]),
)
.unwrap()
.collect::<Result<Vec<_>, _>>()
.unwrap()
} else {
vec![]
};
let mut iter_expected = expected_final
.into_iter()
.map(|(k, (_, v))| (k, v))
.collect::<Vec<_>>();
iter_expected.sort();
assert_eq!(
iter_expected, iter_without_deletions,
"clairvoyant construction mismatches expectation"
);
assert_eq!(
iter_expected, iter_with_deletions,
"construction interleaved with deletions mismatches expectation"
);
}
pub fn test_clairvoyant_construction_matches_interleaved_construction_proved(
operations_by_version: Vec<Vec<(KeyHash, Option<OwnedValue>)>>,
) {
let mut expected_final = HashMap::new();
for (version, operations) in operations_by_version.iter().enumerate() {
for (key, value) in operations {
if let Some(value) = value {
expected_final.insert(*key, (version, value.clone()));
} else {
expected_final.remove(key);
}
}
}
let mut clairvoyant_operations_by_version = Vec::new();
for (version, operations) in operations_by_version.iter().enumerate() {
let mut clairvoyant_operations = Vec::new();
for (key, value) in operations {
if let Some((expected_version, _)) = expected_final.get(key) {
if let Some(value) = value {
if version == *expected_version {
clairvoyant_operations.push((*key, value.clone()));
}
}
}
}
clairvoyant_operations_by_version.push(clairvoyant_operations);
}
let (_db_without_deletions, version_without_deletions, roots_proofs_without_deletions) =
init_mock_db_versioned::<Sha256>(clairvoyant_operations_by_version, true);
let (_db_with_deletions, version_with_deletions, roots_proofs_with_deletions) =
init_mock_db_versioned_with_deletions::<Sha256>(operations_by_version, true);
if version_without_deletions != PRE_GENESIS_VERSION {
let mut old_root = RootHash(Node::new_null().hash::<Sha256>());
for (new_root, proof, ops) in roots_proofs_without_deletions.unwrap() {
assert!(proof.verify_update(old_root, new_root, ops).is_ok());
old_root = new_root;
}
}
if version_with_deletions != PRE_GENESIS_VERSION {
let mut old_root = RootHash(Node::new_null().hash::<Sha256>());
for (new_root, proof, ops) in roots_proofs_with_deletions.unwrap() {
assert!(proof.verify_update(old_root, new_root, ops).is_ok());
old_root = new_root;
}
}
}
pub fn arb_kv_pair_with_distinct_last_nibble(
) -> impl Strategy<Value = ((KeyHash, OwnedValue), (KeyHash, OwnedValue))> {
(
any::<KeyHash>().prop_filter("Can't be 0xffffff...", |key| *key != KeyHash([0xff; 32])),
vec(any::<OwnedValue>(), 2),
)
.prop_map(|(key1, accounts)| {
let key2 = plus_one(key1);
((key1, accounts[0].clone()), (key2, accounts[1].clone()))
})
}
pub fn test_get_with_proof_with_distinct_last_nibble<H: SimpleHasher>(
(kv1, kv2): ((KeyHash, OwnedValue), (KeyHash, OwnedValue)),
) {
let mut kvs = HashMap::new();
kvs.insert(kv1.0, kv1.1);
kvs.insert(kv2.0, kv2.1);
let (db, version) = init_mock_db::<H>(&kvs);
let tree = JellyfishMerkleTree::<_, H>::new(&db);
test_existent_keys_impl(&tree, version, &kvs);
}
pub fn arb_tree_with_index(
tree_size: usize,
) -> impl Strategy<Value = (BTreeMap<KeyHash, OwnedValue>, usize)> {
btree_map(any::<KeyHash>(), any::<OwnedValue>(), 1..tree_size).prop_flat_map(|btree| {
let len = btree.len();
(Just(btree), 0..len)
})
}
pub fn test_get_range_proof<H: SimpleHasher>((btree, n): (BTreeMap<KeyHash, OwnedValue>, usize)) {
let (db, version) = init_mock_db::<H>(&btree.clone().into_iter().collect());
let tree = JellyfishMerkleTree::<_, H>::new(&db);
let nth_key = btree.keys().nth(n).unwrap();
let proof = tree.get_range_proof(*nth_key, version).unwrap();
verify_range_proof(
tree.get_root_hash(version).unwrap(),
btree.into_iter().take(n + 1).collect(),
proof,
);
}
fn test_existent_keys_impl<'a, H: SimpleHasher>(
tree: &JellyfishMerkleTree<'a, MockTreeStore, H>,
version: Version,
existent_kvs: &HashMap<KeyHash, OwnedValue>,
) {
let root_hash = tree.get_root_hash(version).unwrap();
for (key, value) in existent_kvs {
let (account, proof) = tree.get_with_proof(*key, version).unwrap();
assert!(proof.verify(root_hash, *key, account.as_ref()).is_ok());
assert_eq!(account.unwrap(), *value);
}
}
fn test_nonexistent_keys_impl<'a, H: SimpleHasher>(
tree: &JellyfishMerkleTree<'a, MockTreeStore, H>,
version: Version,
nonexistent_keys: &[KeyHash],
) {
let root_hash = tree.get_root_hash(version).unwrap();
for key in nonexistent_keys {
let (account, proof) = tree.get_with_proof(*key, version).unwrap();
assert!(proof.verify(root_hash, *key, account.as_ref()).is_ok());
assert_eq!(account, None);
}
}
fn verify_range_proof<H: SimpleHasher>(
expected_root_hash: RootHash,
btree: BTreeMap<KeyHash, OwnedValue>,
proof: SparseMerkleRangeProof<H>,
) {
let mut btree1 = BTreeMap::new();
for (key, value) in &btree {
let leaf = LeafNode::new(*key, ValueHash::with::<H>(value.as_slice()));
btree1.insert(*key, leaf.hash::<H>());
}
let last_proven_key = *btree
.keys()
.last()
.expect("We are proving at least one key.");
for (i, sibling) in last_proven_key
.0
.iter_bits()
.enumerate()
.filter_map(|(i, bit)| if !bit { Some(i) } else { None })
.zip(proof.right_siblings().iter().rev())
{
let mut buf: Vec<_> = last_proven_key.0.iter_bits().take(i).collect();
buf.push(true);
buf.resize(256, false);
let key = KeyHash(<[u8; 32]>::from_bit_iter(buf.into_iter()).unwrap());
btree1.insert(key, sibling.hash::<H>());
}
let mut kvs = vec![];
for (key, value) in &btree1 {
let prev_common_prefix_len =
prev_key(&btree1, key).map(|pkey| pkey.0.common_prefix_bits_len(&key.0));
let next_common_prefix_len =
next_key(&btree1, key).map(|nkey| nkey.0.common_prefix_bits_len(&key.0));
let len = match (prev_common_prefix_len, next_common_prefix_len) {
(Some(plen), Some(nlen)) => core::cmp::max(plen, nlen),
(Some(plen), None) => plen,
(None, Some(nlen)) => nlen,
(None, None) => 0,
};
let transformed_key: Vec<_> = key.0.iter_bits().take(len + 1).collect();
kvs.push((transformed_key, *value));
}
assert_eq!(compute_root_hash::<H>(kvs), expected_root_hash);
}
fn reduce<'a>(kvs: &'a [(&[bool], [u8; 32])]) -> Vec<(&'a [bool], [u8; 32])> {
kvs.iter().map(|(key, value)| (&key[1..], *value)).collect()
}
fn prev_key<K, V>(btree: &BTreeMap<K, V>, key: &K) -> Option<K>
where
K: Clone + Ord,
{
btree
.range((Bound::Unbounded, Bound::Excluded(key)))
.next_back()
.map(|(k, _v)| k.clone())
}
fn next_key<K, V>(btree: &BTreeMap<K, V>, key: &K) -> Option<K>
where
K: Clone + Ord,
{
btree
.range((Bound::Excluded(key), Bound::Unbounded))
.next()
.map(|(k, _v)| k.clone())
}
fn compute_root_hash<H: SimpleHasher>(kvs: Vec<(Vec<bool>, [u8; 32])>) -> RootHash {
let mut kv_ref = vec![];
for (key, value) in &kvs {
kv_ref.push((&key[..], *value));
}
RootHash(compute_root_hash_impl::<H>(kv_ref))
}
fn compute_root_hash_impl<H: SimpleHasher>(kvs: Vec<(&[bool], [u8; 32])>) -> [u8; 32] {
assert!(!kvs.is_empty());
if kvs.len() == 1 {
return kvs[0].1;
}
let left_hash;
let right_hash;
match kvs.iter().position(|(key, _value)| key[0]) {
Some(0) => {
left_hash = SPARSE_MERKLE_PLACEHOLDER_HASH;
right_hash = compute_root_hash_impl::<H>(reduce(&kvs));
}
Some(index) => {
left_hash = compute_root_hash_impl::<H>(reduce(&kvs[..index]));
right_hash = compute_root_hash_impl::<H>(reduce(&kvs[index..]));
}
None => {
left_hash = compute_root_hash_impl::<H>(reduce(&kvs));
right_hash = SPARSE_MERKLE_PLACEHOLDER_HASH;
}
}
SparseMerkleInternalNode::new(left_hash, right_hash).hash::<H>()
}
pub fn test_get_leaf_count<H: SimpleHasher>(keys: HashSet<KeyHash>) {
let kvs = keys.into_iter().map(|k| (k, vec![])).collect();
let (db, version) = init_mock_db::<H>(&kvs);
let tree = JellyfishMerkleTree::<_, H>::new(&db);
assert_eq!(tree.get_leaf_count(version).unwrap(), kvs.len())
}