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, SEQUENCER_REGISTRY_CODE_REX6,
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 let code = if spec >= MegaSpecId::REX6 {
571 SEQUENCER_REGISTRY_CODE_REX6
572 } else {
573 SEQUENCER_REGISTRY_CODE
574 };
575 self.set_account_code(SEQUENCER_REGISTRY_ADDRESS, Bytecode::new_raw(code));
576 }
577 }
578}
579
580impl<N, P> EvmeState<N, P>
582where
583 N: Network,
584 P: Provider<N>,
585{
586 pub async fn new_forked(
589 provider: P,
590 fork_block: Option<u64>,
591 prestate: EvmState,
592 block_hashes: HashMap<u64, B256>,
593 ) -> Result<Self> {
594 let block_num = if let Some(block_num) = fork_block {
596 BlockNumber::from(block_num)
597 } else {
598 let latest_block = provider
600 .get_block_number()
601 .await
602 .map_err(|e| EvmeError::RpcError(format!("Failed to fetch latest block: {}", e)))?;
603 BlockNumber::from(latest_block)
604 };
605
606 let alloy_db = AlloyDB::new(provider, block_num.into());
608
609 let wrapped_db =
611 WrapDatabaseAsync::new(alloy_db).expect("Failed to create wrapped database");
612
613 let db = CacheDB::new(wrapped_db);
615
616 let code_map: HashMap<_, _> = prestate
618 .values()
619 .filter_map(|account| {
620 account.info.code.clone().map(|code| (account.info.code_hash, code))
621 })
622 .collect();
623
624 Ok(Self { backend: EvmeBackend::Forked(Box::new(db)), prestate, code_map, block_hashes })
625 }
626}
627
628impl<N, P> Database for EvmeState<N, P>
629where
630 N: Network,
631 P: Provider<N> + std::fmt::Debug,
632{
633 type Error = EvmeError;
634
635 fn basic(&mut self, address: Address) -> std::result::Result<Option<AccountInfo>, Self::Error> {
636 if let Some(account) = self.prestate.get(&address) {
638 trace!(address = %address, account = ?account, "Loaded account basic from prestate");
639 return Ok(Some(account.info.clone()));
640 }
641
642 match &mut self.backend {
644 EvmeBackend::Empty(db) => {
645 let account = db.basic(address).unwrap();
646 trace!(address = %address, account = ?account, "Loaded account basic from empty state");
647 Ok(account)
648 }
649 EvmeBackend::Forked(db) => {
650 let account = db.basic(address).map_err(|e| {
651 EvmeError::RpcError(format!("Failed to fetch account {}: {:?}", address, e))
652 })?;
653 trace!(address = %address, account = ?account, "Loaded account basic from forked state");
654 Ok(account)
655 }
656 }
657 }
658
659 fn code_by_hash(
660 &mut self,
661 code_hash: alloy_primitives::B256,
662 ) -> std::result::Result<Bytecode, Self::Error> {
663 if let Some(code) = self.code_map.get(&code_hash) {
665 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from prestate");
666 return Ok(code.clone());
667 }
668
669 match &mut self.backend {
671 EvmeBackend::Empty(db) => {
672 let code = db.code_by_hash(code_hash).unwrap();
673 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from empty state");
674 Ok(code)
675 }
676 EvmeBackend::Forked(db) => {
677 let code = db.code_by_hash(code_hash).map_err(|e| {
678 EvmeError::RpcError(format!(
679 "Failed to fetch code by hash {}: {:?}",
680 code_hash, e
681 ))
682 })?;
683 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from forked state");
684 Ok(code)
685 }
686 }
687 }
688
689 fn storage(&mut self, address: Address, index: U256) -> std::result::Result<U256, Self::Error> {
690 if let Some(account) = self.prestate.get(&address) {
692 if let Some(slot) = account.storage.get(&index) {
693 trace!(address = %address, index = %index, slot = %slot.present_value, "Loaded storage from prestate");
694 return Ok(slot.present_value);
695 }
696 }
697
698 match &mut self.backend {
700 EvmeBackend::Empty(db) => {
701 let storage = db.storage(address, index).unwrap();
702 trace!(address = %address, index = %index, storage = %storage, "Loaded storage from empty state");
703 Ok(storage)
704 }
705 EvmeBackend::Forked(db) => {
706 let storage = db.storage(address, index).map_err(|e| {
707 EvmeError::RpcError(format!(
708 "Failed to fetch storage for {} at slot {}: {:?}",
709 address, index, e
710 ))
711 })?;
712 trace!(address = %address, index = %index, storage = %storage, "Loaded storage from forked state");
713 Ok(storage)
714 }
715 }
716 }
717
718 fn block_hash(
719 &mut self,
720 number: u64,
721 ) -> std::result::Result<alloy_primitives::B256, Self::Error> {
722 if let Some(hash) = self.block_hashes.get(&number) {
724 trace!(number = %number, hash = %hash, "Loaded block hash from provided overrides");
725 return Ok(*hash);
726 }
727
728 match &mut self.backend {
730 EvmeBackend::Empty(db) => {
731 let hash = db.block_hash(number).unwrap();
732 trace!(number = %number, hash = %hash, "Loaded block hash from empty state");
733 Ok(hash)
734 }
735 EvmeBackend::Forked(db) => {
736 let hash = db.block_hash(number).map_err(|e| {
737 EvmeError::RpcError(format!(
738 "Failed to fetch block hash for block {}: {:?}",
739 number, e
740 ))
741 })?;
742 trace!(number = %number, hash = %hash, "Loaded block hash from forked state");
743 Ok(hash)
744 }
745 }
746 }
747}
748
749impl<N, P> DatabaseRef for EvmeState<N, P>
750where
751 N: Network,
752 P: Provider<N> + std::fmt::Debug,
753{
754 type Error = EvmeError;
755
756 fn basic_ref(&self, address: Address) -> std::result::Result<Option<AccountInfo>, Self::Error> {
757 if let Some(account) = self.prestate.get(&address) {
759 trace!(address = %address, account = ?account, "Loaded account basic from prestate");
760 return Ok(Some(account.info.clone()));
761 }
762
763 match &self.backend {
765 EvmeBackend::Empty(db) => {
766 let account = db.basic_ref(address).unwrap();
767 trace!(address = %address, account = ?account, "Loaded account basic from empty state");
768 Ok(account)
769 }
770 EvmeBackend::Forked(db) => {
771 let account = db.basic_ref(address).map_err(|e| {
772 EvmeError::RpcError(format!("Failed to fetch account {}: {:?}", address, e))
773 })?;
774 trace!(address = %address, account = ?account, "Loaded account basic from forked state");
775 Ok(account)
776 }
777 }
778 }
779
780 fn code_by_hash_ref(
781 &self,
782 code_hash: alloy_primitives::B256,
783 ) -> std::result::Result<Bytecode, Self::Error> {
784 if let Some(code) = self.code_map.get(&code_hash) {
786 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from prestate");
787 return Ok(code.clone());
788 }
789
790 match &self.backend {
792 EvmeBackend::Empty(db) => {
793 let code = db.code_by_hash_ref(code_hash).unwrap();
794 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from empty state");
795 Ok(code)
796 }
797 EvmeBackend::Forked(db) => {
798 let code = db.code_by_hash_ref(code_hash).map_err(|e| {
799 EvmeError::RpcError(format!(
800 "Failed to fetch code by hash {}: {:?}",
801 code_hash, e
802 ))
803 })?;
804 trace!(code_hash = %code_hash, code = ?code, "Loaded code by hash from forked state");
805 Ok(code)
806 }
807 }
808 }
809
810 fn storage_ref(&self, address: Address, index: U256) -> std::result::Result<U256, Self::Error> {
811 if let Some(account) = self.prestate.get(&address) {
813 if let Some(slot) = account.storage.get(&index) {
814 trace!(address = %address, index = %index, slot = %slot.present_value, "Loaded storage from prestate");
815 return Ok(slot.present_value);
816 }
817 }
818
819 match &self.backend {
821 EvmeBackend::Empty(db) => {
822 let storage = db.storage_ref(address, index).unwrap();
823 trace!(address = %address, index = %index, storage = %storage, "Loaded storage from empty state");
824 Ok(storage)
825 }
826 EvmeBackend::Forked(db) => {
827 let storage = db.storage_ref(address, index).map_err(|e| {
828 EvmeError::RpcError(format!(
829 "Failed to fetch storage for {} at slot {}: {:?}",
830 address, index, e
831 ))
832 })?;
833 trace!(address = %address, index = %index, storage = %storage, "Loaded storage from forked state");
834 Ok(storage)
835 }
836 }
837 }
838
839 fn block_hash_ref(
840 &self,
841 number: u64,
842 ) -> std::result::Result<alloy_primitives::B256, Self::Error> {
843 if let Some(hash) = self.block_hashes.get(&number) {
845 trace!(number = %number, hash = %hash, "Loaded block hash from provided overrides");
846 return Ok(*hash);
847 }
848
849 match &self.backend {
851 EvmeBackend::Empty(db) => {
852 let hash = db.block_hash_ref(number).unwrap();
853 trace!(number = %number, hash = %hash, "Loaded block hash from empty state");
854 Ok(hash)
855 }
856 EvmeBackend::Forked(db) => {
857 let hash = db.block_hash_ref(number).map_err(|e| {
858 EvmeError::RpcError(format!(
859 "Failed to fetch block hash for block {}: {:?}",
860 number, e
861 ))
862 })?;
863 trace!(number = %number, hash = %hash, "Loaded block hash from forked state");
864 Ok(hash)
865 }
866 }
867 }
868}