1use self::state::trie_storage;
3use super::executor::new_evm_with_inspector;
4use crate::{
5 ForkChoice, NodeConfig, PrecompileFactory,
6 config::PruneStateHistoryConfig,
7 eth::{
8 backend::{
9 cheats::{CheatEcrecover, CheatsManager},
10 db::{Db, MaybeFullDatabase, SerializableState, StateDb},
11 env::Env,
12 executor::{ExecutedTransactions, TransactionExecutor},
13 fork::ClientFork,
14 genesis::GenesisConfig,
15 mem::{
16 state::{storage_root, trie_accounts},
17 storage::MinedTransactionReceipt,
18 },
19 notifications::{NewBlockNotification, NewBlockNotifications},
20 time::{TimeManager, utc_from_secs},
21 validate::TransactionValidator,
22 },
23 error::{BlockchainError, ErrDetail, InvalidTransactionError},
24 fees::{FeeDetails, FeeManager, MIN_SUGGESTED_PRIORITY_FEE},
25 macros::node_info,
26 pool::transactions::PoolTransaction,
27 sign::build_typed_transaction,
28 },
29 mem::{
30 inspector::AnvilInspector,
31 storage::{BlockchainStorage, InMemoryBlockStates, MinedBlockOutcome},
32 },
33};
34use alloy_chains::NamedChain;
35use alloy_consensus::{
36 Blob, BlockHeader, EnvKzgSettings, Header, Signed, Transaction as TransactionTrait,
37 TrieAccount, TxEnvelope, Typed2718,
38 proofs::{calculate_receipt_root, calculate_transaction_root},
39 transaction::Recovered,
40};
41use alloy_eips::{
42 BlockNumHash, Encodable2718, eip2935, eip4844::kzg_to_versioned_hash, eip7840::BlobParams,
43 eip7910::SystemContract,
44};
45use alloy_evm::{
46 Database, Evm, FromRecoveredTx,
47 eth::EthEvmContext,
48 overrides::{OverrideBlockHashes, apply_state_overrides},
49 precompiles::{DynPrecompile, Precompile, PrecompilesMap},
50};
51use alloy_network::{
52 AnyHeader, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTxEnvelope, AnyTxType,
53 ReceiptResponse, TransactionBuilder, UnknownTxEnvelope, UnknownTypedTransaction,
54};
55use alloy_primitives::{
56 Address, B256, Bytes, TxHash, TxKind, U64, U256, hex, keccak256, logs_bloom,
57 map::{AddressMap, HashMap, HashSet},
58};
59use alloy_rpc_types::{
60 AccessList, Block as AlloyBlock, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,
61 EIP1186AccountProofResponse as AccountProof, EIP1186StorageProof as StorageProof, Filter,
62 Header as AlloyHeader, Index, Log, Transaction, TransactionReceipt,
63 anvil::Forking,
64 request::TransactionRequest,
65 serde_helpers::JsonStorageKey,
66 simulate::{SimBlock, SimCallResult, SimulatePayload, SimulatedBlock},
67 state::EvmOverrides,
68 trace::{
69 filter::TraceFilter,
70 geth::{
71 FourByteFrame, GethDebugBuiltInTracerType, GethDebugTracerType,
72 GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, NoopFrame,
73 },
74 parity::{LocalizedTransactionTrace, TraceResultsWithTransactionHash, TraceType},
75 },
76};
77use alloy_serde::{OtherFields, WithOtherFields};
78use alloy_signer::Signature;
79use alloy_trie::{HashBuilder, Nibbles, proof::ProofRetainer};
80use anvil_core::eth::{
81 block::{Block, BlockInfo},
82 transaction::{MaybeImpersonatedTransaction, PendingTransaction, TransactionInfo},
83};
84use anvil_rpc::error::RpcError;
85use chrono::Datelike;
86use eyre::{Context, Result};
87use flate2::{Compression, read::GzDecoder, write::GzEncoder};
88use foundry_evm::{
89 backend::{DatabaseError, DatabaseResult, RevertStateSnapshotAction},
90 constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE,
91 core::{either_evm::EitherEvm, precompiles::EC_RECOVER},
92 decode::RevertDecoder,
93 inspectors::AccessListInspector,
94 traces::{
95 CallTraceDecoder, FourByteInspector, GethTraceBuilder, TracingInspector,
96 TracingInspectorConfig,
97 },
98 utils::{get_blob_base_fee_update_fraction, get_blob_base_fee_update_fraction_by_spec_id},
99};
100use foundry_primitives::{
101 FoundryReceiptEnvelope, FoundryTransactionRequest, FoundryTxEnvelope, FoundryTxReceipt,
102 get_deposit_tx_parts,
103};
104use futures::channel::mpsc::{UnboundedSender, unbounded};
105use op_alloy_consensus::DEPOSIT_TX_TYPE_ID;
106use op_revm::{OpContext, OpHaltReason, OpTransaction};
107use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
108use revm::{
109 DatabaseCommit, Inspector,
110 context::{Block as RevmBlock, BlockEnv, Cfg, TxEnv},
111 context_interface::{
112 block::BlobExcessGasAndPrice,
113 result::{ExecutionResult, Output, ResultAndState},
114 },
115 database::{CacheDB, DbAccount, WrapDatabaseRef},
116 interpreter::InstructionResult,
117 precompile::{PrecompileSpecId, Precompiles},
118 primitives::{KECCAK_EMPTY, hardfork::SpecId},
119 state::AccountInfo,
120};
121use std::{
122 collections::BTreeMap,
123 fmt::Debug,
124 io::{Read, Write},
125 ops::{Mul, Not},
126 path::PathBuf,
127 sync::Arc,
128 time::Duration,
129};
130use storage::{Blockchain, DEFAULT_HISTORY_LIMIT, MinedTransaction};
131use tokio::sync::RwLock as AsyncRwLock;
132
133pub mod cache;
134pub mod fork_db;
135pub mod in_memory_db;
136pub mod inspector;
137pub mod state;
138pub mod storage;
139
140pub trait DatabaseRef: revm::DatabaseRef<Error = DatabaseError> + Debug {}
144impl<T> DatabaseRef for T where T: revm::DatabaseRef<Error = DatabaseError> + Debug {}
145impl DatabaseRef for dyn crate::eth::backend::db::Db {}
146
147pub const MIN_TRANSACTION_GAS: u128 = 21000;
149pub const MIN_CREATE_GAS: u128 = 53000;
151
152pub type State = foundry_evm::utils::StateChangeset;
153
154#[derive(Debug)]
156pub enum BlockRequest {
157 Pending(Vec<Arc<PoolTransaction>>),
158 Number(u64),
159}
160
161impl BlockRequest {
162 pub fn block_number(&self) -> BlockNumber {
163 match *self {
164 Self::Pending(_) => BlockNumber::Pending,
165 Self::Number(n) => BlockNumber::Number(n),
166 }
167 }
168}
169
170#[derive(Clone, Debug)]
172pub struct Backend {
173 db: Arc<AsyncRwLock<Box<dyn Db>>>,
193 blockchain: Blockchain,
195 states: Arc<RwLock<InMemoryBlockStates>>,
197 env: Arc<RwLock<Env>>,
199 fork: Arc<RwLock<Option<ClientFork>>>,
201 time: TimeManager,
203 cheats: CheatsManager,
205 fees: FeeManager,
207 genesis: GenesisConfig,
209 new_block_listeners: Arc<Mutex<Vec<UnboundedSender<NewBlockNotification>>>>,
211 active_state_snapshots: Arc<Mutex<HashMap<U256, (u64, B256)>>>,
213 enable_steps_tracing: bool,
214 print_logs: bool,
215 print_traces: bool,
216 call_trace_decoder: Arc<CallTraceDecoder>,
218 prune_state_history_config: PruneStateHistoryConfig,
220 transaction_block_keeper: Option<usize>,
222 node_config: Arc<AsyncRwLock<NodeConfig>>,
223 slots_in_an_epoch: u64,
225 precompile_factory: Option<Arc<dyn PrecompileFactory>>,
227 mining: Arc<tokio::sync::Mutex<()>>,
229 disable_pool_balance_checks: bool,
231}
232
233impl Backend {
234 #[expect(clippy::too_many_arguments)]
236 pub async fn with_genesis(
237 db: Arc<AsyncRwLock<Box<dyn Db>>>,
238 env: Arc<RwLock<Env>>,
239 genesis: GenesisConfig,
240 fees: FeeManager,
241 fork: Arc<RwLock<Option<ClientFork>>>,
242 enable_steps_tracing: bool,
243 print_logs: bool,
244 print_traces: bool,
245 call_trace_decoder: Arc<CallTraceDecoder>,
246 prune_state_history_config: PruneStateHistoryConfig,
247 max_persisted_states: Option<usize>,
248 transaction_block_keeper: Option<usize>,
249 automine_block_time: Option<Duration>,
250 cache_path: Option<PathBuf>,
251 node_config: Arc<AsyncRwLock<NodeConfig>>,
252 ) -> Result<Self> {
253 let blockchain = if let Some(fork) = fork.read().as_ref() {
255 trace!(target: "backend", "using forked blockchain at {}", fork.block_number());
256 Blockchain::forked(fork.block_number(), fork.block_hash(), fork.total_difficulty())
257 } else {
258 let env = env.read();
259 Blockchain::new(
260 &env,
261 env.evm_env.cfg_env.spec,
262 fees.is_eip1559().then(|| fees.base_fee()),
263 genesis.timestamp,
264 genesis.number,
265 )
266 };
267
268 if fork.read().is_none() {
271 let mut write_env = env.write();
272 write_env.evm_env.block_env.number = U256::from(genesis.number);
273 }
274
275 let start_timestamp = if let Some(fork) = fork.read().as_ref() {
276 fork.timestamp()
277 } else {
278 genesis.timestamp
279 };
280
281 let mut states = if prune_state_history_config.is_config_enabled() {
282 prune_state_history_config
284 .max_memory_history
285 .map(|limit| InMemoryBlockStates::new(limit, 0))
286 .unwrap_or_default()
287 .memory_only()
288 } else if max_persisted_states.is_some() {
289 max_persisted_states
290 .map(|limit| InMemoryBlockStates::new(DEFAULT_HISTORY_LIMIT, limit))
291 .unwrap_or_default()
292 } else {
293 Default::default()
294 };
295
296 if let Some(cache_path) = cache_path {
297 states = states.disk_path(cache_path);
298 }
299
300 let (slots_in_an_epoch, precompile_factory, disable_pool_balance_checks) = {
301 let cfg = node_config.read().await;
302 (cfg.slots_in_an_epoch, cfg.precompile_factory.clone(), cfg.disable_pool_balance_checks)
303 };
304
305 let backend = Self {
306 db,
307 blockchain,
308 states: Arc::new(RwLock::new(states)),
309 env,
310 fork,
311 time: TimeManager::new(start_timestamp),
312 cheats: Default::default(),
313 new_block_listeners: Default::default(),
314 fees,
315 genesis,
316 active_state_snapshots: Arc::new(Mutex::new(Default::default())),
317 enable_steps_tracing,
318 print_logs,
319 print_traces,
320 call_trace_decoder,
321 prune_state_history_config,
322 transaction_block_keeper,
323 node_config,
324 slots_in_an_epoch,
325 precompile_factory,
326 mining: Arc::new(tokio::sync::Mutex::new(())),
327 disable_pool_balance_checks,
328 };
329
330 if let Some(interval_block_time) = automine_block_time {
331 backend.update_interval_mine_block_time(interval_block_time);
332 }
333
334 backend.apply_genesis().await.wrap_err("failed to create genesis")?;
336 Ok(backend)
337 }
338
339 pub async fn set_create2_deployer(&self, address: Address) -> DatabaseResult<()> {
341 self.set_code(address, Bytes::from_static(DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE)).await?;
342
343 Ok(())
344 }
345
346 pub(crate) fn update_interval_mine_block_time(&self, block_time: Duration) {
348 self.states.write().update_interval_mine_block_time(block_time)
349 }
350
351 async fn apply_genesis(&self) -> Result<(), DatabaseError> {
355 trace!(target: "backend", "setting genesis balances");
356
357 if self.fork.read().is_some() {
358 let mut genesis_accounts_futures = Vec::with_capacity(self.genesis.accounts.len());
360 for address in self.genesis.accounts.iter().copied() {
361 let db = Arc::clone(&self.db);
362
363 genesis_accounts_futures.push(tokio::task::spawn(async move {
366 let db = db.read().await;
367 let info = db.basic_ref(address)?.unwrap_or_default();
368 Ok::<_, DatabaseError>((address, info))
369 }));
370 }
371
372 let genesis_accounts = futures::future::join_all(genesis_accounts_futures).await;
373
374 let mut db = self.db.write().await;
375
376 for res in genesis_accounts {
377 let (address, mut info) = res.unwrap()?;
378 info.balance = self.genesis.balance;
379 db.insert_account(address, info.clone());
380 }
381 } else {
382 let mut db = self.db.write().await;
383 for (account, info) in self.genesis.account_infos() {
384 db.insert_account(account, info);
385 }
386
387 db.insert_block_hash(U256::from(self.best_number()), self.best_hash());
390
391 if self.spec_id() >= SpecId::PRAGUE {
393 db.set_code(
394 eip2935::HISTORY_STORAGE_ADDRESS,
395 eip2935::HISTORY_STORAGE_CODE.clone(),
396 )?;
397 }
398 }
399
400 let db = self.db.write().await;
401 self.genesis.apply_genesis_json_alloc(db)?;
403
404 trace!(target: "backend", "set genesis balances");
405
406 Ok(())
407 }
408
409 pub fn impersonate(&self, addr: Address) -> bool {
413 if self.cheats.impersonated_accounts().contains(&addr) {
414 return true;
415 }
416 let mut env = self.env.write();
418 env.evm_env.cfg_env.disable_eip3607 = true;
419 self.cheats.impersonate(addr)
420 }
421
422 pub fn stop_impersonating(&self, addr: Address) {
426 self.cheats.stop_impersonating(&addr);
427 }
428
429 pub fn auto_impersonate_account(&self, enabled: bool) {
431 self.cheats.set_auto_impersonate_account(enabled);
432 }
433
434 pub fn get_fork(&self) -> Option<ClientFork> {
436 self.fork.read().clone()
437 }
438
439 pub fn get_db(&self) -> &Arc<AsyncRwLock<Box<dyn Db>>> {
441 &self.db
442 }
443
444 pub async fn get_account(&self, address: Address) -> DatabaseResult<AccountInfo> {
446 Ok(self.db.read().await.basic_ref(address)?.unwrap_or_default())
447 }
448
449 pub fn is_fork(&self) -> bool {
451 self.fork.read().is_some()
452 }
453
454 pub async fn reset_fork(&self, forking: Forking) -> Result<(), BlockchainError> {
456 if !self.is_fork() {
457 if let Some(eth_rpc_url) = forking.clone().json_rpc_url {
458 let mut env = self.env.read().clone();
459
460 let (db, config) = {
461 let mut node_config = self.node_config.write().await;
462
463 node_config.base_fee.take();
466
467 node_config.setup_fork_db_config(eth_rpc_url, &mut env, &self.fees).await?
468 };
469
470 *self.db.write().await = Box::new(db);
471
472 let fork = ClientFork::new(config, Arc::clone(&self.db));
473
474 *self.env.write() = env;
475 *self.fork.write() = Some(fork);
476 } else {
477 return Err(RpcError::invalid_params(
478 "Forking not enabled and RPC URL not provided to start forking",
479 )
480 .into());
481 }
482 }
483
484 if let Some(fork) = self.get_fork() {
485 let block_number =
486 forking.block_number.map(BlockNumber::from).unwrap_or(BlockNumber::Latest);
487 fork.reset(forking.json_rpc_url.clone(), block_number).await?;
489 let fork_block_number = fork.block_number();
490 let fork_block = fork
491 .block_by_number(fork_block_number)
492 .await?
493 .ok_or(BlockchainError::BlockNotFound)?;
494 {
496 if let Some(fork_url) = forking.json_rpc_url {
497 self.reset_block_number(fork_url, fork_block_number).await?;
498 } else {
499 {
502 let maybe_fork_url = { self.node_config.read().await.eth_rpc_url.clone() };
503 if let Some(fork_url) = maybe_fork_url {
504 self.reset_block_number(fork_url, fork_block_number).await?;
505 }
506 }
507
508 let gas_limit = self.node_config.read().await.fork_gas_limit(&fork_block);
509 let mut env = self.env.write();
510
511 env.evm_env.cfg_env.chain_id = fork.chain_id();
512 env.evm_env.block_env = BlockEnv {
513 number: U256::from(fork_block_number),
514 timestamp: U256::from(fork_block.header.timestamp),
515 gas_limit,
516 difficulty: fork_block.header.difficulty,
517 prevrandao: Some(fork_block.header.mix_hash.unwrap_or_default()),
518 beneficiary: env.evm_env.block_env.beneficiary,
520 basefee: env.evm_env.block_env.basefee,
521 ..env.evm_env.block_env.clone()
522 };
523
524 let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(
527 fork_block.header.gas_used,
528 gas_limit,
529 fork_block.header.base_fee_per_gas.unwrap_or_default(),
530 );
531
532 self.fees.set_base_fee(next_block_base_fee);
533 }
534
535 self.time.reset(fork_block.header.timestamp);
537
538 self.blockchain.storage.write().total_difficulty = fork.total_difficulty();
540 }
541 *self.blockchain.storage.write() = BlockchainStorage::forked(
543 fork.block_number(),
544 fork.block_hash(),
545 fork.total_difficulty(),
546 );
547 self.states.write().clear();
548 self.db.write().await.clear();
549
550 self.apply_genesis().await?;
551
552 trace!(target: "backend", "reset fork");
553
554 Ok(())
555 } else {
556 Err(RpcError::invalid_params("Forking not enabled").into())
557 }
558 }
559
560 pub async fn reset_to_in_mem(&self) -> Result<(), BlockchainError> {
562 *self.fork.write() = None;
564
565 let env = self.env.read().clone();
567 let genesis_timestamp = self.genesis.timestamp;
568 let genesis_number = self.genesis.number;
569 let spec_id = self.spec_id();
570
571 {
573 let mut env = self.env.write();
574 env.evm_env.block_env.number = U256::from(genesis_number);
575 env.evm_env.block_env.timestamp = U256::from(genesis_timestamp);
576 env.evm_env.block_env.basefee = self.fees.base_fee();
578 env.evm_env.block_env.prevrandao = Some(B256::ZERO);
579 }
580
581 let base_fee = if self.fees.is_eip1559() { Some(self.fees.base_fee()) } else { None };
583 *self.blockchain.storage.write() =
584 BlockchainStorage::new(&env, spec_id, base_fee, genesis_timestamp, genesis_number);
585 self.states.write().clear();
586
587 self.db.write().await.clear();
589
590 self.time.reset(genesis_timestamp);
592
593 if self.fees.is_eip1559() {
595 self.fees.set_base_fee(crate::eth::fees::INITIAL_BASE_FEE);
596 }
597
598 self.fees.set_gas_price(crate::eth::fees::INITIAL_GAS_PRICE);
599
600 self.apply_genesis().await?;
602
603 trace!(target: "backend", "reset to fresh in-memory state");
604
605 Ok(())
606 }
607
608 async fn reset_block_number(
609 &self,
610 fork_url: String,
611 fork_block_number: u64,
612 ) -> Result<(), BlockchainError> {
613 let mut node_config = self.node_config.write().await;
614 node_config.fork_choice = Some(ForkChoice::Block(fork_block_number as i128));
615
616 let mut env = self.env.read().clone();
617 let (forked_db, client_fork_config) =
618 node_config.setup_fork_db_config(fork_url, &mut env, &self.fees).await?;
619
620 *self.db.write().await = Box::new(forked_db);
621 let fork = ClientFork::new(client_fork_config, Arc::clone(&self.db));
622 *self.fork.write() = Some(fork);
623 *self.env.write() = env;
624
625 Ok(())
626 }
627
628 pub fn time(&self) -> &TimeManager {
630 &self.time
631 }
632
633 pub fn cheats(&self) -> &CheatsManager {
635 &self.cheats
636 }
637
638 pub fn skip_blob_validation(&self, impersonator: Option<Address>) -> bool {
640 self.cheats().auto_impersonate_accounts()
641 || impersonator
642 .is_some_and(|addr| self.cheats().impersonated_accounts().contains(&addr))
643 }
644
645 pub fn fees(&self) -> &FeeManager {
647 &self.fees
648 }
649
650 pub fn env(&self) -> &Arc<RwLock<Env>> {
652 &self.env
653 }
654
655 pub fn best_hash(&self) -> B256 {
657 self.blockchain.storage.read().best_hash
658 }
659
660 pub fn best_number(&self) -> u64 {
662 self.blockchain.storage.read().best_number
663 }
664
665 pub fn set_block_number(&self, number: u64) {
667 let mut env = self.env.write();
668 env.evm_env.block_env.number = U256::from(number);
669 }
670
671 pub fn coinbase(&self) -> Address {
673 self.env.read().evm_env.block_env.beneficiary
674 }
675
676 pub fn chain_id(&self) -> U256 {
678 U256::from(self.env.read().evm_env.cfg_env.chain_id)
679 }
680
681 pub fn set_chain_id(&self, chain_id: u64) {
682 self.env.write().evm_env.cfg_env.chain_id = chain_id;
683 }
684
685 pub fn genesis_time(&self) -> u64 {
687 self.genesis.timestamp
688 }
689
690 pub async fn current_balance(&self, address: Address) -> DatabaseResult<U256> {
692 Ok(self.get_account(address).await?.balance)
693 }
694
695 pub async fn current_nonce(&self, address: Address) -> DatabaseResult<u64> {
697 Ok(self.get_account(address).await?.nonce)
698 }
699
700 pub fn set_coinbase(&self, address: Address) {
702 self.env.write().evm_env.block_env.beneficiary = address;
703 }
704
705 pub async fn set_nonce(&self, address: Address, nonce: U256) -> DatabaseResult<()> {
707 self.db.write().await.set_nonce(address, nonce.try_into().unwrap_or(u64::MAX))
708 }
709
710 pub async fn set_balance(&self, address: Address, balance: U256) -> DatabaseResult<()> {
712 self.db.write().await.set_balance(address, balance)
713 }
714
715 pub async fn set_code(&self, address: Address, code: Bytes) -> DatabaseResult<()> {
717 self.db.write().await.set_code(address, code)
718 }
719
720 pub async fn set_storage_at(
722 &self,
723 address: Address,
724 slot: U256,
725 val: B256,
726 ) -> DatabaseResult<()> {
727 self.db.write().await.set_storage_at(address, slot.into(), val)
728 }
729
730 pub fn spec_id(&self) -> SpecId {
732 self.env.read().evm_env.cfg_env.spec
733 }
734
735 pub fn is_eip1559(&self) -> bool {
737 (self.spec_id() as u8) >= (SpecId::LONDON as u8)
738 }
739
740 pub fn is_eip3675(&self) -> bool {
742 (self.spec_id() as u8) >= (SpecId::MERGE as u8)
743 }
744
745 pub fn is_eip2930(&self) -> bool {
747 (self.spec_id() as u8) >= (SpecId::BERLIN as u8)
748 }
749
750 pub fn is_eip4844(&self) -> bool {
752 (self.spec_id() as u8) >= (SpecId::CANCUN as u8)
753 }
754
755 pub fn is_eip7702(&self) -> bool {
757 (self.spec_id() as u8) >= (SpecId::PRAGUE as u8)
758 }
759
760 pub fn is_optimism(&self) -> bool {
762 self.env.read().networks.is_optimism()
763 }
764
765 pub fn precompiles(&self) -> BTreeMap<String, Address> {
767 let spec_id = self.env.read().evm_env.cfg_env.spec;
768 let precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec_id));
769
770 let mut precompiles_map = BTreeMap::<String, Address>::default();
771 for (address, precompile) in precompiles.inner() {
772 precompiles_map.insert(precompile.id().name().to_string(), *address);
773 }
774
775 precompiles_map.extend(self.env.read().networks.precompiles());
777
778 if let Some(factory) = &self.precompile_factory {
779 for (address, precompile) in factory.precompiles() {
780 precompiles_map.insert(precompile.precompile_id().to_string(), address);
781 }
782 }
783
784 precompiles_map
785 }
786
787 pub fn system_contracts(&self) -> BTreeMap<SystemContract, Address> {
789 let mut system_contracts = BTreeMap::<SystemContract, Address>::default();
790
791 let spec_id = self.env.read().evm_env.cfg_env.spec;
792
793 if spec_id >= SpecId::CANCUN {
794 system_contracts.extend(SystemContract::cancun());
795 }
796
797 if spec_id >= SpecId::PRAGUE {
798 system_contracts.extend(SystemContract::prague(None));
799 }
800
801 system_contracts
802 }
803
804 pub fn blob_params(&self) -> BlobParams {
806 let spec_id = self.env.read().evm_env.cfg_env.spec;
807
808 if spec_id >= SpecId::OSAKA {
809 return BlobParams::osaka();
810 }
811
812 if spec_id >= SpecId::PRAGUE {
813 return BlobParams::prague();
814 }
815
816 BlobParams::cancun()
817 }
818
819 pub fn ensure_eip1559_active(&self) -> Result<(), BlockchainError> {
821 if self.is_eip1559() {
822 return Ok(());
823 }
824 Err(BlockchainError::EIP1559TransactionUnsupportedAtHardfork)
825 }
826
827 pub fn ensure_eip2930_active(&self) -> Result<(), BlockchainError> {
829 if self.is_eip2930() {
830 return Ok(());
831 }
832 Err(BlockchainError::EIP2930TransactionUnsupportedAtHardfork)
833 }
834
835 pub fn ensure_eip4844_active(&self) -> Result<(), BlockchainError> {
836 if self.is_eip4844() {
837 return Ok(());
838 }
839 Err(BlockchainError::EIP4844TransactionUnsupportedAtHardfork)
840 }
841
842 pub fn ensure_eip7702_active(&self) -> Result<(), BlockchainError> {
843 if self.is_eip7702() {
844 return Ok(());
845 }
846 Err(BlockchainError::EIP7702TransactionUnsupportedAtHardfork)
847 }
848
849 pub fn ensure_op_deposits_active(&self) -> Result<(), BlockchainError> {
851 if self.is_optimism() {
852 return Ok(());
853 }
854 Err(BlockchainError::DepositTransactionUnsupported)
855 }
856
857 pub fn gas_limit(&self) -> u64 {
859 self.env.read().evm_env.block_env.gas_limit
860 }
861
862 pub fn set_gas_limit(&self, gas_limit: u64) {
864 self.env.write().evm_env.block_env.gas_limit = gas_limit;
865 }
866
867 pub fn base_fee(&self) -> u64 {
869 self.fees.base_fee()
870 }
871
872 pub fn is_min_priority_fee_enforced(&self) -> bool {
874 self.fees.is_min_priority_fee_enforced()
875 }
876
877 pub fn excess_blob_gas_and_price(&self) -> Option<BlobExcessGasAndPrice> {
878 self.fees.excess_blob_gas_and_price()
879 }
880
881 pub fn set_base_fee(&self, basefee: u64) {
883 self.fees.set_base_fee(basefee)
884 }
885
886 pub fn set_gas_price(&self, price: u128) {
888 self.fees.set_gas_price(price)
889 }
890
891 pub fn elasticity(&self) -> f64 {
892 self.fees.elasticity()
893 }
894
895 pub fn total_difficulty(&self) -> U256 {
900 self.blockchain.storage.read().total_difficulty
901 }
902
903 pub async fn create_state_snapshot(&self) -> U256 {
907 let num = self.best_number();
908 let hash = self.best_hash();
909 let id = self.db.write().await.snapshot_state();
910 trace!(target: "backend", "creating snapshot {} at {}", id, num);
911 self.active_state_snapshots.lock().insert(id, (num, hash));
912 id
913 }
914
915 pub async fn revert_state_snapshot(&self, id: U256) -> Result<bool, BlockchainError> {
917 let block = { self.active_state_snapshots.lock().remove(&id) };
918 if let Some((num, hash)) = block {
919 let best_block_hash = {
920 let current_height = self.best_number();
922 let mut storage = self.blockchain.storage.write();
923
924 for n in ((num + 1)..=current_height).rev() {
925 trace!(target: "backend", "reverting block {}", n);
926 if let Some(hash) = storage.hashes.remove(&n)
927 && let Some(block) = storage.blocks.remove(&hash)
928 {
929 for tx in block.body.transactions {
930 let _ = storage.transactions.remove(&tx.hash());
931 }
932 }
933 }
934
935 storage.best_number = num;
936 storage.best_hash = hash;
937 hash
938 };
939 let block =
940 self.block_by_hash(best_block_hash).await?.ok_or(BlockchainError::BlockNotFound)?;
941
942 let reset_time = block.header.timestamp;
943 self.time.reset(reset_time);
944
945 let mut env = self.env.write();
946 env.evm_env.block_env = BlockEnv {
947 number: U256::from(num),
948 timestamp: U256::from(block.header.timestamp),
949 difficulty: block.header.difficulty,
950 prevrandao: Some(block.header.mix_hash.unwrap_or_default()),
952 gas_limit: block.header.gas_limit,
953 beneficiary: env.evm_env.block_env.beneficiary,
955 basefee: env.evm_env.block_env.basefee,
956 ..Default::default()
957 }
958 }
959 Ok(self.db.write().await.revert_state(id, RevertStateSnapshotAction::RevertRemove))
960 }
961
962 pub fn list_state_snapshots(&self) -> BTreeMap<U256, (u64, B256)> {
963 self.active_state_snapshots.lock().clone().into_iter().collect()
964 }
965
966 pub async fn serialized_state(
968 &self,
969 preserve_historical_states: bool,
970 ) -> Result<SerializableState, BlockchainError> {
971 let at = self.env.read().evm_env.block_env.clone();
972 let best_number = self.blockchain.storage.read().best_number;
973 let blocks = self.blockchain.storage.read().serialized_blocks();
974 let transactions = self.blockchain.storage.read().serialized_transactions();
975 let historical_states = if preserve_historical_states {
976 Some(self.states.write().serialized_states())
977 } else {
978 None
979 };
980
981 let state = self.db.read().await.dump_state(
982 at,
983 best_number,
984 blocks,
985 transactions,
986 historical_states,
987 )?;
988 state.ok_or_else(|| {
989 RpcError::invalid_params("Dumping state not supported with the current configuration")
990 .into()
991 })
992 }
993
994 pub async fn dump_state(
996 &self,
997 preserve_historical_states: bool,
998 ) -> Result<Bytes, BlockchainError> {
999 let state = self.serialized_state(preserve_historical_states).await?;
1000 let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
1001 encoder
1002 .write_all(&serde_json::to_vec(&state).unwrap_or_default())
1003 .map_err(|_| BlockchainError::DataUnavailable)?;
1004 Ok(encoder.finish().unwrap_or_default().into())
1005 }
1006
1007 pub async fn load_state(&self, state: SerializableState) -> Result<bool, BlockchainError> {
1009 self.blockchain.storage.write().load_blocks(state.blocks.clone());
1011 self.blockchain.storage.write().load_transactions(state.transactions.clone());
1012 if let Some(block) = state.block.clone() {
1014 self.env.write().evm_env.block_env = block.clone();
1015
1016 let fork_num_and_hash = self.get_fork().map(|f| (f.block_number(), f.block_hash()));
1019
1020 let best_number = state.best_block_number.unwrap_or(block.number.saturating_to());
1021 if let Some((number, hash)) = fork_num_and_hash {
1022 trace!(target: "backend", state_block_number=?best_number, fork_block_number=?number);
1023 if best_number > number {
1027 self.blockchain.storage.write().best_number = best_number;
1028 let best_hash =
1029 self.blockchain.storage.read().hash(best_number.into()).ok_or_else(
1030 || {
1031 BlockchainError::RpcError(RpcError::internal_error_with(format!(
1032 "Best hash not found for best number {best_number}",
1033 )))
1034 },
1035 )?;
1036 self.blockchain.storage.write().best_hash = best_hash;
1037 } else {
1038 self.blockchain.storage.write().best_number = number;
1041 self.blockchain.storage.write().best_hash = hash;
1042 }
1043 } else {
1044 self.blockchain.storage.write().best_number = best_number;
1045
1046 let best_hash =
1048 self.blockchain.storage.read().hash(best_number.into()).ok_or_else(|| {
1049 BlockchainError::RpcError(RpcError::internal_error_with(format!(
1050 "Best hash not found for best number {best_number}",
1051 )))
1052 })?;
1053
1054 self.blockchain.storage.write().best_hash = best_hash;
1055 }
1056 }
1057
1058 if let Some(latest) = state.blocks.iter().max_by_key(|b| b.header.number) {
1059 let header = &latest.header;
1060 let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(
1061 header.gas_used,
1062 header.gas_limit,
1063 header.base_fee_per_gas.unwrap_or_default(),
1064 );
1065 let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas(
1066 header.excess_blob_gas.unwrap_or_default(),
1067 header.blob_gas_used.unwrap_or_default(),
1068 );
1069
1070 self.fees.set_base_fee(next_block_base_fee);
1072
1073 self.fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(
1074 next_block_excess_blob_gas,
1075 get_blob_base_fee_update_fraction(
1076 self.env.read().evm_env.cfg_env.chain_id,
1077 header.timestamp,
1078 ),
1079 ));
1080 }
1081
1082 if !self.db.write().await.load_state(state.clone())? {
1083 return Err(RpcError::invalid_params(
1084 "Loading state not supported with the current configuration",
1085 )
1086 .into());
1087 }
1088
1089 if let Some(historical_states) = state.historical_states {
1090 self.states.write().load_states(historical_states);
1091 }
1092
1093 Ok(true)
1094 }
1095
1096 pub async fn load_state_bytes(&self, buf: Bytes) -> Result<bool, BlockchainError> {
1098 let orig_buf = &buf.0[..];
1099 let mut decoder = GzDecoder::new(orig_buf);
1100 let mut decoded_data = Vec::new();
1101
1102 let state: SerializableState = serde_json::from_slice(if decoder.header().is_some() {
1103 decoder
1104 .read_to_end(decoded_data.as_mut())
1105 .map_err(|_| BlockchainError::FailedToDecodeStateDump)?;
1106 &decoded_data
1107 } else {
1108 &buf.0
1109 })
1110 .map_err(|_| BlockchainError::FailedToDecodeStateDump)?;
1111
1112 self.load_state(state).await
1113 }
1114
1115 fn next_env(&self) -> Env {
1120 let mut env = self.env.read().clone();
1121 env.evm_env.block_env.number = env.evm_env.block_env.number.saturating_add(U256::from(1));
1123 env.evm_env.block_env.basefee = self.base_fee();
1124 env.evm_env.block_env.blob_excess_gas_and_price = self.excess_blob_gas_and_price();
1125 env.evm_env.block_env.timestamp = U256::from(self.time.current_call_timestamp());
1126 env
1127 }
1128
1129 fn new_evm_with_inspector_ref<'db, I, DB>(
1131 &self,
1132 db: &'db DB,
1133 env: &Env,
1134 inspector: &'db mut I,
1135 ) -> EitherEvm<WrapDatabaseRef<&'db DB>, &'db mut I, PrecompilesMap>
1136 where
1137 DB: DatabaseRef + ?Sized,
1138 I: Inspector<EthEvmContext<WrapDatabaseRef<&'db DB>>>
1139 + Inspector<OpContext<WrapDatabaseRef<&'db DB>>>,
1140 WrapDatabaseRef<&'db DB>: Database<Error = DatabaseError>,
1141 {
1142 let mut evm = new_evm_with_inspector(WrapDatabaseRef(db), env, inspector);
1143 self.env.read().networks.inject_precompiles(evm.precompiles_mut());
1144
1145 if let Some(factory) = &self.precompile_factory {
1146 evm.precompiles_mut().extend_precompiles(factory.precompiles());
1147 }
1148
1149 let cheats = Arc::new(self.cheats.clone());
1150 if cheats.has_recover_overrides() {
1151 let cheat_ecrecover = CheatEcrecover::new(Arc::clone(&cheats));
1152 evm.precompiles_mut().apply_precompile(&EC_RECOVER, move |_| {
1153 Some(DynPrecompile::new_stateful(
1154 cheat_ecrecover.precompile_id().clone(),
1155 move |input| cheat_ecrecover.call(input),
1156 ))
1157 });
1158 }
1159
1160 evm
1161 }
1162
1163 pub async fn inspect_tx(
1165 &self,
1166 tx: Arc<PoolTransaction>,
1167 ) -> Result<
1168 (InstructionResult, Option<Output>, u64, State, Vec<revm::primitives::Log>),
1169 BlockchainError,
1170 > {
1171 let mut env = self.next_env();
1172 env.tx = FromRecoveredTx::from_recovered_tx(
1173 tx.pending_transaction.transaction.as_ref(),
1174 *tx.pending_transaction.sender(),
1175 );
1176
1177 if env.networks.is_optimism() {
1178 env.tx.enveloped_tx = Some(tx.pending_transaction.transaction.encoded_2718().into());
1179 }
1180
1181 let db = self.db.read().await;
1182 let mut inspector = self.build_inspector();
1183 let mut evm = self.new_evm_with_inspector_ref(&**db, &env, &mut inspector);
1184 let ResultAndState { result, state } = evm.transact(env.tx)?;
1185 let (exit_reason, gas_used, out, logs) = match result {
1186 ExecutionResult::Success { reason, gas_used, logs, output, .. } => {
1187 (reason.into(), gas_used, Some(output), Some(logs))
1188 }
1189 ExecutionResult::Revert { gas_used, output } => {
1190 (InstructionResult::Revert, gas_used, Some(Output::Call(output)), None)
1191 }
1192 ExecutionResult::Halt { reason, gas_used } => {
1193 let eth_reason = op_haltreason_to_instruction_result(reason);
1194 (eth_reason, gas_used, None, None)
1195 }
1196 };
1197
1198 drop(evm);
1199 inspector.print_logs();
1200
1201 if self.print_traces {
1202 inspector.print_traces(self.call_trace_decoder.clone());
1203 }
1204
1205 Ok((exit_reason, out, gas_used, state, logs.unwrap_or_default()))
1206 }
1207
1208 pub async fn pending_block(&self, pool_transactions: Vec<Arc<PoolTransaction>>) -> BlockInfo {
1212 self.with_pending_block(pool_transactions, |_, block| block).await
1213 }
1214
1215 pub async fn with_pending_block<F, T>(
1219 &self,
1220 pool_transactions: Vec<Arc<PoolTransaction>>,
1221 f: F,
1222 ) -> T
1223 where
1224 F: FnOnce(Box<dyn MaybeFullDatabase + '_>, BlockInfo) -> T,
1225 {
1226 let db = self.db.read().await;
1227 let env = self.next_env();
1228
1229 let mut cache_db = CacheDB::new(&*db);
1230
1231 let storage = self.blockchain.storage.read();
1232
1233 let executor = TransactionExecutor {
1234 db: &mut cache_db,
1235 validator: self,
1236 pending: pool_transactions.into_iter(),
1237 evm_env: env.evm_env,
1238 parent_hash: storage.best_hash,
1239 gas_used: 0,
1240 blob_gas_used: 0,
1241 enable_steps_tracing: self.enable_steps_tracing,
1242 print_logs: self.print_logs,
1243 print_traces: self.print_traces,
1244 call_trace_decoder: self.call_trace_decoder.clone(),
1245 precompile_factory: self.precompile_factory.clone(),
1246 networks: self.env.read().networks,
1247 blob_params: self.blob_params(),
1248 cheats: self.cheats().clone(),
1249 };
1250
1251 let executed = executor.execute();
1253 f(Box::new(cache_db), executed.block)
1254 }
1255
1256 pub async fn mine_block(
1261 &self,
1262 pool_transactions: Vec<Arc<PoolTransaction>>,
1263 ) -> MinedBlockOutcome {
1264 self.do_mine_block(pool_transactions).await
1265 }
1266
1267 async fn do_mine_block(
1268 &self,
1269 pool_transactions: Vec<Arc<PoolTransaction>>,
1270 ) -> MinedBlockOutcome {
1271 let _mining_guard = self.mining.lock().await;
1272 trace!(target: "backend", "creating new block with {} transactions", pool_transactions.len());
1273
1274 let (outcome, header, block_hash) = {
1275 let current_base_fee = self.base_fee();
1276 let current_excess_blob_gas_and_price = self.excess_blob_gas_and_price();
1277
1278 let mut env = self.env.read().clone();
1279
1280 if env.evm_env.block_env.basefee == 0 {
1281 env.evm_env.cfg_env.disable_base_fee = true;
1284 }
1285
1286 let block_number = self.blockchain.storage.read().best_number.saturating_add(1);
1287
1288 if is_arbitrum(env.evm_env.cfg_env.chain_id) {
1290 env.evm_env.block_env.number = U256::from(block_number);
1292 } else {
1293 env.evm_env.block_env.number =
1294 env.evm_env.block_env.number.saturating_add(U256::from(1));
1295 }
1296
1297 env.evm_env.block_env.basefee = current_base_fee;
1298 env.evm_env.block_env.blob_excess_gas_and_price = current_excess_blob_gas_and_price;
1299
1300 let best_hash = self.blockchain.storage.read().best_hash;
1301
1302 let mut input = Vec::with_capacity(40);
1303 input.extend_from_slice(best_hash.as_slice());
1304 input.extend_from_slice(&block_number.to_le_bytes());
1305 env.evm_env.block_env.prevrandao = Some(keccak256(&input));
1306
1307 if self.prune_state_history_config.is_state_history_supported() {
1308 let db = self.db.read().await.current_state();
1309 self.states.write().insert(best_hash, db);
1311 }
1312
1313 let (executed_tx, block_hash) = {
1314 let mut db = self.db.write().await;
1315
1316 env.evm_env.block_env.timestamp = U256::from(self.time.next_timestamp());
1320
1321 let executor = TransactionExecutor {
1322 db: &mut **db,
1323 validator: self,
1324 pending: pool_transactions.into_iter(),
1325 evm_env: env.evm_env.clone(),
1326 parent_hash: best_hash,
1327 gas_used: 0,
1328 blob_gas_used: 0,
1329 enable_steps_tracing: self.enable_steps_tracing,
1330 print_logs: self.print_logs,
1331 print_traces: self.print_traces,
1332 call_trace_decoder: self.call_trace_decoder.clone(),
1333 networks: self.env.read().networks,
1334 precompile_factory: self.precompile_factory.clone(),
1335 blob_params: self.blob_params(),
1336 cheats: self.cheats().clone(),
1337 };
1338 let executed_tx = executor.execute();
1339
1340 let block_hash = executed_tx.block.block.header.hash_slow();
1342 db.insert_block_hash(U256::from(executed_tx.block.block.header.number), block_hash);
1343
1344 (executed_tx, block_hash)
1345 };
1346
1347 let ExecutedTransactions { block, included, invalid } = executed_tx;
1349 let BlockInfo { block, transactions, receipts } = block;
1350
1351 let header = block.header.clone();
1352
1353 trace!(
1354 target: "backend",
1355 "Mined block {} with {} tx {:?}",
1356 block_number,
1357 transactions.len(),
1358 transactions.iter().map(|tx| tx.transaction_hash).collect::<Vec<_>>()
1359 );
1360 let mut storage = self.blockchain.storage.write();
1361 storage.best_number = block_number;
1363 storage.best_hash = block_hash;
1364 if !self.is_eip3675() {
1367 storage.total_difficulty =
1368 storage.total_difficulty.saturating_add(header.difficulty);
1369 }
1370
1371 storage.blocks.insert(block_hash, block);
1372 storage.hashes.insert(block_number, block_hash);
1373
1374 node_info!("");
1375 for (info, receipt) in transactions.into_iter().zip(receipts) {
1377 node_info!(" Transaction: {:?}", info.transaction_hash);
1379 if let Some(contract) = &info.contract_address {
1380 node_info!(" Contract created: {contract}");
1381 }
1382 node_info!(" Gas used: {}", receipt.cumulative_gas_used());
1383 if !info.exit.is_ok() {
1384 let r = RevertDecoder::new().decode(
1385 info.out.as_ref().map(|b| &b[..]).unwrap_or_default(),
1386 Some(info.exit),
1387 );
1388 node_info!(" Error: reverted with: {r}");
1389 }
1390 node_info!("");
1391
1392 let mined_tx = MinedTransaction { info, receipt, block_hash, block_number };
1393 storage.transactions.insert(mined_tx.info.transaction_hash, mined_tx);
1394 }
1395
1396 if let Some(transaction_block_keeper) = self.transaction_block_keeper
1398 && storage.blocks.len() > transaction_block_keeper
1399 {
1400 let to_clear = block_number
1401 .saturating_sub(transaction_block_keeper.try_into().unwrap_or(u64::MAX));
1402 storage.remove_block_transactions_by_number(to_clear)
1403 }
1404
1405 env.evm_env.block_env.difficulty = U256::from(0);
1407
1408 *self.env.write() = env;
1410
1411 let timestamp = utc_from_secs(header.timestamp);
1412
1413 node_info!(" Block Number: {}", block_number);
1414 node_info!(" Block Hash: {:?}", block_hash);
1415 if timestamp.year() > 9999 {
1416 node_info!(" Block Time: {:?}\n", timestamp.to_rfc3339());
1418 } else {
1419 node_info!(" Block Time: {:?}\n", timestamp.to_rfc2822());
1420 }
1421
1422 let outcome = MinedBlockOutcome { block_number, included, invalid };
1423
1424 (outcome, header, block_hash)
1425 };
1426 let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(
1427 header.gas_used,
1428 header.gas_limit,
1429 header.base_fee_per_gas.unwrap_or_default(),
1430 );
1431 let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas(
1432 header.excess_blob_gas.unwrap_or_default(),
1433 header.blob_gas_used.unwrap_or_default(),
1434 );
1435
1436 self.fees.set_base_fee(next_block_base_fee);
1438
1439 self.fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(
1440 next_block_excess_blob_gas,
1441 get_blob_base_fee_update_fraction_by_spec_id(*self.env.read().evm_env.spec_id()),
1442 ));
1443
1444 self.notify_on_new_block(header, block_hash);
1446
1447 outcome
1448 }
1449
1450 pub async fn call(
1456 &self,
1457 request: WithOtherFields<TransactionRequest>,
1458 fee_details: FeeDetails,
1459 block_request: Option<BlockRequest>,
1460 overrides: EvmOverrides,
1461 ) -> Result<(InstructionResult, Option<Output>, u128, State), BlockchainError> {
1462 self.with_database_at(block_request, |state, mut block| {
1463 let block_number = block.number;
1464 let (exit, out, gas, state) = {
1465 let mut cache_db = CacheDB::new(state);
1466 if let Some(state_overrides) = overrides.state {
1467 apply_state_overrides(state_overrides.into_iter().collect(), &mut cache_db)?;
1468 }
1469 if let Some(block_overrides) = overrides.block {
1470 cache_db.apply_block_overrides(*block_overrides, &mut block);
1471 }
1472 self.call_with_state(&cache_db, request, fee_details, block)
1473 }?;
1474 trace!(target: "backend", "call return {:?} out: {:?} gas {} on block {}", exit, out, gas, block_number);
1475 Ok((exit, out, gas, state))
1476 }).await?
1477 }
1478
1479 fn build_call_env(
1488 &self,
1489 request: WithOtherFields<TransactionRequest>,
1490 fee_details: FeeDetails,
1491 block_env: BlockEnv,
1492 ) -> Env {
1493 let tx_type = request.minimal_tx_type() as u8;
1494
1495 let WithOtherFields::<TransactionRequest> {
1496 inner:
1497 TransactionRequest {
1498 from,
1499 to,
1500 gas,
1501 value,
1502 input,
1503 access_list,
1504 blob_versioned_hashes,
1505 authorization_list,
1506 nonce,
1507 sidecar: _,
1508 chain_id,
1509 .. },
1511 other,
1512 } = request;
1513
1514 let FeeDetails {
1515 gas_price,
1516 max_fee_per_gas,
1517 max_priority_fee_per_gas,
1518 max_fee_per_blob_gas,
1519 } = fee_details;
1520
1521 let gas_limit = gas.unwrap_or(block_env.gas_limit);
1522 let mut env = self.env.read().clone();
1523 env.evm_env.block_env = block_env;
1524 env.evm_env.cfg_env.disable_block_gas_limit = true;
1527 env.evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
1528
1529 env.evm_env.cfg_env.disable_base_fee = true;
1535
1536 env.evm_env.cfg_env.disable_nonce_check = true;
1538
1539 let gas_price = gas_price.or(max_fee_per_gas).unwrap_or_else(|| {
1540 self.fees().raw_gas_price().saturating_add(MIN_SUGGESTED_PRIORITY_FEE)
1541 });
1542 let caller = from.unwrap_or_default();
1543 let to = to.as_ref().and_then(TxKind::to);
1544 let blob_hashes = blob_versioned_hashes.unwrap_or_default();
1545 let mut base = TxEnv {
1546 caller,
1547 gas_limit,
1548 gas_price,
1549 gas_priority_fee: max_priority_fee_per_gas,
1550 max_fee_per_blob_gas: max_fee_per_blob_gas
1551 .or_else(|| {
1552 if !blob_hashes.is_empty() {
1553 env.evm_env.block_env.blob_gasprice()
1554 } else {
1555 Some(0)
1556 }
1557 })
1558 .unwrap_or_default(),
1559 kind: match to {
1560 Some(addr) => TxKind::Call(*addr),
1561 None => TxKind::Create,
1562 },
1563 tx_type,
1564 value: value.unwrap_or_default(),
1565 data: input.into_input().unwrap_or_default(),
1566 chain_id: Some(chain_id.unwrap_or(self.env.read().evm_env.cfg_env.chain_id)),
1567 access_list: access_list.unwrap_or_default(),
1568 blob_hashes,
1569 ..Default::default()
1570 };
1571 base.set_signed_authorization(authorization_list.unwrap_or_default());
1572 env.tx = OpTransaction { base, ..Default::default() };
1573
1574 if let Some(nonce) = nonce {
1575 env.tx.base.nonce = nonce;
1576 }
1577
1578 if env.evm_env.block_env.basefee == 0 {
1579 env.evm_env.cfg_env.disable_base_fee = true;
1582 }
1583
1584 if let Ok(deposit) = get_deposit_tx_parts(&other) {
1586 env.tx.deposit = deposit;
1587 }
1588
1589 env
1590 }
1591
1592 fn build_inspector(&self) -> AnvilInspector {
1594 let mut inspector = AnvilInspector::default();
1595
1596 if self.print_logs {
1597 inspector = inspector.with_log_collector();
1598 }
1599 if self.print_traces {
1600 inspector = inspector.with_trace_printer();
1601 }
1602
1603 inspector
1604 }
1605
1606 pub async fn simulate(
1608 &self,
1609 request: SimulatePayload,
1610 block_request: Option<BlockRequest>,
1611 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>, BlockchainError> {
1612 self.with_database_at(block_request, |state, mut block_env| {
1613 let SimulatePayload {
1614 block_state_calls,
1615 trace_transfers,
1616 validation,
1617 return_full_transactions,
1618 } = request;
1619 let mut cache_db = CacheDB::new(state);
1620 let mut block_res = Vec::with_capacity(block_state_calls.len());
1621
1622 for block in block_state_calls {
1624 let SimBlock { block_overrides, state_overrides, calls } = block;
1625 let mut call_res = Vec::with_capacity(calls.len());
1626 let mut log_index = 0;
1627 let mut gas_used = 0;
1628 let mut transactions = Vec::with_capacity(calls.len());
1629 let mut logs= Vec::new();
1630
1631 if let Some(state_overrides) = state_overrides {
1633 apply_state_overrides(state_overrides, &mut cache_db)?;
1634 }
1635 if let Some(block_overrides) = block_overrides {
1636 cache_db.apply_block_overrides(block_overrides, &mut block_env);
1637 }
1638
1639 for (req_idx, request) in calls.into_iter().enumerate() {
1641 let fee_details = FeeDetails::new(
1642 request.gas_price,
1643 request.max_fee_per_gas,
1644 request.max_priority_fee_per_gas,
1645 request.max_fee_per_blob_gas,
1646 )?
1647 .or_zero_fees();
1648
1649 let mut env = self.build_call_env(
1650 WithOtherFields::new(request.clone()),
1651 fee_details,
1652 block_env.clone(),
1653 );
1654
1655 env.evm_env.cfg_env.disable_eip3607 = true;
1657
1658 if !validation {
1659 env.evm_env.cfg_env.disable_base_fee = !validation;
1660 env.evm_env.block_env.basefee = 0;
1661 }
1662
1663 let mut inspector = self.build_inspector();
1664
1665 let ResultAndState { result, state } = if trace_transfers {
1667 inspector = inspector.with_transfers();
1670 let mut evm= self.new_evm_with_inspector_ref(
1671 &cache_db,
1672 &env,
1673 &mut inspector,
1674 );
1675
1676 trace!(target: "backend", env=?env.evm_env, spec=?env.evm_env.spec_id(),"simulate evm env");
1677 evm.transact(env.tx)?
1678 } else {
1679 let mut evm = self.new_evm_with_inspector_ref(
1680 &cache_db,
1681 &env,
1682 &mut inspector,
1683 );
1684 trace!(target: "backend", env=?env.evm_env, spec=?env.evm_env.spec_id(),"simulate evm env");
1685 evm.transact(env.tx)?
1686 };
1687 trace!(target: "backend", ?result, ?request, "simulate call");
1688
1689 inspector.print_logs();
1690 if self.print_traces {
1691 inspector.into_print_traces(self.call_trace_decoder.clone());
1692 }
1693
1694 cache_db.commit(state);
1696 gas_used += result.gas_used();
1697
1698 let from = request.from.unwrap_or_default();
1700
1701 let mut request = Into::<FoundryTransactionRequest>::into(WithOtherFields::new(request));
1702 request.prep_for_submission();
1703
1704 let typed_tx = request.build_unsigned().map_err(|e| BlockchainError::InvalidTransactionRequest(e.to_string()))?;
1705
1706 let tx = build_typed_transaction(
1707 typed_tx,
1708 Signature::new(Default::default(), Default::default(), false),
1709 )?;
1710 let tx_hash = tx.hash();
1711 let rpc_tx = transaction_build(
1712 None,
1713 MaybeImpersonatedTransaction::impersonated(tx, from),
1714 None,
1715 None,
1716 Some(block_env.basefee),
1717 );
1718 transactions.push(rpc_tx);
1719
1720 let return_data = result.output().cloned().unwrap_or_default();
1721 let sim_res = SimCallResult {
1722 return_data,
1723 gas_used: result.gas_used(),
1724 status: result.is_success(),
1725 error: result.is_success().not().then(|| {
1726 alloy_rpc_types::simulate::SimulateError {
1727 code: -3200,
1728 message: "execution failed".to_string(),
1729 }
1730 }),
1731 logs: result.clone()
1732 .into_logs()
1733 .into_iter()
1734 .enumerate()
1735 .map(|(idx, log)| Log {
1736 inner: log,
1737 block_number: Some(block_env.number.saturating_to()),
1738 block_timestamp: Some(block_env.timestamp.saturating_to()),
1739 transaction_index: Some(req_idx as u64),
1740 log_index: Some((idx + log_index) as u64),
1741 removed: false,
1742
1743 block_hash: None,
1744 transaction_hash: Some(tx_hash),
1745 })
1746 .collect(),
1747 };
1748 logs.extend(sim_res.logs.iter().map(|log| log.inner.clone()));
1749 log_index += sim_res.logs.len();
1750 call_res.push(sim_res);
1751 }
1752
1753 let transactions_envelopes: Vec<AnyTxEnvelope> = transactions
1754 .iter()
1755 .map(|tx| AnyTxEnvelope::from(tx.clone()))
1756 .collect();
1757 let header = Header {
1758 logs_bloom: logs_bloom(logs.iter()),
1759 transactions_root: calculate_transaction_root(&transactions_envelopes),
1760 receipts_root: calculate_receipt_root(&transactions_envelopes),
1761 parent_hash: Default::default(),
1762 beneficiary: block_env.beneficiary,
1763 state_root: Default::default(),
1764 difficulty: Default::default(),
1765 number: block_env.number.saturating_to(),
1766 gas_limit: block_env.gas_limit,
1767 gas_used,
1768 timestamp: block_env.timestamp.saturating_to(),
1769 extra_data: Default::default(),
1770 mix_hash: Default::default(),
1771 nonce: Default::default(),
1772 base_fee_per_gas: Some(block_env.basefee),
1773 withdrawals_root: None,
1774 blob_gas_used: None,
1775 excess_blob_gas: None,
1776 parent_beacon_block_root: None,
1777 requests_hash: None,
1778 ..Default::default()
1779 };
1780 let mut block = alloy_rpc_types::Block {
1781 header: AnyRpcHeader {
1782 hash: header.hash_slow(),
1783 inner: header.into(),
1784 total_difficulty: None,
1785 size: None,
1786 },
1787 uncles: vec![],
1788 transactions: BlockTransactions::Full(transactions),
1789 withdrawals: None,
1790 };
1791
1792 if !return_full_transactions {
1793 block.transactions.convert_to_hashes();
1794 }
1795
1796 for res in &mut call_res {
1797 res.logs.iter_mut().for_each(|log| {
1798 log.block_hash = Some(block.header.hash);
1799 });
1800 }
1801
1802 let simulated_block = SimulatedBlock {
1803 inner: AnyRpcBlock::new(WithOtherFields::new(block)),
1804 calls: call_res,
1805 };
1806
1807 block_env.number += U256::from(1);
1809 block_env.timestamp += U256::from(12);
1810 block_env.basefee = simulated_block
1811 .inner
1812 .header
1813 .next_block_base_fee(self.fees.base_fee_params())
1814 .unwrap_or_default();
1815
1816 block_res.push(simulated_block);
1817 }
1818
1819 Ok(block_res)
1820 })
1821 .await?
1822 }
1823
1824 pub fn call_with_state(
1825 &self,
1826 state: &dyn DatabaseRef,
1827 request: WithOtherFields<TransactionRequest>,
1828 fee_details: FeeDetails,
1829 block_env: BlockEnv,
1830 ) -> Result<(InstructionResult, Option<Output>, u128, State), BlockchainError> {
1831 let mut inspector = self.build_inspector();
1832
1833 let env = self.build_call_env(request, fee_details, block_env);
1834 let mut evm = self.new_evm_with_inspector_ref(state, &env, &mut inspector);
1835 let ResultAndState { result, state } = evm.transact(env.tx)?;
1836 let (exit_reason, gas_used, out) = match result {
1837 ExecutionResult::Success { reason, gas_used, output, .. } => {
1838 (reason.into(), gas_used, Some(output))
1839 }
1840 ExecutionResult::Revert { gas_used, output } => {
1841 (InstructionResult::Revert, gas_used, Some(Output::Call(output)))
1842 }
1843 ExecutionResult::Halt { reason, gas_used } => {
1844 (op_haltreason_to_instruction_result(reason), gas_used, None)
1845 }
1846 };
1847 drop(evm);
1848 inspector.print_logs();
1849
1850 if self.print_traces {
1851 inspector.into_print_traces(self.call_trace_decoder.clone());
1852 }
1853
1854 Ok((exit_reason, out, gas_used as u128, state))
1855 }
1856
1857 pub async fn call_with_tracing(
1858 &self,
1859 request: WithOtherFields<TransactionRequest>,
1860 fee_details: FeeDetails,
1861 block_request: Option<BlockRequest>,
1862 opts: GethDebugTracingCallOptions,
1863 ) -> Result<GethTrace, BlockchainError> {
1864 let GethDebugTracingCallOptions {
1865 tracing_options, block_overrides, state_overrides, ..
1866 } = opts;
1867 let GethDebugTracingOptions { config, tracer, tracer_config, .. } = tracing_options;
1868
1869 self.with_database_at(block_request, |state, mut block| {
1870 let block_number = block.number;
1871
1872 let mut cache_db = CacheDB::new(state);
1873 if let Some(state_overrides) = state_overrides {
1874 apply_state_overrides(state_overrides, &mut cache_db)?;
1875 }
1876 if let Some(block_overrides) = block_overrides {
1877 cache_db.apply_block_overrides(block_overrides, &mut block);
1878 }
1879
1880 if let Some(tracer) = tracer {
1881 return match tracer {
1882 GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
1883 GethDebugBuiltInTracerType::CallTracer => {
1884 let call_config = tracer_config
1885 .into_call_config()
1886 .map_err(|e| RpcError::invalid_params(e.to_string()))?;
1887
1888 let mut inspector = self.build_inspector().with_tracing_config(
1889 TracingInspectorConfig::from_geth_call_config(&call_config),
1890 );
1891
1892 let env = self.build_call_env(request, fee_details, block);
1893 let mut evm =
1894 self.new_evm_with_inspector_ref(&cache_db, &env, &mut inspector);
1895 let ResultAndState { result, state: _ } = evm.transact(env.tx)?;
1896
1897 drop(evm);
1898
1899 inspector.print_logs();
1900 if self.print_traces {
1901 inspector.print_traces(self.call_trace_decoder.clone());
1902 }
1903
1904 let tracing_inspector = inspector.tracer.expect("tracer disappeared");
1905
1906 Ok(tracing_inspector
1907 .into_geth_builder()
1908 .geth_call_traces(call_config, result.gas_used())
1909 .into())
1910 }
1911 GethDebugBuiltInTracerType::PreStateTracer => {
1912 let pre_state_config = tracer_config
1913 .into_pre_state_config()
1914 .map_err(|e| RpcError::invalid_params(e.to_string()))?;
1915
1916 let mut inspector = TracingInspector::new(
1917 TracingInspectorConfig::from_geth_prestate_config(
1918 &pre_state_config,
1919 ),
1920 );
1921
1922 let env = self.build_call_env(request, fee_details, block);
1923 let mut evm =
1924 self.new_evm_with_inspector_ref(&cache_db, &env, &mut inspector);
1925 let result = evm.transact(env.tx)?;
1926
1927 drop(evm);
1928
1929 Ok(inspector
1930 .into_geth_builder()
1931 .geth_prestate_traces(&result, &pre_state_config, cache_db)?
1932 .into())
1933 }
1934 GethDebugBuiltInTracerType::NoopTracer => Ok(NoopFrame::default().into()),
1935 GethDebugBuiltInTracerType::FourByteTracer
1936 | GethDebugBuiltInTracerType::MuxTracer
1937 | GethDebugBuiltInTracerType::FlatCallTracer
1938 | GethDebugBuiltInTracerType::Erc7562Tracer => {
1939 Err(RpcError::invalid_params("unsupported tracer type").into())
1940 }
1941 },
1942 #[cfg(not(feature = "js-tracer"))]
1943 GethDebugTracerType::JsTracer(_) => {
1944 Err(RpcError::invalid_params("unsupported tracer type").into())
1945 }
1946 #[cfg(feature = "js-tracer")]
1947 GethDebugTracerType::JsTracer(code) => {
1948 use alloy_evm::IntoTxEnv;
1949 let config = tracer_config.into_json();
1950 let mut inspector =
1951 revm_inspectors::tracing::js::JsInspector::new(code, config)
1952 .map_err(|err| BlockchainError::Message(err.to_string()))?;
1953
1954 let env = self.build_call_env(request, fee_details, block.clone());
1955 let mut evm =
1956 self.new_evm_with_inspector_ref(&cache_db, &env, &mut inspector);
1957 let result = evm.transact(env.tx.clone())?;
1958 let res = evm
1959 .inspector_mut()
1960 .json_result(result, &env.tx.into_tx_env(), &block, &cache_db)
1961 .map_err(|err| BlockchainError::Message(err.to_string()))?;
1962
1963 Ok(GethTrace::JS(res))
1964 }
1965 };
1966 }
1967
1968 let mut inspector = self
1970 .build_inspector()
1971 .with_tracing_config(TracingInspectorConfig::from_geth_config(&config));
1972
1973 let env = self.build_call_env(request, fee_details, block);
1974 let mut evm = self.new_evm_with_inspector_ref(&cache_db, &env, &mut inspector);
1975 let ResultAndState { result, state: _ } = evm.transact(env.tx)?;
1976
1977 let (exit_reason, gas_used, out) = match result {
1978 ExecutionResult::Success { reason, gas_used, output, .. } => {
1979 (reason.into(), gas_used, Some(output))
1980 }
1981 ExecutionResult::Revert { gas_used, output } => {
1982 (InstructionResult::Revert, gas_used, Some(Output::Call(output)))
1983 }
1984 ExecutionResult::Halt { reason, gas_used } => {
1985 (op_haltreason_to_instruction_result(reason), gas_used, None)
1986 }
1987 };
1988
1989 drop(evm);
1990 let tracing_inspector = inspector.tracer.expect("tracer disappeared");
1991 let return_value = out.as_ref().map(|o| o.data()).cloned().unwrap_or_default();
1992
1993 trace!(target: "backend", ?exit_reason, ?out, %gas_used, %block_number, "trace call");
1994
1995 let res = tracing_inspector
1996 .into_geth_builder()
1997 .geth_traces(gas_used, return_value, config)
1998 .into();
1999
2000 Ok(res)
2001 })
2002 .await?
2003 }
2004
2005 pub fn build_access_list_with_state(
2006 &self,
2007 state: &dyn DatabaseRef,
2008 request: WithOtherFields<TransactionRequest>,
2009 fee_details: FeeDetails,
2010 block_env: BlockEnv,
2011 ) -> Result<(InstructionResult, Option<Output>, u64, AccessList), BlockchainError> {
2012 let mut inspector =
2013 AccessListInspector::new(request.access_list.clone().unwrap_or_default());
2014
2015 let env = self.build_call_env(request, fee_details, block_env);
2016 let mut evm = self.new_evm_with_inspector_ref(state, &env, &mut inspector);
2017 let ResultAndState { result, state: _ } = evm.transact(env.tx)?;
2018 let (exit_reason, gas_used, out) = match result {
2019 ExecutionResult::Success { reason, gas_used, output, .. } => {
2020 (reason.into(), gas_used, Some(output))
2021 }
2022 ExecutionResult::Revert { gas_used, output } => {
2023 (InstructionResult::Revert, gas_used, Some(Output::Call(output)))
2024 }
2025 ExecutionResult::Halt { reason, gas_used } => {
2026 (op_haltreason_to_instruction_result(reason), gas_used, None)
2027 }
2028 };
2029 drop(evm);
2030 let access_list = inspector.access_list();
2031 Ok((exit_reason, out, gas_used, access_list))
2032 }
2033
2034 fn get_receipts(
2036 &self,
2037 tx_hashes: impl IntoIterator<Item = TxHash>,
2038 ) -> Vec<FoundryReceiptEnvelope> {
2039 let storage = self.blockchain.storage.read();
2040 let mut receipts = vec![];
2041
2042 for hash in tx_hashes {
2043 if let Some(tx) = storage.transactions.get(&hash) {
2044 receipts.push(tx.receipt.clone());
2045 }
2046 }
2047
2048 receipts
2049 }
2050
2051 async fn logs_for_block(
2053 &self,
2054 filter: Filter,
2055 hash: B256,
2056 ) -> Result<Vec<Log>, BlockchainError> {
2057 if let Some(block) = self.blockchain.get_block_by_hash(&hash) {
2058 return Ok(self.mined_logs_for_block(filter, block, hash));
2059 }
2060
2061 if let Some(fork) = self.get_fork() {
2062 return Ok(fork.logs(&filter).await?);
2063 }
2064
2065 Ok(Vec::new())
2066 }
2067
2068 fn mined_logs_for_block(&self, filter: Filter, block: Block, block_hash: B256) -> Vec<Log> {
2070 let mut all_logs = Vec::new();
2071 let mut block_log_index = 0u32;
2072
2073 let storage = self.blockchain.storage.read();
2074
2075 for tx in block.body.transactions {
2076 let Some(tx) = storage.transactions.get(&tx.hash()) else {
2077 continue;
2078 };
2079
2080 let logs = tx.receipt.logs();
2081 let transaction_hash = tx.info.transaction_hash;
2082
2083 for log in logs {
2084 if filter.matches(log) {
2085 all_logs.push(Log {
2086 inner: log.clone(),
2087 block_hash: Some(block_hash),
2088 block_number: Some(block.header.number),
2089 block_timestamp: Some(block.header.timestamp),
2090 transaction_hash: Some(transaction_hash),
2091 transaction_index: Some(tx.info.transaction_index),
2092 log_index: Some(block_log_index as u64),
2093 removed: false,
2094 });
2095 }
2096 block_log_index += 1;
2097 }
2098 }
2099 all_logs
2100 }
2101
2102 async fn logs_for_range(
2104 &self,
2105 filter: &Filter,
2106 mut from: u64,
2107 to: u64,
2108 ) -> Result<Vec<Log>, BlockchainError> {
2109 let mut all_logs = Vec::new();
2110
2111 if let Some(fork) = self.get_fork() {
2113 let mut to_on_fork = to;
2114
2115 if !fork.predates_fork(to) {
2116 to_on_fork = fork.block_number();
2118 }
2119
2120 if fork.predates_fork_inclusive(from) {
2121 let filter = filter.clone().from_block(from).to_block(to_on_fork);
2123 all_logs = fork.logs(&filter).await?;
2124
2125 from = fork.block_number() + 1;
2127 }
2128 }
2129
2130 for number in from..=to {
2131 if let Some((block, hash)) = self.get_block_with_hash(number) {
2132 all_logs.extend(self.mined_logs_for_block(filter.clone(), block, hash));
2133 }
2134 }
2135
2136 Ok(all_logs)
2137 }
2138
2139 pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>, BlockchainError> {
2141 trace!(target: "backend", "get logs [{:?}]", filter);
2142 if let Some(hash) = filter.get_block_hash() {
2143 self.logs_for_block(filter, hash).await
2144 } else {
2145 let best = self.best_number();
2146 let to_block =
2147 self.convert_block_number(filter.block_option.get_to_block().copied()).min(best);
2148 let from_block =
2149 self.convert_block_number(filter.block_option.get_from_block().copied());
2150 if from_block > best {
2151 return Err(BlockchainError::BlockOutOfRange(best, from_block));
2152 }
2153
2154 self.logs_for_range(&filter, from_block, to_block).await
2155 }
2156 }
2157
2158 pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>, BlockchainError> {
2159 trace!(target: "backend", "get block by hash {:?}", hash);
2160 if let tx @ Some(_) = self.mined_block_by_hash(hash) {
2161 return Ok(tx);
2162 }
2163
2164 if let Some(fork) = self.get_fork() {
2165 return Ok(fork.block_by_hash(hash).await?);
2166 }
2167
2168 Ok(None)
2169 }
2170
2171 pub async fn block_by_hash_full(
2172 &self,
2173 hash: B256,
2174 ) -> Result<Option<AnyRpcBlock>, BlockchainError> {
2175 trace!(target: "backend", "get block by hash {:?}", hash);
2176 if let tx @ Some(_) = self.get_full_block(hash) {
2177 return Ok(tx);
2178 }
2179
2180 if let Some(fork) = self.get_fork() {
2181 return Ok(fork.block_by_hash_full(hash).await?);
2182 }
2183
2184 Ok(None)
2185 }
2186
2187 fn mined_block_by_hash(&self, hash: B256) -> Option<AnyRpcBlock> {
2188 let block = self.blockchain.get_block_by_hash(&hash)?;
2189 Some(self.convert_block_with_hash(block, Some(hash)))
2190 }
2191
2192 pub(crate) async fn mined_transactions_by_block_number(
2193 &self,
2194 number: BlockNumber,
2195 ) -> Option<Vec<AnyRpcTransaction>> {
2196 if let Some(block) = self.get_block(number) {
2197 return self.mined_transactions_in_block(&block);
2198 }
2199 None
2200 }
2201
2202 pub(crate) fn mined_transactions_in_block(
2204 &self,
2205 block: &Block,
2206 ) -> Option<Vec<AnyRpcTransaction>> {
2207 let mut transactions = Vec::with_capacity(block.body.transactions.len());
2208 let base_fee = block.header.base_fee_per_gas;
2209 let storage = self.blockchain.storage.read();
2210 for hash in block.body.transactions.iter().map(|tx| tx.hash()) {
2211 let info = storage.transactions.get(&hash)?.info.clone();
2212 let tx = block.body.transactions.get(info.transaction_index as usize)?.clone();
2213
2214 let tx = transaction_build(Some(hash), tx, Some(block), Some(info), base_fee);
2215 transactions.push(tx);
2216 }
2217 Some(transactions)
2218 }
2219
2220 pub async fn block_by_number(
2221 &self,
2222 number: BlockNumber,
2223 ) -> Result<Option<AnyRpcBlock>, BlockchainError> {
2224 trace!(target: "backend", "get block by number {:?}", number);
2225 if let tx @ Some(_) = self.mined_block_by_number(number) {
2226 return Ok(tx);
2227 }
2228
2229 if let Some(fork) = self.get_fork() {
2230 let number = self.convert_block_number(Some(number));
2231 if fork.predates_fork_inclusive(number) {
2232 return Ok(fork.block_by_number(number).await?);
2233 }
2234 }
2235
2236 Ok(None)
2237 }
2238
2239 pub async fn block_by_number_full(
2240 &self,
2241 number: BlockNumber,
2242 ) -> Result<Option<AnyRpcBlock>, BlockchainError> {
2243 trace!(target: "backend", "get block by number {:?}", number);
2244 if let tx @ Some(_) = self.get_full_block(number) {
2245 return Ok(tx);
2246 }
2247
2248 if let Some(fork) = self.get_fork() {
2249 let number = self.convert_block_number(Some(number));
2250 if fork.predates_fork_inclusive(number) {
2251 return Ok(fork.block_by_number_full(number).await?);
2252 }
2253 }
2254
2255 Ok(None)
2256 }
2257
2258 fn get_block_with_hash(&self, id: impl Into<BlockId>) -> Option<(Block, B256)> {
2260 let hash = match id.into() {
2261 BlockId::Hash(hash) => hash.block_hash,
2262 BlockId::Number(number) => {
2263 let storage = self.blockchain.storage.read();
2264 let slots_in_an_epoch = self.slots_in_an_epoch;
2265 match number {
2266 BlockNumber::Latest => storage.best_hash,
2267 BlockNumber::Earliest => storage.genesis_hash,
2268 BlockNumber::Pending => return None,
2269 BlockNumber::Number(num) => *storage.hashes.get(&num)?,
2270 BlockNumber::Safe => {
2271 if storage.best_number > (slots_in_an_epoch) {
2272 *storage.hashes.get(&(storage.best_number - (slots_in_an_epoch)))?
2273 } else {
2274 storage.genesis_hash }
2276 }
2277 BlockNumber::Finalized => {
2278 if storage.best_number > (slots_in_an_epoch * 2) {
2279 *storage.hashes.get(&(storage.best_number - (slots_in_an_epoch * 2)))?
2280 } else {
2281 storage.genesis_hash
2282 }
2283 }
2284 }
2285 }
2286 };
2287 let block = self.get_block_by_hash(hash)?;
2288 Some((block, hash))
2289 }
2290
2291 pub fn get_block(&self, id: impl Into<BlockId>) -> Option<Block> {
2292 self.get_block_with_hash(id).map(|(block, _)| block)
2293 }
2294
2295 pub fn get_block_by_hash(&self, hash: B256) -> Option<Block> {
2296 self.blockchain.get_block_by_hash(&hash)
2297 }
2298
2299 pub fn mined_block_by_number(&self, number: BlockNumber) -> Option<AnyRpcBlock> {
2300 let (block, hash) = self.get_block_with_hash(number)?;
2301 let mut block = self.convert_block_with_hash(block, Some(hash));
2302 block.transactions.convert_to_hashes();
2303 Some(block)
2304 }
2305
2306 pub fn get_full_block(&self, id: impl Into<BlockId>) -> Option<AnyRpcBlock> {
2307 let (block, hash) = self.get_block_with_hash(id)?;
2308 let transactions = self.mined_transactions_in_block(&block)?;
2309 let mut block = self.convert_block_with_hash(block, Some(hash));
2310 block.inner.transactions = BlockTransactions::Full(transactions);
2311 Some(block)
2312 }
2313
2314 pub fn convert_block(&self, block: Block) -> AnyRpcBlock {
2316 self.convert_block_with_hash(block, None)
2317 }
2318
2319 pub fn convert_block_with_hash(&self, block: Block, known_hash: Option<B256>) -> AnyRpcBlock {
2322 let size = U256::from(alloy_rlp::encode(&block).len() as u32);
2323
2324 let header = block.header.clone();
2325 let transactions = block.body.transactions;
2326
2327 let hash = known_hash.unwrap_or_else(|| header.hash_slow());
2328 let Header { number, withdrawals_root, .. } = header;
2329
2330 let block = AlloyBlock {
2331 header: AlloyHeader {
2332 inner: AnyHeader::from(header),
2333 hash,
2334 total_difficulty: Some(self.total_difficulty()),
2335 size: Some(size),
2336 },
2337 transactions: alloy_rpc_types::BlockTransactions::Hashes(
2338 transactions.into_iter().map(|tx| tx.hash()).collect(),
2339 ),
2340 uncles: vec![],
2341 withdrawals: withdrawals_root.map(|_| Default::default()),
2342 };
2343
2344 let mut block = WithOtherFields::new(block);
2345
2346 if is_arbitrum(self.env.read().evm_env.cfg_env.chain_id) {
2348 block.other.insert("l1BlockNumber".to_string(), number.into());
2350 }
2351
2352 AnyRpcBlock::from(block)
2353 }
2354
2355 pub async fn ensure_block_number<T: Into<BlockId>>(
2361 &self,
2362 block_id: Option<T>,
2363 ) -> Result<u64, BlockchainError> {
2364 let current = self.best_number();
2365 let requested =
2366 match block_id.map(Into::into).unwrap_or(BlockId::Number(BlockNumber::Latest)) {
2367 BlockId::Hash(hash) => {
2368 self.block_by_hash(hash.block_hash)
2369 .await?
2370 .ok_or(BlockchainError::BlockNotFound)?
2371 .header
2372 .number
2373 }
2374 BlockId::Number(num) => match num {
2375 BlockNumber::Latest | BlockNumber::Pending => current,
2376 BlockNumber::Earliest => U64::ZERO.to::<u64>(),
2377 BlockNumber::Number(num) => num,
2378 BlockNumber::Safe => current.saturating_sub(self.slots_in_an_epoch),
2379 BlockNumber::Finalized => current.saturating_sub(self.slots_in_an_epoch * 2),
2380 },
2381 };
2382
2383 if requested > current {
2384 Err(BlockchainError::BlockOutOfRange(current, requested))
2385 } else {
2386 Ok(requested)
2387 }
2388 }
2389
2390 pub fn convert_block_number(&self, block: Option<BlockNumber>) -> u64 {
2391 let current = self.best_number();
2392 match block.unwrap_or(BlockNumber::Latest) {
2393 BlockNumber::Latest | BlockNumber::Pending => current,
2394 BlockNumber::Earliest => 0,
2395 BlockNumber::Number(num) => num,
2396 BlockNumber::Safe => current.saturating_sub(self.slots_in_an_epoch),
2397 BlockNumber::Finalized => current.saturating_sub(self.slots_in_an_epoch * 2),
2398 }
2399 }
2400
2401 pub async fn with_database_at<F, T>(
2403 &self,
2404 block_request: Option<BlockRequest>,
2405 f: F,
2406 ) -> Result<T, BlockchainError>
2407 where
2408 F: FnOnce(Box<dyn MaybeFullDatabase + '_>, BlockEnv) -> T,
2409 {
2410 let block_number = match block_request {
2411 Some(BlockRequest::Pending(pool_transactions)) => {
2412 let result = self
2413 .with_pending_block(pool_transactions, |state, block| {
2414 let block = block.block;
2415 let block = BlockEnv {
2416 number: U256::from(block.header.number),
2417 beneficiary: block.header.beneficiary,
2418 timestamp: U256::from(block.header.timestamp),
2419 difficulty: block.header.difficulty,
2420 prevrandao: Some(block.header.mix_hash),
2421 basefee: block.header.base_fee_per_gas.unwrap_or_default(),
2422 gas_limit: block.header.gas_limit,
2423 ..Default::default()
2424 };
2425 f(state, block)
2426 })
2427 .await;
2428 return Ok(result);
2429 }
2430 Some(BlockRequest::Number(bn)) => Some(BlockNumber::Number(bn)),
2431 None => None,
2432 };
2433 let block_number = self.convert_block_number(block_number);
2434 let current_number = self.best_number();
2435
2436 if block_number > current_number {
2438 return Err(BlockchainError::BlockOutOfRange(current_number, block_number));
2439 }
2440
2441 if block_number < current_number {
2442 if let Some((block_hash, block)) = self
2443 .block_by_number(BlockNumber::Number(block_number))
2444 .await?
2445 .map(|block| (block.header.hash, block))
2446 {
2447 let read_guard = self.states.upgradable_read();
2448 if let Some(state_db) = read_guard.get_state(&block_hash) {
2449 return Ok(get_block_env(state_db, block_number, block, f));
2450 } else {
2451 let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);
2452 if let Some(state) = write_guard.get_on_disk_state(&block_hash) {
2453 return Ok(get_block_env(state, block_number, block, f));
2454 }
2455 }
2456 }
2457
2458 warn!(target: "backend", "Not historic state found for block={}", block_number);
2459 return Err(BlockchainError::BlockOutOfRange(current_number, block_number));
2460 }
2461
2462 let db = self.db.read().await;
2463 let block = self.env.read().evm_env.block_env.clone();
2464 Ok(f(Box::new(&**db), block))
2465 }
2466
2467 pub async fn storage_at(
2468 &self,
2469 address: Address,
2470 index: U256,
2471 block_request: Option<BlockRequest>,
2472 ) -> Result<B256, BlockchainError> {
2473 self.with_database_at(block_request, |db, _| {
2474 trace!(target: "backend", "get storage for {:?} at {:?}", address, index);
2475 let val = db.storage_ref(address, index)?;
2476 Ok(val.into())
2477 })
2478 .await?
2479 }
2480
2481 pub async fn get_code(
2486 &self,
2487 address: Address,
2488 block_request: Option<BlockRequest>,
2489 ) -> Result<Bytes, BlockchainError> {
2490 self.with_database_at(block_request, |db, _| self.get_code_with_state(&db, address)).await?
2491 }
2492
2493 pub fn get_code_with_state(
2494 &self,
2495 state: &dyn DatabaseRef,
2496 address: Address,
2497 ) -> Result<Bytes, BlockchainError> {
2498 trace!(target: "backend", "get code for {:?}", address);
2499 let account = state.basic_ref(address)?.unwrap_or_default();
2500 if account.code_hash == KECCAK_EMPTY {
2501 return Ok(Default::default());
2503 }
2504 let code = if let Some(code) = account.code {
2505 code
2506 } else {
2507 state.code_by_hash_ref(account.code_hash)?
2508 };
2509 Ok(code.bytes()[..code.len()].to_vec().into())
2510 }
2511
2512 pub async fn get_balance(
2516 &self,
2517 address: Address,
2518 block_request: Option<BlockRequest>,
2519 ) -> Result<U256, BlockchainError> {
2520 self.with_database_at(block_request, |db, _| self.get_balance_with_state(db, address))
2521 .await?
2522 }
2523
2524 pub async fn get_account_at_block(
2525 &self,
2526 address: Address,
2527 block_request: Option<BlockRequest>,
2528 ) -> Result<TrieAccount, BlockchainError> {
2529 self.with_database_at(block_request, |block_db, _| {
2530 let db = block_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;
2531 let account = db.get(&address).cloned().unwrap_or_default();
2532 let storage_root = storage_root(&account.storage);
2533 let code_hash = account.info.code_hash;
2534 let balance = account.info.balance;
2535 let nonce = account.info.nonce;
2536 Ok(TrieAccount { balance, nonce, code_hash, storage_root })
2537 })
2538 .await?
2539 }
2540
2541 pub fn get_balance_with_state<D>(
2542 &self,
2543 state: D,
2544 address: Address,
2545 ) -> Result<U256, BlockchainError>
2546 where
2547 D: DatabaseRef,
2548 {
2549 trace!(target: "backend", "get balance for {:?}", address);
2550 Ok(state.basic_ref(address)?.unwrap_or_default().balance)
2551 }
2552
2553 pub async fn get_nonce(
2557 &self,
2558 address: Address,
2559 block_request: BlockRequest,
2560 ) -> Result<u64, BlockchainError> {
2561 if let BlockRequest::Pending(pool_transactions) = &block_request
2562 && let Some(value) = get_pool_transactions_nonce(pool_transactions, address)
2563 {
2564 return Ok(value);
2565 }
2566 let final_block_request = match block_request {
2567 BlockRequest::Pending(_) => BlockRequest::Number(self.best_number()),
2568 BlockRequest::Number(bn) => BlockRequest::Number(bn),
2569 };
2570
2571 self.with_database_at(Some(final_block_request), |db, _| {
2572 trace!(target: "backend", "get nonce for {:?}", address);
2573 Ok(db.basic_ref(address)?.unwrap_or_default().nonce)
2574 })
2575 .await?
2576 }
2577
2578 pub async fn trace_transaction(
2580 &self,
2581 hash: B256,
2582 ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {
2583 if let Some(traces) = self.mined_parity_trace_transaction(hash) {
2584 return Ok(traces);
2585 }
2586
2587 if let Some(fork) = self.get_fork() {
2588 return Ok(fork.trace_transaction(hash).await?);
2589 }
2590
2591 Ok(vec![])
2592 }
2593
2594 pub(crate) fn mined_parity_trace_transaction(
2596 &self,
2597 hash: B256,
2598 ) -> Option<Vec<LocalizedTransactionTrace>> {
2599 self.blockchain.storage.read().transactions.get(&hash).map(|tx| tx.parity_traces())
2600 }
2601
2602 pub(crate) fn mined_transaction(&self, hash: B256) -> Option<MinedTransaction> {
2604 self.blockchain.storage.read().transactions.get(&hash).cloned()
2605 }
2606
2607 pub(crate) fn mined_parity_trace_block(
2609 &self,
2610 block: u64,
2611 ) -> Option<Vec<LocalizedTransactionTrace>> {
2612 let block = self.get_block(block)?;
2613 let mut traces = vec![];
2614 let storage = self.blockchain.storage.read();
2615 for tx in block.body.transactions {
2616 traces.extend(storage.transactions.get(&tx.hash())?.parity_traces());
2617 }
2618 Some(traces)
2619 }
2620
2621 pub async fn debug_trace_transaction(
2623 &self,
2624 hash: B256,
2625 opts: GethDebugTracingOptions,
2626 ) -> Result<GethTrace, BlockchainError> {
2627 #[cfg(feature = "js-tracer")]
2628 if let Some(tracer_type) = opts.tracer.as_ref()
2629 && tracer_type.is_js()
2630 {
2631 return self
2632 .trace_tx_with_js_tracer(hash, tracer_type.as_str().to_string(), opts.clone())
2633 .await;
2634 }
2635
2636 if let Some(trace) = self.mined_geth_trace_transaction(hash, opts.clone()).await {
2637 return trace;
2638 }
2639
2640 if let Some(fork) = self.get_fork() {
2641 return Ok(fork.debug_trace_transaction(hash, opts).await?);
2642 }
2643
2644 Ok(GethTrace::Default(Default::default()))
2645 }
2646
2647 fn replay_tx_with_inspector<I, F, T>(
2648 &self,
2649 hash: B256,
2650 mut inspector: I,
2651 f: F,
2652 ) -> Result<T, BlockchainError>
2653 where
2654 for<'a> I: Inspector<EthEvmContext<WrapDatabaseRef<&'a CacheDB<Box<&'a StateDb>>>>>
2655 + Inspector<OpContext<WrapDatabaseRef<&'a CacheDB<Box<&'a StateDb>>>>>
2656 + 'a,
2657 for<'a> F:
2658 FnOnce(ResultAndState<OpHaltReason>, CacheDB<Box<&'a StateDb>>, I, TxEnv, Env) -> T,
2659 {
2660 let block = {
2661 let storage = self.blockchain.storage.read();
2662 let MinedTransaction { block_hash, .. } = storage
2663 .transactions
2664 .get(&hash)
2665 .cloned()
2666 .ok_or(BlockchainError::TransactionNotFound)?;
2667
2668 storage.blocks.get(&block_hash).cloned().ok_or(BlockchainError::BlockNotFound)?
2669 };
2670
2671 let index = block
2672 .body
2673 .transactions
2674 .iter()
2675 .position(|tx| tx.hash() == hash)
2676 .expect("transaction not found in block");
2677
2678 let pool_txs: Vec<Arc<PoolTransaction>> = block.body.transactions[..index]
2679 .iter()
2680 .map(|tx| {
2681 let pending_tx =
2682 PendingTransaction::from_maybe_impersonated(tx.clone()).expect("is valid");
2683 Arc::new(PoolTransaction {
2684 pending_transaction: pending_tx,
2685 requires: vec![],
2686 provides: vec![],
2687 priority: crate::eth::pool::transactions::TransactionPriority(0),
2688 })
2689 })
2690 .collect();
2691
2692 let trace = |parent_state: &StateDb| -> Result<T, BlockchainError> {
2693 let mut cache_db = CacheDB::new(Box::new(parent_state));
2694
2695 let mut env = self.env.read().clone();
2697
2698 env.evm_env.block_env = BlockEnv {
2699 number: U256::from(block.header.number),
2700 beneficiary: block.header.beneficiary,
2701 timestamp: U256::from(block.header.timestamp),
2702 difficulty: block.header.difficulty,
2703 prevrandao: Some(block.header.mix_hash),
2704 basefee: block.header.base_fee_per_gas.unwrap_or_default(),
2705 gas_limit: block.header.gas_limit,
2706 ..Default::default()
2707 };
2708
2709 let executor = TransactionExecutor {
2710 db: &mut cache_db,
2711 validator: self,
2712 pending: pool_txs.into_iter(),
2713 evm_env: env.evm_env.clone(),
2714 parent_hash: block.header.parent_hash,
2715 gas_used: 0,
2716 blob_gas_used: 0,
2717 enable_steps_tracing: self.enable_steps_tracing,
2718 print_logs: self.print_logs,
2719 print_traces: self.print_traces,
2720 call_trace_decoder: self.call_trace_decoder.clone(),
2721 precompile_factory: self.precompile_factory.clone(),
2722 networks: self.env.read().networks,
2723 blob_params: self.blob_params(),
2724 cheats: self.cheats().clone(),
2725 };
2726
2727 let _ = executor.execute();
2728
2729 let target_tx = block.body.transactions[index].clone();
2730 let target_tx = PendingTransaction::from_maybe_impersonated(target_tx)?;
2731 let mut tx_env: OpTransaction<TxEnv> = FromRecoveredTx::from_recovered_tx(
2732 target_tx.transaction.as_ref(),
2733 *target_tx.sender(),
2734 );
2735 if env.networks.is_optimism() {
2736 tx_env.enveloped_tx = Some(target_tx.transaction.encoded_2718().into());
2737 }
2738
2739 let mut evm = self.new_evm_with_inspector_ref(&cache_db, &env, &mut inspector);
2740
2741 let result = evm
2742 .transact(tx_env.clone())
2743 .map_err(|err| BlockchainError::Message(err.to_string()))?;
2744
2745 Ok(f(result, cache_db, inspector, tx_env.base, env))
2746 };
2747
2748 let read_guard = self.states.upgradable_read();
2749 if let Some(state) = read_guard.get_state(&block.header.parent_hash) {
2750 trace(state)
2751 } else {
2752 let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);
2753 let state = write_guard
2754 .get_on_disk_state(&block.header.parent_hash)
2755 .ok_or(BlockchainError::BlockNotFound)?;
2756 trace(state)
2757 }
2758 }
2759
2760 #[cfg(feature = "js-tracer")]
2762 pub async fn trace_tx_with_js_tracer(
2763 &self,
2764 hash: B256,
2765 code: String,
2766 opts: GethDebugTracingOptions,
2767 ) -> Result<GethTrace, BlockchainError> {
2768 let GethDebugTracingOptions { tracer_config, .. } = opts;
2769 let config = tracer_config.into_json();
2770 let inspector = revm_inspectors::tracing::js::JsInspector::new(code, config)
2771 .map_err(|err| BlockchainError::Message(err.to_string()))?;
2772 let trace = self.replay_tx_with_inspector(
2773 hash,
2774 inspector,
2775 |result, cache_db, mut inspector, tx_env, env| {
2776 inspector
2777 .json_result(
2778 result,
2779 &alloy_evm::IntoTxEnv::into_tx_env(tx_env),
2780 &env.evm_env.block_env,
2781 &cache_db,
2782 )
2783 .map_err(|e| BlockchainError::Message(e.to_string()))
2784 },
2785 )??;
2786 Ok(GethTrace::JS(trace))
2787 }
2788
2789 pub async fn debug_code_by_hash(
2791 &self,
2792 code_hash: B256,
2793 block_id: Option<BlockId>,
2794 ) -> Result<Option<Bytes>, BlockchainError> {
2795 if let Ok(code) = self.db.read().await.code_by_hash_ref(code_hash) {
2796 return Ok(Some(code.original_bytes()));
2797 }
2798 if let Some(fork) = self.get_fork() {
2799 return Ok(fork.debug_code_by_hash(code_hash, block_id).await?);
2800 }
2801
2802 Ok(None)
2803 }
2804
2805 pub async fn debug_db_get(&self, key: String) -> Result<Option<Bytes>, BlockchainError> {
2813 let key_bytes = if key.starts_with("0x") {
2814 hex::decode(&key)
2815 .map_err(|_| BlockchainError::Message("Invalid hex key".to_string()))?
2816 } else {
2817 key.into_bytes()
2818 };
2819
2820 if key_bytes.len() != 33 {
2822 return Err(BlockchainError::Message(format!(
2823 "Invalid key length: expected 33 bytes, got {}",
2824 key_bytes.len()
2825 )));
2826 }
2827
2828 if key_bytes[0] != 0x63 {
2830 return Err(BlockchainError::Message(
2831 "Key prefix must be 0x63 for code hash lookups".to_string(),
2832 ));
2833 }
2834
2835 let code_hash = B256::from_slice(&key_bytes[1..33]);
2836
2837 self.debug_code_by_hash(code_hash, None).await
2839 }
2840
2841 fn geth_trace(
2842 &self,
2843 tx: &MinedTransaction,
2844 opts: GethDebugTracingOptions,
2845 ) -> Result<GethTrace, BlockchainError> {
2846 let GethDebugTracingOptions { config, tracer, tracer_config, .. } = opts;
2847
2848 if let Some(tracer) = tracer {
2849 match tracer {
2850 GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
2851 GethDebugBuiltInTracerType::FourByteTracer => {
2852 let inspector = FourByteInspector::default();
2853 let res = self.replay_tx_with_inspector(
2854 tx.info.transaction_hash,
2855 inspector,
2856 |_, _, inspector, _, _| FourByteFrame::from(inspector).into(),
2857 )?;
2858 return Ok(res);
2859 }
2860 GethDebugBuiltInTracerType::CallTracer => {
2861 return match tracer_config.into_call_config() {
2862 Ok(call_config) => {
2863 let inspector = TracingInspector::new(
2864 TracingInspectorConfig::from_geth_call_config(&call_config),
2865 );
2866 let frame = self.replay_tx_with_inspector(
2867 tx.info.transaction_hash,
2868 inspector,
2869 |_, _, inspector, _, _| {
2870 inspector
2871 .geth_builder()
2872 .geth_call_traces(
2873 call_config,
2874 tx.receipt.cumulative_gas_used(),
2875 )
2876 .into()
2877 },
2878 )?;
2879 Ok(frame)
2880 }
2881 Err(e) => Err(RpcError::invalid_params(e.to_string()).into()),
2882 };
2883 }
2884 GethDebugBuiltInTracerType::PreStateTracer => {
2885 return match tracer_config.into_pre_state_config() {
2886 Ok(pre_state_config) => {
2887 let inspector = TracingInspector::new(
2888 TracingInspectorConfig::from_geth_prestate_config(
2889 &pre_state_config,
2890 ),
2891 );
2892 let frame = self.replay_tx_with_inspector(
2893 tx.info.transaction_hash,
2894 inspector,
2895 |state, db, inspector, _, _| {
2896 inspector.geth_builder().geth_prestate_traces(
2897 &state,
2898 &pre_state_config,
2899 db,
2900 )
2901 },
2902 )??;
2903 Ok(frame.into())
2904 }
2905 Err(e) => Err(RpcError::invalid_params(e.to_string()).into()),
2906 };
2907 }
2908 GethDebugBuiltInTracerType::NoopTracer
2909 | GethDebugBuiltInTracerType::MuxTracer
2910 | GethDebugBuiltInTracerType::Erc7562Tracer
2911 | GethDebugBuiltInTracerType::FlatCallTracer => {}
2912 },
2913 GethDebugTracerType::JsTracer(_code) => {}
2914 }
2915
2916 return Ok(NoopFrame::default().into());
2917 }
2918
2919 Ok(GethTraceBuilder::new(tx.info.traces.clone())
2921 .geth_traces(
2922 tx.receipt.cumulative_gas_used(),
2923 tx.info.out.clone().unwrap_or_default(),
2924 config,
2925 )
2926 .into())
2927 }
2928
2929 async fn mined_geth_trace_transaction(
2930 &self,
2931 hash: B256,
2932 opts: GethDebugTracingOptions,
2933 ) -> Option<Result<GethTrace, BlockchainError>> {
2934 self.blockchain.storage.read().transactions.get(&hash).map(|tx| self.geth_trace(tx, opts))
2935 }
2936
2937 pub async fn trace_block(
2939 &self,
2940 block: BlockNumber,
2941 ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {
2942 let number = self.convert_block_number(Some(block));
2943 if let Some(traces) = self.mined_parity_trace_block(number) {
2944 return Ok(traces);
2945 }
2946
2947 if let Some(fork) = self.get_fork()
2948 && fork.predates_fork(number)
2949 {
2950 return Ok(fork.trace_block(number).await?);
2951 }
2952
2953 Ok(vec![])
2954 }
2955
2956 pub async fn trace_replay_block_transactions(
2958 &self,
2959 block: BlockNumber,
2960 trace_types: HashSet<TraceType>,
2961 ) -> Result<Vec<TraceResultsWithTransactionHash>, BlockchainError> {
2962 let block_number = self.convert_block_number(Some(block));
2963
2964 if let Some(results) =
2966 self.mined_parity_trace_replay_block_transactions(block_number, &trace_types)
2967 {
2968 return Ok(results);
2969 }
2970
2971 if let Some(fork) = self.get_fork()
2973 && fork.predates_fork(block_number)
2974 {
2975 return Ok(fork.trace_replay_block_transactions(block_number, trace_types).await?);
2976 }
2977
2978 Ok(vec![])
2979 }
2980
2981 fn mined_parity_trace_replay_block_transactions(
2983 &self,
2984 block_number: u64,
2985 trace_types: &HashSet<TraceType>,
2986 ) -> Option<Vec<TraceResultsWithTransactionHash>> {
2987 let block = self.get_block(block_number)?;
2988
2989 let parent_hash = block.header.parent_hash;
2991 let trace_config = TracingInspectorConfig::from_parity_config(trace_types);
2992
2993 let read_guard = self.states.upgradable_read();
2994 if let Some(state) = read_guard.get_state(&parent_hash) {
2995 self.replay_block_transactions_with_inspector(&block, state, trace_config, trace_types)
2996 } else {
2997 let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);
2998 let state = write_guard.get_on_disk_state(&parent_hash)?;
2999 self.replay_block_transactions_with_inspector(&block, state, trace_config, trace_types)
3000 }
3001 }
3002
3003 fn replay_block_transactions_with_inspector(
3005 &self,
3006 block: &Block,
3007 parent_state: &StateDb,
3008 trace_config: TracingInspectorConfig,
3009 trace_types: &HashSet<TraceType>,
3010 ) -> Option<Vec<TraceResultsWithTransactionHash>> {
3011 let mut cache_db = CacheDB::new(Box::new(parent_state));
3012 let mut results = Vec::new();
3013
3014 let mut env = self.env.read().clone();
3016 env.evm_env.block_env = BlockEnv {
3017 number: U256::from(block.header.number),
3018 beneficiary: block.header.beneficiary,
3019 timestamp: U256::from(block.header.timestamp),
3020 difficulty: block.header.difficulty,
3021 prevrandao: Some(block.header.mix_hash),
3022 basefee: block.header.base_fee_per_gas.unwrap_or_default(),
3023 gas_limit: block.header.gas_limit,
3024 ..Default::default()
3025 };
3026
3027 for tx_envelope in &block.body.transactions {
3029 let tx_hash = tx_envelope.hash();
3030
3031 let mut inspector = TracingInspector::new(trace_config);
3033
3034 let pending_tx =
3036 PendingTransaction::from_maybe_impersonated(tx_envelope.clone()).ok()?;
3037 let mut tx_env: OpTransaction<TxEnv> = FromRecoveredTx::from_recovered_tx(
3038 pending_tx.transaction.as_ref(),
3039 *pending_tx.sender(),
3040 );
3041 if env.networks.is_optimism() {
3042 tx_env.enveloped_tx = Some(pending_tx.transaction.encoded_2718().into());
3043 }
3044
3045 let mut evm = self.new_evm_with_inspector_ref(&cache_db, &env, &mut inspector);
3047 let result = evm.transact(tx_env.clone()).ok()?;
3048
3049 let full_trace = inspector
3051 .into_parity_builder()
3052 .into_trace_results_with_state(&result, trace_types, &cache_db)
3053 .ok()?;
3054
3055 results.push(TraceResultsWithTransactionHash { transaction_hash: tx_hash, full_trace });
3056
3057 cache_db.commit(result.state);
3059 }
3060
3061 Some(results)
3062 }
3063
3064 pub async fn transaction_receipt(
3065 &self,
3066 hash: B256,
3067 ) -> Result<Option<FoundryTxReceipt>, BlockchainError> {
3068 if let Some(receipt) = self.mined_transaction_receipt(hash) {
3069 return Ok(Some(receipt.inner));
3070 }
3071
3072 if let Some(fork) = self.get_fork() {
3073 let receipt = fork.transaction_receipt(hash).await?;
3074 let number = self.convert_block_number(
3075 receipt.clone().and_then(|r| r.block_number()).map(BlockNumber::from),
3076 );
3077
3078 if fork.predates_fork_inclusive(number) {
3079 return Ok(receipt);
3080 }
3081 }
3082
3083 Ok(None)
3084 }
3085
3086 pub async fn trace_filter(
3088 &self,
3089 filter: TraceFilter,
3090 ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {
3091 let matcher = filter.matcher();
3092 let start = filter.from_block.unwrap_or(0);
3093 let end = filter.to_block.unwrap_or_else(|| self.best_number());
3094
3095 if start > end {
3096 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3097 "invalid block range, ensure that to block is greater than from block".to_string(),
3098 )));
3099 }
3100
3101 let dist = end - start;
3102 if dist > 300 {
3103 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3104 "block range too large, currently limited to 300".to_string(),
3105 )));
3106 }
3107
3108 let mut trace_tasks = vec![];
3110 for num in start..=end {
3111 trace_tasks.push(self.trace_block(num.into()));
3112 }
3113
3114 let traces = futures::future::try_join_all(trace_tasks).await?;
3116 let filtered_traces =
3117 traces.into_iter().flatten().filter(|trace| matcher.matches(&trace.trace));
3118
3119 let filtered_traces: Vec<_> = if let Some(after) = filter.after {
3121 filtered_traces.skip(after as usize).collect()
3122 } else {
3123 filtered_traces.collect()
3124 };
3125
3126 let filtered_traces: Vec<_> = if let Some(count) = filter.count {
3127 filtered_traces.into_iter().take(count as usize).collect()
3128 } else {
3129 filtered_traces
3130 };
3131
3132 Ok(filtered_traces)
3133 }
3134
3135 pub fn mined_receipts(&self, hash: B256) -> Option<Vec<FoundryReceiptEnvelope>> {
3137 let block = self.mined_block_by_hash(hash)?;
3138 let mut receipts = Vec::new();
3139 let storage = self.blockchain.storage.read();
3140 for tx in block.transactions.hashes() {
3141 let receipt = storage.transactions.get(&tx)?.receipt.clone();
3142 receipts.push(receipt);
3143 }
3144 Some(receipts)
3145 }
3146
3147 pub fn mined_block_receipts(&self, id: impl Into<BlockId>) -> Option<Vec<FoundryTxReceipt>> {
3149 let mut receipts = Vec::new();
3150 let block = self.get_block(id)?;
3151
3152 for transaction in block.body.transactions {
3153 let receipt = self.mined_transaction_receipt(transaction.hash())?;
3154 receipts.push(receipt.inner);
3155 }
3156
3157 Some(receipts)
3158 }
3159
3160 pub(crate) fn mined_transaction_receipt(&self, hash: B256) -> Option<MinedTransactionReceipt> {
3162 let MinedTransaction { info, receipt: tx_receipt, block_hash, .. } =
3163 self.blockchain.get_transaction_by_hash(&hash)?;
3164
3165 let index = info.transaction_index as usize;
3166 let block = self.blockchain.get_block_by_hash(&block_hash)?;
3167 let transaction = block.body.transactions[index].clone();
3168
3169 let excess_blob_gas = block.header.excess_blob_gas;
3171 let blob_gas_price =
3172 alloy_eips::eip4844::calc_blob_gasprice(excess_blob_gas.unwrap_or_default());
3173 let blob_gas_used = transaction.blob_gas_used();
3174
3175 let effective_gas_price = transaction.effective_gas_price(block.header.base_fee_per_gas);
3176
3177 let receipts = self.get_receipts(block.body.transactions.iter().map(|tx| tx.hash()));
3178 let next_log_index = receipts[..index].iter().map(|r| r.logs().len()).sum::<usize>();
3179
3180 let tx_receipt = tx_receipt.convert_logs_rpc(
3181 BlockNumHash::new(block.header.number, block_hash),
3182 block.header.timestamp,
3183 info.transaction_hash,
3184 info.transaction_index,
3185 next_log_index,
3186 );
3187
3188 let receipt = TransactionReceipt {
3189 inner: tx_receipt,
3190 transaction_hash: info.transaction_hash,
3191 transaction_index: Some(info.transaction_index),
3192 block_number: Some(block.header.number),
3193 gas_used: info.gas_used,
3194 contract_address: info.contract_address,
3195 effective_gas_price,
3196 block_hash: Some(block_hash),
3197 from: info.from,
3198 to: info.to,
3199 blob_gas_price: Some(blob_gas_price),
3200 blob_gas_used,
3201 };
3202
3203 let inner = FoundryTxReceipt::with_timestamp(receipt, block.header.timestamp);
3205 Some(MinedTransactionReceipt { inner, out: info.out })
3206 }
3207
3208 pub async fn block_receipts(
3210 &self,
3211 number: BlockId,
3212 ) -> Result<Option<Vec<FoundryTxReceipt>>, BlockchainError> {
3213 if let Some(receipts) = self.mined_block_receipts(number) {
3214 return Ok(Some(receipts));
3215 }
3216
3217 if let Some(fork) = self.get_fork() {
3218 let number = match self.ensure_block_number(Some(number)).await {
3219 Err(_) => return Ok(None),
3220 Ok(n) => n,
3221 };
3222
3223 if fork.predates_fork_inclusive(number) {
3224 let receipts = fork.block_receipts(number).await?;
3225
3226 return Ok(receipts);
3227 }
3228 }
3229
3230 Ok(None)
3231 }
3232
3233 pub async fn transaction_by_block_number_and_index(
3234 &self,
3235 number: BlockNumber,
3236 index: Index,
3237 ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {
3238 if let Some(block) = self.mined_block_by_number(number) {
3239 return Ok(self.mined_transaction_by_block_hash_and_index(block.header.hash, index));
3240 }
3241
3242 if let Some(fork) = self.get_fork() {
3243 let number = self.convert_block_number(Some(number));
3244 if fork.predates_fork(number) {
3245 return Ok(fork
3246 .transaction_by_block_number_and_index(number, index.into())
3247 .await?);
3248 }
3249 }
3250
3251 Ok(None)
3252 }
3253
3254 pub async fn transaction_by_block_hash_and_index(
3255 &self,
3256 hash: B256,
3257 index: Index,
3258 ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {
3259 if let tx @ Some(_) = self.mined_transaction_by_block_hash_and_index(hash, index) {
3260 return Ok(tx);
3261 }
3262
3263 if let Some(fork) = self.get_fork() {
3264 return Ok(fork.transaction_by_block_hash_and_index(hash, index.into()).await?);
3265 }
3266
3267 Ok(None)
3268 }
3269
3270 pub fn mined_transaction_by_block_hash_and_index(
3271 &self,
3272 block_hash: B256,
3273 index: Index,
3274 ) -> Option<AnyRpcTransaction> {
3275 let (info, block, tx) = {
3276 let storage = self.blockchain.storage.read();
3277 let block = storage.blocks.get(&block_hash).cloned()?;
3278 let index: usize = index.into();
3279 let tx = block.body.transactions.get(index)?.clone();
3280 let info = storage.transactions.get(&tx.hash())?.info.clone();
3281 (info, block, tx)
3282 };
3283
3284 Some(transaction_build(
3285 Some(info.transaction_hash),
3286 tx,
3287 Some(&block),
3288 Some(info),
3289 block.header.base_fee_per_gas,
3290 ))
3291 }
3292
3293 pub async fn transaction_by_hash(
3294 &self,
3295 hash: B256,
3296 ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {
3297 trace!(target: "backend", "transaction_by_hash={:?}", hash);
3298 if let tx @ Some(_) = self.mined_transaction_by_hash(hash) {
3299 return Ok(tx);
3300 }
3301
3302 if let Some(fork) = self.get_fork() {
3303 return fork
3304 .transaction_by_hash(hash)
3305 .await
3306 .map_err(BlockchainError::AlloyForkProvider);
3307 }
3308
3309 Ok(None)
3310 }
3311
3312 pub fn mined_transaction_by_hash(&self, hash: B256) -> Option<AnyRpcTransaction> {
3313 let (info, block) = {
3314 let storage = self.blockchain.storage.read();
3315 let MinedTransaction { info, block_hash, .. } =
3316 storage.transactions.get(&hash)?.clone();
3317 let block = storage.blocks.get(&block_hash).cloned()?;
3318 (info, block)
3319 };
3320 let tx = block.body.transactions.get(info.transaction_index as usize)?.clone();
3321
3322 Some(transaction_build(
3323 Some(info.transaction_hash),
3324 tx,
3325 Some(&block),
3326 Some(info),
3327 block.header.base_fee_per_gas,
3328 ))
3329 }
3330
3331 pub fn get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<alloy_consensus::Blob>>> {
3332 if let Some(tx) = self.mined_transaction_by_hash(hash)
3334 && let Ok(typed_tx) = FoundryTxEnvelope::try_from(tx)
3335 && let Some(sidecar) = typed_tx.sidecar()
3336 {
3337 return Ok(Some(sidecar.sidecar.blobs().to_vec()));
3338 }
3339
3340 Ok(None)
3341 }
3342
3343 pub fn get_blobs_by_block_id(
3344 &self,
3345 id: impl Into<BlockId>,
3346 versioned_hashes: Vec<B256>,
3347 ) -> Result<Option<Vec<alloy_consensus::Blob>>> {
3348 Ok(self.get_block(id).map(|block| {
3349 block
3350 .body
3351 .transactions
3352 .iter()
3353 .filter_map(|tx| tx.as_ref().sidecar())
3354 .flat_map(|sidecar| {
3355 sidecar.sidecar.blobs().iter().zip(sidecar.sidecar.commitments().iter())
3356 })
3357 .filter(|(_, commitment)| {
3358 versioned_hashes.is_empty()
3360 || versioned_hashes.contains(&kzg_to_versioned_hash(commitment.as_slice()))
3361 })
3362 .map(|(blob, _)| *blob)
3363 .collect()
3364 }))
3365 }
3366
3367 pub fn get_blob_by_versioned_hash(&self, hash: B256) -> Result<Option<Blob>> {
3368 let storage = self.blockchain.storage.read();
3369 for block in storage.blocks.values() {
3370 for tx in &block.body.transactions {
3371 let typed_tx = tx.as_ref();
3372 if let Some(sidecar) = typed_tx.sidecar() {
3373 for versioned_hash in sidecar.sidecar.versioned_hashes() {
3374 if versioned_hash == hash
3375 && let Some(index) =
3376 sidecar.sidecar.commitments().iter().position(|commitment| {
3377 kzg_to_versioned_hash(commitment.as_slice()) == *hash
3378 })
3379 && let Some(blob) = sidecar.sidecar.blobs().get(index)
3380 {
3381 return Ok(Some(*blob));
3382 }
3383 }
3384 }
3385 }
3386 }
3387 Ok(None)
3388 }
3389
3390 pub async fn impersonate_signature(
3392 &self,
3393 signature: Bytes,
3394 address: Address,
3395 ) -> Result<(), BlockchainError> {
3396 self.cheats.add_recover_override(signature, address);
3397 Ok(())
3398 }
3399
3400 pub async fn prove_account_at(
3404 &self,
3405 address: Address,
3406 keys: Vec<B256>,
3407 block_request: Option<BlockRequest>,
3408 ) -> Result<AccountProof, BlockchainError> {
3409 let block_number = block_request.as_ref().map(|r| r.block_number());
3410
3411 self.with_database_at(block_request, |block_db, _| {
3412 trace!(target: "backend", "get proof for {:?} at {:?}", address, block_number);
3413 let db = block_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;
3414 let account = db.get(&address).cloned().unwrap_or_default();
3415
3416 let mut builder = HashBuilder::default()
3417 .with_proof_retainer(ProofRetainer::new(vec![Nibbles::unpack(keccak256(address))]));
3418
3419 for (key, account) in trie_accounts(db) {
3420 builder.add_leaf(key, &account);
3421 }
3422
3423 let _ = builder.root();
3424
3425 let proof = builder
3426 .take_proof_nodes()
3427 .into_nodes_sorted()
3428 .into_iter()
3429 .map(|(_, v)| v)
3430 .collect();
3431 let (storage_hash, storage_proofs) = prove_storage(&account.storage, &keys);
3432
3433 let account_proof = AccountProof {
3434 address,
3435 balance: account.info.balance,
3436 nonce: account.info.nonce,
3437 code_hash: account.info.code_hash,
3438 storage_hash,
3439 account_proof: proof,
3440 storage_proof: keys
3441 .into_iter()
3442 .zip(storage_proofs)
3443 .map(|(key, proof)| {
3444 let storage_key: U256 = key.into();
3445 let value = account.storage.get(&storage_key).copied().unwrap_or_default();
3446 StorageProof { key: JsonStorageKey::Hash(key), value, proof }
3447 })
3448 .collect(),
3449 };
3450
3451 Ok(account_proof)
3452 })
3453 .await?
3454 }
3455
3456 pub fn new_block_notifications(&self) -> NewBlockNotifications {
3458 let (tx, rx) = unbounded();
3459 self.new_block_listeners.lock().push(tx);
3460 trace!(target: "backed", "added new block listener");
3461 rx
3462 }
3463
3464 fn notify_on_new_block(&self, header: Header, hash: B256) {
3466 self.new_block_listeners.lock().retain(|tx| !tx.is_closed());
3469
3470 let notification = NewBlockNotification { hash, header: Arc::new(header) };
3471
3472 self.new_block_listeners
3473 .lock()
3474 .retain(|tx| tx.unbounded_send(notification.clone()).is_ok());
3475 }
3476
3477 pub async fn reorg(
3484 &self,
3485 depth: u64,
3486 tx_pairs: HashMap<u64, Vec<Arc<PoolTransaction>>>,
3487 common_block: Block,
3488 ) -> Result<(), BlockchainError> {
3489 self.rollback(common_block).await?;
3490 for i in 0..depth {
3492 let to_be_mined = tx_pairs.get(&i).cloned().unwrap_or_else(Vec::new);
3493 let outcome = self.do_mine_block(to_be_mined).await;
3494 node_info!(
3495 " Mined reorg block number {}. With {} valid txs and with invalid {} txs",
3496 outcome.block_number,
3497 outcome.included.len(),
3498 outcome.invalid.len()
3499 );
3500 }
3501
3502 Ok(())
3503 }
3504
3505 pub async fn rollback(&self, common_block: Block) -> Result<(), BlockchainError> {
3510 let common_state = {
3512 let return_state_or_throw_err =
3513 |db: Option<&StateDb>| -> Result<AddressMap<DbAccount>, BlockchainError> {
3514 let state_db = db.ok_or(BlockchainError::DataUnavailable)?;
3515 let db_full =
3516 state_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;
3517 Ok(db_full.clone())
3518 };
3519
3520 let hash = &common_block.header.hash_slow();
3521 let read_guard = self.states.upgradable_read();
3522 if let Some(db) = read_guard.get_state(hash) {
3523 return_state_or_throw_err(Some(db))?
3524 } else {
3525 let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);
3526 return_state_or_throw_err(write_guard.get_on_disk_state(hash))?
3527 }
3528 };
3529
3530 {
3531 self.blockchain
3533 .storage
3534 .write()
3535 .unwind_to(common_block.header.number, common_block.header.hash_slow());
3536
3537 let mut env = self.env.write();
3539 env.evm_env.block_env.number = U256::from(common_block.header.number);
3540 env.evm_env.block_env.timestamp = U256::from(common_block.header.timestamp);
3541 env.evm_env.block_env.gas_limit = common_block.header.gas_limit;
3542 env.evm_env.block_env.difficulty = common_block.header.difficulty;
3543 env.evm_env.block_env.prevrandao = Some(common_block.header.mix_hash);
3544
3545 self.time.reset(env.evm_env.block_env.timestamp.saturating_to());
3546 }
3547
3548 {
3549 let block_hashes: Vec<_> = {
3553 let storage = self.blockchain.storage.read();
3554 let min_block = common_block.header.number.saturating_sub(256);
3555 storage
3556 .hashes
3557 .iter()
3558 .filter(|(num, _)| **num >= min_block)
3559 .map(|(&num, &hash)| (num, hash))
3560 .collect()
3561 };
3562
3563 let mut db = self.db.write().await;
3565 db.clear();
3566
3567 for (address, acc) in common_state {
3569 db.insert_account(address, acc.info);
3570 for (key, value) in acc.storage {
3571 db.set_storage_at(address, key.into(), value.into())?;
3572 }
3573 }
3574
3575 for (block_num, hash) in block_hashes {
3578 db.insert_block_hash(U256::from(block_num), hash);
3579 }
3580 }
3581
3582 Ok(())
3583 }
3584}
3585
3586fn get_block_env<F, T>(state: &StateDb, block_number: u64, block: AnyRpcBlock, f: F) -> T
3587where
3588 F: FnOnce(Box<dyn MaybeFullDatabase + '_>, BlockEnv) -> T,
3589{
3590 let block = BlockEnv {
3591 number: U256::from(block_number),
3592 beneficiary: block.header.beneficiary,
3593 timestamp: U256::from(block.header.timestamp),
3594 difficulty: block.header.difficulty,
3595 prevrandao: block.header.mix_hash,
3596 basefee: block.header.base_fee_per_gas.unwrap_or_default(),
3597 gas_limit: block.header.gas_limit,
3598 ..Default::default()
3599 };
3600 f(Box::new(state), block)
3601}
3602
3603fn get_pool_transactions_nonce(
3605 pool_transactions: &[Arc<PoolTransaction>],
3606 address: Address,
3607) -> Option<u64> {
3608 if let Some(highest_nonce) = pool_transactions
3609 .iter()
3610 .filter(|tx| *tx.pending_transaction.sender() == address)
3611 .map(|tx| tx.pending_transaction.nonce())
3612 .max()
3613 {
3614 let tx_count = highest_nonce.saturating_add(1);
3615 return Some(tx_count);
3616 }
3617 None
3618}
3619
3620#[async_trait::async_trait]
3621impl TransactionValidator for Backend {
3622 async fn validate_pool_transaction(
3623 &self,
3624 tx: &PendingTransaction,
3625 ) -> Result<(), BlockchainError> {
3626 let address = *tx.sender();
3627 let account = self.get_account(address).await?;
3628 let env = self.next_env();
3629 Ok(self.validate_pool_transaction_for(tx, &account, &env)?)
3630 }
3631
3632 fn validate_pool_transaction_for(
3633 &self,
3634 pending: &PendingTransaction,
3635 account: &AccountInfo,
3636 env: &Env,
3637 ) -> Result<(), InvalidTransactionError> {
3638 let tx = &pending.transaction;
3639
3640 if let Some(tx_chain_id) = tx.chain_id() {
3641 let chain_id = self.chain_id();
3642 if chain_id.to::<u64>() != tx_chain_id {
3643 if let FoundryTxEnvelope::Legacy(tx) = tx.as_ref() {
3644 if env.evm_env.cfg_env.spec >= SpecId::SPURIOUS_DRAGON
3646 && tx.chain_id().is_none()
3647 {
3648 warn!(target: "backend", ?chain_id, ?tx_chain_id, "incompatible EIP155-based V");
3649 return Err(InvalidTransactionError::IncompatibleEIP155);
3650 }
3651 } else {
3652 warn!(target: "backend", ?chain_id, ?tx_chain_id, "invalid chain id");
3653 return Err(InvalidTransactionError::InvalidChainId);
3654 }
3655 }
3656 }
3657
3658 let is_deposit_tx = matches!(pending.transaction.as_ref(), FoundryTxEnvelope::Deposit(_));
3660 let nonce = tx.nonce();
3661 if nonce < account.nonce && !is_deposit_tx {
3662 warn!(target: "backend", "[{:?}] nonce too low", tx.hash());
3663 return Err(InvalidTransactionError::NonceTooLow);
3664 }
3665
3666 if env.evm_env.cfg_env.spec >= SpecId::CANCUN && tx.is_eip4844() {
3668 let blob_tx = match tx.as_ref() {
3670 FoundryTxEnvelope::Eip4844(tx) => tx.tx(),
3671 _ => unreachable!(),
3672 };
3673
3674 let blob_count = blob_tx.tx().blob_versioned_hashes.len();
3675
3676 if blob_count == 0 {
3678 return Err(InvalidTransactionError::NoBlobHashes);
3679 }
3680
3681 let max_blob_count = self.blob_params().max_blob_count as usize;
3683 if blob_count > max_blob_count {
3684 return Err(InvalidTransactionError::TooManyBlobs(blob_count, max_blob_count));
3685 }
3686
3687 if !self.skip_blob_validation(Some(*pending.sender()))
3689 && let Err(err) = blob_tx.validate(EnvKzgSettings::default().get())
3690 {
3691 return Err(InvalidTransactionError::BlobTransactionValidationError(err));
3692 }
3693 }
3694
3695 if env.evm_env.cfg_env.spec >= SpecId::SHANGHAI && tx.kind() == TxKind::Create {
3697 let max_initcode_size = env
3698 .evm_env
3699 .cfg_env
3700 .limit_contract_code_size
3701 .map(|limit| limit.saturating_mul(2))
3702 .unwrap_or(revm::primitives::eip3860::MAX_INITCODE_SIZE);
3703 if tx.input().len() > max_initcode_size {
3704 return Err(InvalidTransactionError::MaxInitCodeSizeExceeded);
3705 }
3706 }
3707
3708 if !self.disable_pool_balance_checks {
3710 if tx.gas_limit() < MIN_TRANSACTION_GAS as u64 {
3712 warn!(target: "backend", "[{:?}] gas too low", tx.hash());
3713 return Err(InvalidTransactionError::GasTooLow);
3714 }
3715
3716 if !env.evm_env.cfg_env.disable_block_gas_limit
3718 && tx.gas_limit() > env.evm_env.block_env.gas_limit
3719 {
3720 warn!(target: "backend", "[{:?}] gas too high", tx.hash());
3721 return Err(InvalidTransactionError::GasTooHigh(ErrDetail {
3722 detail: String::from("tx.gas_limit > env.block.gas_limit"),
3723 }));
3724 }
3725
3726 if env.evm_env.cfg_env.tx_gas_limit_cap.is_none()
3728 && tx.gas_limit() > env.evm_env.cfg_env().tx_gas_limit_cap()
3729 {
3730 warn!(target: "backend", "[{:?}] gas too high", tx.hash());
3731 return Err(InvalidTransactionError::GasTooHigh(ErrDetail {
3732 detail: String::from("tx.gas_limit > env.cfg.tx_gas_limit_cap"),
3733 }));
3734 }
3735
3736 if env.evm_env.cfg_env.spec >= SpecId::LONDON {
3738 if tx.max_fee_per_gas() < env.evm_env.block_env.basefee.into() && !is_deposit_tx {
3739 warn!(target: "backend", "max fee per gas={}, too low, block basefee={}", tx.max_fee_per_gas(), env.evm_env.block_env.basefee);
3740 return Err(InvalidTransactionError::FeeCapTooLow);
3741 }
3742
3743 if let (Some(max_priority_fee_per_gas), max_fee_per_gas) =
3744 (tx.as_ref().max_priority_fee_per_gas(), tx.as_ref().max_fee_per_gas())
3745 && max_priority_fee_per_gas > max_fee_per_gas
3746 {
3747 warn!(target: "backend", "max priority fee per gas={}, too high, max fee per gas={}", max_priority_fee_per_gas, max_fee_per_gas);
3748 return Err(InvalidTransactionError::TipAboveFeeCap);
3749 }
3750 }
3751
3752 if env.evm_env.cfg_env.spec >= SpecId::CANCUN
3754 && tx.is_eip4844()
3755 && let Some(max_fee_per_blob_gas) = tx.max_fee_per_blob_gas()
3756 && let Some(blob_gas_and_price) = &env.evm_env.block_env.blob_excess_gas_and_price
3757 && max_fee_per_blob_gas < blob_gas_and_price.blob_gasprice
3758 {
3759 warn!(target: "backend", "max fee per blob gas={}, too low, block blob gas price={}", max_fee_per_blob_gas, blob_gas_and_price.blob_gasprice);
3760 return Err(InvalidTransactionError::BlobFeeCapTooLow(
3761 max_fee_per_blob_gas,
3762 blob_gas_and_price.blob_gasprice,
3763 ));
3764 }
3765
3766 let max_cost =
3767 (tx.gas_limit() as u128).saturating_mul(tx.max_fee_per_gas()).saturating_add(
3768 tx.blob_gas_used()
3769 .map(|g| g as u128)
3770 .unwrap_or(0)
3771 .mul(tx.max_fee_per_blob_gas().unwrap_or(0)),
3772 );
3773 let value = tx.value();
3774 match tx.as_ref() {
3775 FoundryTxEnvelope::Deposit(deposit_tx) => {
3776 if value > account.balance + U256::from(deposit_tx.mint) {
3782 warn!(target: "backend", "[{:?}] insufficient balance={}, required={} account={:?}", tx.hash(), account.balance + U256::from(deposit_tx.mint), value, *pending.sender());
3783 return Err(InvalidTransactionError::InsufficientFunds);
3784 }
3785 }
3786 _ => {
3787 let req_funds =
3789 max_cost.checked_add(value.saturating_to()).ok_or_else(|| {
3790 warn!(target: "backend", "[{:?}] cost too high", tx.hash());
3791 InvalidTransactionError::InsufficientFunds
3792 })?;
3793 if account.balance < U256::from(req_funds) {
3794 warn!(target: "backend", "[{:?}] insufficient balance={}, required={} account={:?}", tx.hash(), account.balance, req_funds, *pending.sender());
3795 return Err(InvalidTransactionError::InsufficientFunds);
3796 }
3797 }
3798 }
3799 }
3800 Ok(())
3801 }
3802
3803 fn validate_for(
3804 &self,
3805 tx: &PendingTransaction,
3806 account: &AccountInfo,
3807 env: &Env,
3808 ) -> Result<(), InvalidTransactionError> {
3809 self.validate_pool_transaction_for(tx, account, env)?;
3810 if tx.nonce() > account.nonce {
3811 return Err(InvalidTransactionError::NonceTooHigh);
3812 }
3813 Ok(())
3814 }
3815}
3816
3817pub fn transaction_build(
3819 tx_hash: Option<B256>,
3820 eth_transaction: MaybeImpersonatedTransaction,
3821 block: Option<&Block>,
3822 info: Option<TransactionInfo>,
3823 base_fee: Option<u64>,
3824) -> AnyRpcTransaction {
3825 if let FoundryTxEnvelope::Deposit(deposit_tx) = eth_transaction.as_ref() {
3826 let dep_tx = deposit_tx;
3827
3828 let ser = serde_json::to_value(dep_tx).expect("could not serialize TxDeposit");
3829 let maybe_deposit_fields = OtherFields::try_from(ser);
3830
3831 match maybe_deposit_fields {
3832 Ok(mut fields) => {
3833 fields.insert("v".to_string(), serde_json::to_value("0x0").unwrap());
3836 fields.insert("r".to_string(), serde_json::to_value(B256::ZERO).unwrap());
3837 fields.insert(String::from("s"), serde_json::to_value(B256::ZERO).unwrap());
3838 fields.insert(String::from("nonce"), serde_json::to_value("0x0").unwrap());
3839
3840 let inner = UnknownTypedTransaction {
3841 ty: AnyTxType(DEPOSIT_TX_TYPE_ID),
3842 fields,
3843 memo: Default::default(),
3844 };
3845
3846 let envelope = AnyTxEnvelope::Unknown(UnknownTxEnvelope {
3847 hash: eth_transaction.hash(),
3848 inner,
3849 });
3850
3851 let tx = Transaction {
3852 inner: Recovered::new_unchecked(envelope, deposit_tx.from),
3853 block_hash: block
3854 .as_ref()
3855 .map(|block| B256::from(keccak256(alloy_rlp::encode(&block.header)))),
3856 block_number: block.as_ref().map(|block| block.header.number),
3857 transaction_index: info.as_ref().map(|info| info.transaction_index),
3858 effective_gas_price: None,
3859 };
3860
3861 return AnyRpcTransaction::from(WithOtherFields::new(tx));
3862 }
3863 Err(_) => {
3864 error!(target: "backend", "failed to serialize deposit transaction");
3865 }
3866 }
3867 }
3868
3869 let transaction = eth_transaction.into_rpc_transaction();
3870 let effective_gas_price = transaction.effective_gas_price(base_fee);
3871
3872 let envelope = transaction.inner;
3873 let from = envelope.signer();
3874
3875 let hash = tx_hash.unwrap_or(*envelope.tx_hash());
3881
3882 let envelope = match envelope.into_inner() {
3883 TxEnvelope::Legacy(signed_tx) => {
3884 let (t, sig, _) = signed_tx.into_parts();
3885 let new_signed = Signed::new_unchecked(t, sig, hash);
3886 AnyTxEnvelope::Ethereum(TxEnvelope::Legacy(new_signed))
3887 }
3888 TxEnvelope::Eip1559(signed_tx) => {
3889 let (t, sig, _) = signed_tx.into_parts();
3890 let new_signed = Signed::new_unchecked(t, sig, hash);
3891 AnyTxEnvelope::Ethereum(TxEnvelope::Eip1559(new_signed))
3892 }
3893 TxEnvelope::Eip2930(signed_tx) => {
3894 let (t, sig, _) = signed_tx.into_parts();
3895 let new_signed = Signed::new_unchecked(t, sig, hash);
3896 AnyTxEnvelope::Ethereum(TxEnvelope::Eip2930(new_signed))
3897 }
3898 TxEnvelope::Eip4844(signed_tx) => {
3899 let (t, sig, _) = signed_tx.into_parts();
3900 let new_signed = Signed::new_unchecked(t, sig, hash);
3901 AnyTxEnvelope::Ethereum(TxEnvelope::Eip4844(new_signed))
3902 }
3903 TxEnvelope::Eip7702(signed_tx) => {
3904 let (t, sig, _) = signed_tx.into_parts();
3905 let new_signed = Signed::new_unchecked(t, sig, hash);
3906 AnyTxEnvelope::Ethereum(TxEnvelope::Eip7702(new_signed))
3907 }
3908 };
3909
3910 let tx = Transaction {
3911 inner: Recovered::new_unchecked(envelope, from),
3912 block_hash: block.as_ref().map(|block| block.header.hash_slow()),
3913 block_number: block.as_ref().map(|block| block.header.number),
3914 transaction_index: info.as_ref().map(|info| info.transaction_index),
3915 effective_gas_price: Some(effective_gas_price),
3917 };
3918 AnyRpcTransaction::from(WithOtherFields::new(tx))
3919}
3920
3921pub fn prove_storage(storage: &HashMap<U256, U256>, keys: &[B256]) -> (B256, Vec<Vec<Bytes>>) {
3927 let keys: Vec<_> = keys.iter().map(|key| Nibbles::unpack(keccak256(key))).collect();
3928
3929 let mut builder = HashBuilder::default().with_proof_retainer(ProofRetainer::new(keys.clone()));
3930
3931 for (key, value) in trie_storage(storage) {
3932 builder.add_leaf(key, &value);
3933 }
3934
3935 let root = builder.root();
3936
3937 let mut proofs = Vec::new();
3938 let all_proof_nodes = builder.take_proof_nodes();
3939
3940 for proof_key in keys {
3941 let matching_proof_nodes =
3944 all_proof_nodes.matching_nodes_sorted(&proof_key).into_iter().map(|(_, node)| node);
3945 proofs.push(matching_proof_nodes.collect());
3946 }
3947
3948 (root, proofs)
3949}
3950
3951pub fn is_arbitrum(chain_id: u64) -> bool {
3952 if let Ok(chain) = NamedChain::try_from(chain_id) {
3953 return chain.is_arbitrum();
3954 }
3955 false
3956}
3957
3958pub fn op_haltreason_to_instruction_result(op_reason: OpHaltReason) -> InstructionResult {
3959 match op_reason {
3960 OpHaltReason::Base(eth_h) => eth_h.into(),
3961 OpHaltReason::FailedDeposit => InstructionResult::Stop,
3962 }
3963}
3964
3965#[cfg(test)]
3966mod tests {
3967 use crate::{NodeConfig, spawn};
3968
3969 #[tokio::test]
3970 async fn test_deterministic_block_mining() {
3971 let genesis_timestamp = 1743944919u64;
3973
3974 let config_a = NodeConfig::test().with_genesis_timestamp(genesis_timestamp.into());
3976 let config_b = NodeConfig::test().with_genesis_timestamp(genesis_timestamp.into());
3977
3978 let (api_a, _handle_a) = spawn(config_a).await;
3979 let (api_b, _handle_b) = spawn(config_b).await;
3980
3981 let outcome_a_1 = api_a.backend.mine_block(vec![]).await;
3983 let outcome_b_1 = api_b.backend.mine_block(vec![]).await;
3984
3985 assert_eq!(outcome_a_1.block_number, outcome_b_1.block_number);
3987
3988 let block_a_1 =
3990 api_a.block_by_number(outcome_a_1.block_number.into()).await.unwrap().unwrap();
3991 let block_b_1 =
3992 api_b.block_by_number(outcome_b_1.block_number.into()).await.unwrap().unwrap();
3993
3994 assert_eq!(
3996 block_a_1.header.hash, block_b_1.header.hash,
3997 "Block hashes should be deterministic. Got {} vs {}",
3998 block_a_1.header.hash, block_b_1.header.hash
3999 );
4000
4001 let outcome_a_2 = api_a.backend.mine_block(vec![]).await;
4003 let outcome_b_2 = api_b.backend.mine_block(vec![]).await;
4004
4005 let block_a_2 =
4006 api_a.block_by_number(outcome_a_2.block_number.into()).await.unwrap().unwrap();
4007 let block_b_2 =
4008 api_b.block_by_number(outcome_b_2.block_number.into()).await.unwrap().unwrap();
4009
4010 assert_eq!(
4011 block_a_2.header.hash, block_b_2.header.hash,
4012 "Second block hashes should also be deterministic. Got {} vs {}",
4013 block_a_2.header.hash, block_b_2.header.hash
4014 );
4015
4016 assert_ne!(
4018 block_a_1.header.hash, block_a_2.header.hash,
4019 "Different blocks should have different hashes"
4020 );
4021 }
4022}