reth_trie/proof_v2/value.rs
1//! Generic value encoder types for proof calculation with lazy evaluation.
2
3use crate::{
4 hashed_cursor::HashedCursorFactory, proof_v2::ProofCalculator, trie_cursor::TrieCursorFactory,
5};
6use alloy_primitives::{B256, U256};
7use alloy_rlp::Encodable;
8use reth_execution_errors::trie::StateProofError;
9use reth_primitives_traits::Account;
10use reth_trie_common::Nibbles;
11use std::rc::Rc;
12
13/// A trait for deferred RLP-encoding of leaf values.
14pub trait DeferredValueEncoder {
15 /// RLP encodes the value into the provided buffer.
16 ///
17 /// # Arguments
18 ///
19 /// * `buf` - A mutable buffer to encode the data into
20 fn encode(self, buf: &mut Vec<u8>) -> Result<(), StateProofError>;
21}
22
23/// A trait for RLP-encoding values for proof calculation. This trait is designed to allow the lazy
24/// computation of leaf values in a generic way.
25///
26/// When calculating a leaf value in a storage trie the [`DeferredValueEncoder`] simply holds onto
27/// the slot value, and the `encode` method synchronously RLP-encodes it.
28///
29/// When calculating a leaf value in the accounts trie we create a [`DeferredValueEncoder`] to
30/// initiate any asynchronous computation of the account's storage root we want to do. Later we call
31/// [`DeferredValueEncoder::encode`] to obtain the result of that computation and RLP-encode it.
32pub trait LeafValueEncoder {
33 /// The type of value being encoded (e.g., U256 for storage, Account for accounts).
34 type Value;
35
36 /// The type that will compute and encode the value when needed.
37 type DeferredEncoder: DeferredValueEncoder;
38
39 /// Returns an encoder that will RLP-encode the value when its `encode` method is called.
40 ///
41 /// # Arguments
42 ///
43 /// * `key` - The key the value was stored at in the DB
44 /// * `value` - The value to encode
45 ///
46 /// The returned deferred encoder will be called as late as possible in the algorithm to
47 /// maximize the time available for parallel computation (e.g., storage root calculation).
48 fn deferred_encoder(&self, key: B256, value: Self::Value) -> Self::DeferredEncoder;
49}
50
51/// An encoder for storage slot values.
52///
53/// This encoder simply RLP-encodes U256 storage values directly.
54#[derive(Debug, Clone, Copy, Default)]
55pub struct StorageValueEncoder;
56
57/// The deferred encoder for a storage slot value.
58#[derive(Debug, Clone, Copy)]
59pub struct StorageDeferredValueEncoder(U256);
60
61impl DeferredValueEncoder for StorageDeferredValueEncoder {
62 fn encode(self, buf: &mut Vec<u8>) -> Result<(), StateProofError> {
63 self.0.encode(buf);
64 Ok(())
65 }
66}
67
68impl LeafValueEncoder for StorageValueEncoder {
69 type Value = U256;
70 type DeferredEncoder = StorageDeferredValueEncoder;
71
72 fn deferred_encoder(&self, _key: B256, value: Self::Value) -> Self::DeferredEncoder {
73 StorageDeferredValueEncoder(value)
74 }
75}
76
77/// An account value encoder that synchronously computes storage roots.
78///
79/// This encoder contains factories for creating trie and hashed cursors. Storage roots are
80/// computed synchronously within the deferred encoder using a `StorageProofCalculator`.
81#[derive(Debug, Clone)]
82pub struct SyncAccountValueEncoder<T, H> {
83 /// Factory for creating trie cursors.
84 trie_cursor_factory: Rc<T>,
85 /// Factory for creating hashed cursors.
86 hashed_cursor_factory: Rc<H>,
87}
88
89impl<T, H> SyncAccountValueEncoder<T, H> {
90 /// Create a new account value encoder with the given factories.
91 pub fn new(trie_cursor_factory: T, hashed_cursor_factory: H) -> Self {
92 Self {
93 trie_cursor_factory: Rc::new(trie_cursor_factory),
94 hashed_cursor_factory: Rc::new(hashed_cursor_factory),
95 }
96 }
97}
98
99/// The deferred encoder for an account value with synchronous storage root calculation.
100#[derive(Debug, Clone)]
101pub struct SyncAccountDeferredValueEncoder<T, H> {
102 trie_cursor_factory: Rc<T>,
103 hashed_cursor_factory: Rc<H>,
104 hashed_address: B256,
105 account: Account,
106}
107
108impl<T, H> DeferredValueEncoder for SyncAccountDeferredValueEncoder<T, H>
109where
110 T: TrieCursorFactory,
111 H: HashedCursorFactory,
112{
113 // Synchronously computes the storage root for this account and RLP-encodes the resulting
114 // `TrieAccount` into `buf`
115 fn encode(self, buf: &mut Vec<u8>) -> Result<(), StateProofError> {
116 // Create cursors for storage proof calculation
117 let trie_cursor = self.trie_cursor_factory.storage_trie_cursor(self.hashed_address)?;
118 let hashed_cursor =
119 self.hashed_cursor_factory.hashed_storage_cursor(self.hashed_address)?;
120
121 // Create storage proof calculator with StorageValueEncoder
122 let mut storage_proof_calculator = ProofCalculator::new_storage(trie_cursor, hashed_cursor);
123
124 // Compute storage root by calling storage_proof with the root path as a target.
125 // This returns just the root node of the storage trie.
126 let storage_root = storage_proof_calculator
127 .storage_proof(self.hashed_address, [Nibbles::new()])
128 .map(|nodes| {
129 // Encode the root node to RLP and hash it
130 let root_node =
131 nodes.first().expect("storage_proof always returns at least the root");
132 root_node.node.encode(buf);
133
134 let storage_root = alloy_primitives::keccak256(buf.as_slice());
135
136 // Clear the buffer so we can re-use it to encode the TrieAccount
137 buf.clear();
138
139 storage_root
140 })?;
141
142 // Combine account with storage root to create TrieAccount
143 let trie_account = self.account.into_trie_account(storage_root);
144
145 // Encode the trie account
146 trie_account.encode(buf);
147
148 Ok(())
149 }
150}
151
152impl<T, H> LeafValueEncoder for SyncAccountValueEncoder<T, H>
153where
154 T: TrieCursorFactory,
155 H: HashedCursorFactory,
156{
157 type Value = Account;
158 type DeferredEncoder = SyncAccountDeferredValueEncoder<T, H>;
159
160 fn deferred_encoder(
161 &self,
162 hashed_address: B256,
163 account: Self::Value,
164 ) -> Self::DeferredEncoder {
165 // Return a deferred encoder that will synchronously compute the storage root when encode()
166 // is called.
167 SyncAccountDeferredValueEncoder {
168 trie_cursor_factory: self.trie_cursor_factory.clone(),
169 hashed_cursor_factory: self.hashed_cursor_factory.clone(),
170 hashed_address,
171 account,
172 }
173 }
174}