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