1use super::{
2 backend::mem::{
3 BlockRequest, DatabaseRef, GasEstimateCallOptions, MonadReplayContext,
4 sanitize_simulation_blocks,
5 },
6 preserve_simulation_request_fields,
7 tempo_consensus::{TempoCertifiedBlock, TempoConsensusState},
8};
9use crate::{
10 ClientFork, LoggingManager, Miner, MiningMode, StorageInfo,
11 eth::{
12 backend::{
13 self, db::SerializableState, mem::MIN_TRANSACTION_GAS,
14 notifications::ChainNotifications, tempo_consensus::TempoConsensusIdentity,
15 validate::TransactionValidator,
16 },
17 error::{
18 BlockchainError, FeeHistoryError, InvalidTransactionError, Result, ToRpcResponseResult,
19 },
20 fees::{
21 FeeDetails, FeeHistoryCache, FeeHistoryCacheItem, MIN_SUGGESTED_PRIORITY_FEE,
22 REWARD_PERCENTILE_RESOLUTION, create_fee_history_cache_item,
23 },
24 macros::node_info,
25 miner::FixedBlockTimeMiner,
26 pool::{
27 Pool, PoolSnapshot,
28 transactions::{
29 PoolTransaction, TransactionOrder, TransactionPriority, TxMarker, to_marker,
30 },
31 },
32 sign::Signer,
33 },
34 filter::{EthFilter, Filters, LogsFilter},
35 mem::transaction_build,
36};
37use alloy_consensus::{
38 Blob, BlockHeader, Transaction, TrieAccount, TxEip4844Variant, TxReceipt, Typed2718,
39 transaction::{Recovered, SignerRecoverable},
40};
41use alloy_dyn_abi::TypedData;
42use alloy_eips::{
43 eip2718::{EIP4844_TX_TYPE_ID, Encodable2718},
44 eip4844::DATA_GAS_PER_BLOB,
45 eip7910::{EthConfig, EthForkConfig},
46};
47use alloy_evm::overrides::{OverrideBlockHashes, apply_state_overrides};
48use alloy_network::{
49 AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, BlockResponse, Network,
50 NetworkTransactionBuilder, ReceiptResponse, TransactionBuilder, TransactionBuilder4844,
51 TransactionResponse, eip2718::Decodable2718,
52};
53use alloy_primitives::{
54 Address, B64, B256, Bytes, TxHash, TxKind, U64, U256,
55 map::{AddressSet, B256Set, HashMap, HashSet},
56};
57use alloy_rlp::{Encodable, Header, PayloadView};
58use alloy_rpc_types::{
59 AccessListResult, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,
60 EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, Work,
61 anvil::{
62 ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo,
63 },
64 debug::ExecutionWitness,
65 erc4337::TransactionConditional,
66 pubsub::TransactionReceiptsParams,
67 request::TransactionRequest,
68 simulate::{MAX_SIMULATE_BLOCKS, SimulatePayload, SimulatedBlock},
69 state::{AccountOverride, EvmOverrides, StateOverride, StateOverridesBuilder},
70 trace::{
71 filter::TraceFilter,
72 geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult},
73 opcode::{BlockOpcodeGas, TransactionOpcodeGas},
74 parity::{
75 LocalizedTransactionTrace, TraceResults, TraceResultsWithTransactionHash, TraceType,
76 },
77 },
78 txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus},
79};
80use alloy_rpc_types_eth::{AccountInfo, Bundle, EthCallResponse, FillTransaction, StateContext};
81use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse};
82use alloy_serde::WithOtherFields;
83use alloy_sol_types::{SolCall, SolValue, sol};
84use anvil_core::{
85 eth::{
86 EthRequest, TempoConsensusQuery,
87 block::{Block, BlockInfo, canonical_block},
88 transaction::{MaybeImpersonatedTransaction, PendingTransaction},
89 },
90 types::{NodeBlobParams, ReorgOptions, TransactionData},
91};
92use anvil_rpc::{
93 error::{ErrorCode, RpcError},
94 response::ResponseResult,
95};
96use foundry_common::{
97 provider::redact_url,
98 tempo::{PaymentLaneClassification, PaymentLaneReason, classify_payment_lane},
99 version::{COMMIT_SHA, SEMVER_VERSION},
100};
101use foundry_evm::{decode::RevertDecoder, utils::StateChangeset};
102use foundry_primitives::{
103 FoundryNetwork, FoundryReceiptEnvelope, FoundryTransactionRequest, FoundryTxEnvelope,
104 FoundryTxReceipt, FoundryTypedTx,
105};
106use futures::{
107 StreamExt, TryFutureExt,
108 channel::{mpsc::Receiver, oneshot},
109};
110use parking_lot::{Mutex, RwLock};
111use revm::{
112 context::BlockEnv,
113 context_interface::{
114 block::BlobExcessGasAndPrice,
115 result::{HaltReason, Output},
116 },
117 database::CacheDB,
118 interpreter::{InstructionResult, SuccessOrHalt, return_ok, return_revert},
119};
120use std::{sync::Arc, time::Duration};
121use tempo_hardfork::TempoHardfork;
122use tempo_primitives::{AASigned, TEMPO_TX_TYPE_ID, transaction::FEE_PAYER_SIGNATURE_MARKER};
123use tokio::{
124 sync::mpsc::{self, UnboundedReceiver, unbounded_channel},
125 try_join,
126};
127
128#[cfg(feature = "base")]
129use base_common_consensus::Eip8130Constants;
130#[cfg(feature = "base")]
131use base_common_evm::EIP8130_TRANSACTION_TYPE;
132#[cfg(feature = "base")]
133use base_common_precompiles::NonceManagerStorage;
134#[cfg(feature = "base")]
135use base_common_rpc_types::{BaseTransactionRequest, Eip8130Nonce};
136#[cfg(feature = "base")]
137use base_execution_eip8130::{FeeCheck, IntrinsicGas};
138
139pub const CLIENT_VERSION: &str = concat!("anvil/v", env!("CARGO_PKG_VERSION"));
141
142#[derive(Clone, Copy)]
143struct TransactionFeeDefaults {
144 gas_price: u128,
145 blob_gas_price: u128,
146}
147
148pub struct EthApi<N: Network> {
152 pool: Arc<Pool<N::TxEnvelope>>,
154 pool_snapshots: Arc<Mutex<HashMap<U256, PoolSnapshot<N::TxEnvelope>>>>,
156 pub backend: Arc<backend::mem::Backend<N>>,
159 is_mining: bool,
161 signers: Arc<Vec<Box<dyn Signer<N>>>>,
163 fee_history_cache: FeeHistoryCache,
165 fee_history_limit: u64,
167 miner: Miner<N::TxEnvelope>,
172 logger: LoggingManager,
174 filters: Filters<N>,
176 transaction_order: Arc<RwLock<TransactionOrder>>,
178 net_listening: bool,
180 instance_id: Arc<RwLock<B256>>,
182 lifecycle_lock: Arc<tokio::sync::RwLock<()>>,
184 reset_lock: Arc<tokio::sync::Mutex<()>>,
186 nonce_locks: Arc<RwLock<HashMap<Address, Arc<tokio::sync::Mutex<()>>>>>,
188}
189
190impl<N: Network> Clone for EthApi<N> {
191 fn clone(&self) -> Self {
192 Self {
193 pool: self.pool.clone(),
194 pool_snapshots: self.pool_snapshots.clone(),
195 backend: self.backend.clone(),
196 is_mining: self.is_mining,
197 signers: self.signers.clone(),
198 fee_history_cache: self.fee_history_cache.clone(),
199 fee_history_limit: self.fee_history_limit,
200 miner: self.miner.clone(),
201 logger: self.logger.clone(),
202 filters: self.filters.clone(),
203 transaction_order: self.transaction_order.clone(),
204 net_listening: self.net_listening,
205 instance_id: self.instance_id.clone(),
206 lifecycle_lock: self.lifecycle_lock.clone(),
207 reset_lock: self.reset_lock.clone(),
208 nonce_locks: self.nonce_locks.clone(),
209 }
210 }
211}
212
213impl<N: Network> EthApi<N> {
216 #[expect(clippy::too_many_arguments)]
218 pub fn new(
219 pool: Arc<Pool<N::TxEnvelope>>,
220 backend: Arc<backend::mem::Backend<N>>,
221 signers: Arc<Vec<Box<dyn Signer<N>>>>,
222 fee_history_cache: FeeHistoryCache,
223 fee_history_limit: u64,
224 miner: Miner<N::TxEnvelope>,
225 logger: LoggingManager,
226 filters: Filters<N>,
227 transactions_order: TransactionOrder,
228 ) -> Self {
229 Self {
230 pool,
231 pool_snapshots: Arc::new(Mutex::new(HashMap::default())),
232 backend,
233 is_mining: true,
234 signers,
235 fee_history_cache,
236 fee_history_limit,
237 miner,
238 logger,
239 filters,
240 net_listening: true,
241 transaction_order: Arc::new(RwLock::new(transactions_order)),
242 instance_id: Arc::new(RwLock::new(B256::random())),
243 lifecycle_lock: Arc::new(tokio::sync::RwLock::new(())),
244 reset_lock: Arc::new(tokio::sync::Mutex::new(())),
245 nonce_locks: Default::default(),
246 }
247 }
248
249 pub fn gas_price(&self) -> u128 {
251 self.gas_price_for_base_fee(self.backend.base_fee())
252 }
253
254 fn gas_price_for_base_fee(&self, base_fee: u64) -> u128 {
256 if self.backend.is_eip1559() {
257 if self.backend.is_min_priority_fee_enforced() {
258 (base_fee as u128).saturating_add(self.lowest_suggestion_tip())
259 } else {
260 base_fee as u128
261 }
262 } else {
263 self.backend.fees().raw_gas_price()
264 }
265 }
266
267 fn lowest_suggestion_tip(&self) -> u128 {
271 let block_number = self.backend.best_number();
272 let cache = self.fee_history_cache.lock();
273 let latest_tip = self
274 .backend
275 .get_block_with_hash(block_number)
276 .and_then(|(_, hash)| cache.get(&block_number).filter(|item| item.block_hash == hash))
277 .and_then(|item| item.rewards.iter().copied().min());
278
279 latest_tip
280 .or_else(|| {
281 cache
282 .iter()
283 .filter(|(number, item)| {
284 self.backend
285 .get_block_with_hash(**number)
286 .is_some_and(|(_, hash)| item.block_hash == hash)
287 })
288 .flat_map(|(_, item)| item.rewards.iter().copied())
289 .min()
290 })
291 .map(|fee| fee.max(MIN_SUGGESTED_PRIORITY_FEE))
292 .unwrap_or(MIN_SUGGESTED_PRIORITY_FEE)
293 }
294
295 pub fn anvil_get_auto_mine(&self) -> Result<bool> {
299 node_info!("anvil_getAutomine");
300 Ok(self.miner.is_auto_mine())
301 }
302
303 pub fn anvil_get_interval_mining(&self) -> Result<Option<u64>> {
307 node_info!("anvil_getIntervalMining");
308 Ok(self.miner.get_interval())
309 }
310
311 pub async fn anvil_set_auto_mine(&self, enable_automine: bool) -> Result<()> {
316 node_info!("evm_setAutomine");
317 if self.miner.is_auto_mine() {
318 if enable_automine {
319 return Ok(());
320 }
321 self.miner.set_mining_mode(MiningMode::None);
322 } else if enable_automine {
323 let listener = self.pool.add_ready_listener();
324 let window = self.backend.node_config.read().await.transaction_coalescing_window;
325 let mode = MiningMode::instant(1_000, listener).with_coalescing_window(window);
326 self.miner.set_mining_mode(mode);
327 }
328 Ok(())
329 }
330
331 pub fn anvil_set_interval_mining(&self, secs: u64) -> Result<()> {
335 node_info!("evm_setIntervalMining");
336 let mining_mode = if secs == 0 {
337 MiningMode::None
338 } else {
339 let block_time = Duration::from_secs(secs);
340
341 self.backend.update_interval_mine_block_time(block_time);
343
344 MiningMode::FixedBlockTime(FixedBlockTimeMiner::new(block_time))
345 };
346 self.miner.set_mining_mode(mining_mode);
347 Ok(())
348 }
349
350 pub async fn anvil_set_mining_paused(&self, paused: bool) -> Result<()> {
358 node_info!("anvil_setMiningPaused");
359 self.miner.set_paused(paused);
360 if paused {
361 drop(self.backend.lock_mining().await);
364 }
365 Ok(())
366 }
367
368 pub fn anvil_get_mining_paused(&self) -> Result<bool> {
372 node_info!("anvil_getMiningPaused");
373 Ok(self.miner.is_paused())
374 }
375
376 pub async fn anvil_drop_transaction(&self, tx_hash: B256) -> Result<Option<B256>> {
380 node_info!("anvil_dropTransaction");
381 Ok(self.pool.drop_transaction(tx_hash).map(|tx| tx.hash()))
382 }
383
384 pub async fn anvil_drop_all_transactions(&self) -> Result<()> {
388 node_info!("anvil_dropAllTransactions");
389 self.pool.clear();
390 Ok(())
391 }
392
393 pub async fn debug_clear_txpool(&self) -> Result<()> {
397 node_info!("debug_clearTxpool");
398 self.pool.clear();
399 Ok(())
400 }
401
402 pub async fn anvil_set_chain_id(&self, chain_id: u64) -> Result<()> {
403 node_info!("anvil_setChainId");
404 self.backend.set_chain_id(chain_id);
405 #[cfg(feature = "base")]
406 self.invalidate_base_eip8130_pool();
407 Ok(())
408 }
409
410 #[cfg(feature = "base")]
412 fn invalidate_base_eip8130_pool(&self) {
413 if self.backend.is_base() {
414 let _ = self.pool.clear_transaction_type(EIP8130_TRANSACTION_TYPE);
415 }
416 }
417
418 pub async fn anvil_set_balance(&self, address: Address, balance: U256) -> Result<()> {
422 node_info!("anvil_setBalance");
423 self.backend.set_balance(address, balance).await?;
424 #[cfg(feature = "base")]
425 self.invalidate_base_eip8130_pool();
426 Ok(())
427 }
428
429 pub async fn anvil_set_code(&self, address: Address, code: Bytes) -> Result<()> {
433 node_info!("anvil_setCode");
434 self.backend.set_code(address, code).await?;
435 #[cfg(feature = "base")]
436 self.invalidate_base_eip8130_pool();
437 Ok(())
438 }
439
440 pub async fn anvil_set_nonce(&self, address: Address, nonce: U256) -> Result<()> {
444 node_info!("anvil_setNonce");
445 self.backend.set_nonce(address, nonce).await?;
446 #[cfg(feature = "base")]
447 self.invalidate_base_eip8130_pool();
448 Ok(())
449 }
450
451 pub async fn anvil_set_storage_at(
455 &self,
456 address: Address,
457 slot: U256,
458 val: B256,
459 ) -> Result<bool> {
460 node_info!("anvil_setStorageAt");
461 self.backend.set_storage_at(address, slot, val).await?;
462 #[cfg(feature = "base")]
463 self.invalidate_base_eip8130_pool();
464 Ok(true)
465 }
466
467 pub async fn anvil_set_logging(&self, enable: bool) -> Result<()> {
471 node_info!("anvil_setLoggingEnabled");
472 self.logger.set_enabled(enable);
473 Ok(())
474 }
475
476 pub async fn anvil_set_min_gas_price(&self, gas: U256) -> Result<()> {
480 node_info!("anvil_setMinGasPrice");
481 if self.backend.is_eip1559() {
482 return Err(RpcError::invalid_params(
483 "anvil_setMinGasPrice is not supported when EIP-1559 is active",
484 )
485 .into());
486 }
487 self.backend.set_gas_price(gas.saturating_to());
488 Ok(())
489 }
490
491 pub async fn anvil_set_next_block_base_fee_per_gas(&self, basefee: U256) -> Result<()> {
495 node_info!("anvil_setNextBlockBaseFeePerGas");
496 if !self.backend.is_eip1559() {
497 return Err(RpcError::invalid_params(
498 "anvil_setNextBlockBaseFeePerGas is only supported when EIP-1559 is active",
499 )
500 .into());
501 }
502 self.backend.set_base_fee(basefee.saturating_to());
503 Ok(())
504 }
505
506 pub async fn anvil_set_coinbase(&self, address: Address) -> Result<()> {
510 node_info!("anvil_setCoinbase");
511 self.backend.set_coinbase(address);
512 Ok(())
513 }
514
515 pub async fn anvil_set_next_block_prevrandao(&self, prevrandao: B256) -> Result<()> {
522 node_info!("anvil_setNextBlockPrevRandao");
523 self.backend.set_next_block_prevrandao(prevrandao);
524 Ok(())
525 }
526
527 pub async fn anvil_set_next_block_parent_beacon_block_root(&self, root: B256) -> Result<()> {
535 node_info!("anvil_setNextBlockParentBeaconBlockRoot");
536 self.backend.set_next_block_parent_beacon_block_root(root);
537 Ok(())
538 }
539
540 pub async fn anvil_node_info(&self) -> Result<WithOtherFields<NodeInfo>> {
544 node_info!("anvil_nodeInfo");
545 let _lifecycle = self.lifecycle_lock.read().await;
546
547 let evm_env = self.backend.evm_env().read().clone();
548 let fork_config = self.backend.get_fork();
549 let tx_order = self.transaction_order.read();
550 let hard_fork = self.backend.hardfork().name();
551
552 let mut node_info = WithOtherFields::new(NodeInfo {
553 current_block_number: self.backend.best_number(),
554 current_block_timestamp: evm_env.block_env.timestamp.saturating_to(),
555 current_block_hash: self.backend.best_hash(),
556 hard_fork,
557 transaction_order: match *tx_order {
558 TransactionOrder::Fifo => "fifo".to_string(),
559 TransactionOrder::Fees => "fees".to_string(),
560 },
561 environment: NodeEnvironment {
562 base_fee: self.backend.base_fee() as u128,
563 chain_id: self.backend.chain_id().to::<u64>(),
564 gas_limit: self.backend.gas_limit(),
565 gas_price: self.gas_price(),
566 },
567 fork_config: fork_config
568 .map(|fork| {
569 let config = fork.config.read();
570
571 NodeForkConfig {
572 fork_url: config.eth_rpc_url().map(redact_url),
573 fork_block_number: Some(config.block_number),
574 fork_retry_backoff: Some(config.backoff.as_millis()),
575 }
576 })
577 .unwrap_or_default(),
578 network: Some(self.backend.execution_profile_name().to_string()),
581 });
582 node_info
585 .other
586 .insert_value(
587 "blobParams".to_string(),
588 NodeBlobParams::from(self.backend.blob_params()),
589 )
590 .map_err(|err| BlockchainError::Internal(err.to_string()))?;
591 Ok(node_info)
592 }
593
594 pub async fn anvil_metadata(&self) -> Result<Metadata> {
598 node_info!("anvil_metadata");
599 let _lifecycle = self.lifecycle_lock.read().await;
600 let fork_config = self.backend.get_fork();
601
602 Ok(Metadata {
603 client_version: CLIENT_VERSION.to_string(),
604 client_semver: Some(SEMVER_VERSION.to_string()),
605 client_commit_sha: Some(COMMIT_SHA.to_string()),
606 chain_id: self.backend.chain_id().to::<u64>(),
607 latest_block_hash: self.backend.best_hash(),
608 latest_block_number: self.backend.best_number(),
609 instance_id: *self.instance_id.read(),
610 forked_network: fork_config.map(|cfg| ForkedNetwork {
611 chain_id: cfg.chain_id(),
612 fork_block_number: cfg.block_number(),
613 fork_block_hash: cfg.block_hash(),
614 }),
615 snapshots: self.backend.list_state_snapshots(),
616 })
617 }
618
619 pub async fn anvil_remove_pool_transactions(&self, address: Address) -> Result<()> {
620 node_info!("anvil_removePoolTransactions");
621 self.pool.remove_transactions_by_address(address);
622 Ok(())
623 }
624
625 pub async fn evm_snapshot(&self) -> Result<U256> {
629 node_info!("evm_snapshot");
630 let _lifecycle = self.lifecycle_lock.read().await;
631 let _mining = self.backend.lock_mining().await;
632 let pool = self.pool.snapshot();
633 let id = self.backend.create_state_snapshot().await;
634 self.pool_snapshots.lock().insert(id, pool);
635 Ok(id)
636 }
637
638 pub async fn evm_increase_time(&self, seconds: U256) -> Result<i64> {
642 node_info!("evm_increaseTime");
643 Ok(self.backend.time().increase_time(seconds.try_into().unwrap_or(u64::MAX)) as i64)
644 }
645
646 pub fn evm_set_next_block_timestamp(&self, seconds: u64) -> Result<()> {
650 node_info!("evm_setNextBlockTimestamp");
651 self.backend.time().set_next_block_timestamp(seconds)
652 }
653
654 pub fn evm_set_time(&self, timestamp: u64) -> Result<u64> {
663 node_info!("evm_setTime");
664 let now = self.backend.time().current_wall_timestamp();
665 self.backend.time().set_time(timestamp);
666
667 let offset = timestamp.saturating_sub(now);
669 Ok(offset)
670 }
671
672 pub fn evm_set_block_gas_limit(&self, gas_limit: U256) -> Result<bool> {
676 node_info!("evm_setBlockGasLimit");
677 self.backend.set_gas_limit(gas_limit.saturating_to());
678 Ok(true)
679 }
680
681 pub fn evm_set_block_timestamp_interval(&self, seconds: u64) -> Result<()> {
685 node_info!("anvil_setBlockTimestampInterval");
686 self.backend.time().set_block_timestamp_interval(seconds);
687 Ok(())
688 }
689
690 pub fn evm_remove_block_timestamp_interval(&self) -> Result<bool> {
694 node_info!("anvil_removeBlockTimestampInterval");
695 Ok(self.backend.time().remove_block_timestamp_interval())
696 }
697
698 pub async fn anvil_set_rpc_url(&self, url: String) -> Result<()> {
702 node_info!("anvil_setRpcUrl");
703 let _reset = self.reset_lock.lock().await;
704 let staged_fork = if let Some(fork) = self.backend.get_fork() {
705 let mut validation_config = self.backend.node_config.read().await.clone();
706 let (expected_identity, block_number, block_hash) = {
707 let config = fork.config.read();
708 (config.endpoint_identity, config.block_number, config.block_hash)
709 };
710 validation_config.fork_chain_id = None;
713 let (provider, endpoint_identity) = validation_config
714 .replacement_fork_provider(
715 &url,
716 expected_identity,
717 block_number,
718 block_hash,
719 self.instance_id(),
720 )
721 .await?;
722 Some((fork, provider, endpoint_identity))
723 } else {
724 None
725 };
726
727 let _lifecycle = self.lifecycle_lock.write().await;
728 let _mining = self.backend.lock_mining().await;
729 let mut node_config = self.backend.node_config.write().await;
730 if let Some((fork, provider, endpoint_identity)) = staged_fork {
731 let mut config = fork.config.write();
732 trace!(target: "backend", "Updated fork rpc from \"{}\" to \"{}\"", config.eth_rpc_url().map(redact_url).unwrap_or_else(|| "none".to_string()), redact_url(&url));
733 config.provider = provider;
734 config.fork_urls = vec![url.clone()];
735 config.fork_chain_id = None;
736 config.endpoint_identity = endpoint_identity;
737 node_config.fork_endpoint_is_anvil = endpoint_identity.is_authoritative();
738 }
739 node_config.fork_urls = vec![url];
741 node_config.fork_chain_id = None;
742 Ok(())
743 }
744
745 pub async fn txpool_status(&self) -> Result<TxpoolStatus> {
751 node_info!("txpool_status");
752 Ok(self.pool.txpool_status())
753 }
754
755 async fn on_blocking_task<C, F, R>(&self, c: C) -> Result<R>
757 where
758 C: FnOnce(Self) -> F,
759 F: Future<Output = Result<R>> + Send + 'static,
760 R: Send + 'static,
761 {
762 let (tx, rx) = oneshot::channel();
763 let this = self.clone();
764 let f = c(this);
765 tokio::task::spawn_blocking(move || {
766 tokio::runtime::Handle::current().block_on(async move {
767 let res = f.await;
768 let _ = tx.send(res);
769 })
770 });
771 rx.await.map_err(|_| BlockchainError::Internal("blocking task panicked".to_string()))?
772 }
773
774 pub fn set_transaction_order(&self, order: TransactionOrder) {
776 *self.transaction_order.write() = order;
777 }
778
779 pub fn chain_id(&self) -> u64 {
781 self.backend.chain_id().to::<u64>()
782 }
783
784 pub fn get_fork(&self) -> Option<ClientFork> {
786 self.backend.get_fork()
787 }
788
789 pub fn instance_id(&self) -> B256 {
791 *self.instance_id.read()
792 }
793
794 pub fn reset_instance_id(&self) {
796 *self.instance_id.write() = B256::random();
797 }
798
799 #[expect(clippy::borrowed_box)]
801 pub fn get_signer(&self, address: Address) -> Option<&Box<dyn Signer<N>>> {
802 self.signers.iter().find(|signer| signer.is_signer_for(address))
803 }
804
805 pub fn new_ready_transactions(&self) -> Receiver<TxHash> {
807 self.pool.add_ready_listener()
808 }
809
810 pub(crate) fn new_ready_transaction_subscription(&self) -> Receiver<TxHash> {
812 self.pool.add_ready_subscription_listener()
813 }
814
815 pub fn is_fork(&self) -> bool {
817 self.backend.is_fork()
818 }
819
820 pub async fn state_root(&self) -> Option<B256> {
822 self.backend.get_db().read().await.maybe_state_root()
823 }
824
825 pub fn is_impersonated(&self, addr: Address) -> bool {
827 self.backend.cheats().is_impersonated(addr)
828 }
829
830 pub fn storage_info(&self) -> StorageInfo<N> {
832 StorageInfo::new(Arc::clone(&self.backend))
833 }
834
835 #[allow(clippy::large_stack_frames)]
837 pub fn anvil_get_blob_by_versioned_hash(
838 &self,
839 hash: B256,
840 ) -> Result<Option<alloy_consensus::Blob>> {
841 node_info!("anvil_getBlobByHash");
842 Ok(self.backend.get_blob_by_versioned_hash(hash)?)
843 }
844
845 pub fn anvil_get_blobs_by_block_id(
847 &self,
848 block_id: impl Into<BlockId>,
849 versioned_hashes: Vec<B256>,
850 ) -> Result<Option<Vec<Blob>>> {
851 node_info!("anvil_getBlobsByBlockId");
852 Ok(self.backend.get_blobs_by_block_id(block_id, versioned_hashes)?)
853 }
854
855 pub fn anvil_get_genesis_time(&self) -> Result<u64> {
859 node_info!("anvil_getGenesisTime");
860 Ok(self.backend.genesis_time())
861 }
862
863 pub fn anvil_get_last_block_wall_time(&self) -> Result<u64> {
867 node_info!("anvil_getLastBlockWallTime");
868 Ok(self.backend.time().last_block_wall_time())
869 }
870
871 pub async fn anvil_reset(&self, forking: Option<Forking>) -> Result<()> {
877 node_info!("anvil_reset");
878 let _reset = self.reset_lock.lock().await;
879 if let Some(forking) = forking {
880 let staged = self.backend.prepare_fork_reset(forking, self.instance_id()).await?;
881 let _lifecycle = self.lifecycle_lock.write().await;
882 let _mining = self.backend.lock_mining().await;
884 self.backend.commit_fork_reset(staged).await?;
885 self.reset_instance_id();
886 self.pool.clear();
887 self.pool_snapshots.lock().clear();
888 self.fee_history_cache.lock().clear();
889 } else {
890 let _lifecycle = self.lifecycle_lock.write().await;
891 let _mining = self.backend.lock_mining().await;
894 let staged = self.backend.prepare_memory_reset().await?;
895 self.backend.commit_memory_reset(staged).await?;
896 self.reset_instance_id();
897 self.pool.clear();
898 self.pool_snapshots.lock().clear();
899 self.fee_history_cache.lock().clear();
900 }
901 Ok(())
902 }
903
904 pub async fn evm_revert(&self, id: U256) -> Result<bool>
909 where
910 N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log>,
911 {
912 node_info!("evm_revert");
913 let _lifecycle = self.lifecycle_lock.read().await;
914 let _mining = self.backend.lock_mining().await;
915 let reverted = self.backend.revert_state_snapshot(id).await?;
916 if reverted {
917 let pool = {
918 let mut snapshots = self.pool_snapshots.lock();
919 let pool = snapshots.remove(&id);
920 snapshots.retain(|snapshot_id, _| *snapshot_id < id);
921 pool
922 };
923 if let Some(pool) = pool {
924 self.pool.restore(pool);
925 }
926 }
927 Ok(reverted)
928 }
929
930 pub async fn anvil_impersonate_account(&self, address: Address) -> Result<()> {
934 node_info!("anvil_impersonateAccount");
935 self.backend.impersonate(address);
936 Ok(())
937 }
938
939 pub async fn anvil_stop_impersonating_account(&self, address: Address) -> Result<()> {
943 node_info!("anvil_stopImpersonatingAccount");
944 self.backend.stop_impersonating(address);
945 Ok(())
946 }
947
948 pub async fn anvil_auto_impersonate_account(&self, enabled: bool) -> Result<()> {
952 node_info!("anvil_autoImpersonateAccount");
953 self.backend.auto_impersonate_account(enabled);
954 Ok(())
955 }
956
957 pub async fn anvil_impersonate_signature(
959 &self,
960 signature: Bytes,
961 address: Address,
962 ) -> Result<()> {
963 node_info!("anvil_impersonateSignature");
964 self.backend.impersonate_signature(signature, address).await
965 }
966
967 pub fn new_block_notifications(&self) -> ChainNotifications {
970 self.backend.new_block_notifications()
971 }
972
973 pub fn client_version(&self) -> Result<String> {
977 node_info!("web3_clientVersion");
978 Ok(CLIENT_VERSION.to_string())
979 }
980
981 pub fn sha3(&self, bytes: Bytes) -> Result<String> {
985 node_info!("web3_sha3");
986 let hash = alloy_primitives::keccak256(bytes.as_ref());
987 Ok(alloy_primitives::hex::encode_prefixed(&hash[..]))
988 }
989
990 pub fn protocol_version(&self) -> Result<u64> {
994 node_info!("eth_protocolVersion");
995 Ok(1)
996 }
997
998 pub fn hashrate(&self) -> Result<U256> {
1002 node_info!("eth_hashrate");
1003 Ok(U256::ZERO)
1004 }
1005
1006 pub fn author(&self) -> Result<Address> {
1010 node_info!("eth_coinbase");
1011 Ok(self.backend.coinbase())
1012 }
1013
1014 pub fn is_mining(&self) -> Result<bool> {
1018 node_info!("eth_mining");
1019 Ok(self.is_mining)
1020 }
1021
1022 pub fn eth_chain_id(&self) -> Result<Option<U64>> {
1028 node_info!("eth_chainId");
1029 Ok(Some(self.backend.chain_id().to::<U64>()))
1030 }
1031
1032 pub fn network_id(&self) -> Result<Option<String>> {
1036 node_info!("eth_networkId");
1037 let chain_id = self.backend.chain_id().to::<u64>();
1038 Ok(Some(format!("{chain_id}")))
1039 }
1040
1041 pub fn net_listening(&self) -> Result<bool> {
1045 node_info!("net_listening");
1046 Ok(self.net_listening)
1047 }
1048
1049 fn eth_gas_price(&self) -> Result<U256> {
1051 node_info!("eth_gasPrice");
1052 Ok(U256::from(self.gas_price()))
1053 }
1054
1055 pub fn base_fee(&self) -> Result<Option<U256>> {
1059 node_info!("eth_baseFee");
1060 Ok(self.backend.is_eip1559().then(|| U256::from(self.backend.base_fee())))
1061 }
1062
1063 pub fn excess_blob_gas_and_price(&self) -> Result<Option<BlobExcessGasAndPrice>> {
1065 Ok(self.backend.excess_blob_gas_and_price())
1066 }
1067
1068 pub fn gas_max_priority_fee_per_gas(&self) -> Result<U256> {
1073 self.max_priority_fee_per_gas()
1074 }
1075
1076 pub fn blob_base_fee(&self) -> Result<U256> {
1080 Ok(U256::from(self.backend.fees().base_fee_per_blob_gas()))
1081 }
1082
1083 pub fn gas_limit(&self) -> U256 {
1085 U256::from(self.backend.gas_limit())
1086 }
1087
1088 pub fn accounts(&self) -> Result<Vec<Address>> {
1092 node_info!("eth_accounts");
1093 let mut unique = AddressSet::default();
1094 let mut accounts: Vec<Address> = Vec::new();
1095 for signer in self.signers.iter() {
1096 accounts.extend(signer.accounts().into_iter().filter(|acc| unique.insert(*acc)));
1097 }
1098 accounts.extend(
1099 self.backend
1100 .cheats()
1101 .impersonated_accounts()
1102 .into_iter()
1103 .filter(|acc| unique.insert(*acc)),
1104 );
1105 Ok(accounts.into_iter().collect())
1106 }
1107
1108 pub fn block_number(&self) -> Result<U256> {
1112 node_info!("eth_blockNumber");
1113 Ok(U256::from(self.backend.best_number()))
1114 }
1115
1116 pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
1120 node_info!("eth_getBlockByHash");
1121 self.backend.block_by_hash(hash).await
1122 }
1123
1124 pub async fn header_by_hash(
1128 &self,
1129 hash: B256,
1130 ) -> Result<Option<WithOtherFields<AnyRpcHeader>>> {
1131 node_info!("eth_getHeaderByHash");
1132 Ok(self.backend.block_by_hash(hash).await?.map(|block| {
1133 let WithOtherFields { inner: block, other } = block.0;
1134 WithOtherFields { inner: block.header, other }
1135 }))
1136 }
1137
1138 pub async fn block_by_hash_full(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
1142 node_info!("eth_getBlockByHash");
1143 self.backend.block_by_hash_full(hash).await
1144 }
1145
1146 pub async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
1150 node_info!("eth_getBlockTransactionCountByHash");
1151 let block = self.backend.block_by_hash(hash).await?;
1152 let txs = block.map(|b| match b.transactions() {
1153 BlockTransactions::Full(txs) => U256::from(txs.len()),
1154 BlockTransactions::Hashes(txs) => U256::from(txs.len()),
1155 BlockTransactions::Uncle => U256::ZERO,
1156 });
1157 Ok(txs)
1158 }
1159
1160 pub async fn block_uncles_count_by_hash(&self, hash: B256) -> Result<U256> {
1164 node_info!("eth_getUncleCountByBlockHash");
1165 let block =
1166 self.backend.block_by_hash(hash).await?.ok_or(BlockchainError::BlockNotFound)?;
1167 Ok(U256::from(block.uncles.len()))
1168 }
1169
1170 pub async fn block_uncles_count_by_number(&self, block_number: BlockNumber) -> Result<U256> {
1174 node_info!("eth_getUncleCountByBlockNumber");
1175 let block = self
1176 .backend
1177 .block_by_number(block_number)
1178 .await?
1179 .ok_or(BlockchainError::BlockNotFound)?;
1180 Ok(U256::from(block.uncles.len()))
1181 }
1182
1183 pub async fn sign_typed_data(
1187 &self,
1188 _address: Address,
1189 _data: serde_json::Value,
1190 ) -> Result<String> {
1191 node_info!("eth_signTypedData");
1192 Err(BlockchainError::RpcUnimplemented)
1193 }
1194
1195 pub async fn sign_typed_data_v3(
1199 &self,
1200 _address: Address,
1201 _data: serde_json::Value,
1202 ) -> Result<String> {
1203 node_info!("eth_signTypedData_v3");
1204 Err(BlockchainError::RpcUnimplemented)
1205 }
1206
1207 pub async fn sign_typed_data_v4(&self, address: Address, data: &TypedData) -> Result<String> {
1211 node_info!("eth_signTypedData_v4");
1212 let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
1213 let signature = signer.sign_typed_data(address, data).await?;
1214 Ok(alloy_primitives::hex::encode_prefixed(signature.as_bytes()))
1215 }
1216
1217 pub async fn sign(&self, address: Address, content: impl AsRef<[u8]>) -> Result<String> {
1221 node_info!("eth_sign");
1222 let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
1223 let signature = signer.sign(address, content.as_ref()).await?;
1224 Ok(alloy_primitives::hex::encode_prefixed(signature.as_bytes()))
1225 }
1226
1227 pub async fn transaction_by_block_hash_and_index(
1231 &self,
1232 hash: B256,
1233 index: Index,
1234 ) -> Result<Option<AnyRpcTransaction>> {
1235 node_info!("eth_getTransactionByBlockHashAndIndex");
1236 self.backend.transaction_by_block_hash_and_index(hash, index).await
1237 }
1238
1239 pub async fn uncle_by_block_hash_and_index(
1243 &self,
1244 block_hash: B256,
1245 idx: Index,
1246 ) -> Result<Option<AnyRpcBlock>> {
1247 node_info!("eth_getUncleByBlockHashAndIndex");
1248 let number = self.backend.ensure_block_number(Some(BlockId::hash(block_hash))).await?;
1249 if let Some(fork) = self.get_fork()
1250 && fork.predates_fork_inclusive(number)
1251 {
1252 return Ok(fork.uncle_by_block_hash_and_index(block_hash, idx.into()).await?);
1253 }
1254 Ok(None)
1256 }
1257
1258 pub async fn uncle_by_block_number_and_index(
1262 &self,
1263 block_number: BlockNumber,
1264 idx: Index,
1265 ) -> Result<Option<AnyRpcBlock>> {
1266 node_info!("eth_getUncleByBlockNumberAndIndex");
1267 let number = self.backend.ensure_block_number(Some(BlockId::Number(block_number))).await?;
1268 if let Some(fork) = self.get_fork()
1269 && fork.predates_fork_inclusive(number)
1270 {
1271 return Ok(fork.uncle_by_block_number_and_index(number, idx.into()).await?);
1272 }
1273 Ok(None)
1275 }
1276
1277 pub fn work(&self) -> Result<Work> {
1281 node_info!("eth_getWork");
1282 Err(BlockchainError::RpcUnimplemented)
1283 }
1284
1285 pub fn syncing(&self) -> Result<bool> {
1289 node_info!("eth_syncing");
1290 Ok(false)
1291 }
1292
1293 pub fn config(&self) -> Result<EthConfig> {
1304 node_info!("eth_config");
1305 Ok(EthConfig {
1306 current: EthForkConfig {
1307 activation_time: 0,
1308 blob_schedule: self.backend.blob_params(),
1309 chain_id: self.backend.chain_id().to::<u64>(),
1310 fork_id: Bytes::from_static(&[0; 4]),
1311 precompiles: self.backend.precompiles(),
1312 system_contracts: self.backend.system_contracts(),
1313 },
1314 next: None,
1315 last: None,
1316 })
1317 }
1318
1319 pub fn submit_work(&self, _: B64, _: B256, _: B256) -> Result<bool> {
1323 node_info!("eth_submitWork");
1324 Err(BlockchainError::RpcUnimplemented)
1325 }
1326
1327 pub fn submit_hashrate(&self, _: U256, _: B256) -> Result<bool> {
1331 node_info!("eth_submitHashrate");
1332 Err(BlockchainError::RpcUnimplemented)
1333 }
1334
1335 pub async fn fee_history(
1339 &self,
1340 block_count: U256,
1341 newest_block: BlockNumber,
1342 reward_percentiles: Vec<f64>,
1343 ) -> Result<FeeHistory>
1344 where
1345 N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log>,
1346 {
1347 node_info!("eth_feeHistory");
1348
1349 if reward_percentiles.iter().any(|p| !(0.0..=100.0).contains(p))
1350 || reward_percentiles.windows(2).any(|pair| pair[0] >= pair[1])
1351 {
1352 return Err(FeeHistoryError::InvalidRewardPercentiles.into());
1353 }
1354 if block_count.is_zero() {
1355 return Ok(FeeHistory::default());
1356 }
1357
1358 let number = self.backend.convert_block_number(Some(newest_block));
1361
1362 let fork = self.get_fork();
1367 let fork_block = fork.as_ref().map(|fork| fork.block_number());
1368
1369 if let (Some(fork), Some(fork_block)) = (fork.as_ref(), fork_block) {
1371 if number <= fork_block {
1374 return fork
1375 .fee_history(
1376 block_count.saturating_to(),
1377 BlockNumber::Number(number),
1378 &reward_percentiles,
1379 )
1380 .await
1381 .map_err(BlockchainError::AlloyForkProvider);
1382 }
1383 }
1384
1385 const MAX_BLOCK_COUNT: u64 = 1024u64;
1386 let block_count = block_count.saturating_to::<u64>().min(MAX_BLOCK_COUNT);
1387
1388 let highest = number;
1390 let lowest = highest.saturating_sub(block_count.saturating_sub(1));
1391 let lowest = if fork.is_none() {
1394 lowest.max(self.backend.genesis_number().min(highest))
1395 } else {
1396 lowest
1397 };
1398
1399 if lowest < self.backend.best_number().saturating_sub(self.fee_history_limit) {
1401 return Err(FeeHistoryError::InvalidBlockRange.into());
1402 }
1403
1404 let mut response = FeeHistory {
1405 oldest_block: lowest,
1406 base_fee_per_gas: Vec::new(),
1407 gas_used_ratio: Vec::new(),
1408 reward: Some(Default::default()),
1409 base_fee_per_blob_gas: Default::default(),
1410 blob_gas_used_ratio: Default::default(),
1411 };
1412 let mut rewards = Vec::new();
1413
1414 let local_lowest = if let (Some(fork), Some(fork_block)) = (fork.as_ref(), fork_block) {
1421 if lowest <= fork_block {
1422 let count_pre = fork_block - lowest + 1;
1423 let pre = fork
1424 .fee_history(count_pre, BlockNumber::Number(fork_block), &reward_percentiles)
1425 .await
1426 .map_err(BlockchainError::AlloyForkProvider)?;
1427 merge_pre_fork_fee_history(&mut response, &mut rewards, pre, fork_block);
1428 fork_block + 1
1430 } else {
1431 lowest
1432 }
1433 } else {
1434 lowest
1435 };
1436
1437 {
1438 let storage_info = self.storage_info();
1439 let blob_params = self.backend.blob_params();
1440
1441 let cached: Vec<Option<FeeHistoryCacheItem>> = {
1445 let cache = self.fee_history_cache.lock();
1446 (local_lowest..=highest).map(|n| cache.get(&n).cloned()).collect()
1447 };
1448
1449 let mut warmed: Vec<(u64, FeeHistoryCacheItem)> = Vec::new();
1455 let mut items: Vec<FeeHistoryCacheItem> = Vec::with_capacity(cached.len());
1456 for (cached_item, n) in cached.into_iter().zip(local_lowest..=highest) {
1457 let hash = self
1458 .backend
1459 .block_hash_by_number(n)
1460 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1461 let item = match cached_item {
1462 Some(item) if item.block_hash == hash => item,
1463 _ => {
1464 let block = self
1465 .backend
1466 .get_block_by_hash(hash)
1467 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1468 let header = block.header;
1469 let (item, block_number) = create_fee_history_cache_item(
1470 hash,
1471 &header,
1472 &storage_info,
1473 blob_params,
1474 );
1475 let block_number = block_number
1479 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1480 warmed.push((block_number, item.clone()));
1481 item
1482 }
1483 };
1484 items.push(item);
1485 }
1486
1487 if !warmed.is_empty() {
1490 let mut cache = self.fee_history_cache.lock();
1491 for (block_number, item) in warmed {
1492 cache.insert(block_number, item);
1493 }
1494 while cache.len() as u64 > self.fee_history_limit {
1495 cache.pop_first();
1496 }
1497 }
1498
1499 for item in items {
1500 response.base_fee_per_gas.push(item.base_fee);
1501 response.base_fee_per_blob_gas.push(item.base_fee_per_blob_gas.unwrap_or(0));
1502 response.blob_gas_used_ratio.push(item.blob_gas_used_ratio);
1503 response.gas_used_ratio.push(item.gas_used_ratio);
1504
1505 if !reward_percentiles.is_empty() {
1507 let mut block_rewards = Vec::new();
1508 for p in &reward_percentiles {
1509 block_rewards.push(reward_at_percentile(&item.rewards, *p));
1510 }
1511 rewards.push(block_rewards);
1512 }
1513 }
1514 }
1515
1516 response.reward = Some(rewards);
1517
1518 let next_number = highest
1523 .checked_add(1)
1524 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(highest)))?;
1525 let (next_base_fee, next_blob_base_fee) = self
1526 .backend
1527 .fee_history_next_fees(highest)
1528 .await
1529 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(next_number)))?;
1530 response.base_fee_per_gas.push(next_base_fee);
1531 response.base_fee_per_blob_gas.push(next_blob_base_fee);
1532
1533 Ok(response)
1534 }
1535
1536 pub fn max_priority_fee_per_gas(&self) -> Result<U256> {
1543 node_info!("eth_maxPriorityFeePerGas");
1544 Ok(U256::from(self.lowest_suggestion_tip()))
1545 }
1546
1547 pub async fn debug_code_by_hash(
1551 &self,
1552 hash: B256,
1553 block_id: Option<BlockId>,
1554 ) -> Result<Option<Bytes>> {
1555 node_info!("debug_codeByHash");
1556 self.backend.debug_code_by_hash(hash, block_id).await
1557 }
1558
1559 pub async fn debug_db_get(&self, key: String) -> Result<Option<Bytes>> {
1564 node_info!("debug_dbGet");
1565 self.backend.debug_db_get(key).await
1566 }
1567
1568 pub fn debug_get_modified_accounts_by_number(
1570 &self,
1571 _start_number: u64,
1572 _end_number: u64,
1573 ) -> Result<()> {
1574 node_info!("debug_getModifiedAccountsByNumber");
1575 Ok(())
1576 }
1577
1578 pub fn debug_free_os_memory(&self) -> Result<()> {
1580 node_info!("debug_freeOSMemory");
1581 Ok(())
1582 }
1583
1584 pub async fn trace_call(
1588 &self,
1589 request: WithOtherFields<TransactionRequest>,
1590 trace_types: HashSet<TraceType>,
1591 block_id: Option<BlockId>,
1592 ) -> Result<TraceResults>
1593 where
1594 N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope>,
1595 {
1596 node_info!("trace_call");
1597 let block_id = block_id.unwrap_or_default();
1598 let block_request = self.trace_block_request(block_id).await?;
1599 let inner = request.as_ref();
1600 let fees = FeeDetails::new(
1601 inner.gas_price,
1602 inner.max_fee_per_gas,
1603 inner.max_priority_fee_per_gas,
1604 inner.max_fee_per_blob_gas,
1605 )?
1606 .or_zero_fees();
1607
1608 self.backend.trace_call(request, fees, trace_types, block_request, block_id).await
1609 }
1610
1611 pub async fn trace_transaction(
1615 &self,
1616 tx_hash: B256,
1617 ) -> Result<Option<Vec<LocalizedTransactionTrace>>> {
1618 node_info!("trace_transaction");
1619 self.backend.trace_transaction(tx_hash).await
1620 }
1621
1622 pub async fn trace_block(&self, block: BlockNumber) -> Result<Vec<LocalizedTransactionTrace>> {
1626 node_info!("trace_block");
1627 self.backend.trace_block(block).await
1628 }
1629
1630 pub async fn trace_filter(
1634 &self,
1635 filter: TraceFilter,
1636 ) -> Result<Vec<LocalizedTransactionTrace>> {
1637 node_info!("trace_filter");
1638 self.backend.trace_filter(filter).await
1639 }
1640
1641 pub async fn trace_get(
1645 &self,
1646 hash: B256,
1647 indices: Vec<Index>,
1648 ) -> Result<Option<LocalizedTransactionTrace>> {
1649 node_info!("trace_get");
1650 self.backend.trace_get(hash, indices).await
1651 }
1652
1653 pub async fn trace_replay_block_transactions(
1657 &self,
1658 block: BlockNumber,
1659 trace_types: HashSet<TraceType>,
1660 ) -> Result<Vec<TraceResultsWithTransactionHash>> {
1661 node_info!("trace_replayBlockTransactions");
1662 self.backend.trace_replay_block_transactions(block, trace_types).await
1663 }
1664
1665 pub async fn trace_replay_transaction(
1669 &self,
1670 transaction: B256,
1671 trace_types: HashSet<TraceType>,
1672 ) -> Result<Option<TraceResultsWithTransactionHash>> {
1673 node_info!("trace_replayTransaction");
1674 self.backend.trace_replay_transaction(transaction, trace_types).await
1675 }
1676
1677 async fn trace_block_request(
1679 &self,
1680 block_id: BlockId,
1681 ) -> Result<BlockRequest<FoundryTxEnvelope>>
1682 where
1683 N: Network<TxEnvelope = FoundryTxEnvelope>,
1684 {
1685 if block_id.is_pending() {
1686 return Ok(BlockRequest::Pending(self.pool.ready_transactions().collect()));
1687 }
1688 Ok(BlockRequest::Number(self.backend.ensure_trace_block_number(block_id).await?))
1689 }
1690}
1691
1692impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> EthApi<N> {
1693 pub async fn serialized_state(
1695 &self,
1696 preserve_historical_states: bool,
1697 ) -> Result<SerializableState> {
1698 self.backend.serialized_state(preserve_historical_states).await
1699 }
1700}
1701
1702impl EthApi<FoundryNetwork> {
1705 pub async fn transaction_by_block_number_and_index(
1709 &self,
1710 block: BlockNumber,
1711 idx: Index,
1712 ) -> Result<Option<AnyRpcTransaction>> {
1713 node_info!("eth_getTransactionByBlockNumberAndIndex");
1714 if block.is_pending() {
1715 return Ok(self.pending_block_full().await?.and_then(|block| {
1716 let WithOtherFields { inner: block, .. } = block.0;
1717 block.transactions.into_transactions().nth(idx.into())
1718 }));
1719 }
1720
1721 self.backend.transaction_by_block_number_and_index(block, idx).await
1722 }
1723
1724 pub async fn anvil_dump_state(
1729 &self,
1730 preserve_historical_states: Option<bool>,
1731 ) -> Result<Bytes> {
1732 node_info!("anvil_dumpState");
1733 self.backend.dump_state(preserve_historical_states.unwrap_or(false)).await
1734 }
1735
1736 pub async fn anvil_load_state(&self, buf: Bytes) -> Result<bool> {
1741 node_info!("anvil_loadState");
1742 let loaded = self.backend.load_state_bytes(buf).await?;
1743 #[cfg(feature = "base")]
1744 if loaded {
1745 self.invalidate_base_eip8130_pool();
1746 }
1747 Ok(loaded)
1748 }
1749
1750 async fn block_request(
1751 &self,
1752 block_number: Option<BlockId>,
1753 ) -> Result<BlockRequest<FoundryTxEnvelope>> {
1754 let block_request = match block_number {
1755 Some(BlockId::Number(BlockNumber::Pending)) => {
1756 let pending_txs = self.pool.ready_transactions().collect();
1757 BlockRequest::Pending(pending_txs)
1758 }
1759 _ => {
1760 let number = self.backend.ensure_block_number(block_number).await?;
1761 BlockRequest::Number(number)
1762 }
1763 };
1764 Ok(block_request)
1765 }
1766
1767 pub async fn debug_account_info_at(
1771 &self,
1772 block_id: BlockId,
1773 tx_index: Index,
1774 address: Address,
1775 ) -> Result<Option<AccountInfo>> {
1776 node_info!("debug_accountInfoAt");
1777 self.backend.debug_account_info_at(block_id, tx_index, address).await
1778 }
1779
1780 pub async fn debug_execution_witness(&self, block: BlockNumber) -> Result<ExecutionWitness> {
1786 node_info!("debug_executionWitness");
1787 self.backend.debug_execution_witness(block).await
1788 }
1789
1790 pub async fn trace_transaction_opcode_gas(
1794 &self,
1795 tx_hash: B256,
1796 ) -> Result<Option<TransactionOpcodeGas>> {
1797 node_info!("trace_transactionOpcodeGas");
1798 self.backend.trace_transaction_opcode_gas(tx_hash).await
1799 }
1800
1801 pub async fn trace_block_opcode_gas(
1805 &self,
1806 block_id: BlockId,
1807 ) -> Result<Option<BlockOpcodeGas>> {
1808 node_info!("trace_blockOpcodeGas");
1809 self.backend.trace_block_opcode_gas(block_id).await
1810 }
1811
1812 pub async fn trace_raw_transaction(
1816 &self,
1817 tx: Bytes,
1818 trace_types: HashSet<TraceType>,
1819 block_number: Option<BlockId>,
1820 ) -> Result<TraceResults> {
1821 node_info!("trace_rawTransaction");
1822
1823 let mut data = tx.as_ref();
1824 if data.is_empty() {
1825 return Err(BlockchainError::EmptyRawTransactionData);
1826 }
1827
1828 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
1829 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
1830 self.ensure_typed_transaction_supported(&transaction)?;
1831
1832 #[cfg(feature = "base")]
1833 let is_eip8130 = transaction.is_eip8130();
1834 let pending_transaction = PendingTransaction::new(transaction).map_err(|error| {
1835 #[cfg(feature = "base")]
1836 if is_eip8130 {
1837 return BlockchainError::Eip8130TransactionRejected(error.to_string());
1838 }
1839 BlockchainError::RecoveryError(error)
1840 })?;
1841 let block_request = self.trace_block_request(block_number.unwrap_or_default()).await?;
1842
1843 self.backend
1844 .trace_raw_transaction(pending_transaction, trace_types, Some(block_request))
1845 .await
1846 }
1847
1848 pub async fn anvil_add_balance(&self, address: Address, balance: U256) -> Result<()> {
1852 node_info!("anvil_addBalance");
1853 self.backend.add_balance(address, balance).await?;
1854 Ok(())
1855 }
1856
1857 async fn rollback_block(&self, number: u64) -> Result<Option<Block>> {
1859 if let Some(block) = self.backend.get_block(number) {
1860 return Ok(Some(block));
1861 }
1862 #[cfg(feature = "monad")]
1863 if self.backend.is_monad()
1864 && let Some(block) = self.backend.monad_rollback_block(number).await?
1865 {
1866 return Ok(Some(block));
1867 }
1868
1869 let Some(fork) = self.get_fork().filter(|fork| fork.block_number() == number) else {
1870 return Ok(None);
1871 };
1872 let Some(header) = fork.root_header().await? else { return Ok(None) };
1873
1874 Ok(Some(Block { header, body: Default::default() }))
1876 }
1877
1878 async fn rollback_backend(
1880 &self,
1881 common_block: Block,
1882 mining_guard: &tokio::sync::MutexGuard<'_, ()>,
1883 ) -> Result<()> {
1884 #[cfg(feature = "monad")]
1885 if self.backend.is_monad() {
1886 return self.backend.rollback_monad(common_block, mining_guard).await;
1887 }
1888 self.backend.rollback(common_block, mining_guard).await
1889 }
1890
1891 pub async fn anvil_rollback(&self, depth: Option<u64>) -> Result<()> {
1902 node_info!("anvil_rollback");
1903 let _lifecycle = self.lifecycle_lock.write().await;
1904 let mining_guard = self.backend.lock_mining().await;
1905 let depth = depth.unwrap_or(1);
1906
1907 let current_height = self.backend.best_number();
1909 let genesis = if self.get_fork().is_some() { 0 } else { self.backend.genesis_number() };
1910 let common_height = current_height.checked_sub(depth).filter(|h| *h >= genesis).ok_or(
1911 BlockchainError::RpcError(RpcError::invalid_params(format!(
1912 "Rollback depth must not exceed current chain height: current height {current_height}, depth {depth}, genesis {genesis}"
1913 ))),
1914 )?;
1915
1916 let common_block =
1918 self.rollback_block(common_height).await?.ok_or(BlockchainError::BlockNotFound)?;
1919
1920 self.rollback_backend(common_block, &mining_guard).await?;
1921 Ok(())
1922 }
1923
1924 fn do_estimate_gas_with_state(
1928 &self,
1929 mut request: FoundryTransactionRequest,
1930 state: &dyn DatabaseRef,
1931 block_env: BlockEnv,
1932 monad_context: Option<MonadReplayContext>,
1933 ) -> Result<u128> {
1934 if request.as_ref().blob_versioned_hashes.is_none() {
1937 request.as_mut().populate_blob_hashes();
1938 }
1939 let inner = request.as_ref();
1940 let fees = FeeDetails::new(
1941 inner.gas_price,
1942 inner.max_fee_per_gas,
1943 inner.max_priority_fee_per_gas,
1944 inner.max_fee_per_blob_gas,
1945 )?
1946 .or_zero_fees();
1947
1948 #[cfg(feature = "base")]
1949 if self.backend.is_base() && request.is_base() {
1950 self.backend.ensure_base_eip8130_active_at(block_env.timestamp.saturating_to())?;
1951 let gas_limit = block_env.gas_limit;
1952 let result = self
1953 .backend
1954 .call_with_state_typed_gas_limit(
1955 state,
1956 request,
1957 fees,
1958 block_env,
1959 GasEstimateCallOptions::new(gas_limit, false, monad_context),
1960 )
1961 .try_into()?;
1962 return match result {
1963 GasEstimationCallResult::Success(gas) => Ok(gas),
1964 GasEstimationCallResult::OutOfGas => {
1965 Err(InvalidTransactionError::BasicOutOfGas(u128::from(gas_limit)).into())
1966 }
1967 GasEstimationCallResult::Revert(output) => {
1968 Err(InvalidTransactionError::Revert(output).into())
1969 }
1970 GasEstimationCallResult::EvmError(error) => Err(BlockchainError::EvmError(error)),
1971 };
1972 }
1973
1974 let mut highest_gas_limit = inner.gas.map_or(block_env.gas_limit.into(), |g| g as u128);
1977
1978 let is_tempo_aa_tx = self.backend.is_tempo() && request.is_tempo();
1981 let is_tempo_keychain = matches!(
1982 &request,
1983 FoundryTransactionRequest::Tempo(request) if request.key_id.is_some()
1984 );
1985 let disable_fee_charge = is_tempo_keychain || inner.from.is_none();
1986
1987 let mut funded_state;
1991 let state = if !is_tempo_aa_tx
1992 && inner.from.is_none()
1993 && let Some(value) = inner.value
1994 && !value.is_zero()
1995 {
1996 funded_state = CacheDB::new(state);
1997 let mut caller = state.basic_ref(Address::ZERO)?.unwrap_or_default();
1998 caller.balance = caller.balance.max(value);
1999 funded_state.insert_account_info(Address::ZERO, caller);
2000 &funded_state as &dyn DatabaseRef
2001 } else {
2002 state
2003 };
2004
2005 let gas_price = fees.gas_price.unwrap_or_default();
2006 if !is_tempo_aa_tx && let Some(from) = inner.from {
2011 let mut available_funds = self.backend.get_balance_with_state(state, from)?;
2012 if let Some(value) = inner.value {
2013 if value > available_funds {
2014 return Err(InvalidTransactionError::InsufficientFunds.into());
2015 }
2016 available_funds -= value;
2018 }
2019 if gas_price > 0 {
2020 if inner.minimal_tx_type().is_eip4844()
2023 && let Some(hashes) = &inner.blob_versioned_hashes
2024 {
2025 let max_fee_per_blob_gas = fees.max_fee_per_blob_gas.unwrap_or_default();
2026 let blob_gas = U256::from(hashes.len() as u64 * DATA_GAS_PER_BLOB);
2027 let blob_cost = blob_gas.saturating_mul(U256::from(max_fee_per_blob_gas));
2028 if blob_cost >= available_funds {
2029 return Err(InvalidTransactionError::InsufficientFunds.into());
2030 }
2031 available_funds -= blob_cost;
2032 }
2033 let allowance =
2035 available_funds.checked_div(U256::from(gas_price)).unwrap_or_default();
2036 highest_gas_limit = std::cmp::min(highest_gas_limit, allowance.saturating_to());
2037 }
2038 }
2039
2040 if !self.backend.is_tempo() {
2045 let to = inner.to.as_ref().and_then(TxKind::to);
2046
2047 let maybe_transfer = (inner.input.input().is_none()
2049 || inner.input.input().is_some_and(|data| data.is_empty()))
2050 && inner.authorization_list.is_none()
2051 && inner.access_list.is_none()
2052 && inner.blob_versioned_hashes.is_none();
2053
2054 if maybe_transfer
2055 && let Some(to) = to
2056 && !self.backend.is_precompile(to, &block_env)
2057 && let Ok(target_code) = self.backend.get_code_with_state(&state, *to)
2058 && target_code.as_ref().is_empty()
2059 {
2060 let probe = self.backend.call_with_state_typed_gas_limit(
2065 &state,
2066 request.clone(),
2067 fees.clone(),
2068 block_env.clone(),
2069 GasEstimateCallOptions::new(
2070 highest_gas_limit.min(MIN_TRANSACTION_GAS) as u64,
2071 disable_fee_charge,
2072 monad_context.clone(),
2073 ),
2074 );
2075 if let Ok(GasEstimationCallResult::Success(gas)) = probe.try_into() {
2076 return Ok(gas);
2077 }
2078 }
2079 }
2080
2081 let ethres = self.backend.call_with_state_typed_gas_limit(
2083 &state,
2084 request.clone(),
2085 fees.clone(),
2086 block_env.clone(),
2087 GasEstimateCallOptions::new(
2088 highest_gas_limit as u64,
2089 disable_fee_charge,
2090 monad_context.clone(),
2091 ),
2092 );
2093
2094 let gas_used = match ethres.try_into()? {
2095 GasEstimationCallResult::Success(gas) => Ok(gas),
2096 GasEstimationCallResult::OutOfGas => {
2097 Err(InvalidTransactionError::BasicOutOfGas(highest_gas_limit).into())
2098 }
2099 GasEstimationCallResult::Revert(output) => {
2100 Err(InvalidTransactionError::Revert(output).into())
2101 }
2102 GasEstimationCallResult::EvmError(err) => {
2103 warn!(target: "node", "estimation failed due to {:?}", err);
2104 Err(BlockchainError::EvmError(err))
2105 }
2106 }?;
2107
2108 let mut lowest_gas_limit = gas_used.saturating_sub(1);
2116
2117 let mut mid_gas_limit =
2119 std::cmp::min(gas_used * 3, (highest_gas_limit + lowest_gas_limit) / 2);
2120
2121 while lowest_gas_limit + 1 < highest_gas_limit {
2123 let ethres = self.backend.call_with_state_typed_gas_limit(
2124 &state,
2125 request.clone(),
2126 fees.clone(),
2127 block_env.clone(),
2128 GasEstimateCallOptions::new(
2129 mid_gas_limit as u64,
2130 disable_fee_charge,
2131 monad_context.clone(),
2132 ),
2133 );
2134
2135 match ethres.try_into()? {
2136 GasEstimationCallResult::Success(_) => {
2137 highest_gas_limit = mid_gas_limit;
2141 }
2142 GasEstimationCallResult::OutOfGas
2143 | GasEstimationCallResult::Revert(_)
2144 | GasEstimationCallResult::EvmError(_) => {
2145 lowest_gas_limit = mid_gas_limit;
2152 }
2153 };
2154 mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
2156 }
2157
2158 trace!(target : "node", "Estimated Gas for call {:?}", highest_gas_limit);
2159
2160 Ok(highest_gas_limit)
2161 }
2162
2163 #[allow(clippy::large_stack_frames)]
2165 pub async fn execute(&self, request: EthRequest) -> ResponseResult {
2166 trace!(target: "rpc::api", "executing eth request");
2167 let _lifecycle = if matches!(
2173 &request,
2174 EthRequest::Reset(_)
2175 | EthRequest::SetRpcUrl(_)
2176 | EthRequest::NodeInfo(_)
2177 | EthRequest::AnvilMetadata(_)
2178 | EthRequest::EvmSnapshot(_)
2179 | EthRequest::EvmRevert(_)
2180 | EthRequest::Reorg(_)
2181 | EthRequest::Rollback(_)
2182 | EthRequest::ConsensusGetFinalization(_)
2183 | EthRequest::ConsensusGetLatest(_)
2184 ) {
2185 None
2186 } else {
2187 Some(self.lifecycle_lock.read().await)
2188 };
2189 match request {
2190 EthRequest::EthProtocolVersion(()) => self.protocol_version().to_rpc_result(),
2191 EthRequest::Web3ClientVersion(()) => self.client_version().to_rpc_result(),
2192 EthRequest::Web3Sha3(content) => self.sha3(content).to_rpc_result(),
2193 EthRequest::EthGetAccount(addr, block) => {
2194 self.get_account(addr, block).await.to_rpc_result()
2195 }
2196 EthRequest::EthGetAccountInfo(addr, block) => {
2197 self.get_account_info(addr, block).await.to_rpc_result()
2198 }
2199 EthRequest::EthGetBalance(addr, block) => {
2200 self.balance(addr, block).await.to_rpc_result()
2201 }
2202 EthRequest::EthGetTransactionByHash(hash) => {
2203 self.transaction_by_hash(hash).await.to_rpc_result()
2204 }
2205 EthRequest::EthPendingTransactions(_) => {
2206 self.pending_transactions().await.to_rpc_result()
2207 }
2208 EthRequest::EthSendTransaction(request) => {
2209 self.send_transaction(*request).await.to_rpc_result()
2210 }
2211 EthRequest::EthResend(request, gas_price, gas_limit) => {
2212 self.resend_transaction(*request, gas_price, gas_limit).await.to_rpc_result()
2213 }
2214 EthRequest::EthSendTransactionSync(request) => {
2215 self.send_transaction_sync(*request).await.to_rpc_result()
2216 }
2217 EthRequest::EthChainId(_) => self.eth_chain_id().to_rpc_result(),
2218 EthRequest::EthNetworkId(_) => self.network_id().to_rpc_result(),
2219 EthRequest::NetListening(_) => self.net_listening().to_rpc_result(),
2220 EthRequest::EthHashrate(()) => self.hashrate().to_rpc_result(),
2221 EthRequest::EthGasPrice(_) => self.eth_gas_price().to_rpc_result(),
2222 EthRequest::EthBaseFee(_) => self.base_fee().to_rpc_result(),
2223 EthRequest::EthMaxPriorityFeePerGas(_) => {
2224 self.gas_max_priority_fee_per_gas().to_rpc_result()
2225 }
2226 EthRequest::EthBlobBaseFee(_) => self.blob_base_fee().to_rpc_result(),
2227 EthRequest::EthAccounts(_) => self.accounts().to_rpc_result(),
2228 EthRequest::EthBlockNumber(_) => self.block_number().to_rpc_result(),
2229 EthRequest::EthCoinbase(()) => self.author().to_rpc_result(),
2230 EthRequest::EthGetStorageAt(addr, slot, block) => {
2231 self.storage_at(addr, slot, block).await.to_rpc_result()
2232 }
2233 EthRequest::EthGetStorageValues(requests, block) => {
2234 self.storage_values(requests, block).await.to_rpc_result()
2235 }
2236 EthRequest::EthGetBlockByHash(hash, full) => {
2237 if full {
2238 self.block_by_hash_full(hash).await.to_rpc_result()
2239 } else {
2240 self.block_by_hash(hash).await.to_rpc_result()
2241 }
2242 }
2243 EthRequest::EthGetHeaderByHash(hash) => self.header_by_hash(hash).await.to_rpc_result(),
2244 EthRequest::EthGetBlockByNumber(num, full) => {
2245 if full {
2246 self.block_by_number_full(num).await.to_rpc_result()
2247 } else {
2248 self.block_by_number(num).await.to_rpc_result()
2249 }
2250 }
2251 EthRequest::EthGetHeaderByNumber(num) => {
2252 self.header_by_number(num).await.to_rpc_result()
2253 }
2254 EthRequest::EthGetBlockAccessList(block_id) => {
2255 self.block_access_list(block_id).await.to_rpc_result()
2256 }
2257 EthRequest::EthGetBlockAccessListByBlockHash(block_hash) => {
2258 self.block_access_list_by_hash(block_hash).await.to_rpc_result()
2259 }
2260 EthRequest::EthGetBlockAccessListByBlockNumber(block_number) => {
2261 self.block_access_list_by_number(block_number).await.to_rpc_result()
2262 }
2263 EthRequest::EthGetBlockAccessListRaw(block_id) => {
2264 self.block_access_list_raw(block_id).await.to_rpc_result()
2265 }
2266 EthRequest::EthGetTransactionCount(params) => {
2267 let (address, block, nonce_key) = params.into_parts();
2268 #[cfg(feature = "base")]
2269 {
2270 self.transaction_count_with_key(address, block, nonce_key).await.to_rpc_result()
2271 }
2272 #[cfg(not(feature = "base"))]
2273 {
2274 if nonce_key.is_some() {
2275 return ResponseResult::Error(RpcError::invalid_params(
2276 "nonce-key transaction counts require Base support",
2277 ));
2278 }
2279 self.transaction_count(address, block).await.to_rpc_result()
2280 }
2281 }
2282 EthRequest::EthGetTransactionCountByHash(hash) => {
2283 self.block_transaction_count_by_hash(hash).await.to_rpc_result()
2284 }
2285 EthRequest::EthGetTransactionCountByNumber(num) => {
2286 self.block_transaction_count_by_number(num).await.to_rpc_result()
2287 }
2288 EthRequest::EthGetUnclesCountByHash(hash) => {
2289 self.block_uncles_count_by_hash(hash).await.to_rpc_result()
2290 }
2291 EthRequest::EthGetUnclesCountByNumber(num) => {
2292 self.block_uncles_count_by_number(num).await.to_rpc_result()
2293 }
2294 EthRequest::EthGetCodeAt(addr, block) => {
2295 self.get_code(addr, block).await.to_rpc_result()
2296 }
2297 EthRequest::EthGetProof(addr, keys, block) => {
2298 self.get_proof(addr, keys, block).await.to_rpc_result()
2299 }
2300 EthRequest::EthSign(addr, content) => self.sign(addr, content).await.to_rpc_result(),
2301 EthRequest::PersonalSign(content, addr) => {
2302 self.sign(addr, content).await.to_rpc_result()
2303 }
2304 EthRequest::EthSignTransaction(request) => {
2305 self.sign_transaction(*request).await.to_rpc_result()
2306 }
2307 EthRequest::EthSignTypedData(addr, data) => {
2308 self.sign_typed_data(addr, data).await.to_rpc_result()
2309 }
2310 EthRequest::EthSignTypedDataV3(addr, data) => {
2311 self.sign_typed_data_v3(addr, data).await.to_rpc_result()
2312 }
2313 EthRequest::EthSignTypedDataV4(addr, data) => {
2314 self.sign_typed_data_v4(addr, &data).await.to_rpc_result()
2315 }
2316 EthRequest::EthSendRawTransaction(tx) => {
2317 self.send_raw_transaction(tx).await.to_rpc_result()
2318 }
2319 EthRequest::EthSendRawTransactionSync(tx, timeout_ms) => {
2320 self.send_raw_transaction_sync(tx, timeout_ms).await.to_rpc_result()
2321 }
2322 EthRequest::EthSendRawTransactionConditional(tx, condition) => {
2323 self.send_raw_transaction_conditional(tx, condition).await.to_rpc_result()
2324 }
2325 EthRequest::EthSignRawTransaction(tx) => {
2326 self.sign_raw_transaction(tx).await.to_rpc_result()
2327 }
2328 EthRequest::AnvilClassifyTransaction(tx) => {
2329 self.anvil_classify_transaction(tx).to_rpc_result()
2330 }
2331 EthRequest::EthCall(call, block, state_override, block_overrides) => self
2332 .call(call, block, EvmOverrides::new(state_override, block_overrides))
2333 .await
2334 .to_rpc_result(),
2335 EthRequest::EthCallMany(bundles, state_context, state_override) => {
2336 self.call_many(bundles, state_context, state_override).await.to_rpc_result()
2337 }
2338 EthRequest::EthCallBundle(bundle) => self.call_bundle(bundle).await.to_rpc_result(),
2339 EthRequest::EthSimulateV1(simulation, block) => {
2340 self.simulate_v1_raw(simulation, block).await.to_rpc_result()
2341 }
2342 EthRequest::EthCreateAccessList(call, block, state_override) => {
2343 self.create_access_list(call, block, state_override).await.to_rpc_result()
2344 }
2345 EthRequest::EthEstimateGas(call, block, state_override, block_overrides) => self
2346 .estimate_gas(call, block, EvmOverrides::new(state_override, block_overrides))
2347 .await
2348 .to_rpc_result(),
2349 EthRequest::EthFillTransaction(request) => {
2350 self.fill_transaction(request).await.to_rpc_result()
2351 }
2352 EthRequest::EthGetRawTransactionByHash(hash) => {
2353 self.raw_transaction(hash).await.to_rpc_result()
2354 }
2355 EthRequest::GetBlobByHash(hash) => {
2356 self.anvil_get_blob_by_versioned_hash(hash).to_rpc_result()
2357 }
2358 EthRequest::GetBlobByTransactionHash(hash) => {
2359 self.anvil_get_blob_by_tx_hash(hash).to_rpc_result()
2360 }
2361 EthRequest::GetGenesisTime(()) => self.anvil_get_genesis_time().to_rpc_result(),
2362 EthRequest::GetLastBlockWallTime(()) => {
2363 self.anvil_get_last_block_wall_time().to_rpc_result()
2364 }
2365 EthRequest::EthGetRawTransactionByBlockHashAndIndex(hash, index) => {
2366 self.raw_transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
2367 }
2368 EthRequest::EthGetRawTransactionByBlockNumberAndIndex(num, index) => {
2369 self.raw_transaction_by_block_number_and_index(num, index).await.to_rpc_result()
2370 }
2371 EthRequest::EthGetTransactionByBlockHashAndIndex(hash, index) => {
2372 self.transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
2373 }
2374 EthRequest::EthGetTransactionByBlockNumberAndIndex(num, index) => {
2375 self.transaction_by_block_number_and_index(num, index).await.to_rpc_result()
2376 }
2377 EthRequest::EthGetTransactionReceipt(tx) => {
2378 self.transaction_receipt(tx).await.to_rpc_result()
2379 }
2380 EthRequest::EthGetBlockReceipts(number) => {
2381 self.block_receipts(number).await.to_rpc_result()
2382 }
2383 EthRequest::EthGetUncleByBlockHashAndIndex(hash, index) => {
2384 self.uncle_by_block_hash_and_index(hash, index).await.to_rpc_result()
2385 }
2386 EthRequest::EthGetUncleByBlockNumberAndIndex(num, index) => {
2387 self.uncle_by_block_number_and_index(num, index).await.to_rpc_result()
2388 }
2389 EthRequest::EthGetLogs(filter) => self.logs(filter).await.to_rpc_result(),
2390 EthRequest::EthGetWork(_) => self.work().to_rpc_result(),
2391 EthRequest::EthSyncing(_) => self.syncing().to_rpc_result(),
2392 EthRequest::EthConfig(_) => self.config().to_rpc_result(),
2393 EthRequest::EthSubmitWork(nonce, pow, digest) => {
2394 self.submit_work(nonce, pow, digest).to_rpc_result()
2395 }
2396 EthRequest::EthSubmitHashRate(rate, id) => {
2397 self.submit_hashrate(rate, id).to_rpc_result()
2398 }
2399 EthRequest::EthFeeHistory(count, newest, reward_percentiles) => {
2400 self.fee_history(count, newest, reward_percentiles).await.to_rpc_result()
2401 }
2402 EthRequest::DebugGetRawTransaction(hash) => {
2404 self.raw_transaction(hash).await.to_rpc_result()
2405 }
2406 EthRequest::DebugGetRawReceipts(block) => {
2407 self.raw_receipts(block).await.to_rpc_result()
2408 }
2409 EthRequest::DebugGetRawTransactions(block) => {
2410 self.raw_transactions(block).await.to_rpc_result()
2411 }
2412 EthRequest::DebugGetRawHeader(block) => self.raw_header(block).await.to_rpc_result(),
2413 EthRequest::DebugGetRawBlock(block) => self.raw_block(block).await.to_rpc_result(),
2414 EthRequest::DebugClearTxpool(_) => self.debug_clear_txpool().await.to_rpc_result(),
2416 EthRequest::DebugTraceTransaction(tx, opts) => {
2418 self.debug_trace_transaction(tx, opts).await.to_rpc_result()
2419 }
2420 EthRequest::DebugTraceCall(tx, block, opts) => {
2422 self.debug_trace_call(tx, block, opts).await.to_rpc_result()
2423 }
2424 EthRequest::DebugCodeByHash(hash, block) => {
2425 self.debug_code_by_hash(hash, block).await.to_rpc_result()
2426 }
2427 EthRequest::DebugDbGet(key) => self.debug_db_get(key).await.to_rpc_result(),
2428 EthRequest::DebugGetModifiedAccountsByNumber(start_number, end_number) => {
2429 self.debug_get_modified_accounts_by_number(start_number, end_number).to_rpc_result()
2430 }
2431 EthRequest::DebugFreeOsMemory(()) => self.debug_free_os_memory().to_rpc_result(),
2432 EthRequest::DebugAccountInfoAt(block_id, tx_index, address) => {
2433 self.debug_account_info_at(block_id, tx_index, address).await.to_rpc_result()
2434 }
2435 EthRequest::DebugExecutionWitness(block) => {
2436 self.debug_execution_witness(block).await.to_rpc_result()
2437 }
2438 EthRequest::DebugTraceBlock(rlp_block, opts) => {
2439 self.debug_trace_block(rlp_block, opts).await.to_rpc_result()
2440 }
2441 EthRequest::DebugTraceBlockByHash(block_hash, opts) => {
2442 self.debug_trace_block_by_hash(block_hash, opts).await.to_rpc_result()
2443 }
2444 EthRequest::DebugTraceBlockByNumber(block_number, opts) => {
2445 self.debug_trace_block_by_number(block_number, opts).await.to_rpc_result()
2446 }
2447 EthRequest::TraceCall(tx, trace_types, block) => {
2448 self.trace_call(tx, trace_types, block).await.to_rpc_result()
2449 }
2450 EthRequest::TraceTransaction(tx) => self.trace_transaction(tx).await.to_rpc_result(),
2451 EthRequest::TraceBlock(block) => self.trace_block(block).await.to_rpc_result(),
2452 EthRequest::TraceFilter(filter) => self.trace_filter(filter).await.to_rpc_result(),
2453 EthRequest::TraceGet(hash, indices) => {
2454 self.trace_get(hash, indices).await.to_rpc_result()
2455 }
2456 EthRequest::TraceReplayBlockTransactions(block, trace_types) => {
2457 self.trace_replay_block_transactions(block, trace_types).await.to_rpc_result()
2458 }
2459 EthRequest::TraceReplayTransaction(transaction, trace_types) => {
2460 self.trace_replay_transaction(transaction, trace_types).await.to_rpc_result()
2461 }
2462 EthRequest::TraceTransactionOpcodeGas(tx_hash) => {
2463 self.trace_transaction_opcode_gas(tx_hash).await.to_rpc_result()
2464 }
2465 EthRequest::TraceBlockOpcodeGas(block_id) => {
2466 self.trace_block_opcode_gas(block_id).await.to_rpc_result()
2467 }
2468 EthRequest::TraceRawTransaction(tx, trace_types, block_number) => {
2469 self.trace_raw_transaction(tx, trace_types, block_number).await.to_rpc_result()
2470 }
2471 EthRequest::TraceCallMany(calls, block_number) => {
2472 self.trace_call_many(calls, block_number).await.to_rpc_result()
2473 }
2474 EthRequest::ImpersonateAccount(addr) => {
2475 self.anvil_impersonate_account(addr).await.to_rpc_result()
2476 }
2477 EthRequest::StopImpersonatingAccount(addr) => {
2478 self.anvil_stop_impersonating_account(addr).await.to_rpc_result()
2479 }
2480 EthRequest::AutoImpersonateAccount(enable) => {
2481 self.anvil_auto_impersonate_account(enable).await.to_rpc_result()
2482 }
2483 EthRequest::ImpersonateSignature(signature, address) => {
2484 self.anvil_impersonate_signature(signature, address).await.to_rpc_result()
2485 }
2486 EthRequest::GetAutoMine(()) => self.anvil_get_auto_mine().to_rpc_result(),
2487 EthRequest::Mine(blocks, interval) => {
2488 self.anvil_mine(blocks, interval).await.to_rpc_result()
2489 }
2490 EthRequest::SetAutomine(enabled) => {
2491 self.anvil_set_auto_mine(enabled).await.to_rpc_result()
2492 }
2493 EthRequest::SetIntervalMining(interval) => {
2494 self.anvil_set_interval_mining(interval).to_rpc_result()
2495 }
2496 EthRequest::GetIntervalMining(()) => self.anvil_get_interval_mining().to_rpc_result(),
2497 EthRequest::SetMiningPaused(paused) => {
2498 self.anvil_set_mining_paused(paused).await.to_rpc_result()
2499 }
2500 EthRequest::GetMiningPaused(()) => self.anvil_get_mining_paused().to_rpc_result(),
2501 EthRequest::DropTransaction(tx) => {
2502 self.anvil_drop_transaction(tx).await.to_rpc_result()
2503 }
2504 EthRequest::DropAllTransactions() => {
2505 self.anvil_drop_all_transactions().await.to_rpc_result()
2506 }
2507 EthRequest::Reset(fork) => {
2508 self.anvil_reset(fork.and_then(|p| p.params)).await.to_rpc_result()
2509 }
2510 EthRequest::SetBalance(addr, val) => {
2511 self.anvil_set_balance(addr, val).await.to_rpc_result()
2512 }
2513 EthRequest::AddBalance(addr, val) => {
2514 self.anvil_add_balance(addr, val).await.to_rpc_result()
2515 }
2516 EthRequest::DealERC20(addr, token_addr, val) => {
2517 self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result()
2518 }
2519 EthRequest::DealTIP20(addr, token_addr, val) => {
2520 self.anvil_deal_tip20(addr, token_addr, val).await.to_rpc_result()
2521 }
2522 EthRequest::SetERC20Allowance(owner, spender, token_addr, val) => self
2523 .anvil_set_erc20_allowance(owner, spender, token_addr, val)
2524 .await
2525 .to_rpc_result(),
2526 EthRequest::SetCode(addr, code) => {
2527 self.anvil_set_code(addr, code).await.to_rpc_result()
2528 }
2529 EthRequest::SetNonce(addr, nonce) => {
2530 self.anvil_set_nonce(addr, nonce).await.to_rpc_result()
2531 }
2532 EthRequest::SetStorageAt(addr, slot, val) => {
2533 self.anvil_set_storage_at(addr, slot, val).await.to_rpc_result()
2534 }
2535 EthRequest::SetCoinbase(addr) => self.anvil_set_coinbase(addr).await.to_rpc_result(),
2536 EthRequest::SetNextBlockPrevRandao(prevrandao) => {
2537 self.anvil_set_next_block_prevrandao(prevrandao).await.to_rpc_result()
2538 }
2539 EthRequest::SetNextBlockParentBeaconBlockRoot(root) => {
2540 self.anvil_set_next_block_parent_beacon_block_root(root).await.to_rpc_result()
2541 }
2542 EthRequest::SetChainId(id) => self.anvil_set_chain_id(id).await.to_rpc_result(),
2543 EthRequest::SetLogging(log) => self.anvil_set_logging(log).await.to_rpc_result(),
2544 EthRequest::SetMinGasPrice(gas) => {
2545 self.anvil_set_min_gas_price(gas).await.to_rpc_result()
2546 }
2547 EthRequest::SetNextBlockBaseFeePerGas(gas) => {
2548 self.anvil_set_next_block_base_fee_per_gas(gas).await.to_rpc_result()
2549 }
2550 EthRequest::DumpState(preserve_historical_states) => self
2551 .anvil_dump_state(preserve_historical_states.and_then(|s| s.params))
2552 .await
2553 .to_rpc_result(),
2554 EthRequest::LoadState(buf) => self.anvil_load_state(buf).await.to_rpc_result(),
2555 EthRequest::NodeInfo(_) => self.anvil_node_info().await.to_rpc_result(),
2556 EthRequest::AnvilMetadata(_) => self.anvil_metadata().await.to_rpc_result(),
2557 EthRequest::EvmSnapshot(_) => self.evm_snapshot().await.to_rpc_result(),
2558 EthRequest::EvmRevert(id) => self.evm_revert(id).await.to_rpc_result(),
2559 EthRequest::EvmIncreaseTime(time) => self.evm_increase_time(time).await.to_rpc_result(),
2560 EthRequest::EvmSetNextBlockTimeStamp(time) => {
2561 if time >= U256::from(u64::MAX) {
2562 return ResponseResult::Error(RpcError::invalid_params(
2563 "The timestamp is too big",
2564 ));
2565 }
2566 let time = time.to::<u64>();
2567 self.evm_set_next_block_timestamp(time).to_rpc_result()
2568 }
2569 EthRequest::EvmSetTime(timestamp) => {
2570 if timestamp >= U256::from(u64::MAX) {
2571 return ResponseResult::Error(RpcError::invalid_params(
2572 "The timestamp is too big",
2573 ));
2574 }
2575 let raw = timestamp.to::<u64>();
2579 let time = if raw > 1_000_000_000_000 {
2580 Duration::from_millis(raw).as_secs()
2581 } else {
2582 raw
2583 };
2584 self.evm_set_time(time).to_rpc_result()
2585 }
2586 EthRequest::EvmSetBlockGasLimit(gas_limit) => {
2587 self.evm_set_block_gas_limit(gas_limit).to_rpc_result()
2588 }
2589 EthRequest::EvmSetBlockTimeStampInterval(time) => {
2590 self.evm_set_block_timestamp_interval(time).to_rpc_result()
2591 }
2592 EthRequest::EvmRemoveBlockTimeStampInterval(()) => {
2593 self.evm_remove_block_timestamp_interval().to_rpc_result()
2594 }
2595 EthRequest::EvmMine(mine) => {
2596 self.evm_mine(mine.and_then(|p| p.params)).await.to_rpc_result()
2597 }
2598 EthRequest::EvmMineDetailed(mine) => {
2599 self.evm_mine_detailed(mine.and_then(|p| p.params)).await.to_rpc_result()
2600 }
2601 EthRequest::SetRpcUrl(url) => self.anvil_set_rpc_url(url).await.to_rpc_result(),
2602 EthRequest::EthSendUnsignedTransaction(tx) => {
2603 self.eth_send_unsigned_transaction(*tx).await.to_rpc_result()
2604 }
2605 EthRequest::EthNewFilter(filter) => self.new_filter(filter).await.to_rpc_result(),
2606 EthRequest::EthGetFilterChanges(id) => self.get_filter_changes(&id).await,
2607 EthRequest::EthNewBlockFilter(_) => self.new_block_filter().await.to_rpc_result(),
2608 EthRequest::EthNewPendingTransactionFilter(full) => {
2609 self.new_pending_transaction_filter(full.unwrap_or(false)).await.to_rpc_result()
2610 }
2611 EthRequest::EthGetFilterLogs(id) => self.get_filter_logs(&id).await.to_rpc_result(),
2612 EthRequest::EthUninstallFilter(id) => self.uninstall_filter(&id).await.to_rpc_result(),
2613 EthRequest::TxPoolStatus(_) => self.txpool_status().await.to_rpc_result(),
2614 EthRequest::TxPoolInspect(_) => self.txpool_inspect().await.to_rpc_result(),
2615 EthRequest::TxPoolContent(_) => self.txpool_content().await.to_rpc_result(),
2616 EthRequest::TxPoolContentFrom(from) => {
2617 self.txpool_content_from(from).await.to_rpc_result()
2618 }
2619 EthRequest::ErigonGetHeaderByNumber(num) => {
2620 self.erigon_get_header_by_number(num).await.to_rpc_result()
2621 }
2622 EthRequest::OtsGetApiLevel(_) => self.ots_get_api_level().await.to_rpc_result(),
2623 EthRequest::OtsGetInternalOperations(hash) => {
2624 self.ots_get_internal_operations(hash).await.to_rpc_result()
2625 }
2626 EthRequest::OtsHasCode(addr, num) => self.ots_has_code(addr, num).await.to_rpc_result(),
2627 EthRequest::OtsTraceTransaction(hash) => {
2628 self.ots_trace_transaction(hash).await.to_rpc_result()
2629 }
2630 EthRequest::OtsGetTransactionError(hash) => {
2631 self.ots_get_transaction_error(hash).await.to_rpc_result()
2632 }
2633 EthRequest::OtsGetBlockDetails(num) => {
2634 self.ots_get_block_details(num).await.to_rpc_result()
2635 }
2636 EthRequest::OtsGetBlockDetailsByHash(hash) => {
2637 self.ots_get_block_details_by_hash(hash).await.to_rpc_result()
2638 }
2639 EthRequest::OtsGetBlockTransactions(num, page, page_size) => {
2640 self.ots_get_block_transactions(num, page, page_size).await.to_rpc_result()
2641 }
2642 EthRequest::OtsSearchTransactionsBefore(address, num, page_size) => {
2643 self.ots_search_transactions_before(address, num, page_size).await.to_rpc_result()
2644 }
2645 EthRequest::OtsSearchTransactionsAfter(address, num, page_size) => {
2646 self.ots_search_transactions_after(address, num, page_size).await.to_rpc_result()
2647 }
2648 EthRequest::OtsGetTransactionBySenderAndNonce(address, nonce) => {
2649 self.ots_get_transaction_by_sender_and_nonce(address, nonce).await.to_rpc_result()
2650 }
2651 EthRequest::EthGetTransactionBySenderAndNonce(sender, nonce) => {
2652 self.transaction_by_sender_and_nonce(sender, nonce).await.to_rpc_result()
2653 }
2654 EthRequest::OtsGetContractCreator(address) => {
2655 self.ots_get_contract_creator(address).await.to_rpc_result()
2656 }
2657 EthRequest::RemovePoolTransactions(address) => {
2658 self.anvil_remove_pool_transactions(address).await.to_rpc_result()
2659 }
2660 EthRequest::Reorg(reorg_options) => {
2661 self.anvil_reorg(reorg_options).await.to_rpc_result()
2662 }
2663 EthRequest::Rollback(depth) => self.anvil_rollback(depth).await.to_rpc_result(),
2664 EthRequest::SetFeeToken(user, token) => {
2665 self.anvil_set_fee_token(user, token).await.to_rpc_result()
2666 }
2667 EthRequest::SetValidatorFeeToken(validator, token) => {
2668 self.anvil_set_validator_fee_token(validator, token).await.to_rpc_result()
2669 }
2670 EthRequest::SetFeeAmmLiquidity(user_token, validator_token, amount) => self
2671 .anvil_set_fee_amm_liquidity(user_token, validator_token, amount)
2672 .await
2673 .to_rpc_result(),
2674 EthRequest::ConsensusGetFinalization(query) => {
2675 self.consensus_get_finalization(query).await.to_rpc_result()
2676 }
2677 EthRequest::ConsensusGetLatest(()) => self.consensus_get_latest().await.to_rpc_result(),
2678 EthRequest::TempoConsensusIdentity(()) => {
2679 self.anvil_tempo_consensus_identity().await.to_rpc_result()
2680 }
2681 EthRequest::TempoRotateConsensusIdentity(()) => {
2682 self.anvil_tempo_rotate_consensus_identity().await.to_rpc_result()
2683 }
2684 }
2685 }
2686
2687 fn sign_request(&self, from: &Address, typed_tx: FoundryTypedTx) -> Result<FoundryTxEnvelope> {
2688 match typed_tx {
2689 #[cfg(feature = "optimism")]
2690 FoundryTypedTx::Deposit(_) => return Ok(typed_tx.into_impersonated()),
2691 _ => {
2692 for signer in self.signers.iter() {
2693 if signer.accounts().contains(from) {
2694 return signer.sign_transaction_from(from, typed_tx);
2695 }
2696 }
2697 }
2698 }
2699 Err(BlockchainError::NoSignerAvailable)
2700 }
2701
2702 async fn inner_raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
2703 match self.pool.get_transaction(hash) {
2704 Some(tx) => Ok(Some(tx.transaction.encoded_2718().into())),
2705 None => match self.backend.transaction_by_hash(hash).await? {
2706 Some(tx) => encode_rpc_transaction(&tx).map(Some),
2707 None => Ok(None),
2708 },
2709 }
2710 }
2711
2712 pub async fn balance(&self, address: Address, block_number: Option<BlockId>) -> Result<U256> {
2716 node_info!("eth_getBalance");
2717 let block_request = self.block_request(block_number).await?;
2718
2719 if let BlockRequest::Number(number) = block_request
2721 && let Some(fork) = self.get_fork()
2722 && fork.predates_fork(number)
2723 {
2724 return Ok(fork.get_balance(address, number).await?);
2725 }
2726
2727 self.backend.get_balance(address, Some(block_request)).await
2728 }
2729
2730 pub async fn get_account(
2734 &self,
2735 address: Address,
2736 block_number: Option<BlockId>,
2737 ) -> Result<TrieAccount> {
2738 node_info!("eth_getAccount");
2739 let block_request = self.block_request(block_number).await?;
2740
2741 if let BlockRequest::Number(number) = block_request
2743 && let Some(fork) = self.get_fork()
2744 && fork.predates_fork(number)
2745 {
2746 return Ok(fork.get_account(address, number).await?);
2747 }
2748
2749 self.backend.get_account_at_block(address, Some(block_request)).await
2750 }
2751
2752 pub async fn get_account_info(
2756 &self,
2757 address: Address,
2758 block_number: Option<BlockId>,
2759 ) -> Result<alloy_rpc_types::eth::AccountInfo> {
2760 node_info!("eth_getAccountInfo");
2761
2762 let block_request = self.block_request(block_number).await?;
2763 if let BlockRequest::Number(number) = block_request
2764 && let Some(fork) = self.get_fork()
2765 {
2766 trace!(target: "node", "get_account_info: fork block {}, requested block {number}", fork.block_number());
2767 if block_number.is_some_and(|block| !block.is_latest())
2768 && fork.predates_fork_inclusive(number)
2769 {
2770 if fork.requires_account_info() {
2771 return Ok(fork.get_account_info(address, number).await?);
2772 }
2773 let balance = fork.get_balance(address, number).map_err(BlockchainError::from);
2774 let code = fork.get_code(address, number).map_err(BlockchainError::from);
2775 let nonce = fork.get_nonce(address, number).map_err(BlockchainError::from);
2776 let (balance, code, nonce) = try_join!(balance, code, nonce)?;
2777 return Ok(alloy_rpc_types::eth::AccountInfo { balance, nonce, code });
2778 }
2779 }
2780
2781 self.backend.get_account_info_at_block(address, Some(block_request)).await
2782 }
2783 pub async fn storage_at(
2787 &self,
2788 address: Address,
2789 index: U256,
2790 block_number: Option<BlockId>,
2791 ) -> Result<B256> {
2792 node_info!("eth_getStorageAt");
2793 let block_request = self.block_request(block_number).await?;
2794
2795 if let BlockRequest::Number(number) = block_request
2797 && let Some(fork) = self.get_fork()
2798 && fork.predates_fork(number)
2799 {
2800 return Ok(B256::from(
2801 fork.storage_at(address, index, Some(BlockNumber::Number(number))).await?,
2802 ));
2803 }
2804
2805 self.backend.storage_at(address, index, Some(block_request)).await
2806 }
2807
2808 pub async fn storage_values(
2812 &self,
2813 requests: HashMap<Address, Vec<B256>>,
2814 block_number: Option<BlockId>,
2815 ) -> Result<HashMap<Address, Vec<B256>>> {
2816 node_info!("eth_getStorageValues");
2817
2818 if requests.is_empty() {
2819 return Err(RpcError::invalid_params("empty request").into());
2820 }
2821
2822 let total_slots: usize = requests.values().map(|s| s.len()).sum();
2823 if total_slots > 1024 {
2824 return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
2825 "total slot count {total_slots} exceeds limit 1024"
2826 ))));
2827 }
2828
2829 let block_request = self.block_request(block_number).await?;
2830
2831 if let BlockRequest::Number(number) = block_request
2833 && let Some(fork) = self.get_fork()
2834 && fork.predates_fork(number)
2835 {
2836 let mut result: HashMap<Address, Vec<B256>> = HashMap::default();
2837 for (address, slots) in requests {
2838 let mut values = Vec::with_capacity(slots.len());
2839 for slot in &slots {
2840 let val = fork
2841 .storage_at(address, (*slot).into(), Some(BlockNumber::Number(number)))
2842 .await?;
2843 values.push(B256::from(val));
2844 }
2845 result.insert(address, values);
2846 }
2847 return Ok(result);
2848 }
2849
2850 self.backend.storage_values(requests, Some(block_request)).await
2851 }
2852
2853 pub async fn block_by_number(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2857 node_info!("eth_getBlockByNumber");
2858 if number.is_pending() {
2859 return Ok(Some(self.pending_block().await?));
2860 }
2861
2862 self.backend.block_by_number(number).await
2863 }
2864
2865 pub async fn header_by_number(
2869 &self,
2870 number: BlockNumber,
2871 ) -> Result<Option<WithOtherFields<AnyRpcHeader>>> {
2872 node_info!("eth_getHeaderByNumber");
2873 if number.is_pending() {
2874 let WithOtherFields { inner: block, other } = self.pending_block().await?.0;
2875 return Ok(Some(WithOtherFields { inner: block.header, other }));
2876 }
2877
2878 Ok(self.backend.block_by_number(number).await?.map(|block| {
2879 let WithOtherFields { inner: block, other } = block.0;
2880 WithOtherFields { inner: block.header, other }
2881 }))
2882 }
2883
2884 pub async fn block_by_number_full(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2888 node_info!("eth_getBlockByNumber");
2889 if number.is_pending() {
2890 return self.pending_block_full().await;
2891 }
2892 self.backend.block_by_number_full(number).await
2893 }
2894
2895 pub async fn block_access_list(&self, block_id: BlockId) -> Result<Option<serde_json::Value>> {
2899 node_info!("eth_getBlockAccessList");
2900 let block_request = self.block_request(Some(block_id)).await?;
2901 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2902
2903 if let Some(fork) = self.get_fork()
2904 && fork.predates_fork_inclusive(number)
2905 {
2906 return Ok(fork.block_access_list(block_id).await?);
2907 }
2908
2909 let block_access_list = match block_id {
2910 BlockId::Hash(hash) => self.backend.block_access_list_by_hash(hash.block_hash),
2911 BlockId::Number(_) => self.backend.block_access_list_by_number(number),
2912 };
2913 Ok(block_access_list
2914 .map(|bal| serde_json::to_value(bal).expect("BAL serialization is infallible")))
2915 }
2916
2917 pub async fn block_access_list_by_hash(
2921 &self,
2922 block_hash: B256,
2923 ) -> Result<Option<serde_json::Value>> {
2924 node_info!("eth_getBlockAccessListByBlockHash");
2925 if let Some(block_access_list) = self.backend.block_access_list_by_hash(block_hash) {
2926 return Ok(Some(
2927 serde_json::to_value(block_access_list).expect("BAL serialization is infallible"),
2928 ));
2929 }
2930
2931 let Some(fork) = self.get_fork() else { return Ok(None) };
2932
2933 if let Some(block) = self.backend.get_block_by_hash(block_hash)
2936 && !fork.predates_fork_inclusive(block.header.number)
2937 {
2938 return Ok(None);
2939 }
2940
2941 Ok(fork.block_access_list_by_hash(block_hash).await?)
2942 }
2943
2944 pub async fn block_access_list_by_number(
2948 &self,
2949 block_number: BlockNumber,
2950 ) -> Result<Option<serde_json::Value>> {
2951 node_info!("eth_getBlockAccessListByBlockNumber");
2952 let block_request = self.block_request(Some(BlockId::Number(block_number))).await?;
2953 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2954
2955 if let Some(fork) = self.get_fork()
2956 && fork.predates_fork_inclusive(number)
2957 {
2958 return Ok(fork.block_access_list_by_number(block_number).await?);
2959 }
2960
2961 Ok(self
2962 .backend
2963 .block_access_list_by_number(number)
2964 .map(|bal| serde_json::to_value(bal).expect("BAL serialization is infallible")))
2965 }
2966
2967 pub async fn block_access_list_raw(&self, block_id: BlockId) -> Result<Option<Bytes>> {
2971 node_info!("eth_getBlockAccessListRaw");
2972 let block_request = self.block_request(Some(block_id)).await?;
2973 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2974
2975 if let Some(fork) = self.get_fork()
2976 && fork.predates_fork_inclusive(number)
2977 {
2978 return Ok(fork.block_access_list_raw(block_id).await?);
2979 }
2980
2981 let block_access_list = match block_id {
2982 BlockId::Hash(hash) => self.backend.block_access_list_by_hash(hash.block_hash),
2983 BlockId::Number(_) => self.backend.block_access_list_by_number(number),
2984 };
2985 Ok(block_access_list.map(|bal| {
2986 let mut encoded = Vec::new();
2987 alloy_rlp::encode_list(&bal, &mut encoded);
2988 encoded.into()
2989 }))
2990 }
2991
2992 pub async fn transaction_count(
2999 &self,
3000 address: Address,
3001 block_number: Option<BlockId>,
3002 ) -> Result<U256> {
3003 node_info!("eth_getTransactionCount");
3004 self.get_transaction_count(address, block_number).await.map(U256::from)
3005 }
3006
3007 #[cfg(feature = "base")]
3009 pub async fn transaction_count_with_key(
3010 &self,
3011 address: Address,
3012 block_number: Option<BlockId>,
3013 nonce_key: Option<U256>,
3014 ) -> Result<U256> {
3015 let Some(nonce_key) = nonce_key else {
3016 return self.transaction_count(address, block_number).await;
3017 };
3018 if nonce_key.is_zero() {
3019 return self.transaction_count(address, block_number).await;
3020 }
3021
3022 let block_request = self.block_request(block_number).await?;
3023 let timestamp = self.backend.block_request_timestamp(&block_request).await?;
3024 self.backend.ensure_base_eip8130_active_at(timestamp)?;
3025 if nonce_key == Eip8130Constants::NONCE_KEY_MAX {
3026 return Err(RpcError::invalid_params(
3027 "nonce_key NONCE_KEY_MAX selects the expiring-nonce channel which has no \
3028 per-channel counter",
3029 )
3030 .into());
3031 }
3032 let slot = NonceManagerStorage::nonce_slot(address, nonce_key)
3033 .map_err(|error| RpcError::invalid_params(error.to_string()))?;
3034 let word = self
3035 .backend
3036 .storage_at(NonceManagerStorage::ADDRESS, slot, Some(block_request))
3037 .await?;
3038 Ok(Eip8130Nonce::decode_channel_nonce(word.into()))
3039 }
3040
3041 pub async fn block_transaction_count_by_number(
3045 &self,
3046 block_number: BlockNumber,
3047 ) -> Result<Option<U256>> {
3048 node_info!("eth_getBlockTransactionCountByNumber");
3049 if block_number.is_pending() {
3050 let txs = self.pool.ready_transactions().collect();
3051 let block = self.backend.pending_block(txs).await?;
3052 return Ok(Some(U256::from(block.block.body.transactions.len())));
3053 }
3054
3055 let block = self.backend.block_by_number(block_number).await?;
3056 let txs = block.map(|b| match b.transactions() {
3057 BlockTransactions::Full(txs) => U256::from(txs.len()),
3058 BlockTransactions::Hashes(txs) => U256::from(txs.len()),
3059 BlockTransactions::Uncle => U256::ZERO,
3060 });
3061 Ok(txs)
3062 }
3063
3064 pub async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {
3068 node_info!("eth_getCode");
3069 let block_request = self.block_request(block_number).await?;
3070 if let BlockRequest::Number(number) = block_request
3072 && let Some(fork) = self.get_fork()
3073 && fork.predates_fork(number)
3074 {
3075 return Ok(fork.get_code(address, number).await?);
3076 }
3077 self.backend.get_code(address, Some(block_request)).await
3078 }
3079
3080 pub async fn get_proof(
3085 &self,
3086 address: Address,
3087 keys: Vec<B256>,
3088 block_number: Option<BlockId>,
3089 ) -> Result<EIP1186AccountProofResponse> {
3090 node_info!("eth_getProof");
3091 let block_request = self.block_request(block_number).await?;
3092
3093 if let BlockRequest::Number(number) = block_request
3096 && let Some(fork) = self.get_fork()
3097 && fork.predates_fork_inclusive(number)
3098 {
3099 return Ok(fork.get_proof(address, keys, Some(number.into())).await?);
3100 }
3101
3102 let proof = self.backend.prove_account_at(address, keys, Some(block_request)).await?;
3103 Ok(proof)
3104 }
3105
3106 pub async fn sign_transaction(
3110 &self,
3111 request: WithOtherFields<TransactionRequest>,
3112 ) -> Result<String> {
3113 node_info!("eth_signTransaction");
3114 let request = self.parse_transaction_request(request)?;
3115
3116 let from = request.from().map(Ok).unwrap_or_else(|| {
3117 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3118 })?;
3119
3120 let nonce = self.request_nonce_for_transaction(&request, from).await?;
3121
3122 let request = self.build_tx_request(request, nonce).await?;
3123
3124 let signed_transaction = self.sign_request(&from, request)?.encoded_2718();
3125 Ok(alloy_primitives::hex::encode_prefixed(signed_transaction))
3126 }
3127
3128 pub async fn send_transaction(
3132 &self,
3133 request: WithOtherFields<TransactionRequest>,
3134 ) -> Result<TxHash> {
3135 node_info!("eth_sendTransaction");
3136 let request = self.parse_transaction_request(request)?;
3137
3138 let from = request.from().map(Ok).unwrap_or_else(|| {
3139 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3140 })?;
3141 let _nonce_guard = if request.nonce().is_none() {
3144 let lock = self.nonce_locks.write().entry(from).or_default().clone();
3145 Some(lock.lock_owned().await)
3146 } else {
3147 None
3148 };
3149 let nonce = self.request_nonce_for_transaction(&request, from).await?;
3150
3151 let typed_tx = self.build_tx_request(request, nonce).await?;
3152
3153 let pending_transaction = if self.is_impersonated(from) {
3155 let transaction = typed_tx.into_impersonated();
3156 self.ensure_typed_transaction_supported(&transaction)?;
3157 trace!(target : "node", ?from, "eth_sendTransaction: impersonating");
3158 PendingTransaction::with_impersonated(transaction, from)
3159 } else {
3160 let transaction = self.sign_request(&from, typed_tx)?;
3161 self.ensure_typed_transaction_supported(&transaction)?;
3162 PendingTransaction::new(transaction)?
3163 };
3164 self.add_pending_transaction(pending_transaction).await
3165 }
3166
3167 pub async fn resend_transaction(
3171 &self,
3172 request: WithOtherFields<TransactionRequest>,
3173 gas_price: Option<U256>,
3174 gas_limit: Option<U64>,
3175 ) -> Result<TxHash> {
3176 node_info!("eth_resend");
3177 let mut request = self.parse_transaction_request(request)?;
3178
3179 let from = request.from().map(Ok).unwrap_or_else(|| {
3180 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3181 })?;
3182 let nonce = request.nonce().ok_or_else(|| {
3183 BlockchainError::InvalidTransactionRequest(
3184 "missing transaction nonce in transaction spec".to_string(),
3185 )
3186 })?;
3187
3188 if !self.pool.contains_sender_nonce(from, nonce) {
3189 return Err(BlockchainError::TransactionNotFound);
3190 }
3191
3192 if let Some(gas_price) = gas_price.filter(|gas_price| !gas_price.is_zero()) {
3193 request.set_gas_price(gas_price.saturating_to());
3194 }
3195
3196 if let Some(gas_limit) = gas_limit.filter(|gas_limit| *gas_limit != U64::ZERO) {
3197 request.set_gas_limit(gas_limit.to());
3198 }
3199
3200 let typed_tx = self.build_tx_request(request, nonce).await?;
3201
3202 let pending_transaction = if self.is_impersonated(from) {
3203 let transaction = typed_tx.into_impersonated();
3204 self.ensure_typed_transaction_supported(&transaction)?;
3205 trace!(target : "node", ?from, "eth_resend: impersonating");
3206 PendingTransaction::with_impersonated(transaction, from)
3207 } else {
3208 let transaction = self.sign_request(&from, typed_tx)?;
3209 self.ensure_typed_transaction_supported(&transaction)?;
3210 PendingTransaction::new(transaction)?
3211 };
3212
3213 self.add_pending_transaction(pending_transaction).await
3214 }
3215
3216 async fn await_transaction_inclusion(&self, hash: TxHash) -> Result<FoundryTxReceipt> {
3218 let mut stream = self.new_block_notifications();
3219 if let Some(receipt) = self.backend.transaction_receipt(hash).await? {
3221 return Ok(receipt);
3222 }
3223 while let Some(notification) = stream.next().await {
3224 if let Some(new_block) = notification.as_new_block()
3225 && let Some(block) = self.backend.get_block_by_hash(new_block.hash)
3226 && block.body.transactions.iter().any(|tx| tx.hash() == hash)
3227 && let Some(receipt) = self.backend.transaction_receipt(hash).await?
3228 {
3229 return Ok(receipt);
3230 }
3231 }
3232
3233 Err(BlockchainError::Message("Failed to await transaction inclusion".to_string()))
3234 }
3235
3236 fn transaction_confirmation_timeout(timeout_ms: Option<u64>) -> Duration {
3237 const TIMEOUT_DURATION: Duration = Duration::from_secs(30);
3238 timeout_ms
3239 .filter(|timeout_ms| *timeout_ms > 0)
3240 .map(Duration::from_millis)
3241 .map(|timeout| timeout.min(TIMEOUT_DURATION))
3242 .unwrap_or(TIMEOUT_DURATION)
3243 }
3244
3245 async fn check_transaction_inclusion(
3247 &self,
3248 hash: TxHash,
3249 timeout_ms: Option<u64>,
3250 ) -> Result<FoundryTxReceipt> {
3251 let timeout_duration = Self::transaction_confirmation_timeout(timeout_ms);
3252 tokio::time::timeout(timeout_duration, self.await_transaction_inclusion(hash))
3253 .await
3254 .unwrap_or_else(|_elapsed| {
3255 Err(BlockchainError::TransactionConfirmationTimeout {
3256 hash,
3257 duration: timeout_duration,
3258 })
3259 })
3260 }
3261
3262 pub async fn send_transaction_sync(
3266 &self,
3267 request: WithOtherFields<TransactionRequest>,
3268 ) -> Result<FoundryTxReceipt> {
3269 node_info!("eth_sendTransactionSync");
3270 let hash = self.send_transaction(request).await?;
3271
3272 let receipt = self.check_transaction_inclusion(hash, None).await?;
3273
3274 Ok(receipt)
3275 }
3276
3277 pub async fn send_raw_transaction(&self, tx: Bytes) -> Result<TxHash> {
3281 node_info!("eth_sendRawTransaction");
3282 if tx.is_empty() {
3283 return Err(BlockchainError::EmptyRawTransactionData);
3284 }
3285
3286 let service_encoded = if self.backend.is_tempo() {
3290 normalize_fee_payer_service_encoding(tx.as_ref())
3291 } else {
3292 None
3293 };
3294 let raw = service_encoded.map(Bytes::from).unwrap_or(tx);
3295
3296 let transaction = if raw.first() == Some(&EIP4844_TX_TYPE_ID) {
3297 let raw = raw.clone();
3300 tokio::task::spawn_blocking(move || FoundryTxEnvelope::decode_2718(&mut raw.as_ref()))
3301 .await
3302 .map_err(|_| {
3303 BlockchainError::Internal("transaction decoding task panicked".into())
3304 })?
3305 } else {
3306 FoundryTxEnvelope::decode_2718(&mut raw.as_ref())
3307 }
3308 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3309
3310 self.ensure_typed_transaction_supported(&transaction)?;
3311
3312 let transaction = match transaction {
3313 FoundryTxEnvelope::Tempo(aa_tx)
3314 if self.backend.is_tempo()
3315 && aa_tx.tx().fee_payer_signature == Some(FEE_PAYER_SIGNATURE_MARKER) =>
3316 {
3317 FoundryTxEnvelope::Tempo(self.sponsor_sign_tempo_transaction(aa_tx).await?)
3318 }
3319 transaction => transaction,
3320 };
3321
3322 if self.backend.is_tempo() && TempoHardfork::from(self.backend.hardfork()).is_t5() {
3323 let classification = classify_payment_lane(raw.as_ref());
3324 trace!(target: "node", tx = ?transaction.hash(), ?classification, "classified transaction lane");
3325 }
3326
3327 #[cfg(feature = "base")]
3328 let is_eip8130 = transaction.is_eip8130();
3329 let pending_transaction = PendingTransaction::new(transaction).map_err(|error| {
3330 #[cfg(feature = "base")]
3331 if is_eip8130 {
3332 return BlockchainError::Eip8130TransactionRejected(error.to_string());
3333 }
3334 BlockchainError::RecoveryError(error)
3335 })?;
3336
3337 self.add_pending_transaction(pending_transaction).await
3338 }
3339
3340 pub async fn send_raw_transaction_conditional(
3344 &self,
3345 tx: Bytes,
3346 _condition: TransactionConditional,
3347 ) -> Result<TxHash> {
3348 node_info!("eth_sendRawTransactionConditional");
3349 self.send_raw_transaction(tx).await
3350 }
3351
3352 pub fn anvil_classify_transaction(&self, tx: Bytes) -> Result<PaymentLaneClassification> {
3354 node_info!("anvil_classifyTransaction");
3355 let mut data = tx.as_ref();
3356 if data.is_empty() {
3357 return Err(BlockchainError::EmptyRawTransactionData);
3358 }
3359
3360 FoundryTxEnvelope::decode_2718(&mut data)
3361 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3362
3363 Ok(self.classify_transaction_lane(tx.as_ref()))
3364 }
3365
3366 fn classify_transaction_lane(&self, raw: &[u8]) -> PaymentLaneClassification {
3367 if !self.backend.is_tempo() {
3368 return PaymentLaneClassification::general(PaymentLaneReason::NotTempo);
3369 }
3370
3371 if !TempoHardfork::from(self.backend.hardfork()).is_t5() {
3372 return PaymentLaneClassification::general(PaymentLaneReason::T5NotActive);
3373 }
3374
3375 classify_payment_lane(raw)
3376 }
3377
3378 pub async fn send_raw_transaction_sync(
3382 &self,
3383 tx: Bytes,
3384 timeout_ms: Option<u64>,
3385 ) -> Result<FoundryTxReceipt> {
3386 node_info!("eth_sendRawTransactionSync");
3387
3388 let hash = self.send_raw_transaction(tx).await?;
3389 let receipt = self.check_transaction_inclusion(hash, timeout_ms).await?;
3390
3391 Ok(receipt)
3392 }
3393
3394 pub async fn sign_raw_transaction(&self, tx: Bytes) -> Result<Bytes> {
3403 node_info!("eth_signRawTransaction");
3404 if !self.backend.is_tempo() {
3405 return Err(BlockchainError::RpcUnimplemented);
3406 }
3407
3408 if tx.is_empty() {
3409 return Err(BlockchainError::EmptyRawTransactionData);
3410 }
3411
3412 let service_encoded = normalize_fee_payer_service_encoding(tx.as_ref());
3415 let mut data = service_encoded.as_deref().unwrap_or(tx.as_ref());
3416
3417 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
3418 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3419
3420 let FoundryTxEnvelope::Tempo(aa_tx) = transaction else {
3421 return Err(RpcError::invalid_params(
3422 "only Tempo (0x76) transactions can be fee-payer signed",
3423 )
3424 .into());
3425 };
3426
3427 let signed = self.sponsor_sign_tempo_transaction(aa_tx).await?;
3428 Ok(FoundryTxEnvelope::Tempo(signed).encoded_2718().into())
3429 }
3430
3431 async fn sponsor_sign_tempo_transaction(&self, tx: AASigned) -> Result<AASigned> {
3437 match tx.tx().fee_payer_signature {
3441 Some(FEE_PAYER_SIGNATURE_MARKER) => {}
3442 Some(_) => {
3443 return Err(
3444 RpcError::invalid_params("transaction is already fee-payer signed").into()
3445 );
3446 }
3447 None => {
3448 return Err(RpcError::invalid_params(
3449 "transaction does not request sponsorship; sign it with the fee payer \
3450 signature placeholder",
3451 )
3452 .into());
3453 }
3454 }
3455
3456 let sender = tx.recover_signer().map_err(|_| {
3457 BlockchainError::RpcError(RpcError::invalid_params(
3458 "transaction must be signed by the sender before fee-payer signing",
3459 ))
3460 })?;
3461
3462 let Some(sponsor) = self.backend.tempo_fee_payer().await else {
3463 return Err(RpcError::invalid_params("no Tempo fee payer account available").into());
3464 };
3465 if sponsor == sender {
3466 return Err(RpcError::invalid_params(format!(
3467 "Tempo fee payer {sponsor} must not equal the transaction sender"
3468 ))
3469 .into());
3470 }
3471 let signer = self.get_signer(sponsor).ok_or(BlockchainError::NoSignerAvailable)?;
3472
3473 let (mut tx, sender_signature, _) = tx.into_parts();
3474 if tx.fee_token.is_none() {
3478 tx.fee_token = Some(self.backend.tempo_user_fee_token(sponsor).await?);
3479 }
3480 let digest = tx.fee_payer_signature_hash(sender);
3481 tx.fee_payer_signature = Some(signer.sign_hash(sponsor, digest).await?);
3482
3483 Ok(tx.into_signed(sender_signature))
3484 }
3485
3486 pub async fn call(
3490 &self,
3491 request: WithOtherFields<TransactionRequest>,
3492 block_number: Option<BlockId>,
3493 overrides: EvmOverrides,
3494 ) -> Result<Bytes> {
3495 node_info!("eth_call");
3496 let block_request = self.block_request(block_number).await?;
3497 if let BlockRequest::Number(number) = block_request
3499 && let Some(fork) = self.get_fork()
3500 && fork.predates_fork(number)
3501 {
3502 if overrides.has_state() || overrides.has_block() {
3503 return Err(BlockchainError::EvmOverrideError(
3504 "not available on past forked blocks".to_string(),
3505 ));
3506 }
3507 return Ok(fork.call_raw(&request, Some(number.into())).await?);
3508 }
3509
3510 #[cfg(feature = "base")]
3511 if self.backend.is_base()
3512 && serde_json::to_value(&request)
3513 .and_then(serde_json::from_value::<BaseTransactionRequest>)
3514 .is_ok_and(|request| request.as_eip8130().is_some())
3515 {
3516 let timestamp = self.backend.block_request_timestamp(&block_request).await?;
3517 self.backend.ensure_base_eip8130_active_at(timestamp)?;
3518 }
3519
3520 let fees = FeeDetails::new(
3521 request.gas_price,
3522 request.max_fee_per_gas,
3523 request.max_priority_fee_per_gas,
3524 request.max_fee_per_blob_gas,
3525 )?
3526 .or_zero_fees();
3527 self.on_blocking_task(|this| async move {
3530 let (exit, out, gas, _) =
3531 this.backend.call(request, fees, Some(block_request), overrides).await?;
3532 trace!(target : "node", "Call status {:?}, gas {}", exit, gas);
3533
3534 ensure_return_ok(exit, &out)
3535 })
3536 .await
3537 }
3538
3539 pub async fn call_many(
3540 &self,
3541 bundles: Vec<Bundle<WithOtherFields<TransactionRequest>>>,
3542 state_context: Option<StateContext>,
3543 state_override: Option<StateOverride>,
3544 ) -> Result<Vec<Vec<EthCallResponse>>> {
3545 node_info!("eth_callMany");
3546 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
3547 if transaction_index.is_some_and(|index| index.index().is_some()) {
3548 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3549 "transactionIndex is not supported for eth_callMany yet".to_string(),
3550 )));
3551 }
3552
3553 let block_request = self.block_request(block_number).await?;
3554 if let BlockRequest::Number(number) = block_request
3555 && let Some(fork) = self.get_fork()
3556 && fork.predates_fork(number)
3557 {
3558 return Ok(fork
3559 .call_many(
3560 bundles,
3561 Some(StateContext { transaction_index, block_number: Some(number.into()) }),
3562 state_override,
3563 )
3564 .await?);
3565 }
3566
3567 self.on_blocking_task(|this| async move {
3568 this.backend.call_many(bundles, Some(block_request), state_override).await
3569 })
3570 .await
3571 }
3572
3573 pub async fn call_bundle(&self, bundle: EthCallBundle) -> Result<EthCallBundleResponse> {
3577 node_info!("eth_callBundle");
3578 if bundle.txs.is_empty() {
3579 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3580 "bundle missing txs".to_string(),
3581 )));
3582 }
3583 if bundle.block_number == 0 {
3584 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3585 "bundle missing blockNumber".to_string(),
3586 )));
3587 }
3588
3589 let block_request = self.block_request(Some(bundle.state_block_number.into())).await?;
3590 if let BlockRequest::Number(number) = block_request
3591 && let Some(fork) = self.get_fork()
3592 && fork.predates_fork(number)
3593 {
3594 return Ok(fork.call_bundle(bundle).await?);
3595 }
3596
3597 let transactions = bundle
3598 .txs
3599 .iter()
3600 .map(|raw| {
3601 let mut data = raw.as_ref();
3602 if data.is_empty() {
3603 return Err(BlockchainError::EmptyRawTransactionData);
3604 }
3605 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
3606 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3607 self.ensure_typed_transaction_supported(&transaction)?;
3608 PendingTransaction::new(transaction).map_err(Into::into)
3609 })
3610 .collect::<Result<Vec<_>>>()?;
3611
3612 self.on_blocking_task(|this| async move {
3613 this.backend.call_bundle(bundle, transactions, Some(block_request)).await
3614 })
3615 .await
3616 }
3617
3618 pub async fn simulate_v1(
3619 &self,
3620 request: SimulatePayload,
3621 block_number: Option<BlockId>,
3622 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
3623 self.simulate_v1_raw(preserve_simulation_request_fields(request), block_number).await
3624 }
3625
3626 pub(crate) async fn simulate_v1_raw(
3627 &self,
3628 mut request: SimulatePayload<WithOtherFields<TransactionRequest>>,
3629 block_number: Option<BlockId>,
3630 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
3631 const DEFAULT_BLOCK_INTERVAL_SECS: u64 = 12;
3632
3633 node_info!("eth_simulateV1");
3634 if request.block_state_calls.is_empty() {
3635 return Err(BlockchainError::RpcError(RpcError::invalid_params("empty input")));
3636 }
3637 if request.block_state_calls.len() > MAX_SIMULATE_BLOCKS as usize {
3638 return Err(BlockchainError::RpcError(RpcError {
3639 code: ErrorCode::ServerError(-38026),
3640 message: "too many blocks".into(),
3641 data: None,
3642 }));
3643 }
3644 let block_id = block_number;
3645 let block_request =
3646 self.block_request(block_number).await.map_err(|error| match error {
3647 BlockchainError::BlockOutOfRange(_, _) | BlockchainError::BlockNotFound => {
3648 BlockchainError::RpcError(RpcError {
3649 code: ErrorCode::ServerError(-32000),
3650 message: "header not found".into(),
3651 data: None,
3652 })
3653 }
3654 error => error,
3655 })?;
3656 let block_interval = self.backend.time().block_timestamp_interval().unwrap_or_else(|| {
3657 self.miner
3658 .block_interval()
3659 .map(|duration| {
3660 duration
3661 .as_secs()
3662 .saturating_add(u64::from(duration.subsec_nanos() != 0))
3663 .max(1)
3664 })
3665 .unwrap_or(DEFAULT_BLOCK_INTERVAL_SECS)
3666 });
3667
3668 if let BlockRequest::Number(number) = block_request
3670 && let Some(fork) = self.get_fork()
3671 && fork.predates_fork(number)
3672 {
3673 let block_id = match block_id {
3674 Some(BlockId::Hash(hash)) => BlockId::Hash(hash),
3675 _ => number.into(),
3676 };
3677 let base_block = fork.fetch_block(block_id).await?.ok_or_else(|| {
3678 BlockchainError::RpcError(RpcError {
3679 code: ErrorCode::ServerError(-32000),
3680 message: "header not found".into(),
3681 data: None,
3682 })
3683 })?;
3684 request.block_state_calls = sanitize_simulation_blocks(
3685 request.block_state_calls,
3686 base_block.header.number(),
3687 base_block.header.timestamp(),
3688 block_interval,
3689 )?;
3690 return Ok(fork.simulate_v1(&request, Some(base_block.header.hash.into())).await?);
3691 }
3692
3693 self.on_blocking_task(|this| async move {
3696 let simulated_blocks =
3697 this.backend.simulate_raw(request, Some(block_request), block_interval).await?;
3698 trace!(target : "node", "Simulate status {:?}", simulated_blocks);
3699
3700 Ok(simulated_blocks)
3701 })
3702 .await
3703 }
3704
3705 pub async fn create_access_list(
3719 &self,
3720 request: WithOtherFields<TransactionRequest>,
3721 block_number: Option<BlockId>,
3722 state_override: Option<StateOverride>,
3723 ) -> Result<AccessListResult> {
3724 node_info!("eth_createAccessList");
3725 let block_request = self.block_request(block_number).await?;
3726 if let BlockRequest::Number(number) = block_request
3728 && let Some(fork) = self.get_fork()
3729 && fork.predates_fork(number)
3730 {
3731 if state_override.is_some() {
3732 return Err(BlockchainError::EvmOverrideError(
3733 "not available on past forked blocks".to_string(),
3734 ));
3735 }
3736 return Ok(fork.create_access_list_raw(&request, Some(number.into())).await?);
3737 }
3738 let typed_request = self.parse_transaction_request(request.clone())?;
3739
3740 #[cfg(feature = "base")]
3741 if self.backend.is_base()
3742 && serde_json::to_value(&request)
3743 .and_then(serde_json::from_value::<BaseTransactionRequest>)
3744 .is_ok_and(|request| request.as_eip8130().is_some())
3745 {
3746 let timestamp = self.backend.block_request_timestamp(&block_request).await?;
3747 self.backend.ensure_base_eip8130_active_at(timestamp)?;
3748 return Err(BlockchainError::InvalidTransactionRequest(
3749 "eth_createAccessList does not support EIP-8130 transaction requests".to_string(),
3750 ));
3751 }
3752
3753 self.backend
3754 .with_database_at_and_context(Some(block_request), |state, block_env, monad_context| {
3755 let mut cache_db = CacheDB::new(&*state);
3756 if let Some(state_override) = state_override {
3757 apply_state_overrides(state_override.into_iter().collect(), &mut cache_db)?;
3758 }
3759
3760 let (_, _, _, access_list) =
3761 self.backend.build_access_list_with_state_and_context(
3762 &cache_db,
3763 request.clone(),
3764 FeeDetails::zero(),
3765 block_env.clone(),
3766 monad_context.clone(),
3767 )?;
3768
3769 let (exit, _, gas_used, _) = self.backend.call_with_state_typed_access_list(
3774 &cache_db,
3775 typed_request,
3776 FeeDetails::zero(),
3777 block_env,
3778 access_list.clone(),
3779 monad_context,
3780 )?;
3781
3782 Ok(AccessListResult {
3783 access_list,
3784 gas_used: U256::from(gas_used),
3785 error: execution_error(exit),
3786 })
3787 })
3788 .await
3789 }
3790
3791 pub async fn estimate_gas(
3796 &self,
3797 request: WithOtherFields<TransactionRequest>,
3798 block_number: Option<BlockId>,
3799 overrides: EvmOverrides,
3800 ) -> Result<U256> {
3801 node_info!("eth_estimateGas");
3802 self.do_estimate_gas(request, block_number.or_else(|| Some(BlockId::pending())), overrides)
3803 .await
3804 .map(U256::from)
3805 }
3806
3807 pub async fn fill_transaction(
3814 &self,
3815 request: WithOtherFields<TransactionRequest>,
3816 ) -> Result<FillTransaction<AnyRpcTransaction>> {
3817 node_info!("eth_fillTransaction");
3818 let mut request = self.parse_transaction_request(request)?;
3819
3820 let from = match request.from() {
3821 Some(from) => from,
3822 None => self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)?,
3823 };
3824
3825 let nonce = self.request_nonce_for_transaction(&request, from).await?;
3826
3827 if request.gas_limit().is_none() {
3829 let estimated_gas =
3830 self.do_estimate_gas_typed(request.clone(), Some(BlockId::pending())).await?;
3831 request.set_gas_limit(estimated_gas as u64);
3832 }
3833
3834 let typed_tx = self.build_tx_request(request, nonce).await?;
3835 let tx = typed_tx.into_impersonated();
3836
3837 let raw = tx.encoded_2718().into();
3838
3839 let mut tx =
3840 transaction_build(None, MaybeImpersonatedTransaction::new(tx), None, None, None);
3841
3842 tx.0.inner.inner = Recovered::new_unchecked(tx.0.inner.inner.into_inner(), from);
3845
3846 Ok(FillTransaction { raw, tx })
3847 }
3848
3849 pub fn anvil_get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<Blob>>> {
3851 node_info!("anvil_getBlobsByTransactionHash");
3852 Ok(self.backend.get_blob_by_tx_hash(hash)?)
3853 }
3854
3855 pub async fn transaction_by_hash(&self, hash: B256) -> Result<Option<AnyRpcTransaction>> {
3862 node_info!("eth_getTransactionByHash");
3863 let mut tx =
3864 self.pool.get_transaction(hash).map(|pending| self.build_pool_transaction(pending));
3865 if tx.is_none() {
3866 tx = self.backend.transaction_by_hash(hash).await?
3867 }
3868
3869 Ok(tx)
3870 }
3871
3872 fn build_pool_transaction(
3873 &self,
3874 pending: PendingTransaction<FoundryTxEnvelope>,
3875 ) -> AnyRpcTransaction {
3876 let from = *pending.sender();
3877 let tx = transaction_build(
3878 Some(*pending.hash()),
3879 pending.transaction,
3880 None,
3881 None,
3882 Some(self.backend.base_fee()),
3883 );
3884
3885 let WithOtherFields { inner: mut tx, other } = tx.0;
3886 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3889
3890 AnyRpcTransaction(WithOtherFields { inner: tx, other })
3891 }
3892
3893 pub async fn pending_transactions(&self) -> Result<Vec<AnyRpcTransaction>> {
3897 node_info!("eth_pendingTransactions");
3898 Ok(self
3899 .pool
3900 .ready_transactions()
3901 .map(|pending| self.build_pool_transaction(pending.pending_transaction.clone()))
3902 .collect())
3903 }
3904
3905 pub async fn transaction_by_sender_and_nonce(
3912 &self,
3913 sender: Address,
3914 nonce: U256,
3915 ) -> Result<Option<AnyRpcTransaction>> {
3916 node_info!("eth_getTransactionBySenderAndNonce");
3917
3918 for pending_tx in self.pool.ready_transactions().chain(self.pool.pending_transactions()) {
3920 if U256::from(pending_tx.pending_transaction.nonce()) == nonce
3921 && *pending_tx.pending_transaction.sender() == sender
3922 {
3923 let tx = transaction_build(
3924 Some(*pending_tx.pending_transaction.hash()),
3925 pending_tx.pending_transaction.transaction.clone(),
3926 None,
3927 None,
3928 Some(self.backend.base_fee()),
3929 );
3930
3931 let WithOtherFields { inner: mut tx, other } = tx.0;
3932 let from = *pending_tx.pending_transaction.sender();
3935 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3936
3937 return Ok(Some(AnyRpcTransaction(WithOtherFields { inner: tx, other })));
3938 }
3939 }
3940
3941 let highest_nonce = self.transaction_count(sender, None).await?.saturating_to::<u64>();
3942 let target_nonce = nonce.saturating_to::<u64>();
3943
3944 if target_nonce >= highest_nonce {
3946 return Ok(None);
3947 }
3948
3949 let latest_block = self.backend.best_number();
3951 let first_block = if self.get_fork().is_some() { 0 } else { self.backend.genesis_number() };
3952 if latest_block <= first_block {
3953 return Ok(None);
3954 }
3955
3956 let mut low = first_block + 1;
3958 let mut high = latest_block;
3959
3960 while low <= high {
3961 let mid = low + (high - low) / 2;
3962 let mid_nonce =
3963 self.transaction_count(sender, Some(mid.into())).await?.saturating_to::<u64>();
3964
3965 if mid_nonce > target_nonce {
3966 high = mid - 1;
3967 } else {
3968 low = mid + 1;
3969 }
3970 }
3971
3972 let target_block = low;
3974 if target_block <= latest_block
3975 && let Some(txs) =
3976 self.backend.mined_transactions_by_block_number(target_block.into()).await
3977 {
3978 for tx in txs {
3979 if tx.from() == sender && tx.nonce() == target_nonce {
3980 return Ok(Some(tx));
3981 }
3982 }
3983 }
3984
3985 Ok(None)
3986 }
3987
3988 pub async fn transaction_receipt(&self, hash: B256) -> Result<Option<FoundryTxReceipt>> {
3992 node_info!("eth_getTransactionReceipt");
3993 self.backend.transaction_receipt(hash).await
3994 }
3995
3996 pub async fn block_receipts(&self, number: BlockId) -> Result<Option<Vec<FoundryTxReceipt>>> {
4000 node_info!("eth_getBlockReceipts");
4001 if number == BlockId::pending() {
4002 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
4003 return Ok(Some(self.backend.pending_block_receipts(transactions).await?));
4004 }
4005
4006 self.backend.block_receipts(number).await
4007 }
4008
4009 pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>> {
4013 node_info!("eth_getLogs");
4014 let best = self.backend.best_number();
4015 let to_block =
4016 self.backend.convert_block_number_at(filter.block_option.get_to_block().copied(), best);
4017 if to_block > best {
4018 return Err(BlockchainError::BlockOutOfRange(best, to_block));
4019 }
4020 self.backend.logs(filter).await
4021 }
4022
4023 pub async fn new_filter(&self, filter: Filter) -> Result<String> {
4027 node_info!("eth_newFilter");
4028 let historic = match filter.block_option.get_from_block() {
4030 Some(BlockNumber::Number(from))
4031 if *from > self.backend.best_number()
4032 && filter.block_option.get_to_block().is_none_or(|to| {
4033 to.is_latest() || to.as_number().is_some_and(|to| to >= *from)
4034 }) =>
4035 {
4036 vec![]
4037 }
4038 Some(_) => self.backend.logs(filter.clone()).await?,
4039 None => vec![],
4040 };
4041 let filter = EthFilter::Logs(Box::new(LogsFilter {
4042 blocks: self.new_block_notifications(),
4043 storage: self.storage_info(),
4044 filter: FilteredParams::new(Some(filter)),
4045 historic: Some(historic),
4046 }));
4047 Ok(self.filters.add_filter(filter).await)
4048 }
4049
4050 pub async fn new_block_filter(&self) -> Result<String> {
4054 node_info!("eth_newBlockFilter");
4055 let filter = EthFilter::Blocks(self.new_block_notifications());
4056 Ok(self.filters.add_filter(filter).await)
4057 }
4058
4059 pub async fn new_pending_transaction_filter(&self, full: bool) -> Result<String> {
4063 node_info!("eth_newPendingTransactionFilter");
4064 let filter = if full {
4065 EthFilter::FullPendingTransactions(self.full_pending_transactions_filter())
4066 } else {
4067 EthFilter::PendingTransactions(self.new_ready_transactions())
4068 };
4069 Ok(self.filters.add_filter(filter).await)
4070 }
4071
4072 pub async fn get_filter_changes(&self, id: &str) -> ResponseResult {
4076 node_info!("eth_getFilterChanges");
4077 self.filters.get_filter_changes(id).await
4078 }
4079
4080 pub async fn get_filter_logs(&self, id: &str) -> Result<Vec<Log>> {
4084 node_info!("eth_getFilterLogs");
4085 if let Some(filter) = self.filters.get_log_filter(id).await {
4086 self.backend.logs(filter).await
4087 } else {
4088 Err(BlockchainError::FilterNotFound)
4089 }
4090 }
4091
4092 pub async fn uninstall_filter(&self, id: &str) -> Result<bool> {
4094 node_info!("eth_uninstallFilter");
4095 Ok(self.filters.uninstall_filter(id).await.is_some())
4096 }
4097
4098 pub async fn raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
4102 node_info!("debug_getRawTransaction");
4103 self.inner_raw_transaction(hash).await
4104 }
4105
4106 pub async fn raw_receipts(&self, block: BlockId) -> Result<Vec<Bytes>> {
4110 node_info!("debug_getRawReceipts");
4111
4112 if let BlockRequest::Number(number) = self.block_request(Some(block)).await?
4114 && let Some(fork) = self.get_fork()
4115 && fork.predates_fork_inclusive(number)
4116 {
4117 let receipts = fork.block_receipts(number).await?.unwrap_or_default();
4118 return Ok(receipts
4119 .into_iter()
4120 .map(|receipt| {
4121 receipt.0.inner.inner.map_logs(|log| log.inner).encoded_2718().into()
4122 })
4123 .collect());
4124 }
4125
4126 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4127 let receipts = self
4128 .backend
4129 .mined_receipts(block.header.hash_slow())
4130 .ok_or(BlockchainError::BlockNotFound)?;
4131 Ok(receipts.into_iter().map(|receipt| receipt.encoded_2718().into()).collect())
4132 }
4133
4134 pub async fn raw_transactions(&self, block: BlockId) -> Result<Vec<Bytes>> {
4138 node_info!("debug_getRawTransactions");
4139
4140 if let Some(block) = self.backend.get_block(block) {
4141 return Ok(block
4142 .body
4143 .transactions
4144 .into_iter()
4145 .map(|tx| tx.into_inner().into_canonical().encoded_2718().into())
4146 .collect());
4147 }
4148
4149 let Some(fork) = self.get_fork() else {
4152 return Ok(Vec::new());
4153 };
4154 let block = match block {
4155 BlockId::Number(BlockNumber::Pending) => None,
4156 BlockId::Number(number) => {
4157 let number = self.backend.convert_block_number(Some(number));
4158 if !fork.predates_fork_inclusive(number) {
4159 return Ok(Vec::new());
4160 }
4161 fork.block_by_number_full(number).await?
4162 }
4163 BlockId::Hash(hash) => fork
4164 .block_by_hash_full(hash.block_hash)
4165 .await?
4166 .filter(|block| fork.predates_fork_inclusive(block.header().number())),
4167 };
4168 let Some(block) = block else {
4169 return Ok(Vec::new());
4170 };
4171 let BlockTransactions::Full(txs) = block.transactions() else {
4172 return Err(BlockchainError::Internal(
4173 "fork provider returned a non-full block for a full block request".to_string(),
4174 ));
4175 };
4176 txs.iter().map(encode_rpc_transaction).collect()
4177 }
4178
4179 pub async fn raw_header(&self, block: BlockId) -> Result<Bytes> {
4183 node_info!("debug_getRawHeader");
4184 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4185 Ok(alloy_rlp::encode(&block.header).into())
4186 }
4187
4188 pub async fn raw_block(&self, block: BlockId) -> Result<Bytes> {
4192 node_info!("debug_getRawBlock");
4193 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4194 Ok(alloy_rlp::encode(canonical_block(block)).into())
4195 }
4196
4197 pub async fn raw_transaction_by_block_hash_and_index(
4201 &self,
4202 block_hash: B256,
4203 index: Index,
4204 ) -> Result<Option<Bytes>> {
4205 node_info!("eth_getRawTransactionByBlockHashAndIndex");
4206 match self.backend.transaction_by_block_hash_and_index(block_hash, index).await? {
4207 Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
4208 None => Ok(None),
4209 }
4210 }
4211
4212 pub async fn raw_transaction_by_block_number_and_index(
4216 &self,
4217 block_number: BlockNumber,
4218 index: Index,
4219 ) -> Result<Option<Bytes>> {
4220 node_info!("eth_getRawTransactionByBlockNumberAndIndex");
4221 match self.transaction_by_block_number_and_index(block_number, index).await? {
4222 Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
4223 None => Ok(None),
4224 }
4225 }
4226
4227 pub async fn debug_trace_transaction(
4231 &self,
4232 tx_hash: B256,
4233 opts: GethDebugTracingOptions,
4234 ) -> Result<GethTrace> {
4235 node_info!("debug_traceTransaction");
4236 self.backend.debug_trace_transaction(tx_hash, opts).await
4237 }
4238
4239 pub async fn debug_trace_block(
4243 &self,
4244 rlp_block: Bytes,
4245 opts: GethDebugTracingOptions,
4246 ) -> Result<Vec<TraceResult>> {
4247 node_info!("debug_traceBlock");
4248 self.backend.debug_trace_block(rlp_block, opts).await
4249 }
4250
4251 pub async fn debug_trace_block_by_hash(
4255 &self,
4256 block_hash: B256,
4257 opts: GethDebugTracingOptions,
4258 ) -> Result<Vec<TraceResult>> {
4259 node_info!("debug_traceBlockByHash");
4260 self.backend.debug_trace_block_by_hash(block_hash, opts).await
4261 }
4262
4263 pub async fn debug_trace_block_by_number(
4267 &self,
4268 block_number: BlockNumber,
4269 opts: GethDebugTracingOptions,
4270 ) -> Result<Vec<TraceResult>> {
4271 node_info!("debug_traceBlockByNumber");
4272 self.backend.debug_trace_block_by_number(block_number, opts).await
4273 }
4274
4275 pub async fn debug_trace_call(
4279 &self,
4280 request: WithOtherFields<TransactionRequest>,
4281 block_number: Option<BlockId>,
4282 opts: GethDebugTracingCallOptions,
4283 ) -> Result<GethTrace> {
4284 node_info!("debug_traceCall");
4285 let block_request = self.block_request(block_number).await?;
4286 let fees = FeeDetails::new(
4287 request.gas_price,
4288 request.max_fee_per_gas,
4289 request.max_priority_fee_per_gas,
4290 request.max_fee_per_blob_gas,
4291 )?
4292 .or_zero_fees();
4293
4294 let result: std::result::Result<GethTrace, BlockchainError> =
4295 self.backend.call_with_tracing(request, fees, Some(block_request), opts).await;
4296 result
4297 }
4298
4299 pub async fn trace_call_many(
4303 &self,
4304 calls: Vec<(WithOtherFields<TransactionRequest>, HashSet<TraceType>)>,
4305 block_number: Option<BlockId>,
4306 ) -> Result<Vec<TraceResults>> {
4307 node_info!("trace_callMany");
4308 let block_request = self.trace_block_request(block_number.unwrap_or_default()).await?;
4309
4310 self.backend.trace_call_many(calls, Some(block_request)).await
4311 }
4312}
4313
4314impl EthApi<FoundryNetwork> {
4317 pub async fn anvil_mine(&self, num_blocks: Option<U256>, interval: Option<U256>) -> Result<()> {
4321 node_info!("anvil_mine");
4322 let interval = interval.map(|i| i.saturating_to::<u64>());
4323 let pin_timestamp = interval == Some(0);
4324 let blocks = num_blocks.unwrap_or(U256::ONE);
4325 if blocks.is_zero() {
4326 return Ok(());
4327 }
4328
4329 self.on_blocking_task(|this| async move {
4330 for _ in 0..blocks.saturating_to::<u64>() {
4332 let pending_increase =
4334 interval.map(|interval| this.backend.time().apply_time_increase(interval));
4335 if let Err(error) = this.mine_one_with_timestamp_pinning(pin_timestamp).await {
4336 if let Some(pending) = pending_increase {
4337 this.backend.time().revert_time_increase(pending);
4338 }
4339 return Err(error);
4340 }
4341 }
4342 Ok(())
4343 })
4344 .await?;
4345
4346 Ok(())
4347 }
4348
4349 async fn find_erc20_storage_slot(
4366 &self,
4367 token_address: Address,
4368 calldata: Bytes,
4369 expected_value: U256,
4370 ) -> Result<B256> {
4371 let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone());
4372
4373 let access_list_result =
4375 self.create_access_list(WithOtherFields::new(tx.clone()), None, None).await?;
4376 let access_list = access_list_result.access_list;
4377
4378 for item in access_list.0 {
4381 if item.address != token_address {
4382 continue;
4383 };
4384 for slot in &item.storage_keys {
4385 let account_override = AccountOverride::default()
4386 .with_state_diff(std::iter::once((*slot, B256::from(expected_value))));
4387
4388 let state_override = StateOverridesBuilder::default()
4389 .append(token_address, account_override)
4390 .build();
4391
4392 let evm_override = EvmOverrides::state(Some(state_override));
4393
4394 let Ok(result) =
4395 self.call(WithOtherFields::new(tx.clone()), None, evm_override).await
4396 else {
4397 continue;
4399 };
4400
4401 let Ok(result_value) = U256::abi_decode(&result) else {
4402 continue;
4404 };
4405
4406 if result_value == expected_value {
4407 return Ok(*slot);
4408 }
4409 }
4410 }
4411
4412 Err(BlockchainError::Message("Unable to find storage slot".to_string()))
4413 }
4414
4415 pub async fn anvil_deal_erc20(
4419 &self,
4420 address: Address,
4421 token_address: Address,
4422 balance: U256,
4423 ) -> Result<()> {
4424 node_info!("anvil_dealERC20");
4425
4426 if self.backend.is_tempo()
4427 && self.backend.try_set_tip20_balance(address, token_address, balance).await?
4428 {
4429 return Ok(());
4430 }
4431
4432 sol! {
4433 #[sol(rpc)]
4434 contract IERC20 {
4435 function balanceOf(address target) external view returns (uint256);
4436 }
4437 }
4438
4439 let calldata = IERC20::balanceOfCall { target: address }.abi_encode().into();
4440
4441 let slot =
4443 self.find_erc20_storage_slot(token_address, calldata, balance).await.map_err(|_| {
4444 BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string())
4445 })?;
4446
4447 self.anvil_set_storage_at(token_address, slot.into(), balance.into()).await?;
4449
4450 Ok(())
4451 }
4452
4453 pub async fn anvil_deal_tip20(
4457 &self,
4458 address: Address,
4459 token_address: Address,
4460 balance: U256,
4461 ) -> Result<()> {
4462 node_info!("anvil_dealTIP20");
4463 self.ensure_tempo_mode()?;
4464 self.backend.set_tip20_balance(address, token_address, balance).await?;
4465 Ok(())
4466 }
4467
4468 pub async fn anvil_set_erc20_allowance(
4472 &self,
4473 owner: Address,
4474 spender: Address,
4475 token_address: Address,
4476 amount: U256,
4477 ) -> Result<()> {
4478 node_info!("anvil_setERC20Allowance");
4479
4480 sol! {
4481 #[sol(rpc)]
4482 contract IERC20 {
4483 function allowance(address owner, address spender) external view returns (uint256);
4484 }
4485 }
4486
4487 let calldata = IERC20::allowanceCall { owner, spender }.abi_encode().into();
4488
4489 let slot =
4491 self.find_erc20_storage_slot(token_address, calldata, amount).await.map_err(|_| {
4492 BlockchainError::Message("Unable to set ERC20 allowance, no slot found".to_string())
4493 })?;
4494
4495 self.anvil_set_storage_at(token_address, slot.into(), amount.into()).await?;
4497
4498 Ok(())
4499 }
4500
4501 #[cfg(feature = "monad")]
4504 fn monad_protocol_reorg_transaction(
4505 &self,
4506 transaction: FoundryTxEnvelope,
4507 ) -> Option<PendingTransaction<FoundryTxEnvelope>> {
4508 if !self.backend.is_monad() {
4509 return None;
4510 }
4511
4512 let pending = PendingTransaction::with_sender(
4513 MaybeImpersonatedTransaction::new(transaction),
4514 monad_revm::staking::constants::SYSTEM_ADDRESS,
4515 );
4516 let tx_env: revm::context::TxEnv = crate::eth::backend::executor::build_tx_env_for_pending(
4517 &pending,
4518 self.backend.cheats(),
4519 );
4520 foundry_evm::core::evm::protocol_system_call(&tx_env)
4521 .is_ok_and(|call| call.is_some())
4522 .then_some(pending)
4523 }
4524
4525 pub async fn anvil_reorg(&self, options: ReorgOptions) -> Result<()> {
4539 node_info!("anvil_reorg");
4540 let _lifecycle = self.lifecycle_lock.write().await;
4541 let mining_guard = self.backend.lock_mining().await;
4542 let depth = options.depth;
4543 let mut tx_block_pairs = options.tx_block_pairs;
4544
4545 if let Some((_, num)) = tx_block_pairs.iter().find(|(_, num)| *num >= depth) {
4546 let Some(last_block) = depth.checked_sub(1) else {
4548 return Err(BlockchainError::RpcError(RpcError::invalid_params(
4549 "Reorg depth must be at least 1 to include transactions",
4550 )));
4551 };
4552 return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
4553 "Block number for reorg tx will exceed the reorged chain height. Block number {num} must not exceed (depth-1) {last_block}"
4554 ))));
4555 }
4556 tx_block_pairs.sort_by_key(|a| a.1);
4557
4558 let current_height = self.backend.best_number();
4560 let genesis = if self.get_fork().is_some() { 0 } else { self.backend.genesis_number() };
4561 let common_height = current_height.checked_sub(depth).filter(|h| *h >= genesis).ok_or(
4562 BlockchainError::RpcError(RpcError::invalid_params(format!(
4563 "Reorg depth must not exceed current chain height: current height {current_height}, depth {depth}, genesis {genesis}"
4564 ))),
4565 )?;
4566
4567 let common_block =
4569 self.rollback_block(common_height).await?.ok_or(BlockchainError::BlockNotFound)?;
4570
4571 #[cfg(feature = "monad")]
4572 let fee_defaults = if self.backend.is_monad() {
4573 self.backend
4574 .monad_rollback_fee_defaults(&common_block, self.lowest_suggestion_tip())
4575 .await
4576 .map(|(gas_price, blob_gas_price)| TransactionFeeDefaults {
4577 gas_price,
4578 blob_gas_price,
4579 })
4580 } else {
4581 None
4582 };
4583 #[cfg(not(feature = "monad"))]
4584 let fee_defaults = None;
4585 let fee_defaults = fee_defaults.or_else(|| {
4588 let (base_fee, blob_fees) = self.backend.next_block_fees_after(&common_block.header);
4589 Some(TransactionFeeDefaults {
4590 gas_price: self.gas_price_for_base_fee(base_fee),
4591 blob_gas_price: self
4592 .backend
4593 .fees()
4594 .blob_params()
4595 .calc_blob_fee(blob_fees.excess_blob_gas),
4596 })
4597 });
4598
4599 let block_pool_txs = if tx_block_pairs.is_empty() {
4602 HashMap::default()
4603 } else {
4604 let mut nonces: HashMap<Address, u64> = HashMap::default();
4607
4608 let mut txs: HashMap<u64, Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>> =
4609 HashMap::default();
4610 for pair in tx_block_pairs {
4611 let (tx_data, block_index) = pair;
4612
4613 let pending = match tx_data {
4614 TransactionData::Raw(bytes) => {
4615 let mut data = bytes.as_ref();
4616 let decoded = FoundryTxEnvelope::decode_2718(&mut data)
4617 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
4618 if matches!(&decoded, FoundryTxEnvelope::Celo(_)) {
4619 self.ensure_typed_transaction_supported(&decoded)?;
4620 }
4621 let protocol_pending = {
4622 #[cfg(feature = "monad")]
4623 {
4624 self.monad_protocol_reorg_transaction(decoded.clone())
4625 }
4626 #[cfg(not(feature = "monad"))]
4627 {
4628 None
4629 }
4630 };
4631 if let Some(pending) = protocol_pending {
4632 pending
4633 } else {
4634 PendingTransaction::new(decoded)?
4635 }
4636 }
4637
4638 TransactionData::JSON(request) => {
4639 let request = if request.transaction_type
4640 == Some(foundry_primitives::CIP64_TX_TYPE)
4641 || request
4642 .other
4643 .get("feeCurrency")
4644 .is_some_and(|value| !value.is_null())
4645 {
4646 self.parse_transaction_request(request)?
4647 } else {
4648 request.inner.into()
4649 };
4650 let from = request.from().map(Ok).unwrap_or_else(|| {
4651 self.accounts()?
4652 .first()
4653 .copied()
4654 .ok_or(BlockchainError::NoSignerAvailable)
4655 })?;
4656
4657 let curr_nonce = nonces.entry(from).or_insert(
4659 self.get_transaction_count(
4660 from,
4661 Some(common_block.header.number().into()),
4662 )
4663 .await?,
4664 );
4665
4666 let typed_tx = self
4668 .build_tx_request_with_fee_defaults(request, *curr_nonce, fee_defaults)
4669 .await?;
4670
4671 *curr_nonce += 1;
4673
4674 let protocol_pending = {
4675 #[cfg(feature = "monad")]
4676 {
4677 if from == monad_revm::staking::constants::SYSTEM_ADDRESS {
4678 self.monad_protocol_reorg_transaction(
4679 typed_tx.clone().into_impersonated(),
4680 )
4681 } else {
4682 None
4683 }
4684 }
4685 #[cfg(not(feature = "monad"))]
4686 {
4687 None
4688 }
4689 };
4690 if let Some(pending) = protocol_pending {
4691 pending
4692 } else if self.is_impersonated(from) {
4693 let transaction = typed_tx.into_impersonated();
4694 self.ensure_typed_transaction_supported(&transaction)?;
4695 PendingTransaction::with_impersonated(transaction, from)
4696 } else {
4697 let transaction = self.sign_request(&from, typed_tx)?;
4698 self.ensure_typed_transaction_supported(&transaction)?;
4699 PendingTransaction::new(transaction)?
4700 }
4701 }
4702 };
4703
4704 let pooled = PoolTransaction::new(pending).with_replay();
4705 txs.entry(block_index).or_default().push(Arc::new(pooled));
4706 }
4707
4708 txs
4709 };
4710
4711 self.rollback_backend(common_block, &mining_guard).await?;
4712 self.backend.reorg(depth, block_pool_txs, &mining_guard).await?;
4713 Ok(())
4714 }
4715
4716 pub async fn evm_mine(&self, opts: Option<MineOptions>) -> Result<String> {
4723 node_info!("evm_mine");
4724
4725 self.do_evm_mine(opts).await?;
4726
4727 Ok("0x0".to_string())
4728 }
4729
4730 pub async fn evm_mine_detailed(&self, opts: Option<MineOptions>) -> Result<Vec<AnyRpcBlock>> {
4740 node_info!("evm_mine_detailed");
4741
4742 let mined_blocks = self.do_evm_mine(opts).await?;
4743
4744 let mut blocks = Vec::with_capacity(mined_blocks as usize);
4745
4746 let latest = self.backend.best_number();
4747 for offset in (0..mined_blocks).rev() {
4748 let block_num = latest - offset;
4749 if let Some(mut block) =
4750 self.backend.block_by_number_full(BlockNumber::Number(block_num)).await?
4751 {
4752 let block_txs = match block.transactions_mut() {
4753 BlockTransactions::Full(txs) => txs,
4754 BlockTransactions::Hashes(_) | BlockTransactions::Uncle => unreachable!(),
4755 };
4756 for tx in block_txs.iter_mut() {
4757 if let Some(receipt) = self.backend.mined_transaction_receipt(tx.tx_hash())
4758 && let Some(output) = receipt.out
4759 {
4760 if !receipt.inner.as_ref().status()
4762 && let Some(reason) = RevertDecoder::new().maybe_decode(&output, None)
4763 {
4764 tx.other.insert(
4765 "revertReason".to_string(),
4766 serde_json::to_value(reason).expect("Infallible"),
4767 );
4768 }
4769 tx.other.insert(
4770 "output".to_string(),
4771 serde_json::to_value(output).expect("Infallible"),
4772 );
4773 }
4774 }
4775 block.transactions = BlockTransactions::Full(block_txs.clone());
4776 blocks.push(block);
4777 }
4778 }
4779
4780 Ok(blocks)
4781 }
4782
4783 pub async fn eth_send_unsigned_transaction(
4787 &self,
4788 request: WithOtherFields<TransactionRequest>,
4789 ) -> Result<TxHash> {
4790 node_info!("eth_sendUnsignedTransaction");
4791 let request = self.parse_transaction_request(request)?;
4792 let from = request.from().ok_or(BlockchainError::NoSignerAvailable)?;
4794
4795 let nonce = self.request_nonce_for_transaction(&request, from).await?;
4796
4797 let typed_tx = self.build_tx_request(request, nonce).await?;
4798
4799 let transaction = typed_tx.into_impersonated();
4800
4801 self.ensure_typed_transaction_supported(&transaction)?;
4802
4803 let pending_transaction = PendingTransaction::with_impersonated(transaction, from);
4804
4805 self.add_pending_transaction(pending_transaction).await
4806 }
4807
4808 pub async fn txpool_inspect(&self) -> Result<TxpoolInspect> {
4815 node_info!("txpool_inspect");
4816 let mut inspect = TxpoolInspect::default();
4817
4818 fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> TxpoolInspectSummary {
4819 let tx = &tx.pending_transaction.transaction;
4820 let to = tx.to();
4821 let gas_price = tx.max_fee_per_gas();
4822 let value = tx.value();
4823 let gas = tx.gas_limit();
4824 TxpoolInspectSummary { to, value, gas, gas_price }
4825 }
4826
4827 for pending in self.pool.ready_transactions() {
4834 let entry = inspect.pending.entry(*pending.pending_transaction.sender()).or_default();
4835 let key = txpool_transaction_key(&pending.pending_transaction);
4836 entry.insert(key, convert(pending));
4837 }
4838 for queued in self.pool.pending_transactions() {
4839 let entry = inspect.queued.entry(*queued.pending_transaction.sender()).or_default();
4840 let key = txpool_transaction_key(&queued.pending_transaction);
4841 entry.insert(key, convert(queued));
4842 }
4843 Ok(inspect)
4844 }
4845
4846 pub async fn txpool_content(&self) -> Result<TxpoolContent<AnyRpcTransaction>> {
4853 node_info!("txpool_content");
4854 self.build_txpool_content(None)
4855 }
4856
4857 fn build_txpool_content(
4862 &self,
4863 filter: Option<Address>,
4864 ) -> Result<TxpoolContent<AnyRpcTransaction>> {
4865 let mut content = TxpoolContent::<AnyRpcTransaction>::default();
4866 fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> Result<AnyRpcTransaction> {
4867 let from = *tx.pending_transaction.sender();
4868 let tx = transaction_build(
4869 Some(tx.hash()),
4870 tx.pending_transaction.transaction.clone(),
4871 None,
4872 None,
4873 None,
4874 );
4875
4876 let WithOtherFields { inner: mut tx, other } = tx.0;
4877
4878 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
4881
4882 let tx = AnyRpcTransaction(WithOtherFields { inner: tx, other });
4883
4884 Ok(tx)
4885 }
4886
4887 for pending in self.pool.ready_transactions() {
4888 let sender = *pending.pending_transaction.sender();
4889 if filter.is_some_and(|from| from != sender) {
4890 continue;
4891 }
4892 let entry = content.pending.entry(sender).or_default();
4893 let key = txpool_transaction_key(&pending.pending_transaction);
4894 entry.insert(key, convert(pending)?);
4895 }
4896 for queued in self.pool.pending_transactions() {
4897 let sender = *queued.pending_transaction.sender();
4898 if filter.is_some_and(|from| from != sender) {
4899 continue;
4900 }
4901 let entry = content.queued.entry(sender).or_default();
4902 let key = txpool_transaction_key(&queued.pending_transaction);
4903 entry.insert(key, convert(queued)?);
4904 }
4905
4906 Ok(content)
4907 }
4908
4909 pub async fn txpool_content_from(
4917 &self,
4918 from: Address,
4919 ) -> Result<TxpoolContentFrom<AnyRpcTransaction>> {
4920 node_info!("txpool_contentFrom");
4921 let mut content = self.build_txpool_content(Some(from))?;
4922 Ok(content.remove_from(&from))
4923 }
4924}
4925
4926impl EthApi<FoundryNetwork> {
4927 async fn do_evm_mine(&self, opts: Option<MineOptions>) -> Result<u64> {
4929 let mut blocks_to_mine = 1u64;
4930
4931 if let Some(opts) = opts {
4932 let timestamp = match opts {
4933 MineOptions::Timestamp(timestamp) => timestamp,
4934 MineOptions::Options { timestamp, blocks } => {
4935 if let Some(blocks) = blocks {
4936 blocks_to_mine = blocks;
4937 }
4938 timestamp
4939 }
4940 };
4941 if let Some(timestamp) = timestamp {
4942 self.evm_set_next_block_timestamp(timestamp)?;
4944 }
4945 }
4946
4947 self.on_blocking_task(|this| async move {
4950 for _ in 0..blocks_to_mine {
4952 this.mine_one().await?;
4953 }
4954 Ok(())
4955 })
4956 .await?;
4957
4958 Ok(blocks_to_mine)
4959 }
4960
4961 async fn do_estimate_gas(
4962 &self,
4963 request: WithOtherFields<TransactionRequest>,
4964 block_number: Option<BlockId>,
4965 overrides: EvmOverrides,
4966 ) -> Result<u128> {
4967 let block_request = self.block_request(block_number).await?;
4968 if let BlockRequest::Number(number) = block_request
4970 && let Some(fork) = self.get_fork()
4971 && fork.predates_fork(number)
4972 {
4973 if overrides.has_state() || overrides.has_block() {
4974 return Err(BlockchainError::EvmOverrideError(
4975 "not available on past forked blocks".to_string(),
4976 ));
4977 }
4978 return Ok(fork.estimate_gas_raw(&request, Some(number.into())).await?);
4979 }
4980
4981 self.on_blocking_task(|this| async move {
4984 let request = this.parse_transaction_request(request)?;
4985 this.backend
4986 .with_database_at_and_context(
4987 Some(block_request),
4988 |state, mut block, monad_context| {
4989 let mut cache_db = CacheDB::new(&*state);
4990 if let Some(state_overrides) = overrides.state {
4991 apply_state_overrides(
4992 state_overrides.into_iter().collect(),
4993 &mut cache_db,
4994 )?;
4995 }
4996 if let Some(block_overrides) = overrides.block {
4997 cache_db.apply_block_overrides(*block_overrides, &mut block);
4998 }
4999 this.do_estimate_gas_with_state(request, &cache_db, block, monad_context)
5000 },
5001 )
5002 .await
5003 })
5004 .await
5005 }
5006
5007 async fn do_estimate_gas_typed(
5008 &self,
5009 request: FoundryTransactionRequest,
5010 block_number: Option<BlockId>,
5011 ) -> Result<u128> {
5012 let block_request = self.block_request(block_number).await?;
5013 self.on_blocking_task(|this| async move {
5014 this.backend
5015 .with_database_at_and_context(Some(block_request), |state, block, monad_context| {
5016 this.do_estimate_gas_with_state(request, &state, block, monad_context)
5017 })
5018 .await
5019 })
5020 .await
5021 }
5022
5023 fn transaction_priority(&self, tx: &FoundryTxEnvelope) -> TransactionPriority {
5025 self.transaction_order.read().priority(tx)
5026 }
5027
5028 pub fn full_pending_transactions(&self) -> UnboundedReceiver<AnyRpcTransaction> {
5030 let (tx, rx) = unbounded_channel();
5031 let mut hashes = self.new_ready_transaction_subscription();
5032
5033 let this = self.clone();
5034
5035 tokio::spawn(async move {
5036 while let Some(hash) = hashes.next().await {
5037 if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
5038 && tx.send(txn).is_err()
5039 {
5040 break;
5041 }
5042 }
5043 });
5044
5045 rx
5046 }
5047
5048 pub fn full_pending_transactions_filter(&self) -> mpsc::Receiver<AnyRpcTransaction> {
5053 let (tx, rx) = mpsc::channel(2048);
5055 let mut hashes = self.new_ready_transactions();
5056 let this = self.clone();
5057
5058 tokio::spawn(async move {
5059 while let Some(hash) = hashes.next().await {
5060 if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
5061 && tx.send(txn).await.is_err()
5062 {
5063 break;
5064 }
5065 }
5066 });
5067
5068 rx
5069 }
5070
5071 pub fn transaction_receipts_subscription(
5073 &self,
5074 filter: TransactionReceiptsParams,
5075 ) -> UnboundedReceiver<Vec<FoundryTxReceipt>> {
5076 let (tx, rx) = unbounded_channel();
5077 let mut blocks = self.new_block_notifications();
5078 let this = self.clone();
5079
5080 tokio::spawn(async move {
5081 let hash_filter = filter
5083 .transaction_hashes
5084 .filter(|hashes| !hashes.is_empty())
5085 .map(|hashes| hashes.into_iter().collect::<B256Set>());
5086
5087 loop {
5088 let notification = tokio::select! {
5089 biased;
5090 _ = tx.closed() => break,
5092 maybe_block = blocks.next() => match maybe_block {
5093 Some(block) => block,
5094 None => break,
5095 },
5096 };
5097
5098 let Some(block) = notification.as_new_block() else {
5099 continue;
5100 };
5101
5102 let receipts = match this.block_receipts(BlockId::hash(block.hash)).await {
5103 Ok(Some(mut receipts)) => {
5104 if let Some(hashes) = &hash_filter {
5105 receipts.retain(|receipt| hashes.contains(&receipt.transaction_hash()));
5106 }
5107 receipts
5108 }
5109 Ok(None) => continue,
5110 Err(err) => {
5111 trace!(target: "node", %err, "failed to build block receipts for subscription");
5112 continue;
5113 }
5114 };
5115
5116 if receipts.is_empty() {
5117 continue;
5118 }
5119
5120 if tx.send(receipts).is_err() {
5121 break;
5122 }
5123 }
5124 });
5125
5126 rx
5127 }
5128
5129 pub async fn mine_one(&self) -> Result<()> {
5131 self.mine_one_with_timestamp_pinning(false).await
5132 }
5133
5134 async fn mine_one_with_timestamp_pinning(&self, pin_timestamp: bool) -> Result<()> {
5135 let _mining = self.backend.lock_mining().await;
5136 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5137 let outcome = self.backend.mine_block_locked(transactions, pin_timestamp).await?;
5138
5139 trace!(target: "node", blocknumber = ?outcome.block_number, "mined block");
5140 if self.pool.on_mined_block(outcome) {
5141 self.miner.retry_ready_transactions();
5142 }
5143 Ok(())
5144 }
5145
5146 async fn pending_block(&self) -> Result<AnyRpcBlock> {
5148 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5149 let info = self.backend.pending_block(transactions).await?;
5150 Ok(self.backend.convert_block(info.block))
5151 }
5152
5153 async fn pending_block_full(&self) -> Result<Option<AnyRpcBlock>> {
5155 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5156 let BlockInfo { block, transactions, receipts: _ } =
5157 self.backend.pending_block(transactions).await?;
5158
5159 let mut partial_block = self.backend.convert_block(block.clone());
5160
5161 let mut block_transactions = Vec::with_capacity(block.body.transactions.len());
5162 let base_fee = self.backend.base_fee();
5163
5164 for info in transactions {
5165 let Some(tx) = block.body.transactions.get(info.transaction_index as usize).cloned()
5166 else {
5167 return Ok(None);
5168 };
5169
5170 let tx = transaction_build(
5171 Some(info.transaction_hash),
5172 tx,
5173 Some(&block),
5174 Some(info),
5175 Some(base_fee),
5176 );
5177 block_transactions.push(tx);
5178 }
5179
5180 partial_block.transactions = BlockTransactions::from(block_transactions);
5181
5182 Ok(Some(partial_block))
5183 }
5184
5185 async fn build_tx_request(
5188 &self,
5189 request: FoundryTransactionRequest,
5190 nonce: u64,
5191 ) -> Result<FoundryTypedTx> {
5192 self.build_tx_request_with_fee_defaults(request, nonce, None).await
5193 }
5194
5195 async fn build_tx_request_with_fee_defaults(
5196 &self,
5197 mut request: FoundryTransactionRequest,
5198 nonce: u64,
5199 fee_defaults: Option<TransactionFeeDefaults>,
5200 ) -> Result<FoundryTypedTx> {
5201 let from = request.from().or(self.accounts()?.first().copied());
5202 if let Some(from) = from {
5203 request.set_from(from);
5204 }
5205
5206 request.chain_id().is_none().then(|| request.set_chain_id(self.chain_id()));
5208 request.nonce().is_none().then(|| request.set_nonce(nonce));
5209 let is_tempo_batch =
5210 matches!(&request, FoundryTransactionRequest::Tempo(tx) if !tx.calls.is_empty());
5211 if request.kind().is_none() && !is_tempo_batch {
5212 request.set_kind(TxKind::default());
5213 }
5214 if request.gas_limit().is_none() {
5215 let fallback_gas_limit = {
5216 let evm_env = self.backend.evm_env().read();
5217 self.backend.fallback_tx_gas_limit(&evm_env)
5218 };
5219 let estimated_gas = self
5220 .do_estimate_gas_typed(request.clone(), None)
5221 .await
5222 .map(|v| v as u64)
5223 .unwrap_or_else(|_| {
5224 if is_simple_transfer_request(request.as_ref()) {
5225 MIN_TRANSACTION_GAS as u64
5226 } else {
5227 fallback_gas_limit
5228 }
5229 });
5230 request.set_gas_limit(estimated_gas);
5231 }
5232
5233 if let Err((tx_type, _)) = request.missing_keys() {
5235 let gas_price = || fee_defaults.map_or_else(|| self.gas_price(), |fees| fees.gas_price);
5236 if tx_type.is_legacy() || tx_type.is_eip2930() {
5237 request.gas_price().is_none().then(|| request.set_gas_price(gas_price()));
5238 }
5239 if tx_type.is_eip2930() {
5240 request
5241 .access_list()
5242 .is_none()
5243 .then(|| request.set_access_list(Default::default()));
5244 }
5245 if tx_type.is_eip1559()
5246 || tx_type.is_eip4844()
5247 || tx_type.is_eip7702()
5248 || tx_type.is_tempo()
5249 || tx_type.is_celo()
5250 {
5251 request
5252 .max_fee_per_gas()
5253 .is_none()
5254 .then(|| request.set_max_fee_per_gas(gas_price()));
5255 request
5256 .max_priority_fee_per_gas()
5257 .is_none()
5258 .then(|| request.set_max_priority_fee_per_gas(MIN_SUGGESTED_PRIORITY_FEE));
5259 }
5260 if tx_type.is_eip4844() {
5261 request.as_ref().max_fee_per_blob_gas().is_none().then(|| {
5262 let blob_gas_price = fee_defaults.map_or_else(
5263 || self.backend.fees().get_next_block_blob_base_fee_per_gas(),
5264 |fees| fees.blob_gas_price,
5265 );
5266 request.as_mut().set_max_fee_per_blob_gas(blob_gas_price)
5267 });
5268 }
5269 }
5270
5271 match request
5272 .build_unsigned()
5273 .map_err(|e| BlockchainError::InvalidTransactionRequest(e.to_string()))?
5274 {
5275 FoundryTypedTx::Eip4844(TxEip4844Variant::TxEip4844(_))
5276 if !self.backend.skip_blob_validation(from) =>
5277 {
5278 Err(BlockchainError::FailedToDecodeTransaction)
5280 }
5281 res => Ok(res),
5282 }
5283 }
5284
5285 async fn get_transaction_count(
5287 &self,
5288 address: Address,
5289 block_number: Option<BlockId>,
5290 ) -> Result<u64> {
5291 let block_request = self.block_request(block_number).await?;
5292
5293 if let BlockRequest::Number(number) = block_request
5294 && let Some(fork) = self.get_fork()
5295 && fork.predates_fork(number)
5296 {
5297 return Ok(fork.get_nonce(address, number).await?);
5298 }
5299
5300 self.backend.get_nonce(address, block_request).await
5301 }
5302
5303 async fn request_nonce(&self, request: &TransactionRequest, from: Address) -> Result<u64> {
5308 if let Some(nonce) = request.nonce {
5309 Ok(nonce)
5310 } else {
5311 self.get_transaction_count(from, Some(BlockId::pending())).await
5312 }
5313 }
5314
5315 async fn add_pending_transaction(
5317 &self,
5318 pending_transaction: PendingTransaction<FoundryTxEnvelope>,
5319 ) -> Result<TxHash> {
5320 let _mining = self.backend.lock_mining().await;
5321 self.backend.validate_pool_transaction(&pending_transaction).await?;
5322
5323 let from = *pending_transaction.sender();
5324 #[cfg(feature = "base")]
5325 let base_markers = self.eip8130_nonce_markers(&pending_transaction).await?;
5326 #[cfg(not(feature = "base"))]
5327 let base_markers = None;
5328
5329 let markers = if base_markers.is_some() {
5330 base_markers
5331 } else {
5332 self.tempo_nonce_markers(&pending_transaction).await?
5333 };
5334 let (requires, provides) = if let Some(markers) = markers {
5335 markers
5336 } else {
5337 let nonce = pending_transaction.transaction.nonce();
5338 let on_chain_nonce = self.backend.current_nonce(from).await?;
5339 (required_marker(nonce, on_chain_nonce, from), vec![to_marker(nonce, from)])
5340 };
5341
5342 debug_assert!(requires != provides);
5343 let priority = self.transaction_priority(&pending_transaction.transaction);
5344 let pool_transaction =
5345 PoolTransaction { requires, provides, pending_transaction, priority, is_replay: false };
5346 let tx = self.pool.add_transaction(pool_transaction)?;
5347 trace!(target: "node", "Added transaction: [{:?}] sender={:?}", tx.hash(), from);
5348 Ok(*tx.hash())
5349 }
5350
5351 async fn tempo_nonce_markers(
5353 &self,
5354 pending: &PendingTransaction<FoundryTxEnvelope>,
5355 ) -> Result<Option<(Vec<TxMarker>, Vec<TxMarker>)>> {
5356 let FoundryTxEnvelope::Tempo(signed) = pending.transaction.as_ref() else {
5357 return Ok(None);
5358 };
5359 let tx = signed.tx();
5360 if tx.nonce_key.is_zero() {
5361 return Ok(None);
5362 }
5363 if tx.nonce_key == U256::MAX {
5364 return Ok(Some((Vec::new(), vec![pending.hash().to_vec()])));
5365 }
5366
5367 let state_nonce = self.backend.tempo_nonce(*pending.sender(), tx.nonce_key, None).await?;
5368 if tx.nonce < state_nonce {
5369 return Err(InvalidTransactionError::NonceTooLow.into());
5370 }
5371
5372 let requires = if tx.nonce == state_nonce {
5373 Vec::new()
5374 } else {
5375 vec![tempo_nonce_marker(*pending.sender(), tx.nonce_key, tx.nonce - 1)]
5376 };
5377 let provides = vec![tempo_nonce_marker(*pending.sender(), tx.nonce_key, tx.nonce)];
5378 Ok(Some((requires, provides)))
5379 }
5380
5381 #[cfg(feature = "base")]
5384 async fn eip8130_nonce_markers(
5385 &self,
5386 pending: &PendingTransaction<FoundryTxEnvelope>,
5387 ) -> Result<Option<(Vec<TxMarker>, Vec<TxMarker>)>> {
5388 if let FoundryTxEnvelope::Eip8130(signed) = pending.transaction.as_ref() {
5389 let tx = signed.tx();
5390 let now = self.backend.eip8130_pool_timestamp_ms();
5391 signed
5392 .validate_admission_static(self.backend.chain_id().to())
5393 .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5394 signed
5395 .validate_timestamp(now)
5396 .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5397 if tx.nonce_key.is_zero() {
5398 let state_nonce = self.backend.current_nonce(*pending.sender()).await?;
5399 if tx.nonce_sequence < state_nonce {
5400 return Err(InvalidTransactionError::NonceTooLow.into());
5401 }
5402 let provides = vec![to_marker(tx.nonce_sequence, *pending.sender())];
5403 self.ensure_eip8130_replacement_price(pending, &provides)?;
5404 self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5405 return Ok(None);
5406 }
5407 if tx.nonce_key == Eip8130Constants::NONCE_KEY_MAX {
5408 let replay_id = tx.replay_id(*pending.sender());
5409 let slot = NonceManagerStorage::expiring_nonce_seen_slot(replay_id);
5410 let word =
5411 self.backend.storage_at(NonceManagerStorage::ADDRESS, slot, None).await?;
5412 let recorded_expiry = (Into::<U256>::into(word) & U256::from(u64::MAX)).to::<u64>();
5413 if recorded_expiry > now {
5414 return Err(BlockchainError::Eip8130TransactionRejected(
5415 "expiring nonce replay has already been recorded".to_string(),
5416 ));
5417 }
5418 let provides = vec![eip8130_replay_marker(replay_id)];
5419 self.ensure_eip8130_replacement_price(pending, &provides)?;
5420 self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5421 return Ok(Some((Vec::new(), provides)));
5422 }
5423
5424 let slot = NonceManagerStorage::nonce_slot(*pending.sender(), tx.nonce_key)
5425 .map_err(|error| BlockchainError::InvalidTransactionRequest(error.to_string()))?;
5426 let word = self.backend.storage_at(NonceManagerStorage::ADDRESS, slot, None).await?;
5427 let state_nonce = Eip8130Nonce::decode_channel_nonce(word.into()).to::<u64>();
5428 if tx.nonce_sequence < state_nonce {
5429 return Err(InvalidTransactionError::NonceTooLow.into());
5430 }
5431
5432 let requires = if tx.nonce_sequence == state_nonce {
5433 Vec::new()
5434 } else {
5435 vec![eip8130_channel_marker(*pending.sender(), tx.nonce_key, tx.nonce_sequence - 1)]
5436 };
5437 let provides =
5438 vec![eip8130_channel_marker(*pending.sender(), tx.nonce_key, tx.nonce_sequence)];
5439 self.ensure_eip8130_replacement_price(pending, &provides)?;
5440 self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5441 return Ok(Some((requires, provides)));
5442 }
5443
5444 Ok(None)
5445 }
5446
5447 #[cfg(feature = "base")]
5449 fn ensure_eip8130_replacement_price(
5450 &self,
5451 pending: &PendingTransaction<FoundryTxEnvelope>,
5452 provides: &[TxMarker],
5453 ) -> Result<()> {
5454 let Some(existing) = self.pool.transaction_with_markers(*pending.sender(), provides) else {
5455 return Ok(());
5456 };
5457 let FoundryTxEnvelope::Eip8130(incoming) = pending.transaction.as_ref() else {
5458 return Ok(());
5459 };
5460 let FoundryTxEnvelope::Eip8130(current) = existing.pending_transaction.transaction.as_ref()
5461 else {
5462 return Ok(());
5463 };
5464
5465 const PRICE_BUMP_PERCENT: u128 = 10;
5466 let bumped =
5467 |price: u128| price.saturating_mul(100 + PRICE_BUMP_PERCENT).saturating_add(99) / 100;
5468 if incoming.tx().max_fee_per_gas < bumped(current.tx().max_fee_per_gas)
5469 || incoming.tx().max_priority_fee_per_gas
5470 < bumped(current.tx().max_priority_fee_per_gas)
5471 {
5472 return Err(
5473 crate::eth::error::PoolError::ReplacementUnderpriced(*pending.hash()).into()
5474 );
5475 }
5476 Ok(())
5477 }
5478
5479 #[cfg(feature = "base")]
5481 async fn ensure_eip8130_payer_reservation(
5482 &self,
5483 pending: &PendingTransaction<FoundryTxEnvelope>,
5484 replacing_markers: &[TxMarker],
5485 ) -> Result<()> {
5486 let FoundryTxEnvelope::Eip8130(incoming) = pending.transaction.as_ref() else {
5487 return Ok(());
5488 };
5489 let payer = incoming.tx().payer.unwrap_or(*pending.sender());
5490 let incoming_cost = FeeCheck::max_fee_charge(
5491 incoming.tx().gas_limit,
5492 IntrinsicGas::max_payer_auth_cost(incoming)
5493 .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?,
5494 incoming.tx().max_fee_per_gas,
5495 );
5496 let mut reserved = U256::ZERO;
5497 for pooled in self.pool.all_transactions() {
5498 if pooled.provides == replacing_markers {
5499 continue;
5500 }
5501 let FoundryTxEnvelope::Eip8130(signed) =
5502 pooled.pending_transaction.transaction.as_ref()
5503 else {
5504 continue;
5505 };
5506 if signed.tx().payer.unwrap_or(*pooled.pending_transaction.sender()) != payer {
5507 continue;
5508 }
5509 let payer_auth = IntrinsicGas::max_payer_auth_cost(signed)
5510 .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5511 reserved = reserved.saturating_add(FeeCheck::max_fee_charge(
5512 signed.tx().gas_limit,
5513 payer_auth,
5514 signed.tx().max_fee_per_gas,
5515 ));
5516 }
5517 let balance = self.backend.get_account(payer).await?.balance;
5518 let required = reserved.saturating_add(incoming_cost);
5519 if balance < required {
5520 return Err(BlockchainError::Eip8130TransactionRejected(format!(
5521 "gas payer balance {balance} is below pending reservation {required}"
5522 )));
5523 }
5524 Ok(())
5525 }
5526
5527 fn ensure_typed_transaction_supported(&self, tx: &FoundryTxEnvelope) -> Result<()> {
5529 match &tx {
5530 FoundryTxEnvelope::Eip2930(_) => self.backend.ensure_eip2930_active(),
5531 FoundryTxEnvelope::Eip1559(_) => self.backend.ensure_eip1559_active(),
5532 FoundryTxEnvelope::Eip4844(_) => self.backend.ensure_eip4844_active(),
5533 FoundryTxEnvelope::Eip7702(_) => self.backend.ensure_eip7702_active(),
5534 #[cfg(any(feature = "base", feature = "optimism"))]
5535 FoundryTxEnvelope::Deposit(_) => self.backend.ensure_deposits_active(),
5536 #[cfg(feature = "optimism")]
5537 FoundryTxEnvelope::PostExec(_) => Err(BlockchainError::InvalidTransactionRequest(
5538 "not implemented for post-exec tx".to_string(),
5539 )),
5540 #[cfg(feature = "base")]
5541 FoundryTxEnvelope::Eip8130(_) => self.backend.ensure_base_eip8130_submission_active(),
5542 FoundryTxEnvelope::Celo(_) => self.backend.ensure_cip64_active(),
5543 FoundryTxEnvelope::Legacy(_) => Ok(()),
5544 FoundryTxEnvelope::Tempo(_) => self.backend.ensure_tempo_active(),
5545 }
5546 }
5547
5548 pub async fn anvil_set_fee_token(&self, user: Address, token: Address) -> Result<()> {
5554 node_info!("anvil_setFeeToken");
5555 self.ensure_tempo_mode()?;
5556 self.backend.set_fee_token(user, token).await?;
5557 Ok(())
5558 }
5559
5560 pub async fn anvil_set_validator_fee_token(
5566 &self,
5567 validator: Address,
5568 token: Address,
5569 ) -> Result<()> {
5570 node_info!("anvil_setValidatorFeeToken");
5571 self.ensure_tempo_mode()?;
5572 self.backend.set_validator_fee_token(validator, token).await?;
5573 Ok(())
5574 }
5575
5576 pub async fn anvil_set_fee_amm_liquidity(
5582 &self,
5583 user_token: Address,
5584 validator_token: Address,
5585 amount: U256,
5586 ) -> Result<()> {
5587 node_info!("anvil_setFeeAmmLiquidity");
5588 self.ensure_tempo_mode()?;
5589 self.backend.set_fee_amm_liquidity(user_token, validator_token, amount).await?;
5590 Ok(())
5591 }
5592
5593 fn ensure_tempo_mode(&self) -> Result<()> {
5595 if self.backend.is_tempo() { Ok(()) } else { Err(BlockchainError::RpcUnimplemented) }
5596 }
5597
5598 fn parse_transaction_request(
5599 &self,
5600 request: WithOtherFields<TransactionRequest>,
5601 ) -> Result<FoundryTransactionRequest> {
5602 self.backend.parse_transaction_request(request)
5603 }
5604
5605 async fn request_nonce_for_transaction(
5606 &self,
5607 request: &FoundryTransactionRequest,
5608 from: Address,
5609 ) -> Result<u64> {
5610 if let FoundryTransactionRequest::Tempo(request) = request
5611 && let Some(nonce_key) = request.nonce_key.filter(|key| !key.is_zero())
5612 {
5613 if let Some(nonce) = request.nonce() {
5614 return Ok(nonce);
5615 }
5616 let nonce = self.backend.tempo_nonce(from, nonce_key, None).await?;
5617 return Ok(nonce);
5618 }
5619 self.request_nonce(request.as_ref(), from).await
5620 }
5621
5622 pub async fn consensus_get_finalization(
5631 &self,
5632 query: TempoConsensusQuery,
5633 ) -> Result<TempoCertifiedBlock> {
5634 node_info!("consensus_getFinalization");
5635 let height = match query {
5636 TempoConsensusQuery::Latest => None,
5637 TempoConsensusQuery::Height(height) => Some(height),
5638 };
5639 self.backend.tempo_finalization(height).await
5640 }
5641
5642 pub async fn consensus_get_latest(&self) -> Result<TempoConsensusState> {
5652 node_info!("consensus_getLatest");
5653 let finalized = self.backend.tempo_latest_finalization().await?;
5654 Ok(TempoConsensusState { finalized, notarized: None })
5655 }
5656
5657 pub async fn anvil_tempo_consensus_identity(&self) -> Result<TempoConsensusIdentity> {
5661 node_info!("anvil_tempoConsensusIdentity");
5662 self.backend.tempo_consensus_identity().await
5663 }
5664
5665 pub async fn anvil_tempo_rotate_consensus_identity(&self) -> Result<TempoConsensusIdentity> {
5669 node_info!("anvil_tempoRotateConsensusIdentity");
5670 self.backend.tempo_rotate_consensus_identity().await
5671 }
5672}
5673
5674fn is_simple_transfer_request(request: &TransactionRequest) -> bool {
5675 request.to.as_ref().and_then(TxKind::to).is_some()
5676 && (request.input.input().is_none()
5677 || request.input.input().is_some_and(|data| data.is_empty()))
5678 && request.authorization_list.is_none()
5679 && request.access_list.is_none()
5680 && request.blob_versioned_hashes.is_none()
5681}
5682
5683fn required_marker(provided_nonce: u64, on_chain_nonce: u64, from: Address) -> Vec<TxMarker> {
5684 if provided_nonce == on_chain_nonce {
5685 return Vec::new();
5686 }
5687 let prev_nonce = provided_nonce.saturating_sub(1);
5688 if on_chain_nonce <= prev_nonce { vec![to_marker(prev_nonce, from)] } else { Vec::new() }
5689}
5690
5691fn tempo_nonce_marker(sender: Address, nonce_key: U256, nonce: u64) -> TxMarker {
5692 let mut marker = b"tempo-nonce".to_vec();
5693 marker.extend_from_slice(sender.as_slice());
5694 marker.extend_from_slice(&nonce_key.to_be_bytes::<32>());
5695 marker.extend_from_slice(&nonce.to_be_bytes());
5696 marker
5697}
5698
5699#[cfg(feature = "base")]
5700fn eip8130_channel_marker(sender: Address, nonce_key: U256, nonce_sequence: u64) -> TxMarker {
5701 let mut marker = b"base-eip8130-channel".to_vec();
5702 marker.extend_from_slice(sender.as_slice());
5703 marker.extend_from_slice(&nonce_key.to_be_bytes::<32>());
5704 marker.extend_from_slice(&nonce_sequence.to_be_bytes());
5705 marker
5706}
5707
5708#[cfg(feature = "base")]
5709fn eip8130_replay_marker(replay_id: B256) -> TxMarker {
5710 let mut marker = b"base-eip8130-replay".to_vec();
5711 marker.extend_from_slice(replay_id.as_slice());
5712 marker
5713}
5714
5715fn normalize_fee_payer_service_encoding(raw: &[u8]) -> Option<Vec<u8>> {
5725 let (tx_type, mut encoded_fields) = raw.split_first()?;
5726 if *tx_type != TEMPO_TX_TYPE_ID {
5727 return None;
5728 }
5729 let PayloadView::List(fields) = Header::decode_raw(&mut encoded_fields).ok()? else {
5730 return None;
5731 };
5732 if !encoded_fields.is_empty() {
5733 return None;
5734 }
5735 if fields.get(11).is_none_or(|field| *field != [0x00]) {
5737 return None;
5738 }
5739
5740 let marker = FEE_PAYER_SIGNATURE_MARKER;
5743 let mut marker_field = Vec::new();
5744 Header { list: true, payload_length: marker.rlp_rs_len() + marker.v().length() }
5745 .encode(&mut marker_field);
5746 marker.write_rlp_vrs(&mut marker_field, marker.v());
5747
5748 let mut payload = Vec::new();
5749 for (index, field) in fields.into_iter().enumerate() {
5750 if index == 11 {
5751 payload.extend_from_slice(&marker_field);
5752 } else {
5753 payload.extend_from_slice(field);
5754 }
5755 }
5756 let mut normalized = vec![TEMPO_TX_TYPE_ID];
5757 Header { list: true, payload_length: payload.len() }.encode(&mut normalized);
5758 normalized.extend_from_slice(&payload);
5759 Some(normalized)
5760}
5761
5762fn encode_rpc_transaction(transaction: &AnyRpcTransaction) -> Result<Bytes> {
5765 FoundryTxEnvelope::encode_rpc_2718(transaction)
5766 .map_err(|_| BlockchainError::UnsupportedTransactionEncoding(transaction.ty()))
5767}
5768
5769fn txpool_transaction_key(pending_transaction: &PendingTransaction<FoundryTxEnvelope>) -> String {
5770 match pending_transaction.transaction.as_ref() {
5771 #[cfg(feature = "base")]
5772 FoundryTxEnvelope::Eip8130(signed) if !signed.tx().nonce_key.is_zero() => {
5773 if signed.tx().nonce_key == Eip8130Constants::NONCE_KEY_MAX {
5774 return signed.tx().replay_id(*pending_transaction.sender()).to_string();
5775 }
5776 format!("{}:{}", signed.tx().nonce_key, signed.tx().nonce_sequence)
5777 }
5778 FoundryTxEnvelope::Tempo(tx) if !tx.tx().nonce_key.is_zero() => {
5779 let tx = tx.tx();
5780 format!("{}:{}", tx.nonce_key, tx.nonce)
5781 }
5782 _ => pending_transaction.nonce().to_string(),
5783 }
5784}
5785
5786fn convert_transact_out(out: &Option<Output>) -> Bytes {
5787 out.as_ref().map(Output::data).cloned().unwrap_or_default()
5788}
5789
5790fn ensure_return_ok(exit: InstructionResult, out: &Option<Output>) -> Result<Bytes> {
5792 let out = convert_transact_out(out);
5793 match exit {
5794 return_ok!() => Ok(out),
5795 return_revert!() => Err(InvalidTransactionError::Revert(Some(out)).into()),
5796 reason => Err(BlockchainError::EvmError(reason)),
5797 }
5798}
5799
5800fn execution_error(exit: InstructionResult) -> Option<String> {
5803 match SuccessOrHalt::<HaltReason>::from(exit) {
5804 SuccessOrHalt::Success(_) => None,
5805 SuccessOrHalt::Revert => Some("execution reverted".to_string()),
5806 SuccessOrHalt::Halt(reason) => Some(reason.to_string()),
5807 SuccessOrHalt::FatalExternalError => Some("fatal external error".to_string()),
5808 SuccessOrHalt::Internal(_) => Some("internal EVM error".to_string()),
5809 }
5810}
5811
5812enum GasEstimationCallResult {
5814 Success(u128),
5815 OutOfGas,
5816 Revert(Option<Bytes>),
5817 EvmError(InstructionResult),
5818}
5819
5820impl TryFrom<Result<(InstructionResult, Option<Output>, u128, StateChangeset)>>
5824 for GasEstimationCallResult
5825{
5826 type Error = BlockchainError;
5827
5828 fn try_from(
5829 res: Result<(InstructionResult, Option<Output>, u128, StateChangeset)>,
5830 ) -> Result<Self> {
5831 match res {
5832 Err(BlockchainError::InvalidTransaction(InvalidTransactionError::GasTooHigh(_))) => {
5834 Ok(Self::OutOfGas)
5835 }
5836 Err(BlockchainError::Message(ref msg))
5838 if msg.contains("insufficient gas for intrinsic cost") =>
5839 {
5840 Ok(Self::OutOfGas)
5841 }
5842 Err(err) => Err(err),
5843 Ok((exit, output, gas, _)) => match exit {
5844 return_ok!() => Ok(Self::Success(gas)),
5845
5846 InstructionResult::Revert => {
5848 Ok(Self::Revert(Some(output.map(|o| o.into_data()).unwrap_or_default())))
5849 }
5850 InstructionResult::CallTooDeep
5851 | InstructionResult::OutOfFunds
5852 | InstructionResult::CreateInitCodeStartingEF00
5853 | InstructionResult::InvalidEOFInitCode
5854 | InstructionResult::InvalidExtDelegateCallTarget => Ok(Self::EvmError(exit)),
5855
5856 InstructionResult::OutOfGas
5858 | InstructionResult::MemoryOOG
5859 | InstructionResult::MemoryLimitOOG
5860 | InstructionResult::PrecompileOOG
5861 | InstructionResult::InvalidOperandOOG
5862 | InstructionResult::ReentrancySentryOOG => Ok(Self::OutOfGas),
5863
5864 InstructionResult::OpcodeNotFound
5866 | InstructionResult::CallNotAllowedInsideStatic
5867 | InstructionResult::StateChangeDuringStaticCall
5868 | InstructionResult::InvalidFEOpcode
5869 | InstructionResult::InvalidJump
5870 | InstructionResult::NotActivated
5871 | InstructionResult::StackUnderflow
5872 | InstructionResult::StackOverflow
5873 | InstructionResult::OutOfOffset
5874 | InstructionResult::CreateCollision
5875 | InstructionResult::OverflowPayment
5876 | InstructionResult::PrecompileError
5877 | InstructionResult::NonceOverflow
5878 | InstructionResult::CreateContractSizeLimit
5879 | InstructionResult::CreateContractStartingWithEF
5880 | InstructionResult::CreateInitCodeSizeLimit
5881 | InstructionResult::InvalidImmediateEncoding
5882 | InstructionResult::FatalExternalError => Ok(Self::EvmError(exit)),
5883 },
5884 }
5885 }
5886}
5887
5888fn merge_pre_fork_fee_history(
5890 response: &mut FeeHistory,
5891 rewards: &mut Vec<Vec<u128>>,
5892 pre: FeeHistory,
5893 fork_block: u64,
5894) {
5895 response.oldest_block = pre.oldest_block;
5897 let count = fork_block.checked_sub(pre.oldest_block).map_or(0, |count| count.saturating_add(1))
5898 as usize;
5899
5900 response.base_fee_per_gas.extend(pre.base_fee_per_gas.into_iter().take(count));
5902 response.gas_used_ratio.extend(pre.gas_used_ratio.into_iter().take(count));
5903 if let Some(reward) = pre.reward {
5904 rewards.extend(reward.into_iter().take(count));
5905 }
5906
5907 response.base_fee_per_blob_gas.extend(pre.base_fee_per_blob_gas.into_iter().take(count));
5909 response.base_fee_per_blob_gas.resize(count, 0);
5910 response.blob_gas_used_ratio.extend(pre.blob_gas_used_ratio.into_iter().take(count));
5911 response.blob_gas_used_ratio.resize(count, 0.0);
5912}
5913
5914fn reward_at_percentile(rewards: &[u128], percentile: f64) -> u128 {
5915 let index = (percentile * REWARD_PERCENTILE_RESOLUTION).round() as usize;
5916 rewards.get(index).copied().unwrap_or_default()
5917}
5918
5919#[cfg(test)]
5920mod tests {
5921 use super::*;
5922 use crate::{NodeConfig, spawn};
5923
5924 #[cfg(feature = "base")]
5925 #[tokio::test(flavor = "multi_thread")]
5926 async fn base_requests_are_rejected_without_execution() {
5927 let (api, _handle) = spawn(NodeConfig::test()).await;
5928 for request in [serde_json::json!({ "type": "0x79" }), serde_json::json!({ "calls": [[]] })]
5929 {
5930 let request = serde_json::from_value(request).unwrap();
5931 assert!(matches!(
5932 api.parse_transaction_request(request),
5933 Err(BlockchainError::BaseTransactionUnsupported)
5934 ));
5935 }
5936 }
5937
5938 #[tokio::test(flavor = "multi_thread")]
5939 async fn set_rpc_url_installs_context_equivalent_identity_with_new_instance() {
5940 let genesis_timestamp = 1_700_000_000u64;
5941 let (_origin_api, origin_handle) =
5942 spawn(NodeConfig::test().with_genesis_timestamp(Some(genesis_timestamp))).await;
5943 let (api, _handle) =
5944 spawn(NodeConfig::test().with_eth_rpc_url(Some(origin_handle.http_endpoint()))).await;
5945 let (target_api, target_handle) =
5946 spawn(NodeConfig::test().with_genesis_timestamp(Some(genesis_timestamp))).await;
5947 let target_url = target_handle.http_endpoint();
5948 let fork = api.backend.get_fork().unwrap();
5949 let identity_before = fork.config.read().endpoint_identity;
5950
5951 api.anvil_set_rpc_url(target_url.clone()).await.unwrap();
5952
5953 let fork = api.backend.get_fork().unwrap();
5954 let config = fork.config.read();
5955 assert!(config.endpoint_identity.context_eq(identity_before));
5956 assert_ne!(config.endpoint_identity.instance_id, identity_before.instance_id);
5957 assert_eq!(config.endpoint_identity.instance_id, Some(target_api.instance_id()));
5958 assert_eq!(config.eth_rpc_url(), Some(target_url.as_str()));
5959 }
5960
5961 #[tokio::test(flavor = "multi_thread")]
5962 async fn memory_reset_stages_live_fees_after_active_mining() {
5963 let (api, _handle) = spawn(NodeConfig::test()).await;
5964 api.backend.set_base_fee(123);
5965
5966 let mining = api.backend.lock_mining().await;
5969 let reset_api = api.clone();
5970 let reset = tokio::spawn(async move { reset_api.anvil_reset(None).await });
5971
5972 tokio::time::timeout(Duration::from_secs(5), async {
5973 while api.lifecycle_lock.try_read().is_ok() {
5974 tokio::task::yield_now().await;
5975 }
5976 })
5977 .await
5978 .unwrap();
5979
5980 api.backend.set_base_fee(456);
5981 drop(mining);
5982 tokio::time::timeout(Duration::from_secs(5), reset).await.unwrap().unwrap().unwrap();
5983
5984 assert_eq!(api.backend.evm_env().read().block_env.basefee, 456);
5985 assert_eq!(api.base_fee().unwrap(), Some(U256::from(crate::eth::fees::INITIAL_BASE_FEE)));
5986 }
5987
5988 #[tokio::test(flavor = "multi_thread")]
5990 async fn fee_history_is_complete_when_cache_entries_are_missing() {
5991 let (api, _handle) = spawn(NodeConfig::test()).await;
5992 let count = 10u64;
5993 api.anvil_mine(Some(U256::from(count)), None).await.unwrap();
5994
5995 tokio::time::timeout(Duration::from_secs(5), async {
5999 loop {
6000 if (1..=count).all(|number| api.fee_history_cache.lock().contains_key(&number)) {
6001 break;
6002 }
6003 tokio::task::yield_now().await;
6004 }
6005 })
6006 .await
6007 .unwrap();
6008 api.fee_history_cache.lock().clear();
6009
6010 let fee_history =
6011 api.fee_history(U256::from(count), BlockNumber::Latest, vec![50.0]).await.unwrap();
6012
6013 assert_eq!(fee_history.oldest_block, 1);
6014 assert_eq!(fee_history.gas_used_ratio.len(), count as usize);
6015 assert_eq!(fee_history.blob_gas_used_ratio.len(), count as usize);
6016 assert_eq!(fee_history.base_fee_per_gas.len(), count as usize + 1);
6017 assert_eq!(fee_history.base_fee_per_blob_gas.len(), count as usize + 1);
6018 let rewards = fee_history.reward.unwrap();
6019 assert_eq!(rewards.len(), count as usize);
6020 assert!(rewards.iter().all(|reward| reward.len() == 1));
6021 }
6022
6023 #[tokio::test(flavor = "multi_thread")]
6024 async fn fee_history_rejects_invalid_reward_percentiles() {
6025 let (api, _handle) = spawn(NodeConfig::test()).await;
6026
6027 for percentiles in [vec![-0.5], vec![100.5], vec![50.0, 25.0], vec![50.0, 50.0]] {
6028 let err =
6029 api.fee_history(U256::ONE, BlockNumber::Latest, percentiles).await.unwrap_err();
6030 assert!(matches!(
6031 err,
6032 BlockchainError::FeeHistory(FeeHistoryError::InvalidRewardPercentiles)
6033 ));
6034 }
6035
6036 for percentiles in [vec![], vec![0.0, 100.0]] {
6037 api.fee_history(U256::ONE, BlockNumber::Latest, percentiles).await.unwrap();
6038 }
6039 }
6040
6041 #[test]
6042 fn fractional_reward_percentiles_use_cache_resolution() {
6043 let rewards = (0..=200).collect::<Vec<_>>();
6044
6045 assert_eq!(reward_at_percentile(&rewards, 0.0), 0);
6046 assert_eq!(reward_at_percentile(&rewards, 0.5), 1);
6047 assert_eq!(reward_at_percentile(&rewards, 1.0), 2);
6048 assert_eq!(reward_at_percentile(&rewards, 100.0), 200);
6049 }
6050
6051 #[test]
6052 fn shortened_pre_fork_fee_history_uses_upstream_start() {
6053 let requested_lowest = 4;
6054 let fork_block = 10;
6055 let pre = FeeHistory {
6056 oldest_block: 5,
6057 base_fee_per_gas: vec![1; 7],
6058 gas_used_ratio: vec![0.0; 6],
6059 reward: Some(vec![vec![]; 6]),
6060 base_fee_per_blob_gas: vec![],
6061 blob_gas_used_ratio: vec![],
6062 };
6063
6064 let mut response = FeeHistory { oldest_block: requested_lowest, ..Default::default() };
6065 let mut rewards = Vec::new();
6066
6067 merge_pre_fork_fee_history(&mut response, &mut rewards, pre, fork_block);
6068
6069 assert_eq!(response.oldest_block, 5);
6070 assert_eq!(response.gas_used_ratio.len(), 6);
6071 assert_eq!(response.base_fee_per_gas.len(), 6);
6072 assert_eq!(response.blob_gas_used_ratio.len(), 6);
6073 assert_eq!(response.base_fee_per_blob_gas.len(), 6);
6074 assert_eq!(rewards.len(), 6);
6075 }
6076}