@ -0,0 +1,356 @@ |
|||
use super::{
|
|||
get_index_tier, get_key_prefix, is_leaf_node, BTreeMap, BTreeSet, EmptySubtreeRoots,
|
|||
InnerNodeInfo, MerkleError, MerklePath, NodeIndex, Rpo256, RpoDigest, Vec,
|
|||
};
|
|||
|
|||
// CONSTANTS
|
|||
// ================================================================================================
|
|||
|
|||
/// The number of levels between tiers.
|
|||
const TIER_SIZE: u8 = super::TieredSmt::TIER_SIZE;
|
|||
|
|||
/// Depths at which leaves can exist in a tiered SMT.
|
|||
const TIER_DEPTHS: [u8; 4] = super::TieredSmt::TIER_DEPTHS;
|
|||
|
|||
/// Maximum node depth. This is also the bottom tier of the tree.
|
|||
const MAX_DEPTH: u8 = super::TieredSmt::MAX_DEPTH;
|
|||
|
|||
// NODE STORE
|
|||
// ================================================================================================
|
|||
|
|||
/// A store of nodes for a Tiered Sparse Merkle tree.
|
|||
///
|
|||
/// The store contains information about all nodes as well as information about which of the nodes
|
|||
/// represent leaf nodes in a Tiered Sparse Merkle tree.
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|||
pub struct NodeStore {
|
|||
nodes: BTreeMap<NodeIndex, RpoDigest>,
|
|||
upper_leaves: BTreeSet<NodeIndex>,
|
|||
bottom_leaves: BTreeSet<u64>,
|
|||
}
|
|||
|
|||
impl NodeStore {
|
|||
// CONSTRUCTOR
|
|||
// --------------------------------------------------------------------------------------------
|
|||
/// Returns a new instance of [NodeStore] instantiated with the specified root node.
|
|||
///
|
|||
/// Root node is assumed to be a root of an empty sparse Merkle tree.
|
|||
pub fn new(root_node: RpoDigest) -> Self {
|
|||
let mut nodes = BTreeMap::default();
|
|||
nodes.insert(NodeIndex::root(), root_node);
|
|||
|
|||
Self {
|
|||
nodes,
|
|||
upper_leaves: BTreeSet::default(),
|
|||
bottom_leaves: BTreeSet::default(),
|
|||
}
|
|||
}
|
|||
|
|||
// PUBLIC ACCESSORS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Returns a node at the specified index.
|
|||
///
|
|||
/// # Errors
|
|||
/// Returns an error if:
|
|||
/// - The specified index depth is 0 or greater than 64.
|
|||
/// - The node with the specified index does not exists in the Merkle tree. This is possible
|
|||
/// when a leaf node with the same index prefix exists at a tier higher than the requested
|
|||
/// node.
|
|||
pub fn get_node(&self, index: NodeIndex) -> Result<RpoDigest, MerkleError> {
|
|||
self.validate_node_access(index)?;
|
|||
Ok(self.get_node_unchecked(&index))
|
|||
}
|
|||
|
|||
/// Returns a Merkle path from the node at the specified index to the root.
|
|||
///
|
|||
/// The node itself is not included in the path.
|
|||
///
|
|||
/// # Errors
|
|||
/// Returns an error if:
|
|||
/// - The specified index depth is 0 or greater than 64.
|
|||
/// - The node with the specified index does not exists in the Merkle tree. This is possible
|
|||
/// when a leaf node with the same index prefix exists at a tier higher than the node to
|
|||
/// which the path is requested.
|
|||
pub fn get_path(&self, mut index: NodeIndex) -> Result<MerklePath, MerkleError> {
|
|||
self.validate_node_access(index)?;
|
|||
|
|||
let mut path = Vec::with_capacity(index.depth() as usize);
|
|||
for _ in 0..index.depth() {
|
|||
let node = self.get_node_unchecked(&index.sibling());
|
|||
path.push(node);
|
|||
index.move_up();
|
|||
}
|
|||
|
|||
Ok(path.into())
|
|||
}
|
|||
|
|||
/// Returns an index at which a leaf node for the specified key should be inserted.
|
|||
///
|
|||
/// The second value in the returned tuple is set to true if the node at the returned index
|
|||
/// is already a leaf node, excluding leaves at the bottom tier (i.e., if the leaf is at the
|
|||
/// bottom tier, false is returned).
|
|||
pub fn get_insert_location(&self, key: &RpoDigest) -> (NodeIndex, bool) {
|
|||
// traverse the tree from the root down checking nodes at tiers 16, 32, and 48. Return if
|
|||
// a node at any of the tiers is either a leaf or a root of an empty subtree.
|
|||
let mse = get_key_prefix(key);
|
|||
for depth in (TIER_DEPTHS[0]..MAX_DEPTH).step_by(TIER_SIZE as usize) {
|
|||
let index = NodeIndex::new_unchecked(depth, mse >> (MAX_DEPTH - depth));
|
|||
if self.upper_leaves.contains(&index) {
|
|||
return (index, true);
|
|||
} else if !self.nodes.contains_key(&index) {
|
|||
return (index, false);
|
|||
}
|
|||
}
|
|||
|
|||
// if we got here, that means all of the nodes checked so far are internal nodes, and
|
|||
// the new node would need to be inserted in the bottom tier.
|
|||
let index = NodeIndex::new_unchecked(MAX_DEPTH, mse);
|
|||
(index, false)
|
|||
}
|
|||
|
|||
// ITERATORS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Returns an iterator over all inner nodes of the Tiered Sparse Merkle tree (i.e., nodes not
|
|||
/// at depths 16 32, 48, or 64).
|
|||
///
|
|||
/// The iterator order is unspecified.
|
|||
pub fn inner_nodes(&self) -> impl Iterator<Item = InnerNodeInfo> + '_ {
|
|||
self.nodes.iter().filter_map(|(index, node)| {
|
|||
if !is_leaf_node(index) {
|
|||
Some(InnerNodeInfo {
|
|||
value: *node,
|
|||
left: self.get_node_unchecked(&index.left_child()),
|
|||
right: self.get_node_unchecked(&index.right_child()),
|
|||
})
|
|||
} else {
|
|||
None
|
|||
}
|
|||
})
|
|||
}
|
|||
|
|||
/// Returns an iterator over the upper leaves (i.e., leaves with depths 16, 32, 48) of the
|
|||
/// Tiered Sparse Merkle tree.
|
|||
pub fn upper_leaves(&self) -> impl Iterator<Item = (&NodeIndex, &RpoDigest)> {
|
|||
self.upper_leaves.iter().map(|index| (index, &self.nodes[index]))
|
|||
}
|
|||
|
|||
/// Returns an iterator over the bottom leaves (i.e., leaves with depth 64) of the Tiered
|
|||
/// Sparse Merkle tree.
|
|||
pub fn bottom_leaves(&self) -> impl Iterator<Item = (&u64, &RpoDigest)> {
|
|||
self.bottom_leaves.iter().map(|value| {
|
|||
let index = NodeIndex::new_unchecked(MAX_DEPTH, *value);
|
|||
(value, &self.nodes[&index])
|
|||
})
|
|||
}
|
|||
|
|||
// STATE MUTATORS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Replaces the leaf node at the specified index with a tree consisting of two leaves located
|
|||
/// at the specified indexes. Recomputes and returns the new root.
|
|||
pub fn replace_leaf_with_subtree(
|
|||
&mut self,
|
|||
leaf_index: NodeIndex,
|
|||
subtree_leaves: [(NodeIndex, RpoDigest); 2],
|
|||
) -> RpoDigest {
|
|||
debug_assert!(is_leaf_node(&leaf_index));
|
|||
debug_assert!(is_leaf_node(&subtree_leaves[0].0));
|
|||
debug_assert!(is_leaf_node(&subtree_leaves[1].0));
|
|||
debug_assert!(!is_empty_root(&subtree_leaves[0].1));
|
|||
debug_assert!(!is_empty_root(&subtree_leaves[1].1));
|
|||
debug_assert_eq!(subtree_leaves[0].0.depth(), subtree_leaves[1].0.depth());
|
|||
debug_assert!(leaf_index.depth() < subtree_leaves[0].0.depth());
|
|||
|
|||
self.upper_leaves.remove(&leaf_index);
|
|||
self.insert_leaf_node(subtree_leaves[0].0, subtree_leaves[0].1);
|
|||
self.insert_leaf_node(subtree_leaves[1].0, subtree_leaves[1].1)
|
|||
}
|
|||
|
|||
/// Replaces a subtree containing the retained and the removed leaf nodes, with a leaf node
|
|||
/// containing the retained leaf.
|
|||
///
|
|||
/// This has the effect of deleting the the node at the `removed_leaf` index from the tree,
|
|||
/// moving the node at the `retained_leaf` index up to the tier specified by `new_depth`.
|
|||
pub fn replace_subtree_with_leaf(
|
|||
&mut self,
|
|||
removed_leaf: NodeIndex,
|
|||
retained_leaf: NodeIndex,
|
|||
new_depth: u8,
|
|||
node: RpoDigest,
|
|||
) -> RpoDigest {
|
|||
debug_assert!(!is_empty_root(&node));
|
|||
debug_assert!(self.is_leaf(&removed_leaf));
|
|||
debug_assert!(self.is_leaf(&retained_leaf));
|
|||
debug_assert_eq!(removed_leaf.depth(), retained_leaf.depth());
|
|||
debug_assert!(removed_leaf.depth() > new_depth);
|
|||
|
|||
// clear leaf flags
|
|||
if removed_leaf.depth() == MAX_DEPTH {
|
|||
self.bottom_leaves.remove(&removed_leaf.value());
|
|||
self.bottom_leaves.remove(&retained_leaf.value());
|
|||
} else {
|
|||
self.upper_leaves.remove(&removed_leaf);
|
|||
self.upper_leaves.remove(&retained_leaf);
|
|||
}
|
|||
|
|||
// remove the branches leading up to the tier to which the retained leaf is to be moved
|
|||
self.remove_branch(removed_leaf, new_depth);
|
|||
self.remove_branch(retained_leaf, new_depth);
|
|||
|
|||
// compute the index of the common root for retained and removed leaves
|
|||
let mut new_index = retained_leaf;
|
|||
new_index.move_up_to(new_depth);
|
|||
debug_assert!(is_leaf_node(&new_index));
|
|||
|
|||
// insert the node at the root index
|
|||
self.insert_leaf_node(new_index, node)
|
|||
}
|
|||
|
|||
/// Inserts the specified node at the specified index; recomputes and returns the new root
|
|||
/// of the Tiered Sparse Merkle tree.
|
|||
///
|
|||
/// This method assumes that node is a non-empty value.
|
|||
pub fn insert_leaf_node(&mut self, mut index: NodeIndex, mut node: RpoDigest) -> RpoDigest {
|
|||
debug_assert!(is_leaf_node(&index));
|
|||
debug_assert!(!is_empty_root(&node));
|
|||
|
|||
// mark the node as the leaf
|
|||
if index.depth() == MAX_DEPTH {
|
|||
self.bottom_leaves.insert(index.value());
|
|||
} else {
|
|||
self.upper_leaves.insert(index);
|
|||
};
|
|||
|
|||
// insert the node and update the path from the node to the root
|
|||
for _ in 0..index.depth() {
|
|||
self.nodes.insert(index, node);
|
|||
let sibling = self.get_node_unchecked(&index.sibling());
|
|||
node = Rpo256::merge(&index.build_node(node, sibling));
|
|||
index.move_up();
|
|||
}
|
|||
|
|||
// update the root
|
|||
self.nodes.insert(NodeIndex::root(), node);
|
|||
node
|
|||
}
|
|||
|
|||
/// Updates the node at the specified index with the specified node value; recomputes and
|
|||
/// returns the new root of the Tiered Sparse Merkle tree.
|
|||
///
|
|||
/// This method can accept `node` as either an empty or a non-empty value.
|
|||
pub fn update_leaf_node(&mut self, mut index: NodeIndex, mut node: RpoDigest) -> RpoDigest {
|
|||
debug_assert!(self.is_leaf(&index));
|
|||
|
|||
// if the value we are updating the node to is a root of an empty tree, clear the leaf
|
|||
// flag for this node
|
|||
if node == EmptySubtreeRoots::empty_hashes(MAX_DEPTH)[index.depth() as usize] {
|
|||
if index.depth() == MAX_DEPTH {
|
|||
self.bottom_leaves.remove(&index.value());
|
|||
} else {
|
|||
self.upper_leaves.remove(&index);
|
|||
}
|
|||
} else {
|
|||
debug_assert!(!is_empty_root(&node));
|
|||
}
|
|||
|
|||
// update the path from the node to the root
|
|||
for _ in 0..index.depth() {
|
|||
if node == EmptySubtreeRoots::empty_hashes(MAX_DEPTH)[index.depth() as usize] {
|
|||
self.nodes.remove(&index);
|
|||
} else {
|
|||
self.nodes.insert(index, node);
|
|||
}
|
|||
|
|||
let sibling = self.get_node_unchecked(&index.sibling());
|
|||
node = Rpo256::merge(&index.build_node(node, sibling));
|
|||
index.move_up();
|
|||
}
|
|||
|
|||
// update the root
|
|||
self.nodes.insert(NodeIndex::root(), node);
|
|||
node
|
|||
}
|
|||
|
|||
/// Replaces the leaf node at the specified index with a root of an empty subtree; recomputes
|
|||
/// and returns the new root of the Tiered Sparse Merkle tree.
|
|||
pub fn clear_leaf_node(&mut self, index: NodeIndex) -> RpoDigest {
|
|||
debug_assert!(self.is_leaf(&index));
|
|||
let node = EmptySubtreeRoots::empty_hashes(MAX_DEPTH)[index.depth() as usize];
|
|||
self.update_leaf_node(index, node)
|
|||
}
|
|||
|
|||
// HELPER METHODS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Returns true if the node at the specified index is a leaf node.
|
|||
fn is_leaf(&self, index: &NodeIndex) -> bool {
|
|||
debug_assert!(is_leaf_node(index));
|
|||
if index.depth() == MAX_DEPTH {
|
|||
self.bottom_leaves.contains(&index.value())
|
|||
} else {
|
|||
self.upper_leaves.contains(index)
|
|||
}
|
|||
}
|
|||
|
|||
/// Checks if the specified index is valid in the context of this Merkle tree.
|
|||
///
|
|||
/// # Errors
|
|||
/// Returns an error if:
|
|||
/// - The specified index depth is 0 or greater than 64.
|
|||
/// - The node for the specified index does not exists in the Merkle tree. This is possible
|
|||
/// when an ancestors of the specified index is a leaf node.
|
|||
fn validate_node_access(&self, index: NodeIndex) -> Result<(), MerkleError> {
|
|||
if index.is_root() {
|
|||
return Err(MerkleError::DepthTooSmall(index.depth()));
|
|||
} else if index.depth() > MAX_DEPTH {
|
|||
return Err(MerkleError::DepthTooBig(index.depth() as u64));
|
|||
} else {
|
|||
// make sure that there are no leaf nodes in the ancestors of the index; since leaf
|
|||
// nodes can live at specific depth, we just need to check these depths.
|
|||
let tier = get_index_tier(&index);
|
|||
let mut tier_index = index;
|
|||
for &depth in TIER_DEPTHS[..tier].iter().rev() {
|
|||
tier_index.move_up_to(depth);
|
|||
if self.upper_leaves.contains(&tier_index) {
|
|||
return Err(MerkleError::NodeNotInSet(index));
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
Ok(())
|
|||
}
|
|||
|
|||
/// Returns a node at the specified index. If the node does not exist at this index, a root
|
|||
/// for an empty subtree at the index's depth is returned.
|
|||
///
|
|||
/// Unlike [NodeStore::get_node()] this does not perform any checks to verify that the
|
|||
/// returned node is valid in the context of this tree.
|
|||
fn get_node_unchecked(&self, index: &NodeIndex) -> RpoDigest {
|
|||
match self.nodes.get(index) {
|
|||
Some(node) => *node,
|
|||
None => EmptySubtreeRoots::empty_hashes(MAX_DEPTH)[index.depth() as usize],
|
|||
}
|
|||
}
|
|||
|
|||
/// Removes a sequence of nodes starting at the specified index and traversing the
|
|||
/// tree up to the specified depth.
|
|||
///
|
|||
/// This method does not update any other nodes and does not recompute the tree root.
|
|||
fn remove_branch(&mut self, mut index: NodeIndex, end_depth: u8) {
|
|||
assert!(index.depth() > end_depth);
|
|||
for _ in 0..(index.depth() - end_depth) {
|
|||
self.nodes.remove(&index);
|
|||
index.move_up()
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
// HELPER FUNCTIONS
|
|||
// ================================================================================================
|
|||
|
|||
/// Returns true if the specified node is a root of an empty tree or an empty value ([ZERO; 4]).
|
|||
fn is_empty_root(node: &RpoDigest) -> bool {
|
|||
EmptySubtreeRoots::empty_hashes(MAX_DEPTH).contains(node)
|
|||
}
|
@ -0,0 +1,580 @@ |
|||
use super::{get_key_prefix, is_leaf_node, BTreeMap, NodeIndex, RpoDigest, StarkField, Vec, Word};
|
|||
use crate::utils::vec;
|
|||
use core::{
|
|||
cmp::{Ord, Ordering},
|
|||
ops::RangeBounds,
|
|||
};
|
|||
use winter_utils::collections::btree_map::Entry;
|
|||
|
|||
// CONSTANTS
|
|||
// ================================================================================================
|
|||
|
|||
/// Depths at which leaves can exist in a tiered SMT.
|
|||
const TIER_DEPTHS: [u8; 4] = super::TieredSmt::TIER_DEPTHS;
|
|||
|
|||
/// Maximum node depth. This is also the bottom tier of the tree.
|
|||
const MAX_DEPTH: u8 = super::TieredSmt::MAX_DEPTH;
|
|||
|
|||
// VALUE STORE
|
|||
// ================================================================================================
|
|||
/// A store for key-value pairs for a Tiered Sparse Merkle tree.
|
|||
///
|
|||
/// The store is organized in a [BTreeMap] where keys are 64 most significant bits of a key, and
|
|||
/// the values are the corresponding key-value pairs (or a list of key-value pairs if more that
|
|||
/// a single key-value pair shares the same 64-bit prefix).
|
|||
///
|
|||
/// The store supports lookup by the full key as well as by the 64-bit key prefix.
|
|||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
|||
pub struct ValueStore {
|
|||
values: BTreeMap<u64, StoreEntry>,
|
|||
}
|
|||
|
|||
impl ValueStore {
|
|||
// PUBLIC ACCESSORS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Returns a reference to the value stored under the specified key, or None if there is no
|
|||
/// value associated with the specified key.
|
|||
pub fn get(&self, key: &RpoDigest) -> Option<&Word> {
|
|||
let prefix = get_key_prefix(key);
|
|||
self.values.get(&prefix).and_then(|entry| entry.get(key))
|
|||
}
|
|||
|
|||
/// Returns the first key-value pair such that the key prefix is greater than or equal to the
|
|||
/// specified prefix.
|
|||
pub fn get_first(&self, prefix: u64) -> Option<&(RpoDigest, Word)> {
|
|||
self.range(prefix..).next()
|
|||
}
|
|||
|
|||
/// Returns the first key-value pair such that the key prefix is greater than or equal to the
|
|||
/// specified prefix and the key value is not equal to the exclude_key value.
|
|||
pub fn get_first_filtered(
|
|||
&self,
|
|||
prefix: u64,
|
|||
exclude_key: &RpoDigest,
|
|||
) -> Option<&(RpoDigest, Word)> {
|
|||
self.range(prefix..).find(|(key, _)| key != exclude_key)
|
|||
}
|
|||
|
|||
/// Returns a vector with key-value pairs for all keys with the specified 64-bit prefix, or
|
|||
/// None if no keys with the specified prefix are present in this store.
|
|||
pub fn get_all(&self, prefix: u64) -> Option<Vec<(RpoDigest, Word)>> {
|
|||
self.values.get(&prefix).map(|entry| match entry {
|
|||
StoreEntry::Single(kv_pair) => vec![*kv_pair],
|
|||
StoreEntry::List(kv_pairs) => kv_pairs.clone(),
|
|||
})
|
|||
}
|
|||
|
|||
/// Returns information about a sibling of a leaf node with the specified index, but only if
|
|||
/// this is the only sibling the leaf has in some subtree starting at the first tier.
|
|||
///
|
|||
/// For example, if `index` is an index at depth 32, and there is a leaf node at depth 32 with
|
|||
/// the same root at depth 16 as `index`, we say that this leaf is a lone sibling.
|
|||
///
|
|||
/// The returned tuple contains: they key-value pair of the sibling as well as the index of
|
|||
/// the node for the root of the common subtree in which both nodes are leaves.
|
|||
///
|
|||
/// This method assumes that the key-value pair for the specified index has already been
|
|||
/// removed from the store.
|
|||
pub fn get_lone_sibling(&self, index: NodeIndex) -> Option<(&RpoDigest, &Word, NodeIndex)> {
|
|||
debug_assert!(is_leaf_node(&index));
|
|||
|
|||
// iterate over tiers from top to bottom, looking at the tiers which are strictly above
|
|||
// the depth of the index. This implies that only tiers at depth 32 and 48 will be
|
|||
// considered. For each tier, check if the parent of the index at the higher tier
|
|||
// contains a single node.
|
|||
for &tier in TIER_DEPTHS.iter().filter(|&t| index.depth() > *t) {
|
|||
// compute the index of the root at a higher tier
|
|||
let mut parent_index = index;
|
|||
parent_index.move_up_to(tier);
|
|||
|
|||
// find the lone sibling, if any; we need to handle the "last node" at a given tier
|
|||
// separately specify the bounds for the search correctly.
|
|||
let start_prefix = parent_index.value() << (MAX_DEPTH - tier);
|
|||
let sibling = if start_prefix.leading_ones() as u8 == tier {
|
|||
let mut iter = self.range(start_prefix..);
|
|||
iter.next().filter(|_| iter.next().is_none())
|
|||
} else {
|
|||
let end_prefix = (parent_index.value() + 1) << (MAX_DEPTH - tier);
|
|||
let mut iter = self.range(start_prefix..end_prefix);
|
|||
iter.next().filter(|_| iter.next().is_none())
|
|||
};
|
|||
|
|||
if let Some((key, value)) = sibling {
|
|||
return Some((key, value, parent_index));
|
|||
}
|
|||
}
|
|||
|
|||
None
|
|||
}
|
|||
|
|||
// STATE MUTATORS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Inserts the specified key-value pair into this store and returns the value previously
|
|||
/// associated with the specified key.
|
|||
///
|
|||
/// If no value was previously associated with the specified key, None is returned.
|
|||
pub fn insert(&mut self, key: RpoDigest, value: Word) -> Option<Word> {
|
|||
let prefix = get_key_prefix(&key);
|
|||
match self.values.entry(prefix) {
|
|||
Entry::Occupied(mut entry) => entry.get_mut().insert(key, value),
|
|||
Entry::Vacant(entry) => {
|
|||
entry.insert(StoreEntry::new(key, value));
|
|||
None
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
/// Removes the key-value pair for the specified key from this store and returns the value
|
|||
/// associated with this key.
|
|||
///
|
|||
/// If no value was associated with the specified key, None is returned.
|
|||
pub fn remove(&mut self, key: &RpoDigest) -> Option<Word> {
|
|||
let prefix = get_key_prefix(key);
|
|||
match self.values.entry(prefix) {
|
|||
Entry::Occupied(mut entry) => {
|
|||
let (value, remove_entry) = entry.get_mut().remove(key);
|
|||
if remove_entry {
|
|||
entry.remove_entry();
|
|||
}
|
|||
value
|
|||
}
|
|||
Entry::Vacant(_) => None,
|
|||
}
|
|||
}
|
|||
|
|||
// HELPER METHODS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Returns an iterator over all key-value pairs contained in this store such that the most
|
|||
/// significant 64 bits of the key lay within the specified bounds.
|
|||
///
|
|||
/// The order of iteration is from the smallest to the largest key.
|
|||
fn range<R: RangeBounds<u64>>(&self, bounds: R) -> impl Iterator<Item = &(RpoDigest, Word)> {
|
|||
self.values.range(bounds).flat_map(|(_, entry)| entry.iter())
|
|||
}
|
|||
}
|
|||
|
|||
// VALUE NODE
|
|||
// ================================================================================================
|
|||
|
|||
/// An entry in the [ValueStore].
|
|||
///
|
|||
/// An entry can contain either a single key-value pair or a vector of key-value pairs sorted by
|
|||
/// key.
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|||
pub enum StoreEntry {
|
|||
Single((RpoDigest, Word)),
|
|||
List(Vec<(RpoDigest, Word)>),
|
|||
}
|
|||
|
|||
impl StoreEntry {
|
|||
// CONSTRUCTOR
|
|||
// --------------------------------------------------------------------------------------------
|
|||
/// Returns a new [StoreEntry] instantiated with a single key-value pair.
|
|||
pub fn new(key: RpoDigest, value: Word) -> Self {
|
|||
Self::Single((key, value))
|
|||
}
|
|||
|
|||
// PUBLIC ACCESSORS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Returns the value associated with the specified key, or None if this entry does not contain
|
|||
/// a value associated with the specified key.
|
|||
pub fn get(&self, key: &RpoDigest) -> Option<&Word> {
|
|||
match self {
|
|||
StoreEntry::Single(kv_pair) => {
|
|||
if kv_pair.0 == *key {
|
|||
Some(&kv_pair.1)
|
|||
} else {
|
|||
None
|
|||
}
|
|||
}
|
|||
StoreEntry::List(kv_pairs) => {
|
|||
match kv_pairs.binary_search_by(|kv_pair| cmp_digests(&kv_pair.0, key)) {
|
|||
Ok(pos) => Some(&kv_pairs[pos].1),
|
|||
Err(_) => None,
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
/// Returns an iterator over all key-value pairs in this entry.
|
|||
pub fn iter(&self) -> impl Iterator<Item = &(RpoDigest, Word)> {
|
|||
EntryIterator {
|
|||
entry: self,
|
|||
pos: 0,
|
|||
}
|
|||
}
|
|||
|
|||
// STATE MUTATORS
|
|||
// --------------------------------------------------------------------------------------------
|
|||
|
|||
/// Inserts the specified key-value pair into this entry and returns the value previously
|
|||
/// associated with the specified key, or None if no value was associated with the specified
|
|||
/// key.
|
|||
///
|
|||
/// If a new key is inserted, this will also transform a `SingleEntry` into a `ListEntry`.
|
|||
pub fn insert(&mut self, key: RpoDigest, value: Word) -> Option<Word> {
|
|||
match self {
|
|||
StoreEntry::Single(kv_pair) => {
|
|||
// if the key is already in this entry, update the value and return
|
|||
if kv_pair.0 == key {
|
|||
let old_value = kv_pair.1;
|
|||
kv_pair.1 = value;
|
|||
return Some(old_value);
|
|||
}
|
|||
|
|||
// transform the entry into a list entry, and make sure the key-value pairs
|
|||
// are sorted by key
|
|||
let mut pairs = vec![*kv_pair, (key, value)];
|
|||
pairs.sort_by(|a, b| cmp_digests(&a.0, &b.0));
|
|||
|
|||
*self = StoreEntry::List(pairs);
|
|||
None
|
|||
}
|
|||
StoreEntry::List(pairs) => {
|
|||
match pairs.binary_search_by(|kv_pair| cmp_digests(&kv_pair.0, &key)) {
|
|||
Ok(pos) => {
|
|||
let old_value = pairs[pos].1;
|
|||
pairs[pos].1 = value;
|
|||
Some(old_value)
|
|||
}
|
|||
Err(pos) => {
|
|||
pairs.insert(pos, (key, value));
|
|||
None
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
/// Removes the key-value pair with the specified key from this entry, and returns the value
|
|||
/// of the removed pair. If the entry did not contain a key-value pair for the specified key,
|
|||
/// None is returned.
|
|||
///
|
|||
/// If the last last key-value pair was removed from the entry, the second tuple value will
|
|||
/// be set to true.
|
|||
pub fn remove(&mut self, key: &RpoDigest) -> (Option<Word>, bool) {
|
|||
match self {
|
|||
StoreEntry::Single(kv_pair) => {
|
|||
if kv_pair.0 == *key {
|
|||
(Some(kv_pair.1), true)
|
|||
} else {
|
|||
(None, false)
|
|||
}
|
|||
}
|
|||
StoreEntry::List(kv_pairs) => {
|
|||
match kv_pairs.binary_search_by(|kv_pair| cmp_digests(&kv_pair.0, key)) {
|
|||
Ok(pos) => {
|
|||
let kv_pair = kv_pairs.remove(pos);
|
|||
if kv_pairs.len() == 1 {
|
|||
*self = StoreEntry::Single(kv_pairs[0]);
|
|||
}
|
|||
(Some(kv_pair.1), false)
|
|||
}
|
|||
Err(_) => (None, false),
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
/// A custom iterator over key-value pairs of a [StoreEntry].
|
|||
///
|
|||
/// For a `SingleEntry` this returns only one value, but for `ListEntry`, this iterates over the
|
|||
/// entire list of key-value pairs.
|
|||
pub struct EntryIterator<'a> {
|
|||
entry: &'a StoreEntry,
|
|||
pos: usize,
|
|||
}
|
|||
|
|||
impl<'a> Iterator for EntryIterator<'a> {
|
|||
type Item = &'a (RpoDigest, Word);
|
|||
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
|||
match self.entry {
|
|||
StoreEntry::Single(kv_pair) => {
|
|||
if self.pos == 0 {
|
|||
self.pos = 1;
|
|||
Some(kv_pair)
|
|||
} else {
|
|||
None
|
|||
}
|
|||
}
|
|||
StoreEntry::List(kv_pairs) => {
|
|||
if self.pos >= kv_pairs.len() {
|
|||
None
|
|||
} else {
|
|||
let kv_pair = &kv_pairs[self.pos];
|
|||
self.pos += 1;
|
|||
Some(kv_pair)
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
// HELPER FUNCTIONS
|
|||
// ================================================================================================
|
|||
|
|||
/// Compares two digests element-by-element using their integer representations starting with the
|
|||
/// most significant element.
|
|||
fn cmp_digests(d1: &RpoDigest, d2: &RpoDigest) -> Ordering {
|
|||
let d1 = Word::from(d1);
|
|||
let d2 = Word::from(d2);
|
|||
|
|||
for (v1, v2) in d1.iter().zip(d2.iter()).rev() {
|
|||
let v1 = v1.as_int();
|
|||
let v2 = v2.as_int();
|
|||
if v1 != v2 {
|
|||
return v1.cmp(&v2);
|
|||
}
|
|||
}
|
|||
|
|||
Ordering::Equal
|
|||
}
|
|||
|
|||
// TESTS
|
|||
// ================================================================================================
|
|||
|
|||
#[cfg(test)]
|
|||
mod tests {
|
|||
|
|||
use super::{RpoDigest, ValueStore};
|
|||
use crate::{
|
|||
merkle::{tiered_smt::values::StoreEntry, NodeIndex},
|
|||
Felt, ONE, WORD_SIZE, ZERO,
|
|||
};
|
|||
|
|||
#[test]
|
|||
fn test_insert() {
|
|||
let mut store = ValueStore::default();
|
|||
|
|||
// insert the first key-value pair into the store
|
|||
let raw_a = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_a = RpoDigest::from([ZERO, ONE, ONE, Felt::new(raw_a)]);
|
|||
let value_a = [ONE; WORD_SIZE];
|
|||
|
|||
assert!(store.insert(key_a, value_a).is_none());
|
|||
assert_eq!(store.values.len(), 1);
|
|||
|
|||
let entry = store.values.get(&raw_a).unwrap();
|
|||
let expected_entry = StoreEntry::Single((key_a, value_a));
|
|||
assert_eq!(entry, &expected_entry);
|
|||
|
|||
// insert a key-value pair with a different key into the store; since the keys are
|
|||
// different, another entry is added to the values map
|
|||
let raw_b = 0b_11111110_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_b = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_b)]);
|
|||
let value_b = [ONE, ZERO, ONE, ZERO];
|
|||
|
|||
assert!(store.insert(key_b, value_b).is_none());
|
|||
assert_eq!(store.values.len(), 2);
|
|||
|
|||
let entry1 = store.values.get(&raw_a).unwrap();
|
|||
let expected_entry1 = StoreEntry::Single((key_a, value_a));
|
|||
assert_eq!(entry1, &expected_entry1);
|
|||
|
|||
let entry2 = store.values.get(&raw_b).unwrap();
|
|||
let expected_entry2 = StoreEntry::Single((key_b, value_b));
|
|||
assert_eq!(entry2, &expected_entry2);
|
|||
|
|||
// insert a key-value pair with the same 64-bit key prefix as the first key; this should
|
|||
// transform the first entry into a List entry
|
|||
let key_c = RpoDigest::from([ONE, ONE, ZERO, Felt::new(raw_a)]);
|
|||
let value_c = [ONE, ONE, ZERO, ZERO];
|
|||
|
|||
assert!(store.insert(key_c, value_c).is_none());
|
|||
assert_eq!(store.values.len(), 2);
|
|||
|
|||
let entry1 = store.values.get(&raw_a).unwrap();
|
|||
let expected_entry1 = StoreEntry::List(vec![(key_c, value_c), (key_a, value_a)]);
|
|||
assert_eq!(entry1, &expected_entry1);
|
|||
|
|||
let entry2 = store.values.get(&raw_b).unwrap();
|
|||
let expected_entry2 = StoreEntry::Single((key_b, value_b));
|
|||
assert_eq!(entry2, &expected_entry2);
|
|||
|
|||
// replace values for keys a and b
|
|||
let value_a2 = [ONE, ONE, ONE, ZERO];
|
|||
let value_b2 = [ZERO, ZERO, ZERO, ONE];
|
|||
|
|||
assert_eq!(store.insert(key_a, value_a2), Some(value_a));
|
|||
assert_eq!(store.values.len(), 2);
|
|||
|
|||
assert_eq!(store.insert(key_b, value_b2), Some(value_b));
|
|||
assert_eq!(store.values.len(), 2);
|
|||
|
|||
let entry1 = store.values.get(&raw_a).unwrap();
|
|||
let expected_entry1 = StoreEntry::List(vec![(key_c, value_c), (key_a, value_a2)]);
|
|||
assert_eq!(entry1, &expected_entry1);
|
|||
|
|||
let entry2 = store.values.get(&raw_b).unwrap();
|
|||
let expected_entry2 = StoreEntry::Single((key_b, value_b2));
|
|||
assert_eq!(entry2, &expected_entry2);
|
|||
|
|||
// insert one more key-value pair with the same 64-bit key-prefix as the first key
|
|||
let key_d = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_a)]);
|
|||
let value_d = [ZERO, ONE, ZERO, ZERO];
|
|||
|
|||
assert!(store.insert(key_d, value_d).is_none());
|
|||
assert_eq!(store.values.len(), 2);
|
|||
|
|||
let entry1 = store.values.get(&raw_a).unwrap();
|
|||
let expected_entry1 =
|
|||
StoreEntry::List(vec![(key_c, value_c), (key_a, value_a2), (key_d, value_d)]);
|
|||
assert_eq!(entry1, &expected_entry1);
|
|||
|
|||
let entry2 = store.values.get(&raw_b).unwrap();
|
|||
let expected_entry2 = StoreEntry::Single((key_b, value_b2));
|
|||
assert_eq!(entry2, &expected_entry2);
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_remove() {
|
|||
// populate the value store
|
|||
let mut store = ValueStore::default();
|
|||
|
|||
let raw_a = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_a = RpoDigest::from([ZERO, ONE, ONE, Felt::new(raw_a)]);
|
|||
let value_a = [ONE; WORD_SIZE];
|
|||
store.insert(key_a, value_a);
|
|||
|
|||
let raw_b = 0b_11111110_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_b = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_b)]);
|
|||
let value_b = [ONE, ZERO, ONE, ZERO];
|
|||
store.insert(key_b, value_b);
|
|||
|
|||
let key_c = RpoDigest::from([ONE, ONE, ZERO, Felt::new(raw_a)]);
|
|||
let value_c = [ONE, ONE, ZERO, ZERO];
|
|||
store.insert(key_c, value_c);
|
|||
|
|||
let key_d = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_a)]);
|
|||
let value_d = [ZERO, ONE, ZERO, ZERO];
|
|||
store.insert(key_d, value_d);
|
|||
|
|||
assert_eq!(store.values.len(), 2);
|
|||
|
|||
let entry1 = store.values.get(&raw_a).unwrap();
|
|||
let expected_entry1 =
|
|||
StoreEntry::List(vec![(key_c, value_c), (key_a, value_a), (key_d, value_d)]);
|
|||
assert_eq!(entry1, &expected_entry1);
|
|||
|
|||
let entry2 = store.values.get(&raw_b).unwrap();
|
|||
let expected_entry2 = StoreEntry::Single((key_b, value_b));
|
|||
assert_eq!(entry2, &expected_entry2);
|
|||
|
|||
// remove non-existent keys
|
|||
let key_e = RpoDigest::from([ZERO, ZERO, ONE, Felt::new(raw_a)]);
|
|||
assert!(store.remove(&key_e).is_none());
|
|||
|
|||
let raw_f = 0b_11111110_11111111_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_f = RpoDigest::from([ZERO, ZERO, ONE, Felt::new(raw_f)]);
|
|||
assert!(store.remove(&key_f).is_none());
|
|||
|
|||
// remove keys from the list entry
|
|||
assert_eq!(store.remove(&key_c).unwrap(), value_c);
|
|||
let entry1 = store.values.get(&raw_a).unwrap();
|
|||
let expected_entry1 = StoreEntry::List(vec![(key_a, value_a), (key_d, value_d)]);
|
|||
assert_eq!(entry1, &expected_entry1);
|
|||
|
|||
assert_eq!(store.remove(&key_a).unwrap(), value_a);
|
|||
let entry1 = store.values.get(&raw_a).unwrap();
|
|||
let expected_entry1 = StoreEntry::Single((key_d, value_d));
|
|||
assert_eq!(entry1, &expected_entry1);
|
|||
|
|||
assert_eq!(store.remove(&key_d).unwrap(), value_d);
|
|||
assert!(store.values.get(&raw_a).is_none());
|
|||
assert_eq!(store.values.len(), 1);
|
|||
|
|||
// remove a key from a single entry
|
|||
assert_eq!(store.remove(&key_b).unwrap(), value_b);
|
|||
assert!(store.values.get(&raw_b).is_none());
|
|||
assert_eq!(store.values.len(), 0);
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_range() {
|
|||
// populate the value store
|
|||
let mut store = ValueStore::default();
|
|||
|
|||
let raw_a = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_a = RpoDigest::from([ZERO, ONE, ONE, Felt::new(raw_a)]);
|
|||
let value_a = [ONE; WORD_SIZE];
|
|||
store.insert(key_a, value_a);
|
|||
|
|||
let raw_b = 0b_11111110_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_b = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_b)]);
|
|||
let value_b = [ONE, ZERO, ONE, ZERO];
|
|||
store.insert(key_b, value_b);
|
|||
|
|||
let key_c = RpoDigest::from([ONE, ONE, ZERO, Felt::new(raw_a)]);
|
|||
let value_c = [ONE, ONE, ZERO, ZERO];
|
|||
store.insert(key_c, value_c);
|
|||
|
|||
let key_d = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_a)]);
|
|||
let value_d = [ZERO, ONE, ZERO, ZERO];
|
|||
store.insert(key_d, value_d);
|
|||
|
|||
let raw_e = 0b_10101000_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_e = RpoDigest::from([ZERO, ONE, ONE, Felt::new(raw_e)]);
|
|||
let value_e = [ZERO, ZERO, ZERO, ONE];
|
|||
store.insert(key_e, value_e);
|
|||
|
|||
// check the entire range
|
|||
let mut iter = store.range(..u64::MAX);
|
|||
assert_eq!(iter.next(), Some(&(key_e, value_e)));
|
|||
assert_eq!(iter.next(), Some(&(key_c, value_c)));
|
|||
assert_eq!(iter.next(), Some(&(key_a, value_a)));
|
|||
assert_eq!(iter.next(), Some(&(key_d, value_d)));
|
|||
assert_eq!(iter.next(), Some(&(key_b, value_b)));
|
|||
assert_eq!(iter.next(), None);
|
|||
|
|||
// check all but e
|
|||
let mut iter = store.range(raw_a..u64::MAX);
|
|||
assert_eq!(iter.next(), Some(&(key_c, value_c)));
|
|||
assert_eq!(iter.next(), Some(&(key_a, value_a)));
|
|||
assert_eq!(iter.next(), Some(&(key_d, value_d)));
|
|||
assert_eq!(iter.next(), Some(&(key_b, value_b)));
|
|||
assert_eq!(iter.next(), None);
|
|||
|
|||
// check all but e and b
|
|||
let mut iter = store.range(raw_a..raw_b);
|
|||
assert_eq!(iter.next(), Some(&(key_c, value_c)));
|
|||
assert_eq!(iter.next(), Some(&(key_a, value_a)));
|
|||
assert_eq!(iter.next(), Some(&(key_d, value_d)));
|
|||
assert_eq!(iter.next(), None);
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_get_lone_sibling() {
|
|||
// populate the value store
|
|||
let mut store = ValueStore::default();
|
|||
|
|||
let raw_a = 0b_10101010_10101010_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_a = RpoDigest::from([ZERO, ONE, ONE, Felt::new(raw_a)]);
|
|||
let value_a = [ONE; WORD_SIZE];
|
|||
store.insert(key_a, value_a);
|
|||
|
|||
let raw_b = 0b_11111111_11111111_00011111_11111111_10010110_10010011_11100000_00000000_u64;
|
|||
let key_b = RpoDigest::from([ONE, ONE, ONE, Felt::new(raw_b)]);
|
|||
let value_b = [ONE, ZERO, ONE, ZERO];
|
|||
store.insert(key_b, value_b);
|
|||
|
|||
// check sibling node for `a`
|
|||
let index = NodeIndex::make(32, 0b_10101010_10101010_00011111_11111110);
|
|||
let parent_index = NodeIndex::make(16, 0b_10101010_10101010);
|
|||
assert_eq!(store.get_lone_sibling(index), Some((&key_a, &value_a, parent_index)));
|
|||
|
|||
// check sibling node for `b`
|
|||
let index = NodeIndex::make(32, 0b_11111111_11111111_00011111_11111111);
|
|||
let parent_index = NodeIndex::make(16, 0b_11111111_11111111);
|
|||
assert_eq!(store.get_lone_sibling(index), Some((&key_b, &value_b, parent_index)));
|
|||
|
|||
// check some other sibling for some other index
|
|||
let index = NodeIndex::make(32, 0b_11101010_10101010);
|
|||
assert_eq!(store.get_lone_sibling(index), None);
|
|||
}
|
|||
}
|