diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree.rs b/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree.rs index 31f07034621..8b2ef008e88 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/filled_tree/tree.rs @@ -77,13 +77,18 @@ impl FilledTreeImpl { fn initialize_filled_tree_output_map_with_placeholders<'a>( updated_skeleton: &impl UpdatedSkeletonTree<'a>, ) -> HashMap>> { - updated_skeleton - .get_nodes() - .filter_map(|(index, node)| match node { - UpdatedSkeletonNode::UnmodifiedSubTree(_) => None, - _ => Some((*index, OnceLock::new())), - }) - .collect() + // `filter_map` erases the exact lower bound of `size_hint`, so capacity must be reserved + // from the underlying node iterator (whose `size_hint` is exact, since it comes from a + // `HashMap::iter()`) before filtering, to actually avoid rehashing. This over-reserves for + // the `UnmodifiedSubTree` nodes filtered out below, trading bounded extra capacity for + // skipping a separate counting pass. + let node_iterator = updated_skeleton.get_nodes(); + let mut filled_tree_output_map = HashMap::with_capacity(node_iterator.size_hint().0); + filled_tree_output_map.extend(node_iterator.filter_map(|(index, node)| match node { + UpdatedSkeletonNode::UnmodifiedSubTree(_) => None, + _ => Some((*index, OnceLock::new())), + })); + filled_tree_output_map } fn initialize_leaf_output_map_with_placeholders( diff --git a/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/tree.rs b/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/tree.rs index 0ca5a28957d..11a739a589f 100644 --- a/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/tree.rs +++ b/crates/starknet_patricia/src/patricia_merkle_tree/updated_skeleton_tree/tree.rs @@ -30,7 +30,9 @@ pub trait UpdatedSkeletonTree<'a>: Sized + Send + Sync { /// Does the skeleton represents an empty-tree (i.e. all leaves are empty). fn is_empty(&self) -> bool; - /// Returns an iterator over all (node index, node) pairs in the tree. + /// Returns an iterator over all (node index, node) pairs in the tree. Callers rely on an + /// exact `size_hint` (lower bound equal to the true count) to pre-allocate; implementations + /// must not wrap this in an adapter (e.g. `filter`) that only yields a lower bound of `0`. fn get_nodes(&self) -> impl Iterator; /// Returns the node with the given index.