1use std::{collections::BTreeMap, path::PathBuf, str::FromStr};
4
5use alloy_network::Network;
6use alloy_primitives::{map::DefaultHashBuilder, Address, BlockNumber, Bytes, B256, U256};
7use alloy_provider::Provider;
8use clap::Parser;
9use op_alloy_network::Optimism;
10
11use mega_evm::revm::{
12 database::{AlloyDB, CacheDB, EmptyDB, WrapDatabaseAsync},
13 primitives::HashMap,
14 state::{Account, AccountInfo, Bytecode, EvmState, EvmStorageSlot},
15 Database, DatabaseRef,
16};
17use tracing::{debug, info, trace};
18
19use super::{EvmeError, Result, RpcCacheStore};
20
21#[derive(Parser, Debug, Clone)]
23#[command(next_help_heading = "State Options")]
24pub struct PreStateArgs {
25 #[arg(long = "fork")]
27 pub fork: bool,
28
29 #[arg(long = "fork.block")]
32 pub fork_block: Option<u64>,
33
34 #[arg(long = "prestate", visible_aliases = ["pre-state"])]
37 pub prestate: Option<PathBuf>,
38
39 #[arg(long = "block-hash", visible_aliases = ["blockhash", "block-hashes", "blockhashes"])]
43 pub block_hashes: Vec<String>,
44
45 #[arg(long = "sender.balance", visible_aliases = ["from.balance"])]
51 pub sender_balance: Option<String>,
52
53 #[arg(long = "faucet")]
58 pub faucet: Vec<String>,
59
60 #[arg(long = "balance")]
64 pub balance: Vec<String>,
65
66 #[arg(long = "storage")]
70 pub storage: Vec<String>,
71}
72
73pub fn parse_ether_value(s: &str) -> Result<U256> {
77 use alloy_primitives::utils::parse_units;
78
79 let s = s.trim();
80
81 let split_pos = s.find(|c: char| !c.is_ascii_digit() && c != '.').unwrap_or(s.len());
83
84 let (num_str, unit) = s.split_at(split_pos);
85 let unit = if unit.is_empty() { "wei" } else { unit };
86
87 let parsed = parse_units(num_str, unit)
88 .map_err(|e| EvmeError::InvalidInput(format!("Invalid ether value '{}': {}", s, e)))?;
89
90 Ok(parsed.into())
91}
92
93impl PreStateArgs {
94 pub fn parse_block_hashes(&self) -> Result<HashMap<u64, B256>> {
98 debug!("Parsing block hashes");
99 let mut map = HashMap::default();
100 for entry in &self.block_hashes {
101 let (num_str, hash_str) = entry.split_once(':').ok_or_else(|| {
102 EvmeError::InvalidInput(format!(
103 "Invalid block hash entry '{}': expected format 'block_number:block_hash'",
104 entry
105 ))
106 })?;
107 let block_num: u64 = num_str.trim().parse().map_err(|e| {
108 EvmeError::InvalidInput(format!(
109 "Invalid block number '{}' in entry '{}': {}",
110 num_str, entry, e
111 ))
112 })?;
113 let block_hash = B256::from_str(hash_str.trim()).map_err(|e| {
114 EvmeError::InvalidInput(format!(
115 "Invalid block hash '{}' in entry '{}': {}",
116 hash_str, entry, e
117 ))
118 })?;
119 map.insert(block_num, block_hash);
120 }
121 trace!(block_hashes = ?map, "Block hashes parsed");
122 Ok(map)
123 }
124
125 pub fn parse_faucet(&self) -> Result<Vec<(Address, U256)>> {
130 let mut entries = Vec::new();
131 for entry in &self.faucet {
132 let (addr_str, value_str) = entry.split_once("+=").ok_or_else(|| {
133 EvmeError::InvalidInput(format!(
134 "Invalid faucet entry '{}': expected format 'ADDRESS+=VALUE'",
135 entry
136 ))
137 })?;
138 let address = Address::from_str(addr_str.trim()).map_err(|e| {
139 EvmeError::InvalidInput(format!(
140 "Invalid address '{}' in faucet entry '{}': {}",
141 addr_str, entry, e
142 ))
143 })?;
144 let wei = parse_ether_value(value_str)?;
145 entries.push((address, wei));
146 }
147 Ok(entries)
148 }
149
150 pub fn parse_balance(&self) -> Result<Vec<(Address, U256)>> {
155 let mut entries = Vec::new();
156 for entry in &self.balance {
157 let (addr_str, value_str) = entry.split_once('=').ok_or_else(|| {
158 EvmeError::InvalidInput(format!(
159 "Invalid balance entry '{}': expected format 'ADDRESS=VALUE'",
160 entry
161 ))
162 })?;
163 let address = Address::from_str(addr_str.trim()).map_err(|e| {
164 EvmeError::InvalidInput(format!(
165 "Invalid address '{}' in balance entry '{}': {}",
166 addr_str, entry, e
167 ))
168 })?;
169 let wei = parse_ether_value(value_str)?;
170 entries.push((address, wei));
171 }
172 Ok(entries)
173 }
174
175 pub fn parse_storage(&self) -> Result<Vec<(Address, U256, U256)>> {
180 let mut entries = Vec::new();
181 for entry in &self.storage {
182 let (addr_str, rest) = entry.split_once(':').ok_or_else(|| {
183 EvmeError::InvalidInput(format!(
184 "Invalid storage entry '{}': expected format 'ADDRESS:SLOT=VALUE'",
185 entry
186 ))
187 })?;
188 let (slot_str, value_str) = rest.split_once('=').ok_or_else(|| {
189 EvmeError::InvalidInput(format!(
190 "Invalid storage entry '{}': expected format 'ADDRESS:SLOT=VALUE'",
191 entry
192 ))
193 })?;
194 let address = Address::from_str(addr_str.trim()).map_err(|e| {
195 EvmeError::InvalidInput(format!(
196 "Invalid address '{}' in storage entry '{}': {}",
197 addr_str, entry, e
198 ))
199 })?;
200 let slot = U256::from_str(slot_str.trim()).map_err(|e| {
201 EvmeError::InvalidInput(format!(
202 "Invalid slot '{}' in storage entry '{}': {}",
203 slot_str, entry, e
204 ))
205 })?;
206 let value = U256::from_str(value_str.trim()).map_err(|e| {
207 EvmeError::InvalidInput(format!(
208 "Invalid value '{}' in storage entry '{}': {}",
209 value_str, entry, e
210 ))
211 })?;
212 entries.push((address, slot, value));
213 }
214 Ok(entries)
215 }
216
217 pub fn load_prestate(&self, sender: &Address) -> Result<EvmState> {
219 let mut prestate = if let Some(pre_state_path) = &self.prestate {
220 info!(prestate_path = ?pre_state_path, "Loading prestate from file");
221 let prestate_content = std::fs::read_to_string(pre_state_path)?;
222 let loaded_prestate: HashMap<Address, AccountState> =
223 serde_json::from_str(&prestate_content).map_err(|e| {
224 EvmeError::InvalidInput(format!("Failed to parse prestate JSON: {}", e))
225 })?;
226 trace!(loaded_prestate = ?loaded_prestate, "Prestate loaded from file");
227 let mut prestate = EvmState::with_capacity_and_hasher(
228 loaded_prestate.len(),
229 DefaultHashBuilder::default(),
230 );
231 for (address, account_state) in loaded_prestate {
232 let account = account_state.into_account()?;
233 prestate.insert(address, account);
234 }
235 trace!(prestate = ?prestate, "Prestate loaded");
236 prestate
237 } else {
238 debug!("No prestate file provided");
239 HashMap::default()
240 };
241
242 for (address, balance) in self.parse_balance()? {
244 info!(address = %address, balance = %balance, "Overriding balance");
245 prestate.entry(address).or_default().info.balance = balance;
246 }
247
248 for (address, slot, value) in self.parse_storage()? {
250 info!(address = %address, slot = %slot, value = %value, "Overriding storage");
251 prestate
252 .entry(address)
253 .or_default()
254 .storage
255 .insert(slot, EvmStorageSlot::new(value, 0));
256 }
257
258 if let Some(sender_balance_str) = &self.sender_balance {
260 let sender_balance = parse_ether_value(sender_balance_str)?;
261 info!(sender = %sender, sender_balance = %sender_balance, "Overriding sender balance");
262 prestate.entry(*sender).or_default().info.set_balance(sender_balance);
263 }
264
265 for (address, balance) in self.parse_faucet()? {
267 info!(address = %address, balance = %balance, "Faucet: adding balance");
268 prestate.entry(address).or_default().info.balance += balance;
269 }
270
271 Ok(prestate)
272 }
273
274 pub async fn create_initial_state(
281 &self,
282 sender: &Address,
283 rpc_args: &super::RpcArgs,
284 ) -> Result<(EvmeState<Optimism, super::OpProvider>, RpcCacheStore)> {
285 let prestate = self.load_prestate(sender)?;
286 let block_hashes = self.parse_block_hashes()?;
287
288 if self.fork {
289 debug!("Creating forked state");
290 if rpc_args.rpc_url.is_none() {
291 return Err(EvmeError::InvalidInput("'--fork' requires '--rpc <URL>'".to_string()));
292 }
293 if rpc_args.capture_file.is_some() || rpc_args.replay_file.is_some() {
294 return Err(EvmeError::InvalidInput(
295 "'--rpc.capture-file' and '--rpc.replay-file' are not supported with '--fork' \
296 in this version"
297 .to_string(),
298 ));
299 }
300 let super::BuildProviderOutput { provider, cache_store, .. } =
301 rpc_args.build_provider().await?;
302 let state =
303 EvmeState::new_forked(provider, self.fork_block, prestate, block_hashes).await?;
304 Ok((state, cache_store))
305 } else {
306 debug!("Creating local state");
307 Ok((EvmeState::new_empty(prestate, block_hashes), RpcCacheStore::noop()))
308 }
309 }
310}
311
312#[derive(Parser, Debug, Clone)]
314#[command(next_help_heading = "State Dump Options")]
315pub struct StateDumpArgs {
316 #[arg(long = "dump")]
318 pub dump: bool,
319
320 #[arg(long = "dump.output")]
322 pub dump_output_file: Option<PathBuf>,
323}
324
325impl StateDumpArgs {
326 pub fn serialize_evm_state(&self, evm_state: &EvmState) -> Result<String> {
328 trace!(evm_state = ?evm_state, "Serializing EVM state");
329 let account_states: BTreeMap<_, _> = evm_state
330 .iter()
331 .map(|(address, account)| (address, AccountState::from_account(account.clone())))
332 .collect();
333 let state_json = serde_json::to_string_pretty(&account_states)
334 .map_err(|e| EvmeError::ExecutionError(format!("Failed to serialize state: {}", e)))?;
335 Ok(state_json)
336 }
337
338 pub fn dump_evm_state(&self, evm_state: &EvmState) -> Result<()> {
340 debug!("Dumping EVM state");
341 let state_json = self.serialize_evm_state(evm_state)?;
342
343 println!();
345 println!("=== State Dump ===");
346 if let Some(ref output_file) = self.dump_output_file {
347 debug!(output_file = ?output_file, "Writing dumped state to file");
348 std::fs::write(output_file, state_json).map_err(|e| {
349 EvmeError::ExecutionError(format!("Failed to write state to file: {}", e))
350 })?;
351 println!("State dump written to: {}", output_file.display());
352 } else {
353 debug!("Printing dumped state to console");
354 println!("{}", state_json);
355 }
356
357 Ok(())
358 }
359}
360
361#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
363#[serde(rename_all = "camelCase")]
364pub struct AccountState {
365 pub balance: Option<U256>,
368 #[serde(default, with = "alloy_serde::quantity::opt")]
370 pub nonce: Option<u64>,
371 pub code: Option<Bytes>,
373 pub code_hash: Option<B256>,
376 pub storage: Option<BTreeMap<U256, U256>>,
378}
379
380impl AccountState {
381 pub fn from_account(account: Account) -> Self {
389 let (code, code_hash) = match &account.info.code {
390 Some(bytecode) => {
391 let bytes: Bytes = bytecode.original_byte_slice().to_vec().into();
392 let hash = if bytes.is_empty() {
393 B256::from(alloy_primitives::KECCAK256_EMPTY)
394 } else {
395 alloy_primitives::keccak256(&bytes)
396 };
397 (Some(bytes), hash)
398 }
399 None => (None, account.info.code_hash),
401 };
402 let storage: BTreeMap<U256, U256> =
403 account.storage.into_iter().map(|(slot, value)| (slot, value.present_value)).collect();
404 Self {
405 balance: Some(account.info.balance),
406 nonce: Some(account.info.nonce),
407 code,
408 code_hash: Some(code_hash),
409 storage: Some(storage),
410 }
411 }
412
413 pub fn into_account(self) -> Result<Account> {
415 let code = self.code.unwrap_or_default();
416 let bytecode = if code.is_empty() {
417 Bytecode::default()
418 } else {
419 Bytecode::new_raw_checked(code).map_err(EvmeError::InvalidBytecode)?
420 };
421 let computed_hash = bytecode.hash_slow();
422 if let Some(code_hash) = self.code_hash {
423 if computed_hash != code_hash {
424 return Err(EvmeError::CodeHashMismatch {
425 expected: code_hash,
426 computed: computed_hash,
427 });
428 }
429 }
430
431 let info = AccountInfo::new(
432 self.balance.unwrap_or_default(),
433 self.nonce.unwrap_or_default(),
434 computed_hash,
435 bytecode,
436 );
437 let storage = self
438 .storage
439 .unwrap_or_default()
440 .into_iter()
441 .map(|(slot, value)| (slot, EvmStorageSlot::new(value, 0)));
442 Ok(Account::from(info).with_storage(storage))
443 }
444}
445
446#[derive(Debug)]
448enum EvmeBackend<N, P>
449where
450 N: Network,
451 P: Provider<N>,
452{
453 Empty(EmptyDB),
455 Forked(Box<CacheDB<WrapDatabaseAsync<AlloyDB<N, P>>>>),
457}
458
459#[derive(Debug)]
461pub struct EvmeState<N, P>
462where
463 N: Network,
464 P: Provider<N>,
465{
466 backend: EvmeBackend<N, P>,
468 prestate: EvmState,
470 code_map: HashMap<alloy_primitives::B256, Bytecode>,
472 block_hashes: HashMap<u64, B256>,
474}
475
476impl<N, P> EvmeState<N, P>
477where
478 N: Network,
479 P: Provider<N>,
480{
481 pub fn new_empty(prestate: EvmState, block_hashes: HashMap<u64, B256>) -> Self {
483 let code_map: HashMap<_, _> = prestate
485 .values()
486 .filter_map(|account| {
487 account.info.code.clone().map(|code| (account.info.code_hash, code))
488 })
489 .collect();
490
491 Self { backend: EvmeBackend::Empty(EmptyDB::default()), prestate, code_map, block_hashes }
492 }
493
494 pub fn insert_account(&mut self, address: Address, account: Account) {
497 if let Some(ref code) = account.info.code {
499 self.code_map.insert(account.info.code_hash, code.clone());
500 }
501 self.prestate.insert(address, account);
502 }
503
504 pub fn insert_storage(&mut self, address: Address, storage: HashMap<U256, EvmStorageSlot>) {
506 self.prestate.entry(address).or_default().storage.extend(storage);
507 }
508
509 pub fn insert_account_with_storage(
512 &mut self,
513 address: Address,
514 info: AccountInfo,
515 storage: HashMap<U256, EvmStorageSlot>,
516 ) {
517 if let Some(ref code) = info.code {
519 self.code_map.insert(info.code_hash, code.clone());
520 }
521 let account = Account::from(info).with_storage(storage.into_iter());
522 self.prestate.insert(address, account);
523 }
524
525 pub fn set_account_balance(&mut self, address: Address, balance: U256) {
527 self.prestate.entry(address).or_default().info.balance = balance;
528 }
529
530 pub fn set_account_nonce(&mut self, address: Address, nonce: u64) {
532 self.prestate.entry(address).or_default().info.nonce = nonce;
533 }
534
535 pub fn set_account_code(&mut self, address: Address, code: Bytecode) {
537 self.code_map.insert(code.hash_slow(), code.clone());
538 self.prestate.entry(address).or_default().info.set_code(code);
539 }
540
541 pub fn set_account_storage(&mut self, address: Address, storage: HashMap<U256, U256>) {
543 self.prestate
544 .entry(address)
545 .or_default()
546 .storage
547 .extend(storage.into_iter().map(|(slot, value)| (slot, EvmStorageSlot::new(value, 0))));
548 }
549
550 pub fn deploy_system_contracts(&mut self, spec: mega_evm::MegaSpecId) {
552 use mega_evm::{
553 flat_system_contract_specs, MegaSpecId, SEQUENCER_REGISTRY_ADDRESS,
554 SEQUENCER_REGISTRY_CODE,
555 };
556
557 for contract in flat_system_contract_specs(super::FixedHardfork::new(spec), 0) {
563 self.set_account_code(contract.address, Bytecode::new_raw(contract.code));
564 }
565
566 if spec >= MegaSpecId::REX5 {
570 self.set_account_code(
571 SEQUENCER_REGISTRY_ADDRESS,
572 Bytecode::new_raw(SEQUENCER_REGISTRY_CODE),
573 );
574 }
575 }
576}
577
578impl<N, P> EvmeState<N, P>
580where
581 N: Network,
582 P: Provider<N>,
583{
584 pub async fn new_forked(
587 provider: P,
588 fork_block: Option<u64>,
589 prestate: EvmState,
590 block_hashes: HashMap<u64, B256>,
591 ) -> Result<Self> {
592 let block_num = if let Some(block_num) = fork_block {
594 BlockNumber::from(block_num)
595 } else {
596 let latest_block = provider
598 .get_block_number()
599 .await
600 .map_err(|e| EvmeError::RpcError(format!("Failed to fetch latest block: {}", e)))?;
601 BlockNumber::from(latest_block)
602 };
603
604 let alloy_db = AlloyDB::new(provider, block_num.into());
606
607 let wrapped_db =
609 WrapDatabaseAsync::new(alloy_db).expect("Failed to create wrapped database");
610
611 let db = CacheDB::new(wrapped_db);
613
614 let code_map: HashMap<_, _> = prestate
616 .values()
617 .filter_map(|account| {
618 account.info.code.clone().map(|code| (account.info.code_hash, code))
619 })
620 .collect();
621
622 Ok(Self { backend: EvmeBackend::Forked(Box::new(db)), prestate, code_map, block_hashes })
623 }
624}
625
626impl<N, P> Database for EvmeState<N, P>
627where
628 N: Network,
629 P: Provider<N> + std::fmt::Debug,
630{
631 type Error = EvmeError;
632
633 fn basic(&mut self, address: Address) -> std::result::Result<Option<AccountInfo>, Self::Error> {
634 if let Some(account) = self.prestate.get(&address) {
636 trace!(address = %address, account = ?account, "Loaded account basic from prestate");
637 return Ok(Some(account.info.clone()));
638 }
639
640 match &mut self.backend {
642 EvmeBackend::Empty(db) => {
643 let account = db.basic(address).unwrap();
644 trace!(address = %address, account = ?account, "Loaded account basic from empty state");
645 Ok(account)
646 }
647 EvmeBackend::Forked(db) => {
648 let account = db.basic(address).map_err(|e| {
649 EvmeError::RpcError(format!("Failed to fetch account {}: {:?}", address, e))
650 })?;
651 trace!(address = %address, account = ?account, "Loaded account basic from forked state");
652 Ok(account)
653 }
654 }
655 }
656
657 fn code_by_hash(
658 &mut self,
659 code_hash: alloy_primitives::B256,
660 ) -> std::result::Result<Bytecode, Self::Error> {
661 if let Some(code) = self.code_map.get(&code_hash) {
663 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from prestate");
664 return Ok(code.clone());
665 }
666
667 match &mut self.backend {
669 EvmeBackend::Empty(db) => {
670 let code = db.code_by_hash(code_hash).unwrap();
671 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from empty state");
672 Ok(code)
673 }
674 EvmeBackend::Forked(db) => {
675 let code = db.code_by_hash(code_hash).map_err(|e| {
676 EvmeError::RpcError(format!(
677 "Failed to fetch code by hash {}: {:?}",
678 code_hash, e
679 ))
680 })?;
681 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from forked state");
682 Ok(code)
683 }
684 }
685 }
686
687 fn storage(&mut self, address: Address, index: U256) -> std::result::Result<U256, Self::Error> {
688 if let Some(account) = self.prestate.get(&address) {
690 if let Some(slot) = account.storage.get(&index) {
691 trace!(address = %address, index = %index, slot = %slot.present_value, "Loaded storage from prestate");
692 return Ok(slot.present_value);
693 }
694 }
695
696 match &mut self.backend {
698 EvmeBackend::Empty(db) => {
699 let storage = db.storage(address, index).unwrap();
700 trace!(address = %address, index = %index, storage = %storage, "Loaded storage from empty state");
701 Ok(storage)
702 }
703 EvmeBackend::Forked(db) => {
704 let storage = db.storage(address, index).map_err(|e| {
705 EvmeError::RpcError(format!(
706 "Failed to fetch storage for {} at slot {}: {:?}",
707 address, index, e
708 ))
709 })?;
710 trace!(address = %address, index = %index, storage = %storage, "Loaded storage from forked state");
711 Ok(storage)
712 }
713 }
714 }
715
716 fn block_hash(
717 &mut self,
718 number: u64,
719 ) -> std::result::Result<alloy_primitives::B256, Self::Error> {
720 if let Some(hash) = self.block_hashes.get(&number) {
722 trace!(number = %number, hash = %hash, "Loaded block hash from provided overrides");
723 return Ok(*hash);
724 }
725
726 match &mut self.backend {
728 EvmeBackend::Empty(db) => {
729 let hash = db.block_hash(number).unwrap();
730 trace!(number = %number, hash = %hash, "Loaded block hash from empty state");
731 Ok(hash)
732 }
733 EvmeBackend::Forked(db) => {
734 let hash = db.block_hash(number).map_err(|e| {
735 EvmeError::RpcError(format!(
736 "Failed to fetch block hash for block {}: {:?}",
737 number, e
738 ))
739 })?;
740 trace!(number = %number, hash = %hash, "Loaded block hash from forked state");
741 Ok(hash)
742 }
743 }
744 }
745}
746
747impl<N, P> DatabaseRef for EvmeState<N, P>
748where
749 N: Network,
750 P: Provider<N> + std::fmt::Debug,
751{
752 type Error = EvmeError;
753
754 fn basic_ref(&self, address: Address) -> std::result::Result<Option<AccountInfo>, Self::Error> {
755 if let Some(account) = self.prestate.get(&address) {
757 trace!(address = %address, account = ?account, "Loaded account basic from prestate");
758 return Ok(Some(account.info.clone()));
759 }
760
761 match &self.backend {
763 EvmeBackend::Empty(db) => {
764 let account = db.basic_ref(address).unwrap();
765 trace!(address = %address, account = ?account, "Loaded account basic from empty state");
766 Ok(account)
767 }
768 EvmeBackend::Forked(db) => {
769 let account = db.basic_ref(address).map_err(|e| {
770 EvmeError::RpcError(format!("Failed to fetch account {}: {:?}", address, e))
771 })?;
772 trace!(address = %address, account = ?account, "Loaded account basic from forked state");
773 Ok(account)
774 }
775 }
776 }
777
778 fn code_by_hash_ref(
779 &self,
780 code_hash: alloy_primitives::B256,
781 ) -> std::result::Result<Bytecode, Self::Error> {
782 if let Some(code) = self.code_map.get(&code_hash) {
784 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from prestate");
785 return Ok(code.clone());
786 }
787
788 match &self.backend {
790 EvmeBackend::Empty(db) => {
791 let code = db.code_by_hash_ref(code_hash).unwrap();
792 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from empty state");
793 Ok(code)
794 }
795 EvmeBackend::Forked(db) => {
796 let code = db.code_by_hash_ref(code_hash).map_err(|e| {
797 EvmeError::RpcError(format!(
798 "Failed to fetch code by hash {}: {:?}",
799 code_hash, e
800 ))
801 })?;
802 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from forked state");
803 Ok(code)
804 }
805 }
806 }
807
808 fn storage_ref(&self, address: Address, index: U256) -> std::result::Result<U256, Self::Error> {
809 if let Some(account) = self.prestate.get(&address) {
811 if let Some(slot) = account.storage.get(&index) {
812 trace!(address = %address, index = %index, slot = %slot.present_value, "Loaded storage from prestate");
813 return Ok(slot.present_value);
814 }
815 }
816
817 match &self.backend {
819 EvmeBackend::Empty(db) => {
820 let storage = db.storage_ref(address, index).unwrap();
821 trace!(address = %address, index = %index, storage = %storage, "Loaded storage from empty state");
822 Ok(storage)
823 }
824 EvmeBackend::Forked(db) => {
825 let storage = db.storage_ref(address, index).map_err(|e| {
826 EvmeError::RpcError(format!(
827 "Failed to fetch storage for {} at slot {}: {:?}",
828 address, index, e
829 ))
830 })?;
831 trace!(address = %address, index = %index, storage = %storage, "Loaded storage from forked state");
832 Ok(storage)
833 }
834 }
835 }
836
837 fn block_hash_ref(
838 &self,
839 number: u64,
840 ) -> std::result::Result<alloy_primitives::B256, Self::Error> {
841 if let Some(hash) = self.block_hashes.get(&number) {
843 trace!(number = %number, hash = %hash, "Loaded block hash from provided overrides");
844 return Ok(*hash);
845 }
846
847 match &self.backend {
849 EvmeBackend::Empty(db) => {
850 let hash = db.block_hash_ref(number).unwrap();
851 trace!(number = %number, hash = %hash, "Loaded block hash from empty state");
852 Ok(hash)
853 }
854 EvmeBackend::Forked(db) => {
855 let hash = db.block_hash_ref(number).map_err(|e| {
856 EvmeError::RpcError(format!(
857 "Failed to fetch block hash for block {}: {:?}",
858 number, e
859 ))
860 })?;
861 trace!(number = %number, hash = %hash, "Loaded block hash from forked state");
862 Ok(hash)
863 }
864 }
865 }
866}