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