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