reth_trie/proof_v2/
node.rs

1use crate::proof_v2::DeferredValueEncoder;
2use alloy_rlp::Encodable;
3use alloy_trie::nodes::ExtensionNodeRef;
4use reth_execution_errors::trie::StateProofError;
5use reth_trie_common::{
6    BranchNode, BranchNodeMasks, ExtensionNode, LeafNode, LeafNodeRef, Nibbles, ProofTrieNode,
7    RlpNode, TrieMask, TrieNode,
8};
9
10/// A trie node which is the child of a branch in the trie.
11#[derive(Debug)]
12pub(crate) enum ProofTrieBranchChild<RF> {
13    /// A leaf node whose value has yet to be calculated and encoded.
14    Leaf {
15        /// The short key of the leaf.
16        short_key: Nibbles,
17        /// The [`DeferredValueEncoder`] which will encode the leaf's value.
18        value: RF,
19    },
20    /// An extension node whose child branch has been converted to an [`RlpNode`]
21    Extension {
22        /// The short key of the leaf.
23        short_key: Nibbles,
24        /// The [`RlpNode`] of the child branch.
25        child: RlpNode,
26    },
27    /// A branch node whose children have already been flattened into [`RlpNode`]s.
28    Branch {
29        /// The node itself, for use during RLP encoding.
30        node: BranchNode,
31        /// Bitmasks carried over from cached `BranchNodeCompact` values, if any.
32        masks: Option<BranchNodeMasks>,
33    },
34    /// A node whose type is not known, as it has already been converted to an [`RlpNode`].
35    RlpNode(RlpNode),
36}
37
38impl<RF: DeferredValueEncoder> ProofTrieBranchChild<RF> {
39    /// Converts this child into its RLP node representation. This potentially also returns an
40    /// `RlpNode` buffer which can be re-used for other [`ProofTrieBranchChild`]s.
41    pub(crate) fn into_rlp(
42        self,
43        buf: &mut Vec<u8>,
44    ) -> Result<(RlpNode, Option<Vec<RlpNode>>), StateProofError> {
45        match self {
46            Self::Leaf { short_key, value } => {
47                // RLP encode the value itself
48                value.encode(buf)?;
49                let value_enc_len = buf.len();
50
51                // Determine the required buffer size for the encoded leaf
52                let leaf_enc_len = LeafNodeRef::new(&short_key, buf).length();
53
54                // We want to re-use buf for the encoding of the leaf node as well. To do this we
55                // will keep appending to it, leaving the already encoded value in-place. First we
56                // must ensure the buffer is big enough, then we'll split.
57                buf.resize(value_enc_len + leaf_enc_len, 0);
58
59                // SAFETY we have just resized the above to be greater than `value_enc_len`, so it
60                // must be in-bounds.
61                let (value_buf, mut leaf_buf) =
62                    unsafe { buf.split_at_mut_unchecked(value_enc_len) };
63
64                // Encode the leaf into the right side of the split buffer, and return the RlpNode.
65                LeafNodeRef::new(&short_key, value_buf).encode(&mut leaf_buf);
66                Ok((RlpNode::from_rlp(&buf[value_enc_len..]), None))
67            }
68            Self::Extension { short_key, child } => {
69                ExtensionNodeRef::new(&short_key, child.as_slice()).encode(buf);
70                Ok((RlpNode::from_rlp(buf), None))
71            }
72            Self::Branch { node: branch_node, .. } => {
73                branch_node.encode(buf);
74                Ok((RlpNode::from_rlp(buf), Some(branch_node.stack)))
75            }
76            Self::RlpNode(rlp_node) => Ok((rlp_node, None)),
77        }
78    }
79
80    /// Converts this child into a [`ProofTrieNode`] having the given path.
81    ///
82    /// # Panics
83    ///
84    /// If called on a [`Self::RlpNode`].
85    pub(crate) fn into_proof_trie_node(
86        self,
87        path: Nibbles,
88        buf: &mut Vec<u8>,
89    ) -> Result<ProofTrieNode, StateProofError> {
90        let (node, masks) = match self {
91            Self::Leaf { short_key, value } => {
92                value.encode(buf)?;
93                // Counter-intuitively a clone is better here than a `core::mem::take`. If we take
94                // the buffer then future RLP-encodes will need to re-allocate a new one, and
95                // RLP-encodes after those may need a bigger buffer and therefore re-alloc again.
96                //
97                // By cloning here we do a single allocation of exactly the size we need to take
98                // this value, and the passed in buffer can remain with whatever large capacity it
99                // already has.
100                let rlp_val = buf.clone();
101                (TrieNode::Leaf(LeafNode::new(short_key, rlp_val)), None)
102            }
103            Self::Extension { short_key, child } => {
104                (TrieNode::Extension(ExtensionNode { key: short_key, child }), None)
105            }
106            Self::Branch { node, masks } => (TrieNode::Branch(node), masks),
107            Self::RlpNode(_) => panic!("Cannot call `into_proof_trie_node` on RlpNode"),
108        };
109
110        Ok(ProofTrieNode { node, path, masks })
111    }
112
113    /// Returns the short key of the child, if it is a leaf or extension, or empty if its a
114    /// [`Self::Branch`] or [`Self::RlpNode`].
115    pub(crate) fn short_key(&self) -> &Nibbles {
116        match self {
117            Self::Leaf { short_key, .. } | Self::Extension { short_key, .. } => short_key,
118            Self::Branch { .. } | Self::RlpNode(_) => {
119                static EMPTY_NIBBLES: Nibbles = Nibbles::new();
120                &EMPTY_NIBBLES
121            }
122        }
123    }
124
125    /// Trims the given number of nibbles off the head of the short key.
126    ///
127    /// If the node is an extension and the given length is the same as its short key length, then
128    /// the node is replaced with its child.
129    ///
130    /// # Panics
131    ///
132    /// - If the given len is longer than the short key
133    /// - If the given len is the same as the length of a leaf's short key
134    /// - If the node is a [`Self::Branch`] or [`Self::RlpNode`]
135    pub(crate) fn trim_short_key_prefix(&mut self, len: usize) {
136        match self {
137            Self::Extension { short_key, child } if short_key.len() == len => {
138                *self = Self::RlpNode(core::mem::take(child));
139            }
140            Self::Leaf { short_key, .. } | Self::Extension { short_key, .. } => {
141                *short_key = trim_nibbles_prefix(short_key, len);
142            }
143            Self::Branch { .. } | Self::RlpNode(_) => {
144                panic!("Cannot call `trim_short_key_prefix` on Branch or RlpNode")
145            }
146        }
147    }
148}
149
150/// A single branch in the trie which is under construction. The actual child nodes of the branch
151/// will be tracked as [`ProofTrieBranchChild`]s on a stack.
152#[derive(Debug)]
153pub(crate) struct ProofTrieBranch {
154    /// The length of the parent extension node's short key. If zero then the branch's parent is
155    /// not an extension but instead another branch.
156    pub(crate) ext_len: u8,
157    /// A mask tracking which child nibbles are set on the branch so far. There will be a single
158    /// child on the stack for each set bit.
159    pub(crate) state_mask: TrieMask,
160    /// Bitmasks which are subsets of `state_mask`.
161    pub(crate) masks: Option<BranchNodeMasks>,
162}
163
164/// Trims the first `len` nibbles from the head of the given `Nibbles`.
165///
166/// # Panics
167///
168/// Panics if the given `len` is greater than the length of the `Nibbles`.
169pub(crate) fn trim_nibbles_prefix(n: &Nibbles, len: usize) -> Nibbles {
170    debug_assert!(n.len() >= len);
171    n.slice_unchecked(len, n.len())
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn test_trim_nibbles_prefix_basic() {
180        // Create nibbles [1, 2, 3, 4, 5, 6]
181        let nibbles = Nibbles::from_nibbles([1, 2, 3, 4, 5, 6]);
182
183        // Trim first 2 nibbles
184        let trimmed = trim_nibbles_prefix(&nibbles, 2);
185        assert_eq!(trimmed.len(), 4);
186
187        // Verify the remaining nibbles are [3, 4, 5, 6]
188        assert_eq!(trimmed.get(0), Some(3));
189        assert_eq!(trimmed.get(1), Some(4));
190        assert_eq!(trimmed.get(2), Some(5));
191        assert_eq!(trimmed.get(3), Some(6));
192    }
193
194    #[test]
195    fn test_trim_nibbles_prefix_zero() {
196        // Create nibbles [10, 11, 12, 13]
197        let nibbles = Nibbles::from_nibbles([10, 11, 12, 13]);
198
199        // Trim zero nibbles - should return identical nibbles
200        let trimmed = trim_nibbles_prefix(&nibbles, 0);
201        assert_eq!(trimmed, nibbles);
202    }
203
204    #[test]
205    fn test_trim_nibbles_prefix_all() {
206        // Create nibbles [1, 2, 3, 4]
207        let nibbles = Nibbles::from_nibbles([1, 2, 3, 4]);
208
209        // Trim all nibbles - should return empty
210        let trimmed = trim_nibbles_prefix(&nibbles, 4);
211        assert!(trimmed.is_empty());
212    }
213
214    #[test]
215    fn test_trim_nibbles_prefix_empty() {
216        // Create empty nibbles
217        let nibbles = Nibbles::new();
218
219        // Trim zero from empty - should return empty
220        let trimmed = trim_nibbles_prefix(&nibbles, 0);
221        assert!(trimmed.is_empty());
222    }
223}