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