1use super::ExecutedBlock;
2use alloy_consensus::BlockHeader;
3use alloy_primitives::{keccak256, Address, BlockNumber, Bytes, StorageKey, StorageValue, B256};
4use reth_errors::ProviderResult;
5use reth_primitives_traits::{Account, Bytecode, NodePrimitives};
6use reth_storage_api::{
7 AccountReader, BlockHashReader, BytecodeReader, HashedPostStateProvider, StateProofProvider,
8 StateProvider, StateProviderBox, StateRootProvider, StorageRootProvider,
9};
10use reth_trie::{
11 updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
12 MultiProofTargets, StorageMultiProof, TrieInput,
13};
14use revm_database::BundleState;
15use std::{borrow::Cow, sync::OnceLock};
16
17#[expect(missing_debug_implementations)]
20pub struct MemoryOverlayStateProviderRef<
21 'a,
22 N: NodePrimitives = reth_ethereum_primitives::EthPrimitives,
23> {
24 pub(crate) historical: Box<dyn StateProvider + 'a>,
26 pub(crate) in_memory: Cow<'a, [ExecutedBlock<N>]>,
28 pub(crate) trie_input: OnceLock<TrieInput>,
30}
31
32impl<'a, N: NodePrimitives> MemoryOverlayStateProviderRef<'a, N> {
33 pub fn new(historical: Box<dyn StateProvider + 'a>, in_memory: Vec<ExecutedBlock<N>>) -> Self {
41 Self { historical, in_memory: Cow::Owned(in_memory), trie_input: OnceLock::new() }
42 }
43
44 pub fn boxed(self) -> Box<dyn StateProvider + 'a> {
46 Box::new(self)
47 }
48
49 fn trie_input(&self) -> &TrieInput {
51 self.trie_input.get_or_init(|| {
52 let mut input = TrieInput::default();
53 for block in self.in_memory.iter().rev() {
55 let data = block.trie_data();
56 input.nodes.extend_from_sorted(&data.trie_updates);
57 input.state.extend_from_sorted(&data.hashed_state);
58 }
59 input
60 })
61 }
62
63 fn merged_hashed_storage(&self, address: Address, storage: HashedStorage) -> HashedStorage {
64 let state = &self.trie_input().state;
65 let mut hashed = state.storages.get(&keccak256(address)).cloned().unwrap_or_default();
66 hashed.extend(&storage);
67 hashed
68 }
69}
70
71impl<N: NodePrimitives> BlockHashReader for MemoryOverlayStateProviderRef<'_, N> {
72 fn block_hash(&self, number: BlockNumber) -> ProviderResult<Option<B256>> {
73 for block in self.in_memory.iter() {
74 if block.recovered_block().number() == number {
75 return Ok(Some(block.recovered_block().hash()));
76 }
77 }
78
79 self.historical.block_hash(number)
80 }
81
82 fn canonical_hashes_range(
83 &self,
84 start: BlockNumber,
85 end: BlockNumber,
86 ) -> ProviderResult<Vec<B256>> {
87 let range = start..end;
88 let mut earliest_block_number = None;
89 let mut in_memory_hashes = Vec::with_capacity(range.size_hint().0);
90
91 for block in self.in_memory.iter() {
93 let block_num = block.recovered_block().number();
94 if range.contains(&block_num) {
95 in_memory_hashes.push(block.recovered_block().hash());
96 earliest_block_number = Some(block_num);
97 }
98 }
99
100 in_memory_hashes.reverse();
104
105 let mut hashes =
106 self.historical.canonical_hashes_range(start, earliest_block_number.unwrap_or(end))?;
107 hashes.append(&mut in_memory_hashes);
108 Ok(hashes)
109 }
110}
111
112impl<N: NodePrimitives> AccountReader for MemoryOverlayStateProviderRef<'_, N> {
113 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
114 for block in self.in_memory.iter() {
115 if let Some(account) = block.execution_output.account(address) {
116 return Ok(account);
117 }
118 }
119
120 self.historical.basic_account(address)
121 }
122}
123
124impl<N: NodePrimitives> StateRootProvider for MemoryOverlayStateProviderRef<'_, N> {
125 fn state_root(&self, state: HashedPostState) -> ProviderResult<B256> {
126 self.state_root_from_nodes(TrieInput::from_state(state))
127 }
128
129 fn state_root_from_nodes(&self, mut input: TrieInput) -> ProviderResult<B256> {
130 input.prepend_self(self.trie_input().clone());
131 self.historical.state_root_from_nodes(input)
132 }
133
134 fn state_root_with_updates(
135 &self,
136 state: HashedPostState,
137 ) -> ProviderResult<(B256, TrieUpdates)> {
138 self.state_root_from_nodes_with_updates(TrieInput::from_state(state))
139 }
140
141 fn state_root_from_nodes_with_updates(
142 &self,
143 mut input: TrieInput,
144 ) -> ProviderResult<(B256, TrieUpdates)> {
145 input.prepend_self(self.trie_input().clone());
146 self.historical.state_root_from_nodes_with_updates(input)
147 }
148}
149
150impl<N: NodePrimitives> StorageRootProvider for MemoryOverlayStateProviderRef<'_, N> {
151 fn storage_root(&self, address: Address, storage: HashedStorage) -> ProviderResult<B256> {
153 let merged = self.merged_hashed_storage(address, storage);
154 self.historical.storage_root(address, merged)
155 }
156
157 fn storage_proof(
159 &self,
160 address: Address,
161 slot: B256,
162 storage: HashedStorage,
163 ) -> ProviderResult<reth_trie::StorageProof> {
164 let merged = self.merged_hashed_storage(address, storage);
165 self.historical.storage_proof(address, slot, merged)
166 }
167
168 fn storage_multiproof(
170 &self,
171 address: Address,
172 slots: &[B256],
173 storage: HashedStorage,
174 ) -> ProviderResult<StorageMultiProof> {
175 let merged = self.merged_hashed_storage(address, storage);
176 self.historical.storage_multiproof(address, slots, merged)
177 }
178}
179
180impl<N: NodePrimitives> StateProofProvider for MemoryOverlayStateProviderRef<'_, N> {
181 fn proof(
182 &self,
183 mut input: TrieInput,
184 address: Address,
185 slots: &[B256],
186 ) -> ProviderResult<AccountProof> {
187 input.prepend_self(self.trie_input().clone());
188 self.historical.proof(input, address, slots)
189 }
190
191 fn multiproof(
192 &self,
193 mut input: TrieInput,
194 targets: MultiProofTargets,
195 ) -> ProviderResult<MultiProof> {
196 input.prepend_self(self.trie_input().clone());
197 self.historical.multiproof(input, targets)
198 }
199
200 fn witness(&self, mut input: TrieInput, target: HashedPostState) -> ProviderResult<Vec<Bytes>> {
201 input.prepend_self(self.trie_input().clone());
202 self.historical.witness(input, target)
203 }
204}
205
206impl<N: NodePrimitives> HashedPostStateProvider for MemoryOverlayStateProviderRef<'_, N> {
207 fn hashed_post_state(&self, bundle_state: &BundleState) -> HashedPostState {
208 self.historical.hashed_post_state(bundle_state)
209 }
210}
211
212impl<N: NodePrimitives> StateProvider for MemoryOverlayStateProviderRef<'_, N> {
213 fn storage(
214 &self,
215 address: Address,
216 storage_key: StorageKey,
217 ) -> ProviderResult<Option<StorageValue>> {
218 for block in self.in_memory.iter() {
219 if let Some(value) = block.execution_output.storage(&address, storage_key.into()) {
220 return Ok(Some(value));
221 }
222 }
223
224 self.historical.storage(address, storage_key)
225 }
226
227 fn storage_by_hashed_key(
228 &self,
229 address: Address,
230 hashed_storage_key: StorageKey,
231 ) -> ProviderResult<Option<StorageValue>> {
232 let hashed_address = keccak256(address);
233 let state = &self.trie_input().state;
234
235 if let Some(hs) = state.storages.get(&hashed_address) {
236 if let Some(value) = hs.storage.get(&hashed_storage_key) {
237 return Ok(Some(*value));
238 }
239 if hs.wiped {
240 return Ok(Some(StorageValue::ZERO));
241 }
242 }
243
244 self.historical.storage_by_hashed_key(address, hashed_storage_key)
245 }
246}
247
248impl<N: NodePrimitives> BytecodeReader for MemoryOverlayStateProviderRef<'_, N> {
249 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
250 for block in self.in_memory.iter() {
251 if let Some(contract) = block.execution_output.bytecode(code_hash) {
252 return Ok(Some(contract));
253 }
254 }
255
256 self.historical.bytecode_by_hash(code_hash)
257 }
258}
259
260#[expect(missing_debug_implementations)]
263pub struct MemoryOverlayStateProvider<N: NodePrimitives = reth_ethereum_primitives::EthPrimitives> {
264 pub(crate) historical: StateProviderBox,
266 pub(crate) in_memory: Vec<ExecutedBlock<N>>,
268 pub(crate) trie_input: OnceLock<TrieInput>,
270}
271
272impl<N: NodePrimitives> MemoryOverlayStateProvider<N> {
273 pub fn new(historical: StateProviderBox, in_memory: Vec<ExecutedBlock<N>>) -> Self {
281 Self { historical, in_memory, trie_input: OnceLock::new() }
282 }
283
284 #[inline(always)]
286 fn as_ref(&self) -> MemoryOverlayStateProviderRef<'_, N> {
287 MemoryOverlayStateProviderRef {
288 historical: Box::new(self.historical.as_ref()),
289 in_memory: Cow::Borrowed(&self.in_memory),
290 trie_input: self.trie_input.clone(),
291 }
292 }
293
294 pub fn boxed(self) -> StateProviderBox {
296 Box::new(self)
297 }
298}
299
300reth_storage_api::macros::delegate_provider_impls!(MemoryOverlayStateProvider<N> where [N: NodePrimitives]);