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
228impl<N: NodePrimitives> BytecodeReader for MemoryOverlayStateProviderRef<'_, N> {
229 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
230 for block in self.in_memory.iter() {
231 if let Some(contract) = block.execution_output.bytecode(code_hash) {
232 return Ok(Some(contract));
233 }
234 }
235
236 self.historical.bytecode_by_hash(code_hash)
237 }
238}
239
240#[expect(missing_debug_implementations)]
243pub struct MemoryOverlayStateProvider<N: NodePrimitives = reth_ethereum_primitives::EthPrimitives> {
244 pub(crate) historical: StateProviderBox,
246 pub(crate) in_memory: Vec<ExecutedBlock<N>>,
248 pub(crate) trie_input: OnceLock<TrieInput>,
250}
251
252impl<N: NodePrimitives> MemoryOverlayStateProvider<N> {
253 pub fn new(historical: StateProviderBox, in_memory: Vec<ExecutedBlock<N>>) -> Self {
261 Self { historical, in_memory, trie_input: OnceLock::new() }
262 }
263
264 #[inline(always)]
266 fn as_ref(&self) -> MemoryOverlayStateProviderRef<'_, N> {
267 MemoryOverlayStateProviderRef {
268 historical: Box::new(self.historical.as_ref()),
269 in_memory: Cow::Borrowed(&self.in_memory),
270 trie_input: self.trie_input.clone(),
271 }
272 }
273
274 pub fn boxed(self) -> StateProviderBox {
276 Box::new(self)
277 }
278}
279
280reth_storage_api::macros::delegate_provider_impls!(MemoryOverlayStateProvider<N> where [N: NodePrimitives]);