1use super::{
2 backend::mem::{
3 BlockRequest, DatabaseRef, GasEstimateCallOptions, MonadReplayContext, State,
4 sanitize_simulation_blocks,
5 },
6 preserve_simulation_request_fields,
7};
8use crate::{
9 ClientFork, LoggingManager, Miner, MiningMode, StorageInfo,
10 eth::{
11 backend::{
12 self, db::SerializableState, mem::MIN_TRANSACTION_GAS,
13 notifications::ChainNotifications, validate::TransactionValidator,
14 },
15 error::{
16 BlockchainError, FeeHistoryError, InvalidTransactionError, Result, ToRpcResponseResult,
17 },
18 fees::{
19 FeeDetails, FeeHistoryCache, FeeHistoryCacheItem, MIN_SUGGESTED_PRIORITY_FEE,
20 REWARD_PERCENTILE_RESOLUTION, create_fee_history_cache_item,
21 },
22 macros::node_info,
23 miner::FixedBlockTimeMiner,
24 pool::{
25 Pool, PoolSnapshot,
26 transactions::{
27 PoolTransaction, TransactionOrder, TransactionPriority, TxMarker, to_marker,
28 },
29 },
30 sign::Signer,
31 },
32 filter::{EthFilter, Filters, LogsFilter},
33 mem::transaction_build,
34};
35use alloy_consensus::{
36 Blob, BlockHeader, Transaction, TrieAccount, TxEip4844Variant, TxReceipt, Typed2718,
37 transaction::{Recovered, SignerRecoverable},
38};
39use alloy_dyn_abi::TypedData;
40use alloy_eips::{
41 eip2718::{EIP4844_TX_TYPE_ID, Encodable2718},
42 eip4844::DATA_GAS_PER_BLOB,
43 eip7910::{EthConfig, EthForkConfig},
44};
45use alloy_evm::overrides::{OverrideBlockHashes, apply_state_overrides};
46use alloy_network::{
47 AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, BlockResponse, Network,
48 NetworkTransactionBuilder, ReceiptResponse, TransactionBuilder, TransactionBuilder4844,
49 TransactionResponse, eip2718::Decodable2718,
50};
51use alloy_primitives::{
52 Address, B64, B256, Bytes, TxHash, TxKind, U64, U256,
53 map::{AddressSet, B256Set, HashMap, HashSet},
54};
55use alloy_rlp::{Encodable, Header, PayloadView};
56use alloy_rpc_types::{
57 AccessListResult, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,
58 EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, Work,
59 anvil::{
60 ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo,
61 },
62 debug::ExecutionWitness,
63 erc4337::TransactionConditional,
64 pubsub::TransactionReceiptsParams,
65 request::TransactionRequest,
66 simulate::{MAX_SIMULATE_BLOCKS, SimulatePayload, SimulatedBlock},
67 state::{AccountOverride, EvmOverrides, StateOverride, StateOverridesBuilder},
68 trace::{
69 filter::TraceFilter,
70 geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult},
71 opcode::{BlockOpcodeGas, TransactionOpcodeGas},
72 parity::{
73 LocalizedTransactionTrace, TraceResults, TraceResultsWithTransactionHash, TraceType,
74 },
75 },
76 txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus},
77};
78use alloy_rpc_types_eth::{AccountInfo, Bundle, EthCallResponse, FillTransaction, StateContext};
79use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse};
80use alloy_serde::WithOtherFields;
81use alloy_sol_types::{SolCall, SolValue, sol};
82use anvil_core::{
83 eth::{
84 EthRequest,
85 block::{Block, BlockInfo, canonical_block},
86 transaction::{MaybeImpersonatedTransaction, PendingTransaction},
87 },
88 types::{ReorgOptions, TransactionData},
89};
90use anvil_rpc::{
91 error::{ErrorCode, RpcError},
92 response::ResponseResult,
93};
94use foundry_common::{
95 provider::redact_url,
96 tempo::{PaymentLaneClassification, PaymentLaneReason, classify_payment_lane},
97 version::{COMMIT_SHA, SEMVER_VERSION},
98};
99use foundry_evm::decode::RevertDecoder;
100use foundry_primitives::{
101 FoundryNetwork, FoundryReceiptEnvelope, FoundryTransactionRequest, FoundryTxEnvelope,
102 FoundryTxReceipt, FoundryTypedTx,
103};
104use futures::{
105 StreamExt, TryFutureExt,
106 channel::{mpsc::Receiver, oneshot},
107};
108use parking_lot::{Mutex, RwLock};
109use revm::{
110 context::BlockEnv,
111 context_interface::{
112 block::BlobExcessGasAndPrice,
113 result::{HaltReason, Output},
114 },
115 database::CacheDB,
116 interpreter::{InstructionResult, SuccessOrHalt, return_ok, return_revert},
117};
118use std::{sync::Arc, time::Duration};
119use tempo_hardfork::TempoHardfork;
120use tempo_primitives::{AASigned, TEMPO_TX_TYPE_ID, transaction::FEE_PAYER_SIGNATURE_MARKER};
121use tokio::{
122 sync::mpsc::{self, UnboundedReceiver, unbounded_channel},
123 try_join,
124};
125
126#[cfg(feature = "base")]
127use base_common_consensus::Eip8130Constants;
128#[cfg(feature = "base")]
129use base_common_evm::EIP8130_TRANSACTION_TYPE;
130#[cfg(feature = "base")]
131use base_common_precompiles::NonceManagerStorage;
132#[cfg(feature = "base")]
133use base_common_rpc_types::{BaseTransactionRequest, Eip8130Nonce};
134#[cfg(feature = "base")]
135use base_execution_eip8130::{FeeCheck, IntrinsicGas};
136
137pub const CLIENT_VERSION: &str = concat!("anvil/v", env!("CARGO_PKG_VERSION"));
139
140#[derive(Clone, Copy)]
141struct TransactionFeeDefaults {
142 gas_price: u128,
143 blob_gas_price: u128,
144}
145
146pub struct EthApi<N: Network> {
150 pool: Arc<Pool<N::TxEnvelope>>,
152 pool_snapshots: Arc<Mutex<HashMap<U256, PoolSnapshot<N::TxEnvelope>>>>,
154 pub backend: Arc<backend::mem::Backend<N>>,
157 is_mining: bool,
159 signers: Arc<Vec<Box<dyn Signer<N>>>>,
161 fee_history_cache: FeeHistoryCache,
163 fee_history_limit: u64,
165 miner: Miner<N::TxEnvelope>,
170 logger: LoggingManager,
172 filters: Filters<N>,
174 transaction_order: Arc<RwLock<TransactionOrder>>,
176 net_listening: bool,
178 instance_id: Arc<RwLock<B256>>,
180 lifecycle_lock: Arc<tokio::sync::RwLock<()>>,
182 reset_lock: Arc<tokio::sync::Mutex<()>>,
184 nonce_locks: Arc<RwLock<HashMap<Address, Arc<tokio::sync::Mutex<()>>>>>,
186}
187
188impl<N: Network> Clone for EthApi<N> {
189 fn clone(&self) -> Self {
190 Self {
191 pool: self.pool.clone(),
192 pool_snapshots: self.pool_snapshots.clone(),
193 backend: self.backend.clone(),
194 is_mining: self.is_mining,
195 signers: self.signers.clone(),
196 fee_history_cache: self.fee_history_cache.clone(),
197 fee_history_limit: self.fee_history_limit,
198 miner: self.miner.clone(),
199 logger: self.logger.clone(),
200 filters: self.filters.clone(),
201 transaction_order: self.transaction_order.clone(),
202 net_listening: self.net_listening,
203 instance_id: self.instance_id.clone(),
204 lifecycle_lock: self.lifecycle_lock.clone(),
205 reset_lock: self.reset_lock.clone(),
206 nonce_locks: self.nonce_locks.clone(),
207 }
208 }
209}
210
211impl<N: Network> EthApi<N> {
214 #[expect(clippy::too_many_arguments)]
216 pub fn new(
217 pool: Arc<Pool<N::TxEnvelope>>,
218 backend: Arc<backend::mem::Backend<N>>,
219 signers: Arc<Vec<Box<dyn Signer<N>>>>,
220 fee_history_cache: FeeHistoryCache,
221 fee_history_limit: u64,
222 miner: Miner<N::TxEnvelope>,
223 logger: LoggingManager,
224 filters: Filters<N>,
225 transactions_order: TransactionOrder,
226 ) -> Self {
227 Self {
228 pool,
229 pool_snapshots: Arc::new(Mutex::new(HashMap::default())),
230 backend,
231 is_mining: true,
232 signers,
233 fee_history_cache,
234 fee_history_limit,
235 miner,
236 logger,
237 filters,
238 net_listening: true,
239 transaction_order: Arc::new(RwLock::new(transactions_order)),
240 instance_id: Arc::new(RwLock::new(B256::random())),
241 lifecycle_lock: Arc::new(tokio::sync::RwLock::new(())),
242 reset_lock: Arc::new(tokio::sync::Mutex::new(())),
243 nonce_locks: Default::default(),
244 }
245 }
246
247 pub fn gas_price(&self) -> u128 {
249 if self.backend.is_eip1559() {
250 if self.backend.is_min_priority_fee_enforced() {
251 (self.backend.base_fee() as u128).saturating_add(self.lowest_suggestion_tip())
252 } else {
253 self.backend.base_fee() as u128
254 }
255 } else {
256 self.backend.fees().raw_gas_price()
257 }
258 }
259
260 fn lowest_suggestion_tip(&self) -> u128 {
264 let block_number = self.backend.best_number();
265 let cache = self.fee_history_cache.lock();
266 let latest_tip = self
267 .backend
268 .get_block_with_hash(block_number)
269 .and_then(|(_, hash)| cache.get(&block_number).filter(|item| item.block_hash == hash))
270 .and_then(|item| item.rewards.iter().copied().min());
271
272 latest_tip
273 .or_else(|| {
274 cache
275 .iter()
276 .filter(|(number, item)| {
277 self.backend
278 .get_block_with_hash(**number)
279 .is_some_and(|(_, hash)| item.block_hash == hash)
280 })
281 .flat_map(|(_, item)| item.rewards.iter().copied())
282 .min()
283 })
284 .map(|fee| fee.max(MIN_SUGGESTED_PRIORITY_FEE))
285 .unwrap_or(MIN_SUGGESTED_PRIORITY_FEE)
286 }
287
288 pub fn anvil_get_auto_mine(&self) -> Result<bool> {
292 node_info!("anvil_getAutomine");
293 Ok(self.miner.is_auto_mine())
294 }
295
296 pub fn anvil_get_interval_mining(&self) -> Result<Option<u64>> {
300 node_info!("anvil_getIntervalMining");
301 Ok(self.miner.get_interval())
302 }
303
304 pub async fn anvil_set_auto_mine(&self, enable_automine: bool) -> Result<()> {
309 node_info!("evm_setAutomine");
310 if self.miner.is_auto_mine() {
311 if enable_automine {
312 return Ok(());
313 }
314 self.miner.set_mining_mode(MiningMode::None);
315 } else if enable_automine {
316 let listener = self.pool.add_ready_listener();
317 let window = self.backend.node_config.read().await.transaction_coalescing_window;
318 let mode = MiningMode::instant(1_000, listener).with_coalescing_window(window);
319 self.miner.set_mining_mode(mode);
320 }
321 Ok(())
322 }
323
324 pub fn anvil_set_interval_mining(&self, secs: u64) -> Result<()> {
328 node_info!("evm_setIntervalMining");
329 let mining_mode = if secs == 0 {
330 MiningMode::None
331 } else {
332 let block_time = Duration::from_secs(secs);
333
334 self.backend.update_interval_mine_block_time(block_time);
336
337 MiningMode::FixedBlockTime(FixedBlockTimeMiner::new(block_time))
338 };
339 self.miner.set_mining_mode(mining_mode);
340 Ok(())
341 }
342
343 pub async fn anvil_drop_transaction(&self, tx_hash: B256) -> Result<Option<B256>> {
347 node_info!("anvil_dropTransaction");
348 Ok(self.pool.drop_transaction(tx_hash).map(|tx| tx.hash()))
349 }
350
351 pub async fn anvil_drop_all_transactions(&self) -> Result<()> {
355 node_info!("anvil_dropAllTransactions");
356 self.pool.clear();
357 Ok(())
358 }
359
360 pub async fn debug_clear_txpool(&self) -> Result<()> {
364 node_info!("debug_clearTxpool");
365 self.pool.clear();
366 Ok(())
367 }
368
369 pub async fn anvil_set_chain_id(&self, chain_id: u64) -> Result<()> {
370 node_info!("anvil_setChainId");
371 self.backend.set_chain_id(chain_id);
372 #[cfg(feature = "base")]
373 self.invalidate_base_eip8130_pool();
374 Ok(())
375 }
376
377 #[cfg(feature = "base")]
379 fn invalidate_base_eip8130_pool(&self) {
380 if self.backend.is_base() {
381 let _ = self.pool.clear_transaction_type(EIP8130_TRANSACTION_TYPE);
382 }
383 }
384
385 pub async fn anvil_set_balance(&self, address: Address, balance: U256) -> Result<()> {
389 node_info!("anvil_setBalance");
390 self.backend.set_balance(address, balance).await?;
391 #[cfg(feature = "base")]
392 self.invalidate_base_eip8130_pool();
393 Ok(())
394 }
395
396 pub async fn anvil_set_code(&self, address: Address, code: Bytes) -> Result<()> {
400 node_info!("anvil_setCode");
401 self.backend.set_code(address, code).await?;
402 #[cfg(feature = "base")]
403 self.invalidate_base_eip8130_pool();
404 Ok(())
405 }
406
407 pub async fn anvil_set_nonce(&self, address: Address, nonce: U256) -> Result<()> {
411 node_info!("anvil_setNonce");
412 self.backend.set_nonce(address, nonce).await?;
413 #[cfg(feature = "base")]
414 self.invalidate_base_eip8130_pool();
415 Ok(())
416 }
417
418 pub async fn anvil_set_storage_at(
422 &self,
423 address: Address,
424 slot: U256,
425 val: B256,
426 ) -> Result<bool> {
427 node_info!("anvil_setStorageAt");
428 self.backend.set_storage_at(address, slot, val).await?;
429 #[cfg(feature = "base")]
430 self.invalidate_base_eip8130_pool();
431 Ok(true)
432 }
433
434 pub async fn anvil_set_logging(&self, enable: bool) -> Result<()> {
438 node_info!("anvil_setLoggingEnabled");
439 self.logger.set_enabled(enable);
440 Ok(())
441 }
442
443 pub async fn anvil_set_min_gas_price(&self, gas: U256) -> Result<()> {
447 node_info!("anvil_setMinGasPrice");
448 if self.backend.is_eip1559() {
449 return Err(RpcError::invalid_params(
450 "anvil_setMinGasPrice is not supported when EIP-1559 is active",
451 )
452 .into());
453 }
454 self.backend.set_gas_price(gas.saturating_to());
455 Ok(())
456 }
457
458 pub async fn anvil_set_next_block_base_fee_per_gas(&self, basefee: U256) -> Result<()> {
462 node_info!("anvil_setNextBlockBaseFeePerGas");
463 if !self.backend.is_eip1559() {
464 return Err(RpcError::invalid_params(
465 "anvil_setNextBlockBaseFeePerGas is only supported when EIP-1559 is active",
466 )
467 .into());
468 }
469 self.backend.set_base_fee(basefee.saturating_to());
470 Ok(())
471 }
472
473 pub async fn anvil_set_coinbase(&self, address: Address) -> Result<()> {
477 node_info!("anvil_setCoinbase");
478 self.backend.set_coinbase(address);
479 Ok(())
480 }
481
482 pub async fn anvil_set_next_block_prevrandao(&self, prevrandao: B256) -> Result<()> {
489 node_info!("anvil_setNextBlockPrevRandao");
490 self.backend.set_next_block_prevrandao(prevrandao);
491 Ok(())
492 }
493
494 pub async fn anvil_set_next_block_parent_beacon_block_root(&self, root: B256) -> Result<()> {
502 node_info!("anvil_setNextBlockParentBeaconBlockRoot");
503 self.backend.set_next_block_parent_beacon_block_root(root);
504 Ok(())
505 }
506
507 pub async fn anvil_node_info(&self) -> Result<NodeInfo> {
511 node_info!("anvil_nodeInfo");
512 let _lifecycle = self.lifecycle_lock.read().await;
513
514 let evm_env = self.backend.evm_env().read().clone();
515 let fork_config = self.backend.get_fork();
516 let tx_order = self.transaction_order.read();
517 let hard_fork = self.backend.hardfork().name();
518
519 Ok(NodeInfo {
520 current_block_number: self.backend.best_number(),
521 current_block_timestamp: evm_env.block_env.timestamp.saturating_to(),
522 current_block_hash: self.backend.best_hash(),
523 hard_fork,
524 transaction_order: match *tx_order {
525 TransactionOrder::Fifo => "fifo".to_string(),
526 TransactionOrder::Fees => "fees".to_string(),
527 },
528 environment: NodeEnvironment {
529 base_fee: self.backend.base_fee() as u128,
530 chain_id: self.backend.chain_id().to::<u64>(),
531 gas_limit: self.backend.gas_limit(),
532 gas_price: self.gas_price(),
533 },
534 fork_config: fork_config
535 .map(|fork| {
536 let config = fork.config.read();
537
538 NodeForkConfig {
539 fork_url: config.eth_rpc_url().map(redact_url),
540 fork_block_number: Some(config.block_number),
541 fork_retry_backoff: Some(config.backoff.as_millis()),
542 }
543 })
544 .unwrap_or_default(),
545 network: Some(self.backend.execution_profile_name().to_string()),
548 })
549 }
550
551 pub async fn anvil_metadata(&self) -> Result<Metadata> {
555 node_info!("anvil_metadata");
556 let _lifecycle = self.lifecycle_lock.read().await;
557 let fork_config = self.backend.get_fork();
558
559 Ok(Metadata {
560 client_version: CLIENT_VERSION.to_string(),
561 client_semver: Some(SEMVER_VERSION.to_string()),
562 client_commit_sha: Some(COMMIT_SHA.to_string()),
563 chain_id: self.backend.chain_id().to::<u64>(),
564 latest_block_hash: self.backend.best_hash(),
565 latest_block_number: self.backend.best_number(),
566 instance_id: *self.instance_id.read(),
567 forked_network: fork_config.map(|cfg| ForkedNetwork {
568 chain_id: cfg.chain_id(),
569 fork_block_number: cfg.block_number(),
570 fork_block_hash: cfg.block_hash(),
571 }),
572 snapshots: self.backend.list_state_snapshots(),
573 })
574 }
575
576 pub async fn anvil_remove_pool_transactions(&self, address: Address) -> Result<()> {
577 node_info!("anvil_removePoolTransactions");
578 self.pool.remove_transactions_by_address(address);
579 Ok(())
580 }
581
582 pub async fn evm_snapshot(&self) -> Result<U256> {
586 node_info!("evm_snapshot");
587 let _lifecycle = self.lifecycle_lock.read().await;
588 let _mining = self.backend.lock_mining().await;
589 let pool = self.pool.snapshot();
590 let id = self.backend.create_state_snapshot().await;
591 self.pool_snapshots.lock().insert(id, pool);
592 Ok(id)
593 }
594
595 pub async fn evm_increase_time(&self, seconds: U256) -> Result<i64> {
599 node_info!("evm_increaseTime");
600 Ok(self.backend.time().increase_time(seconds.try_into().unwrap_or(u64::MAX)) as i64)
601 }
602
603 pub fn evm_set_next_block_timestamp(&self, seconds: u64) -> Result<()> {
607 node_info!("evm_setNextBlockTimestamp");
608 self.backend.time().set_next_block_timestamp(seconds)
609 }
610
611 pub fn evm_set_time(&self, timestamp: u64) -> Result<u64> {
620 node_info!("evm_setTime");
621 let now = self.backend.time().current_call_timestamp();
622 self.backend.time().set_time(timestamp);
623
624 let offset = timestamp.saturating_sub(now);
626 Ok(offset)
627 }
628
629 pub fn evm_set_block_gas_limit(&self, gas_limit: U256) -> Result<bool> {
633 node_info!("evm_setBlockGasLimit");
634 self.backend.set_gas_limit(gas_limit.saturating_to());
635 Ok(true)
636 }
637
638 pub fn evm_set_block_timestamp_interval(&self, seconds: u64) -> Result<()> {
642 node_info!("anvil_setBlockTimestampInterval");
643 self.backend.time().set_block_timestamp_interval(seconds);
644 Ok(())
645 }
646
647 pub fn evm_remove_block_timestamp_interval(&self) -> Result<bool> {
651 node_info!("anvil_removeBlockTimestampInterval");
652 Ok(self.backend.time().remove_block_timestamp_interval())
653 }
654
655 pub async fn anvil_set_rpc_url(&self, url: String) -> Result<()> {
659 node_info!("anvil_setRpcUrl");
660 let _reset = self.reset_lock.lock().await;
661 let staged_fork = if let Some(fork) = self.backend.get_fork() {
662 let mut validation_config = self.backend.node_config.read().await.clone();
663 let (expected_identity, block_number, block_hash) = {
664 let config = fork.config.read();
665 (config.endpoint_identity, config.block_number, config.block_hash)
666 };
667 validation_config.fork_chain_id = None;
670 let (provider, endpoint_identity) = validation_config
671 .replacement_fork_provider(
672 &url,
673 expected_identity,
674 block_number,
675 block_hash,
676 self.instance_id(),
677 )
678 .await?;
679 Some((fork, provider, endpoint_identity))
680 } else {
681 None
682 };
683
684 let _lifecycle = self.lifecycle_lock.write().await;
685 let _mining = self.backend.lock_mining().await;
686 let mut node_config = self.backend.node_config.write().await;
687 if let Some((fork, provider, endpoint_identity)) = staged_fork {
688 let mut config = fork.config.write();
689 trace!(target: "backend", "Updated fork rpc from \"{}\" to \"{}\"", config.eth_rpc_url().map(redact_url).unwrap_or_else(|| "none".to_string()), redact_url(&url));
690 config.provider = provider;
691 config.fork_urls = vec![url.clone()];
692 config.fork_chain_id = None;
693 config.endpoint_identity = endpoint_identity;
694 node_config.fork_endpoint_is_anvil = endpoint_identity.is_authoritative();
695 }
696 node_config.fork_urls = vec![url];
698 node_config.fork_chain_id = None;
699 Ok(())
700 }
701
702 pub async fn txpool_status(&self) -> Result<TxpoolStatus> {
708 node_info!("txpool_status");
709 Ok(self.pool.txpool_status())
710 }
711
712 async fn on_blocking_task<C, F, R>(&self, c: C) -> Result<R>
714 where
715 C: FnOnce(Self) -> F,
716 F: Future<Output = Result<R>> + Send + 'static,
717 R: Send + 'static,
718 {
719 let (tx, rx) = oneshot::channel();
720 let this = self.clone();
721 let f = c(this);
722 tokio::task::spawn_blocking(move || {
723 tokio::runtime::Handle::current().block_on(async move {
724 let res = f.await;
725 let _ = tx.send(res);
726 })
727 });
728 rx.await.map_err(|_| BlockchainError::Internal("blocking task panicked".to_string()))?
729 }
730
731 pub fn set_transaction_order(&self, order: TransactionOrder) {
733 *self.transaction_order.write() = order;
734 }
735
736 pub fn chain_id(&self) -> u64 {
738 self.backend.chain_id().to::<u64>()
739 }
740
741 pub fn get_fork(&self) -> Option<ClientFork> {
743 self.backend.get_fork()
744 }
745
746 pub fn instance_id(&self) -> B256 {
748 *self.instance_id.read()
749 }
750
751 pub fn reset_instance_id(&self) {
753 *self.instance_id.write() = B256::random();
754 }
755
756 #[expect(clippy::borrowed_box)]
758 pub fn get_signer(&self, address: Address) -> Option<&Box<dyn Signer<N>>> {
759 self.signers.iter().find(|signer| signer.is_signer_for(address))
760 }
761
762 pub fn new_ready_transactions(&self) -> Receiver<TxHash> {
764 self.pool.add_ready_listener()
765 }
766
767 pub fn is_fork(&self) -> bool {
769 self.backend.is_fork()
770 }
771
772 pub async fn state_root(&self) -> Option<B256> {
774 self.backend.get_db().read().await.maybe_state_root()
775 }
776
777 pub fn is_impersonated(&self, addr: Address) -> bool {
779 self.backend.cheats().is_impersonated(addr)
780 }
781
782 pub fn storage_info(&self) -> StorageInfo<N> {
784 StorageInfo::new(Arc::clone(&self.backend))
785 }
786
787 #[allow(clippy::large_stack_frames)]
789 pub fn anvil_get_blob_by_versioned_hash(
790 &self,
791 hash: B256,
792 ) -> Result<Option<alloy_consensus::Blob>> {
793 node_info!("anvil_getBlobByHash");
794 Ok(self.backend.get_blob_by_versioned_hash(hash)?)
795 }
796
797 pub fn anvil_get_blobs_by_block_id(
799 &self,
800 block_id: impl Into<BlockId>,
801 versioned_hashes: Vec<B256>,
802 ) -> Result<Option<Vec<Blob>>> {
803 node_info!("anvil_getBlobsByBlockId");
804 Ok(self.backend.get_blobs_by_block_id(block_id, versioned_hashes)?)
805 }
806
807 pub fn anvil_get_genesis_time(&self) -> Result<u64> {
811 node_info!("anvil_getGenesisTime");
812 Ok(self.backend.genesis_time())
813 }
814
815 pub fn anvil_get_last_block_wall_time(&self) -> Result<u64> {
819 node_info!("anvil_getLastBlockWallTime");
820 Ok(self.backend.time().last_block_wall_time())
821 }
822
823 pub async fn anvil_reset(&self, forking: Option<Forking>) -> Result<()> {
829 node_info!("anvil_reset");
830 let _reset = self.reset_lock.lock().await;
831 if let Some(forking) = forking {
832 let staged = self.backend.prepare_fork_reset(forking, self.instance_id()).await?;
833 let _lifecycle = self.lifecycle_lock.write().await;
834 let _mining = self.backend.lock_mining().await;
836 self.backend.commit_fork_reset(staged).await?;
837 self.reset_instance_id();
838 self.pool.clear();
839 self.pool_snapshots.lock().clear();
840 self.fee_history_cache.lock().clear();
841 } else {
842 let _lifecycle = self.lifecycle_lock.write().await;
843 let _mining = self.backend.lock_mining().await;
846 let staged = self.backend.prepare_memory_reset().await?;
847 self.backend.commit_memory_reset(staged).await?;
848 self.reset_instance_id();
849 self.pool.clear();
850 self.pool_snapshots.lock().clear();
851 self.fee_history_cache.lock().clear();
852 }
853 Ok(())
854 }
855
856 pub async fn evm_revert(&self, id: U256) -> Result<bool>
861 where
862 N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log>,
863 {
864 node_info!("evm_revert");
865 let _lifecycle = self.lifecycle_lock.read().await;
866 let _mining = self.backend.lock_mining().await;
867 let reverted = self.backend.revert_state_snapshot(id).await?;
868 if reverted {
869 let pool = {
870 let mut snapshots = self.pool_snapshots.lock();
871 let pool = snapshots.remove(&id);
872 snapshots.retain(|snapshot_id, _| *snapshot_id < id);
873 pool
874 };
875 if let Some(pool) = pool {
876 self.pool.restore(pool);
877 }
878 }
879 Ok(reverted)
880 }
881
882 pub async fn anvil_impersonate_account(&self, address: Address) -> Result<()> {
886 node_info!("anvil_impersonateAccount");
887 self.backend.impersonate(address);
888 Ok(())
889 }
890
891 pub async fn anvil_stop_impersonating_account(&self, address: Address) -> Result<()> {
895 node_info!("anvil_stopImpersonatingAccount");
896 self.backend.stop_impersonating(address);
897 Ok(())
898 }
899
900 pub async fn anvil_auto_impersonate_account(&self, enabled: bool) -> Result<()> {
904 node_info!("anvil_autoImpersonateAccount");
905 self.backend.auto_impersonate_account(enabled);
906 Ok(())
907 }
908
909 pub async fn anvil_impersonate_signature(
911 &self,
912 signature: Bytes,
913 address: Address,
914 ) -> Result<()> {
915 node_info!("anvil_impersonateSignature");
916 self.backend.impersonate_signature(signature, address).await
917 }
918
919 pub fn new_block_notifications(&self) -> ChainNotifications {
922 self.backend.new_block_notifications()
923 }
924
925 pub fn client_version(&self) -> Result<String> {
929 node_info!("web3_clientVersion");
930 Ok(CLIENT_VERSION.to_string())
931 }
932
933 pub fn sha3(&self, bytes: Bytes) -> Result<String> {
937 node_info!("web3_sha3");
938 let hash = alloy_primitives::keccak256(bytes.as_ref());
939 Ok(alloy_primitives::hex::encode_prefixed(&hash[..]))
940 }
941
942 pub fn protocol_version(&self) -> Result<u64> {
946 node_info!("eth_protocolVersion");
947 Ok(1)
948 }
949
950 pub fn hashrate(&self) -> Result<U256> {
954 node_info!("eth_hashrate");
955 Ok(U256::ZERO)
956 }
957
958 pub fn author(&self) -> Result<Address> {
962 node_info!("eth_coinbase");
963 Ok(self.backend.coinbase())
964 }
965
966 pub fn is_mining(&self) -> Result<bool> {
970 node_info!("eth_mining");
971 Ok(self.is_mining)
972 }
973
974 pub fn eth_chain_id(&self) -> Result<Option<U64>> {
980 node_info!("eth_chainId");
981 Ok(Some(self.backend.chain_id().to::<U64>()))
982 }
983
984 pub fn network_id(&self) -> Result<Option<String>> {
988 node_info!("eth_networkId");
989 let chain_id = self.backend.chain_id().to::<u64>();
990 Ok(Some(format!("{chain_id}")))
991 }
992
993 pub fn net_listening(&self) -> Result<bool> {
997 node_info!("net_listening");
998 Ok(self.net_listening)
999 }
1000
1001 fn eth_gas_price(&self) -> Result<U256> {
1003 node_info!("eth_gasPrice");
1004 Ok(U256::from(self.gas_price()))
1005 }
1006
1007 pub fn base_fee(&self) -> Result<Option<U256>> {
1011 node_info!("eth_baseFee");
1012 Ok(self.backend.is_eip1559().then(|| U256::from(self.backend.base_fee())))
1013 }
1014
1015 pub fn excess_blob_gas_and_price(&self) -> Result<Option<BlobExcessGasAndPrice>> {
1017 Ok(self.backend.excess_blob_gas_and_price())
1018 }
1019
1020 pub fn gas_max_priority_fee_per_gas(&self) -> Result<U256> {
1025 self.max_priority_fee_per_gas()
1026 }
1027
1028 pub fn blob_base_fee(&self) -> Result<U256> {
1032 Ok(U256::from(self.backend.fees().base_fee_per_blob_gas()))
1033 }
1034
1035 pub fn gas_limit(&self) -> U256 {
1037 U256::from(self.backend.gas_limit())
1038 }
1039
1040 pub fn accounts(&self) -> Result<Vec<Address>> {
1044 node_info!("eth_accounts");
1045 let mut unique = AddressSet::default();
1046 let mut accounts: Vec<Address> = Vec::new();
1047 for signer in self.signers.iter() {
1048 accounts.extend(signer.accounts().into_iter().filter(|acc| unique.insert(*acc)));
1049 }
1050 accounts.extend(
1051 self.backend
1052 .cheats()
1053 .impersonated_accounts()
1054 .into_iter()
1055 .filter(|acc| unique.insert(*acc)),
1056 );
1057 Ok(accounts.into_iter().collect())
1058 }
1059
1060 pub fn block_number(&self) -> Result<U256> {
1064 node_info!("eth_blockNumber");
1065 Ok(U256::from(self.backend.best_number()))
1066 }
1067
1068 pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
1072 node_info!("eth_getBlockByHash");
1073 self.backend.block_by_hash(hash).await
1074 }
1075
1076 pub async fn header_by_hash(
1080 &self,
1081 hash: B256,
1082 ) -> Result<Option<WithOtherFields<AnyRpcHeader>>> {
1083 node_info!("eth_getHeaderByHash");
1084 Ok(self.backend.block_by_hash(hash).await?.map(|block| {
1085 let WithOtherFields { inner: block, other } = block.0;
1086 WithOtherFields { inner: block.header, other }
1087 }))
1088 }
1089
1090 pub async fn block_by_hash_full(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
1094 node_info!("eth_getBlockByHash");
1095 self.backend.block_by_hash_full(hash).await
1096 }
1097
1098 pub async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
1102 node_info!("eth_getBlockTransactionCountByHash");
1103 let block = self.backend.block_by_hash(hash).await?;
1104 let txs = block.map(|b| match b.transactions() {
1105 BlockTransactions::Full(txs) => U256::from(txs.len()),
1106 BlockTransactions::Hashes(txs) => U256::from(txs.len()),
1107 BlockTransactions::Uncle => U256::ZERO,
1108 });
1109 Ok(txs)
1110 }
1111
1112 pub async fn block_uncles_count_by_hash(&self, hash: B256) -> Result<U256> {
1116 node_info!("eth_getUncleCountByBlockHash");
1117 let block =
1118 self.backend.block_by_hash(hash).await?.ok_or(BlockchainError::BlockNotFound)?;
1119 Ok(U256::from(block.uncles.len()))
1120 }
1121
1122 pub async fn block_uncles_count_by_number(&self, block_number: BlockNumber) -> Result<U256> {
1126 node_info!("eth_getUncleCountByBlockNumber");
1127 let block = self
1128 .backend
1129 .block_by_number(block_number)
1130 .await?
1131 .ok_or(BlockchainError::BlockNotFound)?;
1132 Ok(U256::from(block.uncles.len()))
1133 }
1134
1135 pub async fn sign_typed_data(
1139 &self,
1140 _address: Address,
1141 _data: serde_json::Value,
1142 ) -> Result<String> {
1143 node_info!("eth_signTypedData");
1144 Err(BlockchainError::RpcUnimplemented)
1145 }
1146
1147 pub async fn sign_typed_data_v3(
1151 &self,
1152 _address: Address,
1153 _data: serde_json::Value,
1154 ) -> Result<String> {
1155 node_info!("eth_signTypedData_v3");
1156 Err(BlockchainError::RpcUnimplemented)
1157 }
1158
1159 pub async fn sign_typed_data_v4(&self, address: Address, data: &TypedData) -> Result<String> {
1163 node_info!("eth_signTypedData_v4");
1164 let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
1165 let signature = signer.sign_typed_data(address, data).await?;
1166 let signature = alloy_primitives::hex::encode(signature.as_bytes());
1167 Ok(format!("0x{signature}"))
1168 }
1169
1170 pub async fn sign(&self, address: Address, content: impl AsRef<[u8]>) -> Result<String> {
1174 node_info!("eth_sign");
1175 let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
1176 let signature =
1177 alloy_primitives::hex::encode(signer.sign(address, content.as_ref()).await?.as_bytes());
1178 Ok(format!("0x{signature}"))
1179 }
1180
1181 pub async fn transaction_by_block_hash_and_index(
1185 &self,
1186 hash: B256,
1187 index: Index,
1188 ) -> Result<Option<AnyRpcTransaction>> {
1189 node_info!("eth_getTransactionByBlockHashAndIndex");
1190 self.backend.transaction_by_block_hash_and_index(hash, index).await
1191 }
1192
1193 pub async fn uncle_by_block_hash_and_index(
1197 &self,
1198 block_hash: B256,
1199 idx: Index,
1200 ) -> Result<Option<AnyRpcBlock>> {
1201 node_info!("eth_getUncleByBlockHashAndIndex");
1202 let number = self.backend.ensure_block_number(Some(BlockId::hash(block_hash))).await?;
1203 if let Some(fork) = self.get_fork()
1204 && fork.predates_fork_inclusive(number)
1205 {
1206 return Ok(fork.uncle_by_block_hash_and_index(block_hash, idx.into()).await?);
1207 }
1208 Ok(None)
1210 }
1211
1212 pub async fn uncle_by_block_number_and_index(
1216 &self,
1217 block_number: BlockNumber,
1218 idx: Index,
1219 ) -> Result<Option<AnyRpcBlock>> {
1220 node_info!("eth_getUncleByBlockNumberAndIndex");
1221 let number = self.backend.ensure_block_number(Some(BlockId::Number(block_number))).await?;
1222 if let Some(fork) = self.get_fork()
1223 && fork.predates_fork_inclusive(number)
1224 {
1225 return Ok(fork.uncle_by_block_number_and_index(number, idx.into()).await?);
1226 }
1227 Ok(None)
1229 }
1230
1231 pub fn work(&self) -> Result<Work> {
1235 node_info!("eth_getWork");
1236 Err(BlockchainError::RpcUnimplemented)
1237 }
1238
1239 pub fn syncing(&self) -> Result<bool> {
1243 node_info!("eth_syncing");
1244 Ok(false)
1245 }
1246
1247 pub fn config(&self) -> Result<EthConfig> {
1258 node_info!("eth_config");
1259 Ok(EthConfig {
1260 current: EthForkConfig {
1261 activation_time: 0,
1262 blob_schedule: self.backend.blob_params(),
1263 chain_id: self.backend.chain_id().to::<u64>(),
1264 fork_id: Bytes::from_static(&[0; 4]),
1265 precompiles: self.backend.precompiles(),
1266 system_contracts: self.backend.system_contracts(),
1267 },
1268 next: None,
1269 last: None,
1270 })
1271 }
1272
1273 pub fn submit_work(&self, _: B64, _: B256, _: B256) -> Result<bool> {
1277 node_info!("eth_submitWork");
1278 Err(BlockchainError::RpcUnimplemented)
1279 }
1280
1281 pub fn submit_hashrate(&self, _: U256, _: B256) -> Result<bool> {
1285 node_info!("eth_submitHashrate");
1286 Err(BlockchainError::RpcUnimplemented)
1287 }
1288
1289 pub async fn fee_history(
1293 &self,
1294 block_count: U256,
1295 newest_block: BlockNumber,
1296 reward_percentiles: Vec<f64>,
1297 ) -> Result<FeeHistory>
1298 where
1299 N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log>,
1300 {
1301 node_info!("eth_feeHistory");
1302
1303 if reward_percentiles.iter().any(|p| !(0.0..=100.0).contains(p))
1304 || reward_percentiles.windows(2).any(|pair| pair[0] >= pair[1])
1305 {
1306 return Err(FeeHistoryError::InvalidRewardPercentiles.into());
1307 }
1308 if block_count.is_zero() {
1309 return Ok(FeeHistory::default());
1310 }
1311
1312 let number = self.backend.convert_block_number(Some(newest_block));
1315
1316 let fork = self.get_fork();
1321 let fork_block = fork.as_ref().map(|fork| fork.block_number());
1322
1323 if let (Some(fork), Some(fork_block)) = (fork.as_ref(), fork_block) {
1325 if number <= fork_block {
1328 return fork
1329 .fee_history(block_count.to(), BlockNumber::Number(number), &reward_percentiles)
1330 .await
1331 .map_err(BlockchainError::AlloyForkProvider);
1332 }
1333 }
1334
1335 const MAX_BLOCK_COUNT: u64 = 1024u64;
1336 let block_count = block_count.saturating_to::<u64>().min(MAX_BLOCK_COUNT);
1337
1338 let highest = number;
1340 let lowest = highest.saturating_sub(block_count.saturating_sub(1));
1341
1342 if lowest < self.backend.best_number().saturating_sub(self.fee_history_limit) {
1344 return Err(FeeHistoryError::InvalidBlockRange.into());
1345 }
1346
1347 let mut response = FeeHistory {
1348 oldest_block: lowest,
1349 base_fee_per_gas: Vec::new(),
1350 gas_used_ratio: Vec::new(),
1351 reward: Some(Default::default()),
1352 base_fee_per_blob_gas: Default::default(),
1353 blob_gas_used_ratio: Default::default(),
1354 };
1355 let mut rewards = Vec::new();
1356
1357 let local_lowest = if let (Some(fork), Some(fork_block)) = (fork.as_ref(), fork_block) {
1364 if lowest <= fork_block {
1365 let count_pre = fork_block - lowest + 1;
1366 let pre = fork
1367 .fee_history(count_pre, BlockNumber::Number(fork_block), &reward_percentiles)
1368 .await
1369 .map_err(BlockchainError::AlloyForkProvider)?;
1370 merge_pre_fork_fee_history(&mut response, &mut rewards, pre, fork_block);
1371 fork_block + 1
1373 } else {
1374 lowest
1375 }
1376 } else {
1377 lowest
1378 };
1379
1380 {
1381 let storage_info = self.storage_info();
1382 let blob_params = self.backend.blob_params();
1383
1384 let cached: Vec<Option<FeeHistoryCacheItem>> = {
1388 let cache = self.fee_history_cache.lock();
1389 (local_lowest..=highest).map(|n| cache.get(&n).cloned()).collect()
1390 };
1391
1392 let mut warmed: Vec<(u64, FeeHistoryCacheItem)> = Vec::new();
1398 let mut items: Vec<FeeHistoryCacheItem> = Vec::with_capacity(cached.len());
1399 for (cached_item, n) in cached.into_iter().zip(local_lowest..=highest) {
1400 let hash = self
1401 .backend
1402 .block_hash_by_number(n)
1403 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1404 let item = match cached_item {
1405 Some(item) if item.block_hash == hash => item,
1406 _ => {
1407 let block = self
1408 .backend
1409 .get_block_by_hash(hash)
1410 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1411 let header = block.header;
1412 let (item, block_number) = create_fee_history_cache_item(
1413 hash,
1414 &header,
1415 &storage_info,
1416 blob_params,
1417 );
1418 let block_number = block_number
1422 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1423 warmed.push((block_number, item.clone()));
1424 item
1425 }
1426 };
1427 items.push(item);
1428 }
1429
1430 if !warmed.is_empty() {
1433 let mut cache = self.fee_history_cache.lock();
1434 for (block_number, item) in warmed {
1435 cache.insert(block_number, item);
1436 }
1437 while cache.len() as u64 > self.fee_history_limit {
1438 cache.pop_first();
1439 }
1440 }
1441
1442 for item in items {
1443 response.base_fee_per_gas.push(item.base_fee);
1444 response.base_fee_per_blob_gas.push(item.base_fee_per_blob_gas.unwrap_or(0));
1445 response.blob_gas_used_ratio.push(item.blob_gas_used_ratio);
1446 response.gas_used_ratio.push(item.gas_used_ratio);
1447
1448 if !reward_percentiles.is_empty() {
1450 let mut block_rewards = Vec::new();
1451 for p in &reward_percentiles {
1452 block_rewards.push(reward_at_percentile(&item.rewards, *p));
1453 }
1454 rewards.push(block_rewards);
1455 }
1456 }
1457 }
1458
1459 response.reward = Some(rewards);
1460
1461 let next_number = highest
1466 .checked_add(1)
1467 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(highest)))?;
1468 let (next_base_fee, next_blob_base_fee) = self
1469 .backend
1470 .fee_history_next_fees(highest)
1471 .await
1472 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(next_number)))?;
1473 response.base_fee_per_gas.push(next_base_fee);
1474 response.base_fee_per_blob_gas.push(next_blob_base_fee);
1475
1476 Ok(response)
1477 }
1478
1479 pub fn max_priority_fee_per_gas(&self) -> Result<U256> {
1486 node_info!("eth_maxPriorityFeePerGas");
1487 Ok(U256::from(self.lowest_suggestion_tip()))
1488 }
1489
1490 pub async fn debug_code_by_hash(
1494 &self,
1495 hash: B256,
1496 block_id: Option<BlockId>,
1497 ) -> Result<Option<Bytes>> {
1498 node_info!("debug_codeByHash");
1499 self.backend.debug_code_by_hash(hash, block_id).await
1500 }
1501
1502 pub async fn debug_db_get(&self, key: String) -> Result<Option<Bytes>> {
1507 node_info!("debug_dbGet");
1508 self.backend.debug_db_get(key).await
1509 }
1510
1511 pub fn debug_get_modified_accounts_by_number(
1513 &self,
1514 _start_number: u64,
1515 _end_number: u64,
1516 ) -> Result<()> {
1517 node_info!("debug_getModifiedAccountsByNumber");
1518 Ok(())
1519 }
1520
1521 pub fn debug_free_os_memory(&self) -> Result<()> {
1523 node_info!("debug_freeOSMemory");
1524 Ok(())
1525 }
1526
1527 pub async fn trace_call(
1531 &self,
1532 request: WithOtherFields<TransactionRequest>,
1533 trace_types: HashSet<TraceType>,
1534 block_id: Option<BlockId>,
1535 ) -> Result<TraceResults>
1536 where
1537 N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope>,
1538 {
1539 node_info!("trace_call");
1540 let block_id = block_id.unwrap_or_default();
1541 let block_request = match &block_id {
1542 BlockId::Number(BlockNumber::Pending) => {
1543 let pending_txs = self.pool.ready_transactions().collect();
1544 BlockRequest::Pending(pending_txs)
1545 }
1546 _ => {
1547 let number = self.backend.ensure_block_number(Some(block_id)).await?;
1548 BlockRequest::Number(number)
1549 }
1550 };
1551 let inner = request.as_ref();
1552 let fees = FeeDetails::new(
1553 inner.gas_price,
1554 inner.max_fee_per_gas,
1555 inner.max_priority_fee_per_gas,
1556 inner.max_fee_per_blob_gas,
1557 )?
1558 .or_zero_fees();
1559
1560 self.backend.trace_call(request, fees, trace_types, block_request, block_id).await
1561 }
1562
1563 pub async fn trace_transaction(
1567 &self,
1568 tx_hash: B256,
1569 ) -> Result<Option<Vec<LocalizedTransactionTrace>>> {
1570 node_info!("trace_transaction");
1571 self.backend.trace_transaction(tx_hash).await
1572 }
1573
1574 pub async fn trace_block(&self, block: BlockNumber) -> Result<Vec<LocalizedTransactionTrace>> {
1578 node_info!("trace_block");
1579 self.backend.trace_block(block).await
1580 }
1581
1582 pub async fn trace_filter(
1586 &self,
1587 filter: TraceFilter,
1588 ) -> Result<Vec<LocalizedTransactionTrace>> {
1589 node_info!("trace_filter");
1590 self.backend.trace_filter(filter).await
1591 }
1592
1593 pub async fn trace_get(
1597 &self,
1598 hash: B256,
1599 indices: Vec<Index>,
1600 ) -> Result<Option<LocalizedTransactionTrace>> {
1601 node_info!("trace_get");
1602 self.backend.trace_get(hash, indices).await
1603 }
1604
1605 pub async fn trace_replay_block_transactions(
1609 &self,
1610 block: BlockNumber,
1611 trace_types: HashSet<TraceType>,
1612 ) -> Result<Option<Vec<TraceResultsWithTransactionHash>>> {
1613 node_info!("trace_replayBlockTransactions");
1614 self.backend.trace_replay_block_transactions(block, trace_types).await
1615 }
1616
1617 pub async fn trace_replay_transaction(
1621 &self,
1622 transaction: B256,
1623 trace_types: HashSet<TraceType>,
1624 ) -> Result<Option<TraceResultsWithTransactionHash>> {
1625 node_info!("trace_replayTransaction");
1626 self.backend.trace_replay_transaction(transaction, trace_types).await
1627 }
1628}
1629
1630impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> EthApi<N> {
1631 pub async fn serialized_state(
1633 &self,
1634 preserve_historical_states: bool,
1635 ) -> Result<SerializableState> {
1636 self.backend.serialized_state(preserve_historical_states).await
1637 }
1638}
1639
1640impl EthApi<FoundryNetwork> {
1643 pub async fn transaction_by_block_number_and_index(
1647 &self,
1648 block: BlockNumber,
1649 idx: Index,
1650 ) -> Result<Option<AnyRpcTransaction>> {
1651 node_info!("eth_getTransactionByBlockNumberAndIndex");
1652 if block.is_pending() {
1653 return Ok(self.pending_block_full().await?.and_then(|block| {
1654 let WithOtherFields { inner: block, .. } = block.0;
1655 block.transactions.into_transactions().nth(idx.into())
1656 }));
1657 }
1658
1659 self.backend.transaction_by_block_number_and_index(block, idx).await
1660 }
1661
1662 pub async fn anvil_dump_state(
1667 &self,
1668 preserve_historical_states: Option<bool>,
1669 ) -> Result<Bytes> {
1670 node_info!("anvil_dumpState");
1671 self.backend.dump_state(preserve_historical_states.unwrap_or(false)).await
1672 }
1673
1674 pub async fn anvil_load_state(&self, buf: Bytes) -> Result<bool> {
1679 node_info!("anvil_loadState");
1680 let loaded = self.backend.load_state_bytes(buf).await?;
1681 #[cfg(feature = "base")]
1682 if loaded {
1683 self.invalidate_base_eip8130_pool();
1684 }
1685 Ok(loaded)
1686 }
1687
1688 async fn block_request(
1689 &self,
1690 block_number: Option<BlockId>,
1691 ) -> Result<BlockRequest<FoundryTxEnvelope>> {
1692 let block_request = match block_number {
1693 Some(BlockId::Number(BlockNumber::Pending)) => {
1694 let pending_txs = self.pool.ready_transactions().collect();
1695 BlockRequest::Pending(pending_txs)
1696 }
1697 _ => {
1698 let number = self.backend.ensure_block_number(block_number).await?;
1699 BlockRequest::Number(number)
1700 }
1701 };
1702 Ok(block_request)
1703 }
1704
1705 pub async fn debug_account_info_at(
1709 &self,
1710 block_id: BlockId,
1711 tx_index: Index,
1712 address: Address,
1713 ) -> Result<Option<AccountInfo>> {
1714 node_info!("debug_accountInfoAt");
1715 self.backend.debug_account_info_at(block_id, tx_index, address).await
1716 }
1717
1718 pub async fn debug_execution_witness(&self, block: BlockNumber) -> Result<ExecutionWitness> {
1724 node_info!("debug_executionWitness");
1725 self.backend.debug_execution_witness(block).await
1726 }
1727
1728 pub async fn trace_transaction_opcode_gas(
1732 &self,
1733 tx_hash: B256,
1734 ) -> Result<Option<TransactionOpcodeGas>> {
1735 node_info!("trace_transactionOpcodeGas");
1736 self.backend.trace_transaction_opcode_gas(tx_hash).await
1737 }
1738
1739 pub async fn trace_block_opcode_gas(
1743 &self,
1744 block_id: BlockId,
1745 ) -> Result<Option<BlockOpcodeGas>> {
1746 node_info!("trace_blockOpcodeGas");
1747 self.backend.trace_block_opcode_gas(block_id).await
1748 }
1749
1750 pub async fn trace_raw_transaction(
1754 &self,
1755 tx: Bytes,
1756 trace_types: HashSet<TraceType>,
1757 block_number: Option<BlockId>,
1758 ) -> Result<TraceResults> {
1759 node_info!("trace_rawTransaction");
1760
1761 let mut data = tx.as_ref();
1762 if data.is_empty() {
1763 return Err(BlockchainError::EmptyRawTransactionData);
1764 }
1765
1766 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
1767 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
1768 self.ensure_typed_transaction_supported(&transaction)?;
1769
1770 #[cfg(feature = "base")]
1771 let is_eip8130 = transaction.is_eip8130();
1772 let pending_transaction = PendingTransaction::new(transaction).map_err(|error| {
1773 #[cfg(feature = "base")]
1774 if is_eip8130 {
1775 return BlockchainError::Eip8130TransactionRejected(error.to_string());
1776 }
1777 BlockchainError::RecoveryError(error)
1778 })?;
1779 let block_request = self.block_request(block_number).await?;
1780
1781 self.backend
1782 .trace_raw_transaction(pending_transaction, trace_types, Some(block_request))
1783 .await
1784 }
1785
1786 pub async fn anvil_add_balance(&self, address: Address, balance: U256) -> Result<()> {
1790 node_info!("anvil_addBalance");
1791 self.backend.add_balance(address, balance).await?;
1792 Ok(())
1793 }
1794
1795 async fn rollback_block(&self, number: u64) -> Result<Option<Block>> {
1798 if let Some(block) = self.backend.get_block(number) {
1799 return Ok(Some(block));
1800 }
1801 #[cfg(feature = "monad")]
1802 {
1803 if self.backend.is_monad() {
1804 self.backend.monad_rollback_block(number).await
1805 } else {
1806 Ok(None)
1807 }
1808 }
1809 #[cfg(not(feature = "monad"))]
1810 {
1811 Ok(None)
1812 }
1813 }
1814
1815 async fn rollback_backend(
1817 &self,
1818 common_block: Block,
1819 mining_guard: &tokio::sync::MutexGuard<'_, ()>,
1820 ) -> Result<()> {
1821 #[cfg(feature = "monad")]
1822 if self.backend.is_monad() {
1823 return self.backend.rollback_monad(common_block, mining_guard).await;
1824 }
1825 self.backend.rollback(common_block, mining_guard).await
1826 }
1827
1828 pub async fn anvil_rollback(&self, depth: Option<u64>) -> Result<()> {
1839 node_info!("anvil_rollback");
1840 let _lifecycle = self.lifecycle_lock.write().await;
1841 let mining_guard = self.backend.lock_mining().await;
1842 let depth = depth.unwrap_or(1);
1843
1844 let current_height = self.backend.best_number();
1846 let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(
1847 RpcError::invalid_params(format!(
1848 "Rollback depth must not exceed current chain height: current height {current_height}, depth {depth}"
1849 )),
1850 ))?;
1851
1852 let common_block =
1854 self.rollback_block(common_height).await?.ok_or(BlockchainError::BlockNotFound)?;
1855
1856 self.rollback_backend(common_block, &mining_guard).await?;
1857 Ok(())
1858 }
1859
1860 fn do_estimate_gas_with_state(
1864 &self,
1865 mut request: FoundryTransactionRequest,
1866 state: &dyn DatabaseRef,
1867 block_env: BlockEnv,
1868 monad_context: Option<MonadReplayContext>,
1869 ) -> Result<u128> {
1870 if request.as_ref().blob_versioned_hashes.is_none() {
1873 request.as_mut().populate_blob_hashes();
1874 }
1875 let inner = request.as_ref();
1876 let fees = FeeDetails::new(
1877 inner.gas_price,
1878 inner.max_fee_per_gas,
1879 inner.max_priority_fee_per_gas,
1880 inner.max_fee_per_blob_gas,
1881 )?
1882 .or_zero_fees();
1883
1884 #[cfg(feature = "base")]
1885 if self.backend.is_base() && request.is_base() {
1886 self.backend.ensure_base_eip8130_active_at(block_env.timestamp.saturating_to())?;
1887 let gas_limit = block_env.gas_limit;
1888 let result = self
1889 .backend
1890 .call_with_state_typed_gas_limit(
1891 state,
1892 request,
1893 fees,
1894 block_env,
1895 GasEstimateCallOptions::new(gas_limit, false, monad_context),
1896 )
1897 .try_into()?;
1898 return match result {
1899 GasEstimationCallResult::Success(gas) => Ok(gas),
1900 GasEstimationCallResult::OutOfGas => {
1901 Err(InvalidTransactionError::BasicOutOfGas(u128::from(gas_limit)).into())
1902 }
1903 GasEstimationCallResult::Revert(output) => {
1904 Err(InvalidTransactionError::Revert(output).into())
1905 }
1906 GasEstimationCallResult::EvmError(error) => Err(BlockchainError::EvmError(error)),
1907 };
1908 }
1909
1910 let mut highest_gas_limit = inner.gas.map_or(block_env.gas_limit.into(), |g| g as u128);
1913
1914 let is_tempo_aa_tx = self.backend.is_tempo() && request.is_tempo();
1917 let is_tempo_keychain = matches!(
1918 &request,
1919 FoundryTransactionRequest::Tempo(request) if request.key_id.is_some()
1920 );
1921 let disable_fee_charge = is_tempo_keychain || inner.from.is_none();
1922
1923 let mut funded_state;
1927 let state = if !is_tempo_aa_tx
1928 && inner.from.is_none()
1929 && let Some(value) = inner.value
1930 && !value.is_zero()
1931 {
1932 funded_state = CacheDB::new(state);
1933 let mut caller = state.basic_ref(Address::ZERO)?.unwrap_or_default();
1934 caller.balance = caller.balance.max(value);
1935 funded_state.insert_account_info(Address::ZERO, caller);
1936 &funded_state as &dyn DatabaseRef
1937 } else {
1938 state
1939 };
1940
1941 let gas_price = fees.gas_price.unwrap_or_default();
1942 if !is_tempo_aa_tx && let Some(from) = inner.from {
1947 let mut available_funds = self.backend.get_balance_with_state(state, from)?;
1948 if let Some(value) = inner.value {
1949 if value > available_funds {
1950 return Err(InvalidTransactionError::InsufficientFunds.into());
1951 }
1952 available_funds -= value;
1954 }
1955 if gas_price > 0 {
1956 if inner.minimal_tx_type().is_eip4844()
1959 && let Some(hashes) = &inner.blob_versioned_hashes
1960 {
1961 let max_fee_per_blob_gas = fees.max_fee_per_blob_gas.unwrap_or_default();
1962 let blob_gas = U256::from(hashes.len() as u64 * DATA_GAS_PER_BLOB);
1963 let blob_cost = blob_gas.saturating_mul(U256::from(max_fee_per_blob_gas));
1964 if blob_cost >= available_funds {
1965 return Err(InvalidTransactionError::InsufficientFunds.into());
1966 }
1967 available_funds -= blob_cost;
1968 }
1969 let allowance =
1971 available_funds.checked_div(U256::from(gas_price)).unwrap_or_default();
1972 highest_gas_limit = std::cmp::min(highest_gas_limit, allowance.saturating_to());
1973 }
1974 }
1975
1976 if !self.backend.is_tempo() {
1981 let to = inner.to.as_ref().and_then(TxKind::to);
1982
1983 let maybe_transfer = (inner.input.input().is_none()
1985 || inner.input.input().is_some_and(|data| data.is_empty()))
1986 && inner.authorization_list.is_none()
1987 && inner.access_list.is_none()
1988 && inner.blob_versioned_hashes.is_none();
1989
1990 if maybe_transfer
1991 && let Some(to) = to
1992 && !self.backend.is_precompile(to, &block_env)
1993 && let Ok(target_code) = self.backend.get_code_with_state(&state, *to)
1994 && target_code.as_ref().is_empty()
1995 {
1996 let probe = self.backend.call_with_state_typed_gas_limit(
2001 &state,
2002 request.clone(),
2003 fees.clone(),
2004 block_env.clone(),
2005 GasEstimateCallOptions::new(
2006 highest_gas_limit.min(MIN_TRANSACTION_GAS) as u64,
2007 disable_fee_charge,
2008 monad_context.clone(),
2009 ),
2010 );
2011 if let Ok(GasEstimationCallResult::Success(gas)) = probe.try_into() {
2012 return Ok(gas);
2013 }
2014 }
2015 }
2016
2017 let ethres = self.backend.call_with_state_typed_gas_limit(
2019 &state,
2020 request.clone(),
2021 fees.clone(),
2022 block_env.clone(),
2023 GasEstimateCallOptions::new(
2024 highest_gas_limit as u64,
2025 disable_fee_charge,
2026 monad_context.clone(),
2027 ),
2028 );
2029
2030 let gas_used = match ethres.try_into()? {
2031 GasEstimationCallResult::Success(gas) => Ok(gas),
2032 GasEstimationCallResult::OutOfGas => {
2033 Err(InvalidTransactionError::BasicOutOfGas(highest_gas_limit).into())
2034 }
2035 GasEstimationCallResult::Revert(output) => {
2036 Err(InvalidTransactionError::Revert(output).into())
2037 }
2038 GasEstimationCallResult::EvmError(err) => {
2039 warn!(target: "node", "estimation failed due to {:?}", err);
2040 Err(BlockchainError::EvmError(err))
2041 }
2042 }?;
2043
2044 let mut lowest_gas_limit = gas_used.saturating_sub(1);
2052
2053 let mut mid_gas_limit =
2055 std::cmp::min(gas_used * 3, (highest_gas_limit + lowest_gas_limit) / 2);
2056
2057 while lowest_gas_limit + 1 < highest_gas_limit {
2059 let ethres = self.backend.call_with_state_typed_gas_limit(
2060 &state,
2061 request.clone(),
2062 fees.clone(),
2063 block_env.clone(),
2064 GasEstimateCallOptions::new(
2065 mid_gas_limit as u64,
2066 disable_fee_charge,
2067 monad_context.clone(),
2068 ),
2069 );
2070
2071 match ethres.try_into()? {
2072 GasEstimationCallResult::Success(_) => {
2073 highest_gas_limit = mid_gas_limit;
2077 }
2078 GasEstimationCallResult::OutOfGas
2079 | GasEstimationCallResult::Revert(_)
2080 | GasEstimationCallResult::EvmError(_) => {
2081 lowest_gas_limit = mid_gas_limit;
2088 }
2089 };
2090 mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
2092 }
2093
2094 trace!(target : "node", "Estimated Gas for call {:?}", highest_gas_limit);
2095
2096 Ok(highest_gas_limit)
2097 }
2098
2099 #[allow(clippy::large_stack_frames)]
2101 pub async fn execute(&self, request: EthRequest) -> ResponseResult {
2102 trace!(target: "rpc::api", "executing eth request");
2103 let _lifecycle = if matches!(
2108 &request,
2109 EthRequest::Reset(_)
2110 | EthRequest::SetRpcUrl(_)
2111 | EthRequest::NodeInfo(_)
2112 | EthRequest::AnvilMetadata(_)
2113 | EthRequest::EvmSnapshot(_)
2114 | EthRequest::EvmRevert(_)
2115 | EthRequest::Reorg(_)
2116 | EthRequest::Rollback(_)
2117 ) {
2118 None
2119 } else {
2120 Some(self.lifecycle_lock.read().await)
2121 };
2122 let response = match request.clone() {
2123 EthRequest::EthProtocolVersion(()) => self.protocol_version().to_rpc_result(),
2124 EthRequest::Web3ClientVersion(()) => self.client_version().to_rpc_result(),
2125 EthRequest::Web3Sha3(content) => self.sha3(content).to_rpc_result(),
2126 EthRequest::EthGetAccount(addr, block) => {
2127 self.get_account(addr, block).await.to_rpc_result()
2128 }
2129 EthRequest::EthGetAccountInfo(addr, block) => {
2130 self.get_account_info(addr, block).await.to_rpc_result()
2131 }
2132 EthRequest::EthGetBalance(addr, block) => {
2133 self.balance(addr, block).await.to_rpc_result()
2134 }
2135 EthRequest::EthGetTransactionByHash(hash) => {
2136 self.transaction_by_hash(hash).await.to_rpc_result()
2137 }
2138 EthRequest::EthPendingTransactions(_) => {
2139 self.pending_transactions().await.to_rpc_result()
2140 }
2141 EthRequest::EthSendTransaction(request) => {
2142 self.send_transaction(*request).await.to_rpc_result()
2143 }
2144 EthRequest::EthResend(request, gas_price, gas_limit) => {
2145 self.resend_transaction(*request, gas_price, gas_limit).await.to_rpc_result()
2146 }
2147 EthRequest::EthSendTransactionSync(request) => {
2148 self.send_transaction_sync(*request).await.to_rpc_result()
2149 }
2150 EthRequest::EthChainId(_) => self.eth_chain_id().to_rpc_result(),
2151 EthRequest::EthNetworkId(_) => self.network_id().to_rpc_result(),
2152 EthRequest::NetListening(_) => self.net_listening().to_rpc_result(),
2153 EthRequest::EthHashrate(()) => self.hashrate().to_rpc_result(),
2154 EthRequest::EthGasPrice(_) => self.eth_gas_price().to_rpc_result(),
2155 EthRequest::EthBaseFee(_) => self.base_fee().to_rpc_result(),
2156 EthRequest::EthMaxPriorityFeePerGas(_) => {
2157 self.gas_max_priority_fee_per_gas().to_rpc_result()
2158 }
2159 EthRequest::EthBlobBaseFee(_) => self.blob_base_fee().to_rpc_result(),
2160 EthRequest::EthAccounts(_) => self.accounts().to_rpc_result(),
2161 EthRequest::EthBlockNumber(_) => self.block_number().to_rpc_result(),
2162 EthRequest::EthCoinbase(()) => self.author().to_rpc_result(),
2163 EthRequest::EthGetStorageAt(addr, slot, block) => {
2164 self.storage_at(addr, slot, block).await.to_rpc_result()
2165 }
2166 EthRequest::EthGetStorageValues(requests, block) => {
2167 self.storage_values(requests, block).await.to_rpc_result()
2168 }
2169 EthRequest::EthGetBlockByHash(hash, full) => {
2170 if full {
2171 self.block_by_hash_full(hash).await.to_rpc_result()
2172 } else {
2173 self.block_by_hash(hash).await.to_rpc_result()
2174 }
2175 }
2176 EthRequest::EthGetHeaderByHash(hash) => self.header_by_hash(hash).await.to_rpc_result(),
2177 EthRequest::EthGetBlockByNumber(num, full) => {
2178 if full {
2179 self.block_by_number_full(num).await.to_rpc_result()
2180 } else {
2181 self.block_by_number(num).await.to_rpc_result()
2182 }
2183 }
2184 EthRequest::EthGetHeaderByNumber(num) => {
2185 self.header_by_number(num).await.to_rpc_result()
2186 }
2187 EthRequest::EthGetBlockAccessList(block_id) => {
2188 self.block_access_list(block_id).await.to_rpc_result()
2189 }
2190 EthRequest::EthGetBlockAccessListByBlockHash(block_hash) => {
2191 self.block_access_list_by_hash(block_hash).await.to_rpc_result()
2192 }
2193 EthRequest::EthGetBlockAccessListByBlockNumber(block_number) => {
2194 self.block_access_list_by_number(block_number).await.to_rpc_result()
2195 }
2196 EthRequest::EthGetBlockAccessListRaw(block_id) => {
2197 self.block_access_list_raw(block_id).await.to_rpc_result()
2198 }
2199 EthRequest::EthGetTransactionCount(params) => {
2200 let (address, block, nonce_key) = params.into_parts();
2201 #[cfg(feature = "base")]
2202 {
2203 self.transaction_count_with_key(address, block, nonce_key).await.to_rpc_result()
2204 }
2205 #[cfg(not(feature = "base"))]
2206 {
2207 if nonce_key.is_some() {
2208 return ResponseResult::Error(RpcError::invalid_params(
2209 "nonce-key transaction counts require Base support",
2210 ));
2211 }
2212 self.transaction_count(address, block).await.to_rpc_result()
2213 }
2214 }
2215 EthRequest::EthGetTransactionCountByHash(hash) => {
2216 self.block_transaction_count_by_hash(hash).await.to_rpc_result()
2217 }
2218 EthRequest::EthGetTransactionCountByNumber(num) => {
2219 self.block_transaction_count_by_number(num).await.to_rpc_result()
2220 }
2221 EthRequest::EthGetUnclesCountByHash(hash) => {
2222 self.block_uncles_count_by_hash(hash).await.to_rpc_result()
2223 }
2224 EthRequest::EthGetUnclesCountByNumber(num) => {
2225 self.block_uncles_count_by_number(num).await.to_rpc_result()
2226 }
2227 EthRequest::EthGetCodeAt(addr, block) => {
2228 self.get_code(addr, block).await.to_rpc_result()
2229 }
2230 EthRequest::EthGetProof(addr, keys, block) => {
2231 self.get_proof(addr, keys, block).await.to_rpc_result()
2232 }
2233 EthRequest::EthSign(addr, content) => self.sign(addr, content).await.to_rpc_result(),
2234 EthRequest::PersonalSign(content, addr) => {
2235 self.sign(addr, content).await.to_rpc_result()
2236 }
2237 EthRequest::EthSignTransaction(request) => {
2238 self.sign_transaction(*request).await.to_rpc_result()
2239 }
2240 EthRequest::EthSignTypedData(addr, data) => {
2241 self.sign_typed_data(addr, data).await.to_rpc_result()
2242 }
2243 EthRequest::EthSignTypedDataV3(addr, data) => {
2244 self.sign_typed_data_v3(addr, data).await.to_rpc_result()
2245 }
2246 EthRequest::EthSignTypedDataV4(addr, data) => {
2247 self.sign_typed_data_v4(addr, &data).await.to_rpc_result()
2248 }
2249 EthRequest::EthSendRawTransaction(tx) => {
2250 self.send_raw_transaction(tx).await.to_rpc_result()
2251 }
2252 EthRequest::EthSendRawTransactionSync(tx, timeout_ms) => {
2253 self.send_raw_transaction_sync(tx, timeout_ms).await.to_rpc_result()
2254 }
2255 EthRequest::EthSendRawTransactionConditional(tx, condition) => {
2256 self.send_raw_transaction_conditional(tx, condition).await.to_rpc_result()
2257 }
2258 EthRequest::EthSignRawTransaction(tx) => {
2259 self.sign_raw_transaction(tx).await.to_rpc_result()
2260 }
2261 EthRequest::AnvilClassifyTransaction(tx) => {
2262 self.anvil_classify_transaction(tx).to_rpc_result()
2263 }
2264 EthRequest::EthCall(call, block, state_override, block_overrides) => self
2265 .call(call, block, EvmOverrides::new(state_override, block_overrides))
2266 .await
2267 .to_rpc_result(),
2268 EthRequest::EthCallMany(bundles, state_context, state_override) => {
2269 self.call_many(bundles, state_context, state_override).await.to_rpc_result()
2270 }
2271 EthRequest::EthCallBundle(bundle) => self.call_bundle(bundle).await.to_rpc_result(),
2272 EthRequest::EthSimulateV1(simulation, block) => {
2273 self.simulate_v1_raw(simulation, block).await.to_rpc_result()
2274 }
2275 EthRequest::EthCreateAccessList(call, block, state_override) => {
2276 self.create_access_list(call, block, state_override).await.to_rpc_result()
2277 }
2278 EthRequest::EthEstimateGas(call, block, state_override, block_overrides) => self
2279 .estimate_gas(call, block, EvmOverrides::new(state_override, block_overrides))
2280 .await
2281 .to_rpc_result(),
2282 EthRequest::EthFillTransaction(request) => {
2283 self.fill_transaction(request).await.to_rpc_result()
2284 }
2285 EthRequest::EthGetRawTransactionByHash(hash) => {
2286 self.raw_transaction(hash).await.to_rpc_result()
2287 }
2288 EthRequest::GetBlobByHash(hash) => {
2289 self.anvil_get_blob_by_versioned_hash(hash).to_rpc_result()
2290 }
2291 EthRequest::GetBlobByTransactionHash(hash) => {
2292 self.anvil_get_blob_by_tx_hash(hash).to_rpc_result()
2293 }
2294 EthRequest::GetGenesisTime(()) => self.anvil_get_genesis_time().to_rpc_result(),
2295 EthRequest::GetLastBlockWallTime(()) => {
2296 self.anvil_get_last_block_wall_time().to_rpc_result()
2297 }
2298 EthRequest::EthGetRawTransactionByBlockHashAndIndex(hash, index) => {
2299 self.raw_transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
2300 }
2301 EthRequest::EthGetRawTransactionByBlockNumberAndIndex(num, index) => {
2302 self.raw_transaction_by_block_number_and_index(num, index).await.to_rpc_result()
2303 }
2304 EthRequest::EthGetTransactionByBlockHashAndIndex(hash, index) => {
2305 self.transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
2306 }
2307 EthRequest::EthGetTransactionByBlockNumberAndIndex(num, index) => {
2308 self.transaction_by_block_number_and_index(num, index).await.to_rpc_result()
2309 }
2310 EthRequest::EthGetTransactionReceipt(tx) => {
2311 self.transaction_receipt(tx).await.to_rpc_result()
2312 }
2313 EthRequest::EthGetBlockReceipts(number) => {
2314 self.block_receipts(number).await.to_rpc_result()
2315 }
2316 EthRequest::EthGetUncleByBlockHashAndIndex(hash, index) => {
2317 self.uncle_by_block_hash_and_index(hash, index).await.to_rpc_result()
2318 }
2319 EthRequest::EthGetUncleByBlockNumberAndIndex(num, index) => {
2320 self.uncle_by_block_number_and_index(num, index).await.to_rpc_result()
2321 }
2322 EthRequest::EthGetLogs(filter) => self.logs(filter).await.to_rpc_result(),
2323 EthRequest::EthGetWork(_) => self.work().to_rpc_result(),
2324 EthRequest::EthSyncing(_) => self.syncing().to_rpc_result(),
2325 EthRequest::EthConfig(_) => self.config().to_rpc_result(),
2326 EthRequest::EthSubmitWork(nonce, pow, digest) => {
2327 self.submit_work(nonce, pow, digest).to_rpc_result()
2328 }
2329 EthRequest::EthSubmitHashRate(rate, id) => {
2330 self.submit_hashrate(rate, id).to_rpc_result()
2331 }
2332 EthRequest::EthFeeHistory(count, newest, reward_percentiles) => {
2333 self.fee_history(count, newest, reward_percentiles).await.to_rpc_result()
2334 }
2335 EthRequest::DebugGetRawTransaction(hash) => {
2337 self.raw_transaction(hash).await.to_rpc_result()
2338 }
2339 EthRequest::DebugGetRawReceipts(block) => {
2340 self.raw_receipts(block).await.to_rpc_result()
2341 }
2342 EthRequest::DebugGetRawTransactions(block) => {
2343 self.raw_transactions(block).await.to_rpc_result()
2344 }
2345 EthRequest::DebugGetRawHeader(block) => self.raw_header(block).await.to_rpc_result(),
2346 EthRequest::DebugGetRawBlock(block) => self.raw_block(block).await.to_rpc_result(),
2347 EthRequest::DebugClearTxpool(_) => self.debug_clear_txpool().await.to_rpc_result(),
2349 EthRequest::DebugTraceTransaction(tx, opts) => {
2351 self.debug_trace_transaction(tx, opts).await.to_rpc_result()
2352 }
2353 EthRequest::DebugTraceCall(tx, block, opts) => {
2355 self.debug_trace_call(tx, block, opts).await.to_rpc_result()
2356 }
2357 EthRequest::DebugCodeByHash(hash, block) => {
2358 self.debug_code_by_hash(hash, block).await.to_rpc_result()
2359 }
2360 EthRequest::DebugDbGet(key) => self.debug_db_get(key).await.to_rpc_result(),
2361 EthRequest::DebugGetModifiedAccountsByNumber(start_number, end_number) => {
2362 self.debug_get_modified_accounts_by_number(start_number, end_number).to_rpc_result()
2363 }
2364 EthRequest::DebugFreeOsMemory(()) => self.debug_free_os_memory().to_rpc_result(),
2365 EthRequest::DebugAccountInfoAt(block_id, tx_index, address) => {
2366 self.debug_account_info_at(block_id, tx_index, address).await.to_rpc_result()
2367 }
2368 EthRequest::DebugExecutionWitness(block) => {
2369 self.debug_execution_witness(block).await.to_rpc_result()
2370 }
2371 EthRequest::DebugTraceBlock(rlp_block, opts) => {
2372 self.debug_trace_block(rlp_block, opts).await.to_rpc_result()
2373 }
2374 EthRequest::DebugTraceBlockByHash(block_hash, opts) => {
2375 self.debug_trace_block_by_hash(block_hash, opts).await.to_rpc_result()
2376 }
2377 EthRequest::DebugTraceBlockByNumber(block_number, opts) => {
2378 self.debug_trace_block_by_number(block_number, opts).await.to_rpc_result()
2379 }
2380 EthRequest::TraceCall(tx, trace_types, block) => {
2381 self.trace_call(tx, trace_types, block).await.to_rpc_result()
2382 }
2383 EthRequest::TraceTransaction(tx) => self.trace_transaction(tx).await.to_rpc_result(),
2384 EthRequest::TraceBlock(block) => self.trace_block(block).await.to_rpc_result(),
2385 EthRequest::TraceFilter(filter) => self.trace_filter(filter).await.to_rpc_result(),
2386 EthRequest::TraceGet(hash, indices) => {
2387 self.trace_get(hash, indices).await.to_rpc_result()
2388 }
2389 EthRequest::TraceReplayBlockTransactions(block, trace_types) => {
2390 self.trace_replay_block_transactions(block, trace_types).await.to_rpc_result()
2391 }
2392 EthRequest::TraceReplayTransaction(transaction, trace_types) => {
2393 self.trace_replay_transaction(transaction, trace_types).await.to_rpc_result()
2394 }
2395 EthRequest::TraceTransactionOpcodeGas(tx_hash) => {
2396 self.trace_transaction_opcode_gas(tx_hash).await.to_rpc_result()
2397 }
2398 EthRequest::TraceBlockOpcodeGas(block_id) => {
2399 self.trace_block_opcode_gas(block_id).await.to_rpc_result()
2400 }
2401 EthRequest::TraceRawTransaction(tx, trace_types, block_number) => {
2402 self.trace_raw_transaction(tx, trace_types, block_number).await.to_rpc_result()
2403 }
2404 EthRequest::TraceCallMany(calls, block_number) => {
2405 self.trace_call_many(calls, block_number).await.to_rpc_result()
2406 }
2407 EthRequest::ImpersonateAccount(addr) => {
2408 self.anvil_impersonate_account(addr).await.to_rpc_result()
2409 }
2410 EthRequest::StopImpersonatingAccount(addr) => {
2411 self.anvil_stop_impersonating_account(addr).await.to_rpc_result()
2412 }
2413 EthRequest::AutoImpersonateAccount(enable) => {
2414 self.anvil_auto_impersonate_account(enable).await.to_rpc_result()
2415 }
2416 EthRequest::ImpersonateSignature(signature, address) => {
2417 self.anvil_impersonate_signature(signature, address).await.to_rpc_result()
2418 }
2419 EthRequest::GetAutoMine(()) => self.anvil_get_auto_mine().to_rpc_result(),
2420 EthRequest::Mine(blocks, interval) => {
2421 self.anvil_mine(blocks, interval).await.to_rpc_result()
2422 }
2423 EthRequest::SetAutomine(enabled) => {
2424 self.anvil_set_auto_mine(enabled).await.to_rpc_result()
2425 }
2426 EthRequest::SetIntervalMining(interval) => {
2427 self.anvil_set_interval_mining(interval).to_rpc_result()
2428 }
2429 EthRequest::GetIntervalMining(()) => self.anvil_get_interval_mining().to_rpc_result(),
2430 EthRequest::DropTransaction(tx) => {
2431 self.anvil_drop_transaction(tx).await.to_rpc_result()
2432 }
2433 EthRequest::DropAllTransactions() => {
2434 self.anvil_drop_all_transactions().await.to_rpc_result()
2435 }
2436 EthRequest::Reset(fork) => {
2437 self.anvil_reset(fork.and_then(|p| p.params)).await.to_rpc_result()
2438 }
2439 EthRequest::SetBalance(addr, val) => {
2440 self.anvil_set_balance(addr, val).await.to_rpc_result()
2441 }
2442 EthRequest::AddBalance(addr, val) => {
2443 self.anvil_add_balance(addr, val).await.to_rpc_result()
2444 }
2445 EthRequest::DealERC20(addr, token_addr, val) => {
2446 self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result()
2447 }
2448 EthRequest::DealTIP20(addr, token_addr, val) => {
2449 self.anvil_deal_tip20(addr, token_addr, val).await.to_rpc_result()
2450 }
2451 EthRequest::SetERC20Allowance(owner, spender, token_addr, val) => self
2452 .anvil_set_erc20_allowance(owner, spender, token_addr, val)
2453 .await
2454 .to_rpc_result(),
2455 EthRequest::SetCode(addr, code) => {
2456 self.anvil_set_code(addr, code).await.to_rpc_result()
2457 }
2458 EthRequest::SetNonce(addr, nonce) => {
2459 self.anvil_set_nonce(addr, nonce).await.to_rpc_result()
2460 }
2461 EthRequest::SetStorageAt(addr, slot, val) => {
2462 self.anvil_set_storage_at(addr, slot, val).await.to_rpc_result()
2463 }
2464 EthRequest::SetCoinbase(addr) => self.anvil_set_coinbase(addr).await.to_rpc_result(),
2465 EthRequest::SetNextBlockPrevRandao(prevrandao) => {
2466 self.anvil_set_next_block_prevrandao(prevrandao).await.to_rpc_result()
2467 }
2468 EthRequest::SetNextBlockParentBeaconBlockRoot(root) => {
2469 self.anvil_set_next_block_parent_beacon_block_root(root).await.to_rpc_result()
2470 }
2471 EthRequest::SetChainId(id) => self.anvil_set_chain_id(id).await.to_rpc_result(),
2472 EthRequest::SetLogging(log) => self.anvil_set_logging(log).await.to_rpc_result(),
2473 EthRequest::SetMinGasPrice(gas) => {
2474 self.anvil_set_min_gas_price(gas).await.to_rpc_result()
2475 }
2476 EthRequest::SetNextBlockBaseFeePerGas(gas) => {
2477 self.anvil_set_next_block_base_fee_per_gas(gas).await.to_rpc_result()
2478 }
2479 EthRequest::DumpState(preserve_historical_states) => self
2480 .anvil_dump_state(preserve_historical_states.and_then(|s| s.params))
2481 .await
2482 .to_rpc_result(),
2483 EthRequest::LoadState(buf) => self.anvil_load_state(buf).await.to_rpc_result(),
2484 EthRequest::NodeInfo(_) => self.anvil_node_info().await.to_rpc_result(),
2485 EthRequest::AnvilMetadata(_) => self.anvil_metadata().await.to_rpc_result(),
2486 EthRequest::EvmSnapshot(_) => self.evm_snapshot().await.to_rpc_result(),
2487 EthRequest::EvmRevert(id) => self.evm_revert(id).await.to_rpc_result(),
2488 EthRequest::EvmIncreaseTime(time) => self.evm_increase_time(time).await.to_rpc_result(),
2489 EthRequest::EvmSetNextBlockTimeStamp(time) => {
2490 if time >= U256::from(u64::MAX) {
2491 return ResponseResult::Error(RpcError::invalid_params(
2492 "The timestamp is too big",
2493 ));
2494 }
2495 let time = time.to::<u64>();
2496 self.evm_set_next_block_timestamp(time).to_rpc_result()
2497 }
2498 EthRequest::EvmSetTime(timestamp) => {
2499 if timestamp >= U256::from(u64::MAX) {
2500 return ResponseResult::Error(RpcError::invalid_params(
2501 "The timestamp is too big",
2502 ));
2503 }
2504 let raw = timestamp.to::<u64>();
2508 let time = if raw > 1_000_000_000_000 {
2509 Duration::from_millis(raw).as_secs()
2510 } else {
2511 raw
2512 };
2513 self.evm_set_time(time).to_rpc_result()
2514 }
2515 EthRequest::EvmSetBlockGasLimit(gas_limit) => {
2516 self.evm_set_block_gas_limit(gas_limit).to_rpc_result()
2517 }
2518 EthRequest::EvmSetBlockTimeStampInterval(time) => {
2519 self.evm_set_block_timestamp_interval(time).to_rpc_result()
2520 }
2521 EthRequest::EvmRemoveBlockTimeStampInterval(()) => {
2522 self.evm_remove_block_timestamp_interval().to_rpc_result()
2523 }
2524 EthRequest::EvmMine(mine) => {
2525 self.evm_mine(mine.and_then(|p| p.params)).await.to_rpc_result()
2526 }
2527 EthRequest::EvmMineDetailed(mine) => {
2528 self.evm_mine_detailed(mine.and_then(|p| p.params)).await.to_rpc_result()
2529 }
2530 EthRequest::SetRpcUrl(url) => self.anvil_set_rpc_url(url).await.to_rpc_result(),
2531 EthRequest::EthSendUnsignedTransaction(tx) => {
2532 self.eth_send_unsigned_transaction(*tx).await.to_rpc_result()
2533 }
2534 EthRequest::EthNewFilter(filter) => self.new_filter(filter).await.to_rpc_result(),
2535 EthRequest::EthGetFilterChanges(id) => self.get_filter_changes(&id).await,
2536 EthRequest::EthNewBlockFilter(_) => self.new_block_filter().await.to_rpc_result(),
2537 EthRequest::EthNewPendingTransactionFilter(full) => {
2538 self.new_pending_transaction_filter(full.unwrap_or(false)).await.to_rpc_result()
2539 }
2540 EthRequest::EthGetFilterLogs(id) => self.get_filter_logs(&id).await.to_rpc_result(),
2541 EthRequest::EthUninstallFilter(id) => self.uninstall_filter(&id).await.to_rpc_result(),
2542 EthRequest::TxPoolStatus(_) => self.txpool_status().await.to_rpc_result(),
2543 EthRequest::TxPoolInspect(_) => self.txpool_inspect().await.to_rpc_result(),
2544 EthRequest::TxPoolContent(_) => self.txpool_content().await.to_rpc_result(),
2545 EthRequest::TxPoolContentFrom(from) => {
2546 self.txpool_content_from(from).await.to_rpc_result()
2547 }
2548 EthRequest::ErigonGetHeaderByNumber(num) => {
2549 self.erigon_get_header_by_number(num).await.to_rpc_result()
2550 }
2551 EthRequest::OtsGetApiLevel(_) => self.ots_get_api_level().await.to_rpc_result(),
2552 EthRequest::OtsGetInternalOperations(hash) => {
2553 self.ots_get_internal_operations(hash).await.to_rpc_result()
2554 }
2555 EthRequest::OtsHasCode(addr, num) => self.ots_has_code(addr, num).await.to_rpc_result(),
2556 EthRequest::OtsTraceTransaction(hash) => {
2557 self.ots_trace_transaction(hash).await.to_rpc_result()
2558 }
2559 EthRequest::OtsGetTransactionError(hash) => {
2560 self.ots_get_transaction_error(hash).await.to_rpc_result()
2561 }
2562 EthRequest::OtsGetBlockDetails(num) => {
2563 self.ots_get_block_details(num).await.to_rpc_result()
2564 }
2565 EthRequest::OtsGetBlockDetailsByHash(hash) => {
2566 self.ots_get_block_details_by_hash(hash).await.to_rpc_result()
2567 }
2568 EthRequest::OtsGetBlockTransactions(num, page, page_size) => {
2569 self.ots_get_block_transactions(num, page, page_size).await.to_rpc_result()
2570 }
2571 EthRequest::OtsSearchTransactionsBefore(address, num, page_size) => {
2572 self.ots_search_transactions_before(address, num, page_size).await.to_rpc_result()
2573 }
2574 EthRequest::OtsSearchTransactionsAfter(address, num, page_size) => {
2575 self.ots_search_transactions_after(address, num, page_size).await.to_rpc_result()
2576 }
2577 EthRequest::OtsGetTransactionBySenderAndNonce(address, nonce) => {
2578 self.ots_get_transaction_by_sender_and_nonce(address, nonce).await.to_rpc_result()
2579 }
2580 EthRequest::EthGetTransactionBySenderAndNonce(sender, nonce) => {
2581 self.transaction_by_sender_and_nonce(sender, nonce).await.to_rpc_result()
2582 }
2583 EthRequest::OtsGetContractCreator(address) => {
2584 self.ots_get_contract_creator(address).await.to_rpc_result()
2585 }
2586 EthRequest::RemovePoolTransactions(address) => {
2587 self.anvil_remove_pool_transactions(address).await.to_rpc_result()
2588 }
2589 EthRequest::Reorg(reorg_options) => {
2590 self.anvil_reorg(reorg_options).await.to_rpc_result()
2591 }
2592 EthRequest::Rollback(depth) => self.anvil_rollback(depth).await.to_rpc_result(),
2593 EthRequest::SetFeeToken(user, token) => {
2594 self.anvil_set_fee_token(user, token).await.to_rpc_result()
2595 }
2596 EthRequest::SetValidatorFeeToken(validator, token) => {
2597 self.anvil_set_validator_fee_token(validator, token).await.to_rpc_result()
2598 }
2599 EthRequest::SetFeeAmmLiquidity(user_token, validator_token, amount) => self
2600 .anvil_set_fee_amm_liquidity(user_token, validator_token, amount)
2601 .await
2602 .to_rpc_result(),
2603 };
2604
2605 if let ResponseResult::Error(err) = &response {
2606 node_info!("\nRPC request failed:");
2607 node_info!(" Request: {:?}", request);
2608 node_info!(" Error: {}\n", err);
2609 }
2610
2611 response
2612 }
2613
2614 fn sign_request(&self, from: &Address, typed_tx: FoundryTypedTx) -> Result<FoundryTxEnvelope> {
2615 match typed_tx {
2616 #[cfg(feature = "optimism")]
2617 FoundryTypedTx::Deposit(_) => return Ok(typed_tx.into_impersonated()),
2618 _ => {
2619 for signer in self.signers.iter() {
2620 if signer.accounts().contains(from) {
2621 return signer.sign_transaction_from(from, typed_tx);
2622 }
2623 }
2624 }
2625 }
2626 Err(BlockchainError::NoSignerAvailable)
2627 }
2628
2629 async fn inner_raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
2630 match self.pool.get_transaction(hash) {
2631 Some(tx) => Ok(Some(tx.transaction.encoded_2718().into())),
2632 None => match self.backend.transaction_by_hash(hash).await? {
2633 Some(tx) => encode_rpc_transaction(&tx).map(Some),
2634 None => Ok(None),
2635 },
2636 }
2637 }
2638
2639 pub async fn balance(&self, address: Address, block_number: Option<BlockId>) -> Result<U256> {
2643 node_info!("eth_getBalance");
2644 let block_request = self.block_request(block_number).await?;
2645
2646 if let BlockRequest::Number(number) = block_request
2648 && let Some(fork) = self.get_fork()
2649 && fork.predates_fork(number)
2650 {
2651 return Ok(fork.get_balance(address, number).await?);
2652 }
2653
2654 self.backend.get_balance(address, Some(block_request)).await
2655 }
2656
2657 pub async fn get_account(
2661 &self,
2662 address: Address,
2663 block_number: Option<BlockId>,
2664 ) -> Result<TrieAccount> {
2665 node_info!("eth_getAccount");
2666 let block_request = self.block_request(block_number).await?;
2667
2668 if let BlockRequest::Number(number) = block_request
2670 && let Some(fork) = self.get_fork()
2671 && fork.predates_fork(number)
2672 {
2673 return Ok(fork.get_account(address, number).await?);
2674 }
2675
2676 self.backend.get_account_at_block(address, Some(block_request)).await
2677 }
2678
2679 pub async fn get_account_info(
2683 &self,
2684 address: Address,
2685 block_number: Option<BlockId>,
2686 ) -> Result<alloy_rpc_types::eth::AccountInfo> {
2687 node_info!("eth_getAccountInfo");
2688
2689 let block_request = self.block_request(block_number).await?;
2690 if let BlockRequest::Number(number) = block_request
2691 && let Some(fork) = self.get_fork()
2692 {
2693 trace!(target: "node", "get_account_info: fork block {}, requested block {number}", fork.block_number());
2694 if block_number.is_some_and(|block| !block.is_latest())
2695 && fork.predates_fork_inclusive(number)
2696 {
2697 if fork.requires_account_info() {
2698 return Ok(fork.get_account_info(address, number).await?);
2699 }
2700 let balance = fork.get_balance(address, number).map_err(BlockchainError::from);
2701 let code = fork.get_code(address, number).map_err(BlockchainError::from);
2702 let nonce = fork.get_nonce(address, number).map_err(BlockchainError::from);
2703 let (balance, code, nonce) = try_join!(balance, code, nonce)?;
2704 return Ok(alloy_rpc_types::eth::AccountInfo { balance, nonce, code });
2705 }
2706 }
2707
2708 self.backend.get_account_info_at_block(address, Some(block_request)).await
2709 }
2710 pub async fn storage_at(
2714 &self,
2715 address: Address,
2716 index: U256,
2717 block_number: Option<BlockId>,
2718 ) -> Result<B256> {
2719 node_info!("eth_getStorageAt");
2720 let block_request = self.block_request(block_number).await?;
2721
2722 if let BlockRequest::Number(number) = block_request
2724 && let Some(fork) = self.get_fork()
2725 && fork.predates_fork(number)
2726 {
2727 return Ok(B256::from(
2728 fork.storage_at(address, index, Some(BlockNumber::Number(number))).await?,
2729 ));
2730 }
2731
2732 self.backend.storage_at(address, index, Some(block_request)).await
2733 }
2734
2735 pub async fn storage_values(
2739 &self,
2740 requests: HashMap<Address, Vec<B256>>,
2741 block_number: Option<BlockId>,
2742 ) -> Result<HashMap<Address, Vec<B256>>> {
2743 node_info!("eth_getStorageValues");
2744
2745 if requests.is_empty() {
2746 return Err(RpcError::invalid_params("empty request").into());
2747 }
2748
2749 let total_slots: usize = requests.values().map(|s| s.len()).sum();
2750 if total_slots > 1024 {
2751 return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
2752 "total slot count {total_slots} exceeds limit 1024"
2753 ))));
2754 }
2755
2756 let block_request = self.block_request(block_number).await?;
2757
2758 if let BlockRequest::Number(number) = block_request
2760 && let Some(fork) = self.get_fork()
2761 && fork.predates_fork(number)
2762 {
2763 let mut result: HashMap<Address, Vec<B256>> = HashMap::default();
2764 for (address, slots) in requests {
2765 let mut values = Vec::with_capacity(slots.len());
2766 for slot in &slots {
2767 let val = fork
2768 .storage_at(address, (*slot).into(), Some(BlockNumber::Number(number)))
2769 .await?;
2770 values.push(B256::from(val));
2771 }
2772 result.insert(address, values);
2773 }
2774 return Ok(result);
2775 }
2776
2777 self.backend.storage_values(requests, Some(block_request)).await
2778 }
2779
2780 pub async fn block_by_number(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2784 node_info!("eth_getBlockByNumber");
2785 if number.is_pending() {
2786 return Ok(Some(self.pending_block().await?));
2787 }
2788
2789 self.backend.block_by_number(number).await
2790 }
2791
2792 pub async fn header_by_number(
2796 &self,
2797 number: BlockNumber,
2798 ) -> Result<Option<WithOtherFields<AnyRpcHeader>>> {
2799 node_info!("eth_getHeaderByNumber");
2800 if number.is_pending() {
2801 let WithOtherFields { inner: block, other } = self.pending_block().await?.0;
2802 return Ok(Some(WithOtherFields { inner: block.header, other }));
2803 }
2804
2805 Ok(self.backend.block_by_number(number).await?.map(|block| {
2806 let WithOtherFields { inner: block, other } = block.0;
2807 WithOtherFields { inner: block.header, other }
2808 }))
2809 }
2810
2811 pub async fn block_by_number_full(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2815 node_info!("eth_getBlockByNumber");
2816 if number.is_pending() {
2817 return self.pending_block_full().await;
2818 }
2819 self.backend.block_by_number_full(number).await
2820 }
2821
2822 pub async fn block_access_list(&self, block_id: BlockId) -> Result<Option<serde_json::Value>> {
2826 node_info!("eth_getBlockAccessList");
2827 let block_request = self.block_request(Some(block_id)).await?;
2828 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2829
2830 if let Some(fork) = self.get_fork()
2831 && fork.predates_fork_inclusive(number)
2832 {
2833 return Ok(fork.block_access_list(block_id).await?);
2834 }
2835
2836 let block_access_list = match block_id {
2837 BlockId::Hash(hash) => self.backend.block_access_list_by_hash(hash.block_hash),
2838 BlockId::Number(_) => self.backend.block_access_list_by_number(number),
2839 };
2840 Ok(block_access_list
2841 .map(|bal| serde_json::to_value(bal).expect("BAL serialization is infallible")))
2842 }
2843
2844 pub async fn block_access_list_by_hash(
2848 &self,
2849 block_hash: B256,
2850 ) -> Result<Option<serde_json::Value>> {
2851 node_info!("eth_getBlockAccessListByBlockHash");
2852 if let Some(block_access_list) = self.backend.block_access_list_by_hash(block_hash) {
2853 return Ok(Some(
2854 serde_json::to_value(block_access_list).expect("BAL serialization is infallible"),
2855 ));
2856 }
2857
2858 let Some(fork) = self.get_fork() else { return Ok(None) };
2859
2860 if let Some(block) = self.backend.get_block_by_hash(block_hash)
2863 && !fork.predates_fork_inclusive(block.header.number)
2864 {
2865 return Ok(None);
2866 }
2867
2868 Ok(fork.block_access_list_by_hash(block_hash).await?)
2869 }
2870
2871 pub async fn block_access_list_by_number(
2875 &self,
2876 block_number: BlockNumber,
2877 ) -> Result<Option<serde_json::Value>> {
2878 node_info!("eth_getBlockAccessListByBlockNumber");
2879 let block_request = self.block_request(Some(BlockId::Number(block_number))).await?;
2880 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2881
2882 if let Some(fork) = self.get_fork()
2883 && fork.predates_fork_inclusive(number)
2884 {
2885 return Ok(fork.block_access_list_by_number(block_number).await?);
2886 }
2887
2888 Ok(self
2889 .backend
2890 .block_access_list_by_number(number)
2891 .map(|bal| serde_json::to_value(bal).expect("BAL serialization is infallible")))
2892 }
2893
2894 pub async fn block_access_list_raw(&self, block_id: BlockId) -> Result<Option<Bytes>> {
2898 node_info!("eth_getBlockAccessListRaw");
2899 let block_request = self.block_request(Some(block_id)).await?;
2900 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2901
2902 if let Some(fork) = self.get_fork()
2903 && fork.predates_fork_inclusive(number)
2904 {
2905 return Ok(fork.block_access_list_raw(block_id).await?);
2906 }
2907
2908 let block_access_list = match block_id {
2909 BlockId::Hash(hash) => self.backend.block_access_list_by_hash(hash.block_hash),
2910 BlockId::Number(_) => self.backend.block_access_list_by_number(number),
2911 };
2912 Ok(block_access_list.map(|bal| {
2913 let mut encoded = Vec::new();
2914 alloy_rlp::encode_list(&bal, &mut encoded);
2915 encoded.into()
2916 }))
2917 }
2918
2919 pub async fn transaction_count(
2926 &self,
2927 address: Address,
2928 block_number: Option<BlockId>,
2929 ) -> Result<U256> {
2930 node_info!("eth_getTransactionCount");
2931 self.get_transaction_count(address, block_number).await.map(U256::from)
2932 }
2933
2934 #[cfg(feature = "base")]
2936 pub async fn transaction_count_with_key(
2937 &self,
2938 address: Address,
2939 block_number: Option<BlockId>,
2940 nonce_key: Option<U256>,
2941 ) -> Result<U256> {
2942 let Some(nonce_key) = nonce_key else {
2943 return self.transaction_count(address, block_number).await;
2944 };
2945 if nonce_key.is_zero() {
2946 return self.transaction_count(address, block_number).await;
2947 }
2948
2949 let block_request = self.block_request(block_number).await?;
2950 let timestamp = self.backend.block_request_timestamp(&block_request).await?;
2951 self.backend.ensure_base_eip8130_active_at(timestamp)?;
2952 if nonce_key == Eip8130Constants::NONCE_KEY_MAX {
2953 return Err(RpcError::invalid_params(
2954 "nonce_key NONCE_KEY_MAX selects the expiring-nonce channel which has no \
2955 per-channel counter",
2956 )
2957 .into());
2958 }
2959 let slot = NonceManagerStorage::nonce_slot(address, nonce_key)
2960 .map_err(|error| RpcError::invalid_params(error.to_string()))?;
2961 let word = self
2962 .backend
2963 .storage_at(NonceManagerStorage::ADDRESS, slot, Some(block_request))
2964 .await?;
2965 Ok(Eip8130Nonce::decode_channel_nonce(word.into()))
2966 }
2967
2968 pub async fn block_transaction_count_by_number(
2972 &self,
2973 block_number: BlockNumber,
2974 ) -> Result<Option<U256>> {
2975 node_info!("eth_getBlockTransactionCountByNumber");
2976 if block_number.is_pending() {
2977 let txs = self.pool.ready_transactions().collect();
2978 let block = self.backend.pending_block(txs).await?;
2979 return Ok(Some(U256::from(block.block.body.transactions.len())));
2980 }
2981
2982 let block = self.backend.block_by_number(block_number).await?;
2983 let txs = block.map(|b| match b.transactions() {
2984 BlockTransactions::Full(txs) => U256::from(txs.len()),
2985 BlockTransactions::Hashes(txs) => U256::from(txs.len()),
2986 BlockTransactions::Uncle => U256::ZERO,
2987 });
2988 Ok(txs)
2989 }
2990
2991 pub async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {
2995 node_info!("eth_getCode");
2996 let block_request = self.block_request(block_number).await?;
2997 if let BlockRequest::Number(number) = block_request
2999 && let Some(fork) = self.get_fork()
3000 && fork.predates_fork(number)
3001 {
3002 return Ok(fork.get_code(address, number).await?);
3003 }
3004 self.backend.get_code(address, Some(block_request)).await
3005 }
3006
3007 pub async fn get_proof(
3012 &self,
3013 address: Address,
3014 keys: Vec<B256>,
3015 block_number: Option<BlockId>,
3016 ) -> Result<EIP1186AccountProofResponse> {
3017 node_info!("eth_getProof");
3018 let block_request = self.block_request(block_number).await?;
3019
3020 if let BlockRequest::Number(number) = block_request
3023 && let Some(fork) = self.get_fork()
3024 && fork.predates_fork_inclusive(number)
3025 {
3026 return Ok(fork.get_proof(address, keys, Some(number.into())).await?);
3027 }
3028
3029 let proof = self.backend.prove_account_at(address, keys, Some(block_request)).await?;
3030 Ok(proof)
3031 }
3032
3033 pub async fn sign_transaction(
3037 &self,
3038 request: WithOtherFields<TransactionRequest>,
3039 ) -> Result<String> {
3040 node_info!("eth_signTransaction");
3041 let request = self.parse_transaction_request(request)?;
3042
3043 let from = request.from().map(Ok).unwrap_or_else(|| {
3044 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3045 })?;
3046
3047 let nonce = self.request_nonce_for_transaction(&request, from).await?;
3048
3049 let request = self.build_tx_request(request, nonce).await?;
3050
3051 let signed_transaction = self.sign_request(&from, request)?.encoded_2718();
3052 Ok(alloy_primitives::hex::encode_prefixed(signed_transaction))
3053 }
3054
3055 pub async fn send_transaction(
3059 &self,
3060 request: WithOtherFields<TransactionRequest>,
3061 ) -> Result<TxHash> {
3062 node_info!("eth_sendTransaction");
3063 let request = self.parse_transaction_request(request)?;
3064
3065 let from = request.from().map(Ok).unwrap_or_else(|| {
3066 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3067 })?;
3068 let _nonce_guard = if request.nonce().is_none() {
3071 let lock = self.nonce_locks.write().entry(from).or_default().clone();
3072 Some(lock.lock_owned().await)
3073 } else {
3074 None
3075 };
3076 let nonce = self.request_nonce_for_transaction(&request, from).await?;
3077
3078 let typed_tx = self.build_tx_request(request, nonce).await?;
3079
3080 let pending_transaction = if self.is_impersonated(from) {
3082 let transaction = typed_tx.into_impersonated();
3083 self.ensure_typed_transaction_supported(&transaction)?;
3084 trace!(target : "node", ?from, "eth_sendTransaction: impersonating");
3085 PendingTransaction::with_impersonated(transaction, from)
3086 } else {
3087 let transaction = self.sign_request(&from, typed_tx)?;
3088 self.ensure_typed_transaction_supported(&transaction)?;
3089 PendingTransaction::new(transaction)?
3090 };
3091 self.add_pending_transaction(pending_transaction).await
3092 }
3093
3094 pub async fn resend_transaction(
3098 &self,
3099 request: WithOtherFields<TransactionRequest>,
3100 gas_price: Option<U256>,
3101 gas_limit: Option<U64>,
3102 ) -> Result<TxHash> {
3103 node_info!("eth_resend");
3104 let mut request = self.parse_transaction_request(request)?;
3105
3106 let from = request.from().map(Ok).unwrap_or_else(|| {
3107 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3108 })?;
3109 let nonce = request.nonce().ok_or_else(|| {
3110 BlockchainError::InvalidTransactionRequest(
3111 "missing transaction nonce in transaction spec".to_string(),
3112 )
3113 })?;
3114
3115 if !self.pool.contains_sender_nonce(from, nonce) {
3116 return Err(BlockchainError::TransactionNotFound);
3117 }
3118
3119 if let Some(gas_price) = gas_price.filter(|gas_price| !gas_price.is_zero()) {
3120 request.set_gas_price(gas_price.saturating_to());
3121 }
3122
3123 if let Some(gas_limit) = gas_limit.filter(|gas_limit| *gas_limit != U64::ZERO) {
3124 request.set_gas_limit(gas_limit.to());
3125 }
3126
3127 let typed_tx = self.build_tx_request(request, nonce).await?;
3128
3129 let pending_transaction = if self.is_impersonated(from) {
3130 let transaction = typed_tx.into_impersonated();
3131 self.ensure_typed_transaction_supported(&transaction)?;
3132 trace!(target : "node", ?from, "eth_resend: impersonating");
3133 PendingTransaction::with_impersonated(transaction, from)
3134 } else {
3135 let transaction = self.sign_request(&from, typed_tx)?;
3136 self.ensure_typed_transaction_supported(&transaction)?;
3137 PendingTransaction::new(transaction)?
3138 };
3139
3140 self.add_pending_transaction(pending_transaction).await
3141 }
3142
3143 async fn await_transaction_inclusion(&self, hash: TxHash) -> Result<FoundryTxReceipt> {
3145 let mut stream = self.new_block_notifications();
3146 if let Some(receipt) = self.backend.transaction_receipt(hash).await? {
3148 return Ok(receipt);
3149 }
3150 while let Some(notification) = stream.next().await {
3151 if let Some(new_block) = notification.as_new_block()
3152 && let Some(block) = self.backend.get_block_by_hash(new_block.hash)
3153 && block.body.transactions.iter().any(|tx| tx.hash() == hash)
3154 && let Some(receipt) = self.backend.transaction_receipt(hash).await?
3155 {
3156 return Ok(receipt);
3157 }
3158 }
3159
3160 Err(BlockchainError::Message("Failed to await transaction inclusion".to_string()))
3161 }
3162
3163 fn transaction_confirmation_timeout(timeout_ms: Option<u64>) -> Duration {
3164 const TIMEOUT_DURATION: Duration = Duration::from_secs(30);
3165 timeout_ms
3166 .filter(|timeout_ms| *timeout_ms > 0)
3167 .map(Duration::from_millis)
3168 .map(|timeout| timeout.min(TIMEOUT_DURATION))
3169 .unwrap_or(TIMEOUT_DURATION)
3170 }
3171
3172 async fn check_transaction_inclusion(
3174 &self,
3175 hash: TxHash,
3176 timeout_ms: Option<u64>,
3177 ) -> Result<FoundryTxReceipt> {
3178 let timeout_duration = Self::transaction_confirmation_timeout(timeout_ms);
3179 tokio::time::timeout(timeout_duration, self.await_transaction_inclusion(hash))
3180 .await
3181 .unwrap_or_else(|_elapsed| {
3182 Err(BlockchainError::TransactionConfirmationTimeout {
3183 hash,
3184 duration: timeout_duration,
3185 })
3186 })
3187 }
3188
3189 pub async fn send_transaction_sync(
3193 &self,
3194 request: WithOtherFields<TransactionRequest>,
3195 ) -> Result<FoundryTxReceipt> {
3196 node_info!("eth_sendTransactionSync");
3197 let hash = self.send_transaction(request).await?;
3198
3199 let receipt = self.check_transaction_inclusion(hash, None).await?;
3200
3201 Ok(receipt)
3202 }
3203
3204 pub async fn send_raw_transaction(&self, tx: Bytes) -> Result<TxHash> {
3208 node_info!("eth_sendRawTransaction");
3209 if tx.is_empty() {
3210 return Err(BlockchainError::EmptyRawTransactionData);
3211 }
3212
3213 let service_encoded = if self.backend.is_tempo() {
3217 normalize_fee_payer_service_encoding(tx.as_ref())
3218 } else {
3219 None
3220 };
3221 let raw = service_encoded.map(Bytes::from).unwrap_or(tx);
3222
3223 let transaction = if raw.first() == Some(&EIP4844_TX_TYPE_ID) {
3224 let raw = raw.clone();
3227 tokio::task::spawn_blocking(move || FoundryTxEnvelope::decode_2718(&mut raw.as_ref()))
3228 .await
3229 .map_err(|_| {
3230 BlockchainError::Internal("transaction decoding task panicked".into())
3231 })?
3232 } else {
3233 FoundryTxEnvelope::decode_2718(&mut raw.as_ref())
3234 }
3235 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3236
3237 self.ensure_typed_transaction_supported(&transaction)?;
3238
3239 let transaction = match transaction {
3240 FoundryTxEnvelope::Tempo(aa_tx)
3241 if self.backend.is_tempo()
3242 && aa_tx.tx().fee_payer_signature == Some(FEE_PAYER_SIGNATURE_MARKER) =>
3243 {
3244 FoundryTxEnvelope::Tempo(self.sponsor_sign_tempo_transaction(aa_tx).await?)
3245 }
3246 transaction => transaction,
3247 };
3248
3249 if self.backend.is_tempo() && TempoHardfork::from(self.backend.hardfork()).is_t5() {
3250 let classification = classify_payment_lane(raw.as_ref());
3251 trace!(target: "node", tx = ?transaction.hash(), ?classification, "classified transaction lane");
3252 }
3253
3254 #[cfg(feature = "base")]
3255 let is_eip8130 = transaction.is_eip8130();
3256 let pending_transaction = PendingTransaction::new(transaction).map_err(|error| {
3257 #[cfg(feature = "base")]
3258 if is_eip8130 {
3259 return BlockchainError::Eip8130TransactionRejected(error.to_string());
3260 }
3261 BlockchainError::RecoveryError(error)
3262 })?;
3263
3264 self.add_pending_transaction(pending_transaction).await
3265 }
3266
3267 pub async fn send_raw_transaction_conditional(
3271 &self,
3272 tx: Bytes,
3273 _condition: TransactionConditional,
3274 ) -> Result<TxHash> {
3275 node_info!("eth_sendRawTransactionConditional");
3276 self.send_raw_transaction(tx).await
3277 }
3278
3279 pub fn anvil_classify_transaction(&self, tx: Bytes) -> Result<PaymentLaneClassification> {
3281 node_info!("anvil_classifyTransaction");
3282 let mut data = tx.as_ref();
3283 if data.is_empty() {
3284 return Err(BlockchainError::EmptyRawTransactionData);
3285 }
3286
3287 FoundryTxEnvelope::decode_2718(&mut data)
3288 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3289
3290 Ok(self.classify_transaction_lane(tx.as_ref()))
3291 }
3292
3293 fn classify_transaction_lane(&self, raw: &[u8]) -> PaymentLaneClassification {
3294 if !self.backend.is_tempo() {
3295 return PaymentLaneClassification::general(PaymentLaneReason::NotTempo);
3296 }
3297
3298 if !TempoHardfork::from(self.backend.hardfork()).is_t5() {
3299 return PaymentLaneClassification::general(PaymentLaneReason::T5NotActive);
3300 }
3301
3302 classify_payment_lane(raw)
3303 }
3304
3305 pub async fn send_raw_transaction_sync(
3309 &self,
3310 tx: Bytes,
3311 timeout_ms: Option<u64>,
3312 ) -> Result<FoundryTxReceipt> {
3313 node_info!("eth_sendRawTransactionSync");
3314
3315 let hash = self.send_raw_transaction(tx).await?;
3316 let receipt = self.check_transaction_inclusion(hash, timeout_ms).await?;
3317
3318 Ok(receipt)
3319 }
3320
3321 pub async fn sign_raw_transaction(&self, tx: Bytes) -> Result<Bytes> {
3330 node_info!("eth_signRawTransaction");
3331 if !self.backend.is_tempo() {
3332 return Err(BlockchainError::RpcUnimplemented);
3333 }
3334
3335 if tx.is_empty() {
3336 return Err(BlockchainError::EmptyRawTransactionData);
3337 }
3338
3339 let service_encoded = normalize_fee_payer_service_encoding(tx.as_ref());
3342 let mut data = service_encoded.as_deref().unwrap_or(tx.as_ref());
3343
3344 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
3345 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3346
3347 let FoundryTxEnvelope::Tempo(aa_tx) = transaction else {
3348 return Err(RpcError::invalid_params(
3349 "only Tempo (0x76) transactions can be fee-payer signed",
3350 )
3351 .into());
3352 };
3353
3354 let signed = self.sponsor_sign_tempo_transaction(aa_tx).await?;
3355 Ok(FoundryTxEnvelope::Tempo(signed).encoded_2718().into())
3356 }
3357
3358 async fn sponsor_sign_tempo_transaction(&self, tx: AASigned) -> Result<AASigned> {
3364 match tx.tx().fee_payer_signature {
3368 Some(FEE_PAYER_SIGNATURE_MARKER) => {}
3369 Some(_) => {
3370 return Err(
3371 RpcError::invalid_params("transaction is already fee-payer signed").into()
3372 );
3373 }
3374 None => {
3375 return Err(RpcError::invalid_params(
3376 "transaction does not request sponsorship; sign it with the fee payer \
3377 signature placeholder",
3378 )
3379 .into());
3380 }
3381 }
3382
3383 let sender = tx.recover_signer().map_err(|_| {
3384 BlockchainError::RpcError(RpcError::invalid_params(
3385 "transaction must be signed by the sender before fee-payer signing",
3386 ))
3387 })?;
3388
3389 let Some(sponsor) = self.backend.tempo_fee_payer().await else {
3390 return Err(RpcError::invalid_params("no Tempo fee payer account available").into());
3391 };
3392 if sponsor == sender {
3393 return Err(RpcError::invalid_params(format!(
3394 "Tempo fee payer {sponsor} must not equal the transaction sender"
3395 ))
3396 .into());
3397 }
3398 let signer = self.get_signer(sponsor).ok_or(BlockchainError::NoSignerAvailable)?;
3399
3400 let (mut tx, sender_signature, _) = tx.into_parts();
3401 if tx.fee_token.is_none() {
3405 tx.fee_token = Some(self.backend.tempo_user_fee_token(sponsor).await?);
3406 }
3407 let digest = tx.fee_payer_signature_hash(sender);
3408 tx.fee_payer_signature = Some(signer.sign_hash(sponsor, digest).await?);
3409
3410 Ok(tx.into_signed(sender_signature))
3411 }
3412
3413 pub async fn call(
3417 &self,
3418 request: WithOtherFields<TransactionRequest>,
3419 block_number: Option<BlockId>,
3420 overrides: EvmOverrides,
3421 ) -> Result<Bytes> {
3422 node_info!("eth_call");
3423 let block_request = self.block_request(block_number).await?;
3424 if let BlockRequest::Number(number) = block_request
3426 && let Some(fork) = self.get_fork()
3427 && fork.predates_fork(number)
3428 {
3429 if overrides.has_state() || overrides.has_block() {
3430 return Err(BlockchainError::EvmOverrideError(
3431 "not available on past forked blocks".to_string(),
3432 ));
3433 }
3434 return Ok(fork.call_raw(&request, Some(number.into())).await?);
3435 }
3436
3437 #[cfg(feature = "base")]
3438 if self.backend.is_base()
3439 && serde_json::to_value(&request)
3440 .and_then(serde_json::from_value::<BaseTransactionRequest>)
3441 .is_ok_and(|request| request.as_eip8130().is_some())
3442 {
3443 let timestamp = self.backend.block_request_timestamp(&block_request).await?;
3444 self.backend.ensure_base_eip8130_active_at(timestamp)?;
3445 }
3446
3447 let fees = FeeDetails::new(
3448 request.gas_price,
3449 request.max_fee_per_gas,
3450 request.max_priority_fee_per_gas,
3451 request.max_fee_per_blob_gas,
3452 )?
3453 .or_zero_fees();
3454 self.on_blocking_task(|this| async move {
3457 let (exit, out, gas, _) =
3458 this.backend.call(request, fees, Some(block_request), overrides).await?;
3459 trace!(target : "node", "Call status {:?}, gas {}", exit, gas);
3460
3461 ensure_return_ok(exit, &out)
3462 })
3463 .await
3464 }
3465
3466 pub async fn call_many(
3467 &self,
3468 bundles: Vec<Bundle<WithOtherFields<TransactionRequest>>>,
3469 state_context: Option<StateContext>,
3470 state_override: Option<StateOverride>,
3471 ) -> Result<Vec<Vec<EthCallResponse>>> {
3472 node_info!("eth_callMany");
3473 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
3474 if transaction_index.is_some_and(|index| index.index().is_some()) {
3475 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3476 "transactionIndex is not supported for eth_callMany yet".to_string(),
3477 )));
3478 }
3479
3480 let block_request = self.block_request(block_number).await?;
3481 if let BlockRequest::Number(number) = block_request
3482 && let Some(fork) = self.get_fork()
3483 && fork.predates_fork(number)
3484 {
3485 return Ok(fork
3486 .call_many(
3487 bundles,
3488 Some(StateContext { transaction_index, block_number: Some(number.into()) }),
3489 state_override,
3490 )
3491 .await?);
3492 }
3493
3494 self.on_blocking_task(|this| async move {
3495 this.backend.call_many(bundles, Some(block_request), state_override).await
3496 })
3497 .await
3498 }
3499
3500 pub async fn call_bundle(&self, bundle: EthCallBundle) -> Result<EthCallBundleResponse> {
3504 node_info!("eth_callBundle");
3505 if bundle.txs.is_empty() {
3506 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3507 "bundle missing txs".to_string(),
3508 )));
3509 }
3510 if bundle.block_number == 0 {
3511 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3512 "bundle missing blockNumber".to_string(),
3513 )));
3514 }
3515
3516 let block_request = self.block_request(Some(bundle.state_block_number.into())).await?;
3517 if let BlockRequest::Number(number) = block_request
3518 && let Some(fork) = self.get_fork()
3519 && fork.predates_fork(number)
3520 {
3521 return Ok(fork.call_bundle(bundle).await?);
3522 }
3523
3524 let transactions = bundle
3525 .txs
3526 .iter()
3527 .map(|raw| {
3528 let mut data = raw.as_ref();
3529 if data.is_empty() {
3530 return Err(BlockchainError::EmptyRawTransactionData);
3531 }
3532 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
3533 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3534 self.ensure_typed_transaction_supported(&transaction)?;
3535 PendingTransaction::new(transaction).map_err(Into::into)
3536 })
3537 .collect::<Result<Vec<_>>>()?;
3538
3539 self.on_blocking_task(|this| async move {
3540 this.backend.call_bundle(bundle, transactions, Some(block_request)).await
3541 })
3542 .await
3543 }
3544
3545 pub async fn simulate_v1(
3546 &self,
3547 request: SimulatePayload,
3548 block_number: Option<BlockId>,
3549 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
3550 self.simulate_v1_raw(preserve_simulation_request_fields(request), block_number).await
3551 }
3552
3553 pub(crate) async fn simulate_v1_raw(
3554 &self,
3555 mut request: SimulatePayload<WithOtherFields<TransactionRequest>>,
3556 block_number: Option<BlockId>,
3557 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
3558 const DEFAULT_BLOCK_INTERVAL_SECS: u64 = 12;
3559
3560 node_info!("eth_simulateV1");
3561 if request.block_state_calls.is_empty() {
3562 return Err(BlockchainError::RpcError(RpcError::invalid_params("empty input")));
3563 }
3564 if request.block_state_calls.len() > MAX_SIMULATE_BLOCKS as usize {
3565 return Err(BlockchainError::RpcError(RpcError {
3566 code: ErrorCode::ServerError(-38026),
3567 message: "too many blocks".into(),
3568 data: None,
3569 }));
3570 }
3571 let block_id = block_number;
3572 let block_request =
3573 self.block_request(block_number).await.map_err(|error| match error {
3574 BlockchainError::BlockOutOfRange(_, _) | BlockchainError::BlockNotFound => {
3575 BlockchainError::RpcError(RpcError {
3576 code: ErrorCode::ServerError(-32000),
3577 message: "header not found".into(),
3578 data: None,
3579 })
3580 }
3581 error => error,
3582 })?;
3583 let block_interval = self.backend.time().block_timestamp_interval().unwrap_or_else(|| {
3584 self.miner
3585 .block_interval()
3586 .map(|duration| {
3587 duration
3588 .as_secs()
3589 .saturating_add(u64::from(duration.subsec_nanos() != 0))
3590 .max(1)
3591 })
3592 .unwrap_or(DEFAULT_BLOCK_INTERVAL_SECS)
3593 });
3594
3595 if let BlockRequest::Number(number) = block_request
3597 && let Some(fork) = self.get_fork()
3598 && fork.predates_fork(number)
3599 {
3600 let block_id = match block_id {
3601 Some(BlockId::Hash(hash)) => BlockId::Hash(hash),
3602 _ => number.into(),
3603 };
3604 let base_block = fork.fetch_block(block_id).await?.ok_or_else(|| {
3605 BlockchainError::RpcError(RpcError {
3606 code: ErrorCode::ServerError(-32000),
3607 message: "header not found".into(),
3608 data: None,
3609 })
3610 })?;
3611 request.block_state_calls = sanitize_simulation_blocks(
3612 request.block_state_calls,
3613 base_block.header.number(),
3614 base_block.header.timestamp(),
3615 block_interval,
3616 )?;
3617 return Ok(fork.simulate_v1(&request, Some(base_block.header.hash.into())).await?);
3618 }
3619
3620 self.on_blocking_task(|this| async move {
3623 let simulated_blocks =
3624 this.backend.simulate_raw(request, Some(block_request), block_interval).await?;
3625 trace!(target : "node", "Simulate status {:?}", simulated_blocks);
3626
3627 Ok(simulated_blocks)
3628 })
3629 .await
3630 }
3631
3632 pub async fn create_access_list(
3646 &self,
3647 request: WithOtherFields<TransactionRequest>,
3648 block_number: Option<BlockId>,
3649 state_override: Option<StateOverride>,
3650 ) -> Result<AccessListResult> {
3651 node_info!("eth_createAccessList");
3652 let block_request = self.block_request(block_number).await?;
3653 if let BlockRequest::Number(number) = block_request
3655 && let Some(fork) = self.get_fork()
3656 && fork.predates_fork(number)
3657 {
3658 if state_override.is_some() {
3659 return Err(BlockchainError::EvmOverrideError(
3660 "not available on past forked blocks".to_string(),
3661 ));
3662 }
3663 return Ok(fork.create_access_list_raw(&request, Some(number.into())).await?);
3664 }
3665 let typed_request = self.parse_transaction_request(request.clone())?;
3666
3667 #[cfg(feature = "base")]
3668 if self.backend.is_base()
3669 && serde_json::to_value(&request)
3670 .and_then(serde_json::from_value::<BaseTransactionRequest>)
3671 .is_ok_and(|request| request.as_eip8130().is_some())
3672 {
3673 let timestamp = self.backend.block_request_timestamp(&block_request).await?;
3674 self.backend.ensure_base_eip8130_active_at(timestamp)?;
3675 return Err(BlockchainError::InvalidTransactionRequest(
3676 "eth_createAccessList does not support EIP-8130 transaction requests".to_string(),
3677 ));
3678 }
3679
3680 self.backend
3681 .with_database_at_and_context(Some(block_request), |state, block_env, monad_context| {
3682 let mut cache_db = CacheDB::new(state);
3683 if let Some(state_override) = state_override {
3684 apply_state_overrides(state_override.into_iter().collect(), &mut cache_db)?;
3685 }
3686
3687 let (_, _, _, access_list) =
3688 self.backend.build_access_list_with_state_and_context(
3689 &cache_db,
3690 request.clone(),
3691 FeeDetails::zero(),
3692 block_env.clone(),
3693 monad_context.clone(),
3694 )?;
3695
3696 let (exit, _, gas_used, _) = self.backend.call_with_state_typed_access_list(
3701 &cache_db,
3702 typed_request,
3703 FeeDetails::zero(),
3704 block_env,
3705 access_list.clone(),
3706 monad_context,
3707 )?;
3708
3709 Ok(AccessListResult {
3710 access_list,
3711 gas_used: U256::from(gas_used),
3712 error: execution_error(exit),
3713 })
3714 })
3715 .await
3716 }
3717
3718 pub async fn estimate_gas(
3723 &self,
3724 request: WithOtherFields<TransactionRequest>,
3725 block_number: Option<BlockId>,
3726 overrides: EvmOverrides,
3727 ) -> Result<U256> {
3728 node_info!("eth_estimateGas");
3729 self.do_estimate_gas(request, block_number.or_else(|| Some(BlockId::pending())), overrides)
3730 .await
3731 .map(U256::from)
3732 }
3733
3734 pub async fn fill_transaction(
3741 &self,
3742 request: WithOtherFields<TransactionRequest>,
3743 ) -> Result<FillTransaction<AnyRpcTransaction>> {
3744 node_info!("eth_fillTransaction");
3745 let mut request = self.parse_transaction_request(request)?;
3746
3747 let from = match request.from() {
3748 Some(from) => from,
3749 None => self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)?,
3750 };
3751
3752 let nonce = self.request_nonce_for_transaction(&request, from).await?;
3753
3754 if request.gas_limit().is_none() {
3756 let estimated_gas =
3757 self.do_estimate_gas_typed(request.clone(), Some(BlockId::pending())).await?;
3758 request.set_gas_limit(estimated_gas as u64);
3759 }
3760
3761 let typed_tx = self.build_tx_request(request, nonce).await?;
3762 let tx = typed_tx.into_impersonated();
3763
3764 let raw = tx.encoded_2718().into();
3765
3766 let mut tx =
3767 transaction_build(None, MaybeImpersonatedTransaction::new(tx), None, None, None);
3768
3769 tx.0.inner.inner = Recovered::new_unchecked(tx.0.inner.inner.into_inner(), from);
3772
3773 Ok(FillTransaction { raw, tx })
3774 }
3775
3776 pub fn anvil_get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<Blob>>> {
3778 node_info!("anvil_getBlobsByTransactionHash");
3779 Ok(self.backend.get_blob_by_tx_hash(hash)?)
3780 }
3781
3782 pub async fn transaction_by_hash(&self, hash: B256) -> Result<Option<AnyRpcTransaction>> {
3789 node_info!("eth_getTransactionByHash");
3790 let mut tx =
3791 self.pool.get_transaction(hash).map(|pending| self.build_pool_transaction(pending));
3792 if tx.is_none() {
3793 tx = self.backend.transaction_by_hash(hash).await?
3794 }
3795
3796 Ok(tx)
3797 }
3798
3799 fn build_pool_transaction(
3800 &self,
3801 pending: PendingTransaction<FoundryTxEnvelope>,
3802 ) -> AnyRpcTransaction {
3803 let from = *pending.sender();
3804 let tx = transaction_build(
3805 Some(*pending.hash()),
3806 pending.transaction,
3807 None,
3808 None,
3809 Some(self.backend.base_fee()),
3810 );
3811
3812 let WithOtherFields { inner: mut tx, other } = tx.0;
3813 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3816
3817 AnyRpcTransaction(WithOtherFields { inner: tx, other })
3818 }
3819
3820 pub async fn pending_transactions(&self) -> Result<Vec<AnyRpcTransaction>> {
3824 node_info!("eth_pendingTransactions");
3825 Ok(self
3826 .pool
3827 .ready_transactions()
3828 .map(|pending| self.build_pool_transaction(pending.pending_transaction.clone()))
3829 .collect())
3830 }
3831
3832 pub async fn transaction_by_sender_and_nonce(
3839 &self,
3840 sender: Address,
3841 nonce: U256,
3842 ) -> Result<Option<AnyRpcTransaction>> {
3843 node_info!("eth_getTransactionBySenderAndNonce");
3844
3845 for pending_tx in self.pool.ready_transactions().chain(self.pool.pending_transactions()) {
3847 if U256::from(pending_tx.pending_transaction.nonce()) == nonce
3848 && *pending_tx.pending_transaction.sender() == sender
3849 {
3850 let tx = transaction_build(
3851 Some(*pending_tx.pending_transaction.hash()),
3852 pending_tx.pending_transaction.transaction.clone(),
3853 None,
3854 None,
3855 Some(self.backend.base_fee()),
3856 );
3857
3858 let WithOtherFields { inner: mut tx, other } = tx.0;
3859 let from = *pending_tx.pending_transaction.sender();
3862 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3863
3864 return Ok(Some(AnyRpcTransaction(WithOtherFields { inner: tx, other })));
3865 }
3866 }
3867
3868 let highest_nonce = self.transaction_count(sender, None).await?.saturating_to::<u64>();
3869 let target_nonce = nonce.saturating_to::<u64>();
3870
3871 if target_nonce >= highest_nonce {
3873 return Ok(None);
3874 }
3875
3876 let latest_block = self.backend.best_number();
3878 if latest_block == 0 {
3879 return Ok(None);
3880 }
3881
3882 let mut low = 1u64;
3884 let mut high = latest_block;
3885
3886 while low <= high {
3887 let mid = low + (high - low) / 2;
3888 let mid_nonce =
3889 self.transaction_count(sender, Some(mid.into())).await?.saturating_to::<u64>();
3890
3891 if mid_nonce > target_nonce {
3892 high = mid - 1;
3893 } else {
3894 low = mid + 1;
3895 }
3896 }
3897
3898 let target_block = low;
3900 if target_block <= latest_block
3901 && let Some(txs) =
3902 self.backend.mined_transactions_by_block_number(target_block.into()).await
3903 {
3904 for tx in txs {
3905 if tx.from() == sender && tx.nonce() == target_nonce {
3906 return Ok(Some(tx));
3907 }
3908 }
3909 }
3910
3911 Ok(None)
3912 }
3913
3914 pub async fn transaction_receipt(&self, hash: B256) -> Result<Option<FoundryTxReceipt>> {
3918 node_info!("eth_getTransactionReceipt");
3919 self.backend.transaction_receipt(hash).await
3920 }
3921
3922 pub async fn block_receipts(&self, number: BlockId) -> Result<Option<Vec<FoundryTxReceipt>>> {
3926 node_info!("eth_getBlockReceipts");
3927 if number == BlockId::pending() {
3928 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
3929 return Ok(Some(self.backend.pending_block_receipts(transactions).await?));
3930 }
3931
3932 self.backend.block_receipts(number).await
3933 }
3934
3935 pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>> {
3939 node_info!("eth_getLogs");
3940 let best = self.backend.best_number();
3941 let to_block =
3942 self.backend.convert_block_number(filter.block_option.get_to_block().copied());
3943 if to_block > best {
3944 return Err(BlockchainError::BlockOutOfRange(best, to_block));
3945 }
3946 let from_block =
3947 self.backend.convert_block_number(filter.block_option.get_from_block().copied());
3948 if from_block > to_block {
3949 return Err(RpcError::invalid_params("invalid block range params").into());
3950 }
3951
3952 self.backend.logs(filter).await
3953 }
3954
3955 pub async fn new_filter(&self, filter: Filter) -> Result<String> {
3959 node_info!("eth_newFilter");
3960 let historic = match filter.block_option.get_from_block() {
3962 Some(BlockNumber::Number(from))
3963 if *from > self.backend.best_number()
3964 && filter.block_option.get_to_block().is_none_or(|to| {
3965 to.is_latest() || to.as_number().is_some_and(|to| to >= *from)
3966 }) =>
3967 {
3968 vec![]
3969 }
3970 Some(_) => self.backend.logs(filter.clone()).await?,
3971 None => vec![],
3972 };
3973 let filter = EthFilter::Logs(Box::new(LogsFilter {
3974 blocks: self.new_block_notifications(),
3975 storage: self.storage_info(),
3976 filter: FilteredParams::new(Some(filter)),
3977 historic: Some(historic),
3978 }));
3979 Ok(self.filters.add_filter(filter).await)
3980 }
3981
3982 pub async fn new_block_filter(&self) -> Result<String> {
3986 node_info!("eth_newBlockFilter");
3987 let filter = EthFilter::Blocks(self.new_block_notifications());
3988 Ok(self.filters.add_filter(filter).await)
3989 }
3990
3991 pub async fn new_pending_transaction_filter(&self, full: bool) -> Result<String> {
3995 node_info!("eth_newPendingTransactionFilter");
3996 let filter = if full {
3997 EthFilter::FullPendingTransactions(self.full_pending_transactions_filter())
3998 } else {
3999 EthFilter::PendingTransactions(self.new_ready_transactions())
4000 };
4001 Ok(self.filters.add_filter(filter).await)
4002 }
4003
4004 pub async fn get_filter_changes(&self, id: &str) -> ResponseResult {
4008 node_info!("eth_getFilterChanges");
4009 self.filters.get_filter_changes(id).await
4010 }
4011
4012 pub async fn get_filter_logs(&self, id: &str) -> Result<Vec<Log>> {
4016 node_info!("eth_getFilterLogs");
4017 if let Some(filter) = self.filters.get_log_filter(id).await {
4018 self.backend.logs(filter).await
4019 } else {
4020 Err(BlockchainError::FilterNotFound)
4021 }
4022 }
4023
4024 pub async fn uninstall_filter(&self, id: &str) -> Result<bool> {
4026 node_info!("eth_uninstallFilter");
4027 Ok(self.filters.uninstall_filter(id).await.is_some())
4028 }
4029
4030 pub async fn raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
4034 node_info!("debug_getRawTransaction");
4035 self.inner_raw_transaction(hash).await
4036 }
4037
4038 pub async fn raw_receipts(&self, block: BlockId) -> Result<Vec<Bytes>> {
4042 node_info!("debug_getRawReceipts");
4043
4044 if let BlockRequest::Number(number) = self.block_request(Some(block)).await?
4046 && let Some(fork) = self.get_fork()
4047 && fork.predates_fork_inclusive(number)
4048 {
4049 let receipts = fork.block_receipts(number).await?.unwrap_or_default();
4050 return Ok(receipts
4051 .into_iter()
4052 .map(|receipt| {
4053 receipt.0.inner.inner.map_logs(|log| log.inner).encoded_2718().into()
4054 })
4055 .collect());
4056 }
4057
4058 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4059 let receipts = self
4060 .backend
4061 .mined_receipts(block.header.hash_slow())
4062 .ok_or(BlockchainError::BlockNotFound)?;
4063 Ok(receipts.into_iter().map(|receipt| receipt.encoded_2718().into()).collect())
4064 }
4065
4066 pub async fn raw_transactions(&self, block: BlockId) -> Result<Vec<Bytes>> {
4070 node_info!("debug_getRawTransactions");
4071
4072 if let Some(block) = self.backend.get_block(block) {
4073 return Ok(block
4074 .body
4075 .transactions
4076 .into_iter()
4077 .map(|tx| tx.into_inner().into_canonical().encoded_2718().into())
4078 .collect());
4079 }
4080
4081 let Some(fork) = self.get_fork() else {
4084 return Ok(Vec::new());
4085 };
4086 let block = match block {
4087 BlockId::Number(BlockNumber::Pending) => None,
4088 BlockId::Number(number) => {
4089 let number = self.backend.convert_block_number(Some(number));
4090 if !fork.predates_fork_inclusive(number) {
4091 return Ok(Vec::new());
4092 }
4093 fork.block_by_number_full(number).await?
4094 }
4095 BlockId::Hash(hash) => fork
4096 .block_by_hash_full(hash.block_hash)
4097 .await?
4098 .filter(|block| fork.predates_fork_inclusive(block.header().number())),
4099 };
4100 let Some(block) = block else {
4101 return Ok(Vec::new());
4102 };
4103 let BlockTransactions::Full(txs) = block.transactions() else {
4104 return Err(BlockchainError::Internal(
4105 "fork provider returned a non-full block for a full block request".to_string(),
4106 ));
4107 };
4108 txs.iter().map(encode_rpc_transaction).collect()
4109 }
4110
4111 pub async fn raw_header(&self, block: BlockId) -> Result<Bytes> {
4115 node_info!("debug_getRawHeader");
4116 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4117 Ok(alloy_rlp::encode(&block.header).into())
4118 }
4119
4120 pub async fn raw_block(&self, block: BlockId) -> Result<Bytes> {
4124 node_info!("debug_getRawBlock");
4125 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4126 Ok(alloy_rlp::encode(canonical_block(block)).into())
4127 }
4128
4129 pub async fn raw_transaction_by_block_hash_and_index(
4133 &self,
4134 block_hash: B256,
4135 index: Index,
4136 ) -> Result<Option<Bytes>> {
4137 node_info!("eth_getRawTransactionByBlockHashAndIndex");
4138 match self.backend.transaction_by_block_hash_and_index(block_hash, index).await? {
4139 Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
4140 None => Ok(None),
4141 }
4142 }
4143
4144 pub async fn raw_transaction_by_block_number_and_index(
4148 &self,
4149 block_number: BlockNumber,
4150 index: Index,
4151 ) -> Result<Option<Bytes>> {
4152 node_info!("eth_getRawTransactionByBlockNumberAndIndex");
4153 match self.transaction_by_block_number_and_index(block_number, index).await? {
4154 Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
4155 None => Ok(None),
4156 }
4157 }
4158
4159 pub async fn debug_trace_transaction(
4163 &self,
4164 tx_hash: B256,
4165 opts: GethDebugTracingOptions,
4166 ) -> Result<GethTrace> {
4167 node_info!("debug_traceTransaction");
4168 self.backend.debug_trace_transaction(tx_hash, opts).await
4169 }
4170
4171 pub async fn debug_trace_block(
4175 &self,
4176 rlp_block: Bytes,
4177 opts: GethDebugTracingOptions,
4178 ) -> Result<Vec<TraceResult>> {
4179 node_info!("debug_traceBlock");
4180 self.backend.debug_trace_block(rlp_block, opts).await
4181 }
4182
4183 pub async fn debug_trace_block_by_hash(
4187 &self,
4188 block_hash: B256,
4189 opts: GethDebugTracingOptions,
4190 ) -> Result<Vec<TraceResult>> {
4191 node_info!("debug_traceBlockByHash");
4192 self.backend.debug_trace_block_by_hash(block_hash, opts).await
4193 }
4194
4195 pub async fn debug_trace_block_by_number(
4199 &self,
4200 block_number: BlockNumber,
4201 opts: GethDebugTracingOptions,
4202 ) -> Result<Vec<TraceResult>> {
4203 node_info!("debug_traceBlockByNumber");
4204 self.backend.debug_trace_block_by_number(block_number, opts).await
4205 }
4206
4207 pub async fn debug_trace_call(
4211 &self,
4212 request: WithOtherFields<TransactionRequest>,
4213 block_number: Option<BlockId>,
4214 opts: GethDebugTracingCallOptions,
4215 ) -> Result<GethTrace> {
4216 node_info!("debug_traceCall");
4217 let block_request = self.block_request(block_number).await?;
4218 let fees = FeeDetails::new(
4219 request.gas_price,
4220 request.max_fee_per_gas,
4221 request.max_priority_fee_per_gas,
4222 request.max_fee_per_blob_gas,
4223 )?
4224 .or_zero_fees();
4225
4226 let result: std::result::Result<GethTrace, BlockchainError> =
4227 self.backend.call_with_tracing(request, fees, Some(block_request), opts).await;
4228 result
4229 }
4230
4231 pub async fn trace_call_many(
4235 &self,
4236 calls: Vec<(WithOtherFields<TransactionRequest>, HashSet<TraceType>)>,
4237 block_number: Option<BlockId>,
4238 ) -> Result<Vec<TraceResults>> {
4239 node_info!("trace_callMany");
4240 let block_request = self.block_request(block_number).await?;
4241
4242 self.backend.trace_call_many(calls, Some(block_request)).await
4243 }
4244}
4245
4246impl EthApi<FoundryNetwork> {
4249 pub async fn anvil_mine(&self, num_blocks: Option<U256>, interval: Option<U256>) -> Result<()> {
4253 node_info!("anvil_mine");
4254 let interval = interval.map(|i| i.saturating_to::<u64>());
4255 let blocks = num_blocks.unwrap_or(U256::ONE);
4256 if blocks.is_zero() {
4257 return Ok(());
4258 }
4259
4260 self.on_blocking_task(|this| async move {
4261 for _ in 0..blocks.saturating_to::<u64>() {
4263 let pending_increase =
4265 interval.map(|interval| this.backend.time().apply_time_increase(interval));
4266 if let Err(error) = this.mine_one().await {
4267 if let Some(pending) = pending_increase {
4268 this.backend.time().revert_time_increase(pending);
4269 }
4270 return Err(error);
4271 }
4272 }
4273 Ok(())
4274 })
4275 .await?;
4276
4277 Ok(())
4278 }
4279
4280 async fn find_erc20_storage_slot(
4297 &self,
4298 token_address: Address,
4299 calldata: Bytes,
4300 expected_value: U256,
4301 ) -> Result<B256> {
4302 let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone());
4303
4304 let access_list_result =
4306 self.create_access_list(WithOtherFields::new(tx.clone()), None, None).await?;
4307 let access_list = access_list_result.access_list;
4308
4309 for item in access_list.0 {
4312 if item.address != token_address {
4313 continue;
4314 };
4315 for slot in &item.storage_keys {
4316 let account_override = AccountOverride::default()
4317 .with_state_diff(std::iter::once((*slot, B256::from(expected_value))));
4318
4319 let state_override = StateOverridesBuilder::default()
4320 .append(token_address, account_override)
4321 .build();
4322
4323 let evm_override = EvmOverrides::state(Some(state_override));
4324
4325 let Ok(result) =
4326 self.call(WithOtherFields::new(tx.clone()), None, evm_override).await
4327 else {
4328 continue;
4330 };
4331
4332 let Ok(result_value) = U256::abi_decode(&result) else {
4333 continue;
4335 };
4336
4337 if result_value == expected_value {
4338 return Ok(*slot);
4339 }
4340 }
4341 }
4342
4343 Err(BlockchainError::Message("Unable to find storage slot".to_string()))
4344 }
4345
4346 pub async fn anvil_deal_erc20(
4350 &self,
4351 address: Address,
4352 token_address: Address,
4353 balance: U256,
4354 ) -> Result<()> {
4355 node_info!("anvil_dealERC20");
4356
4357 if self.backend.is_tempo()
4358 && self.backend.try_set_tip20_balance(address, token_address, balance).await?
4359 {
4360 return Ok(());
4361 }
4362
4363 sol! {
4364 #[sol(rpc)]
4365 contract IERC20 {
4366 function balanceOf(address target) external view returns (uint256);
4367 }
4368 }
4369
4370 let calldata = IERC20::balanceOfCall { target: address }.abi_encode().into();
4371
4372 let slot =
4374 self.find_erc20_storage_slot(token_address, calldata, balance).await.map_err(|_| {
4375 BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string())
4376 })?;
4377
4378 self.anvil_set_storage_at(token_address, slot.into(), balance.into()).await?;
4380
4381 Ok(())
4382 }
4383
4384 pub async fn anvil_deal_tip20(
4388 &self,
4389 address: Address,
4390 token_address: Address,
4391 balance: U256,
4392 ) -> Result<()> {
4393 node_info!("anvil_dealTIP20");
4394 self.ensure_tempo_mode()?;
4395 self.backend.set_tip20_balance(address, token_address, balance).await?;
4396 Ok(())
4397 }
4398
4399 pub async fn anvil_set_erc20_allowance(
4403 &self,
4404 owner: Address,
4405 spender: Address,
4406 token_address: Address,
4407 amount: U256,
4408 ) -> Result<()> {
4409 node_info!("anvil_setERC20Allowance");
4410
4411 sol! {
4412 #[sol(rpc)]
4413 contract IERC20 {
4414 function allowance(address owner, address spender) external view returns (uint256);
4415 }
4416 }
4417
4418 let calldata = IERC20::allowanceCall { owner, spender }.abi_encode().into();
4419
4420 let slot =
4422 self.find_erc20_storage_slot(token_address, calldata, amount).await.map_err(|_| {
4423 BlockchainError::Message("Unable to set ERC20 allowance, no slot found".to_string())
4424 })?;
4425
4426 self.anvil_set_storage_at(token_address, slot.into(), amount.into()).await?;
4428
4429 Ok(())
4430 }
4431
4432 #[cfg(feature = "monad")]
4435 fn monad_protocol_reorg_transaction(
4436 &self,
4437 transaction: FoundryTxEnvelope,
4438 ) -> Option<PendingTransaction<FoundryTxEnvelope>> {
4439 if !self.backend.is_monad() {
4440 return None;
4441 }
4442
4443 let pending = PendingTransaction::with_sender(
4444 MaybeImpersonatedTransaction::new(transaction),
4445 monad_revm::staking::constants::SYSTEM_ADDRESS,
4446 );
4447 let tx_env: revm::context::TxEnv = crate::eth::backend::executor::build_tx_env_for_pending(
4448 &pending,
4449 self.backend.cheats(),
4450 );
4451 foundry_evm::core::evm::protocol_system_call(&tx_env)
4452 .is_ok_and(|call| call.is_some())
4453 .then_some(pending)
4454 }
4455
4456 pub async fn anvil_reorg(&self, options: ReorgOptions) -> Result<()> {
4470 node_info!("anvil_reorg");
4471 let _lifecycle = self.lifecycle_lock.write().await;
4472 let mining_guard = self.backend.lock_mining().await;
4473 let depth = options.depth;
4474 let mut tx_block_pairs = options.tx_block_pairs;
4475
4476 if let Some((_, num)) = tx_block_pairs.iter().find(|(_, num)| *num >= depth) {
4477 let Some(last_block) = depth.checked_sub(1) else {
4479 return Err(BlockchainError::RpcError(RpcError::invalid_params(
4480 "Reorg depth must be at least 1 to include transactions",
4481 )));
4482 };
4483 return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
4484 "Block number for reorg tx will exceed the reorged chain height. Block number {num} must not exceed (depth-1) {last_block}"
4485 ))));
4486 }
4487 tx_block_pairs.sort_by_key(|a| a.1);
4488
4489 let current_height = self.backend.best_number();
4491 let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(
4492 RpcError::invalid_params(format!(
4493 "Reorg depth must not exceed current chain height: current height {current_height}, depth {depth}"
4494 )),
4495 ))?;
4496
4497 let common_block =
4499 self.rollback_block(common_height).await?.ok_or(BlockchainError::BlockNotFound)?;
4500
4501 #[cfg(feature = "monad")]
4502 let fee_defaults = if self.backend.is_monad() {
4503 self.backend
4504 .monad_rollback_fee_defaults(&common_block, self.lowest_suggestion_tip())
4505 .await
4506 .map(|(gas_price, blob_gas_price)| TransactionFeeDefaults {
4507 gas_price,
4508 blob_gas_price,
4509 })
4510 } else {
4511 None
4512 };
4513 #[cfg(not(feature = "monad"))]
4514 let fee_defaults = None;
4515
4516 let block_pool_txs = if tx_block_pairs.is_empty() {
4519 HashMap::default()
4520 } else {
4521 let mut nonces: HashMap<Address, u64> = HashMap::default();
4524
4525 let mut txs: HashMap<u64, Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>> =
4526 HashMap::default();
4527 for pair in tx_block_pairs {
4528 let (tx_data, block_index) = pair;
4529
4530 let pending = match tx_data {
4531 TransactionData::Raw(bytes) => {
4532 let mut data = bytes.as_ref();
4533 let decoded = FoundryTxEnvelope::decode_2718(&mut data)
4534 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
4535 if matches!(&decoded, FoundryTxEnvelope::Celo(_)) {
4536 self.ensure_typed_transaction_supported(&decoded)?;
4537 }
4538 let protocol_pending = {
4539 #[cfg(feature = "monad")]
4540 {
4541 self.monad_protocol_reorg_transaction(decoded.clone())
4542 }
4543 #[cfg(not(feature = "monad"))]
4544 {
4545 None
4546 }
4547 };
4548 if let Some(pending) = protocol_pending {
4549 pending
4550 } else {
4551 PendingTransaction::new(decoded)?
4552 }
4553 }
4554
4555 TransactionData::JSON(request) => {
4556 let request = if request.transaction_type
4557 == Some(foundry_primitives::CIP64_TX_TYPE)
4558 || request
4559 .other
4560 .get("feeCurrency")
4561 .is_some_and(|value| !value.is_null())
4562 {
4563 self.parse_transaction_request(request)?
4564 } else {
4565 request.inner.into()
4566 };
4567 let from = request.from().map(Ok).unwrap_or_else(|| {
4568 self.accounts()?
4569 .first()
4570 .copied()
4571 .ok_or(BlockchainError::NoSignerAvailable)
4572 })?;
4573
4574 let curr_nonce = nonces.entry(from).or_insert(
4576 self.get_transaction_count(
4577 from,
4578 Some(common_block.header.number().into()),
4579 )
4580 .await?,
4581 );
4582
4583 let typed_tx = self
4585 .build_tx_request_with_fee_defaults(request, *curr_nonce, fee_defaults)
4586 .await?;
4587
4588 *curr_nonce += 1;
4590
4591 let protocol_pending = {
4592 #[cfg(feature = "monad")]
4593 {
4594 if from == monad_revm::staking::constants::SYSTEM_ADDRESS {
4595 self.monad_protocol_reorg_transaction(
4596 typed_tx.clone().into_impersonated(),
4597 )
4598 } else {
4599 None
4600 }
4601 }
4602 #[cfg(not(feature = "monad"))]
4603 {
4604 None
4605 }
4606 };
4607 if let Some(pending) = protocol_pending {
4608 pending
4609 } else if self.is_impersonated(from) {
4610 let transaction = typed_tx.into_impersonated();
4611 self.ensure_typed_transaction_supported(&transaction)?;
4612 PendingTransaction::with_impersonated(transaction, from)
4613 } else {
4614 let transaction = self.sign_request(&from, typed_tx)?;
4615 self.ensure_typed_transaction_supported(&transaction)?;
4616 PendingTransaction::new(transaction)?
4617 }
4618 }
4619 };
4620
4621 let pooled = PoolTransaction::new(pending).with_replay();
4622 txs.entry(block_index).or_default().push(Arc::new(pooled));
4623 }
4624
4625 txs
4626 };
4627
4628 self.rollback_backend(common_block, &mining_guard).await?;
4629 self.backend.reorg(depth, block_pool_txs, &mining_guard).await?;
4630 Ok(())
4631 }
4632
4633 pub async fn evm_mine(&self, opts: Option<MineOptions>) -> Result<String> {
4640 node_info!("evm_mine");
4641
4642 self.do_evm_mine(opts).await?;
4643
4644 Ok("0x0".to_string())
4645 }
4646
4647 pub async fn evm_mine_detailed(&self, opts: Option<MineOptions>) -> Result<Vec<AnyRpcBlock>> {
4657 node_info!("evm_mine_detailed");
4658
4659 let mined_blocks = self.do_evm_mine(opts).await?;
4660
4661 let mut blocks = Vec::with_capacity(mined_blocks as usize);
4662
4663 let latest = self.backend.best_number();
4664 for offset in (0..mined_blocks).rev() {
4665 let block_num = latest - offset;
4666 if let Some(mut block) =
4667 self.backend.block_by_number_full(BlockNumber::Number(block_num)).await?
4668 {
4669 let block_txs = match block.transactions_mut() {
4670 BlockTransactions::Full(txs) => txs,
4671 BlockTransactions::Hashes(_) | BlockTransactions::Uncle => unreachable!(),
4672 };
4673 for tx in block_txs.iter_mut() {
4674 if let Some(receipt) = self.backend.mined_transaction_receipt(tx.tx_hash())
4675 && let Some(output) = receipt.out
4676 {
4677 if !receipt.inner.as_ref().status()
4679 && let Some(reason) = RevertDecoder::new().maybe_decode(&output, None)
4680 {
4681 tx.other.insert(
4682 "revertReason".to_string(),
4683 serde_json::to_value(reason).expect("Infallible"),
4684 );
4685 }
4686 tx.other.insert(
4687 "output".to_string(),
4688 serde_json::to_value(output).expect("Infallible"),
4689 );
4690 }
4691 }
4692 block.transactions = BlockTransactions::Full(block_txs.clone());
4693 blocks.push(block);
4694 }
4695 }
4696
4697 Ok(blocks)
4698 }
4699
4700 pub async fn eth_send_unsigned_transaction(
4704 &self,
4705 request: WithOtherFields<TransactionRequest>,
4706 ) -> Result<TxHash> {
4707 node_info!("eth_sendUnsignedTransaction");
4708 let request = self.parse_transaction_request(request)?;
4709 let from = request.from().ok_or(BlockchainError::NoSignerAvailable)?;
4711
4712 let nonce = self.request_nonce_for_transaction(&request, from).await?;
4713
4714 let typed_tx = self.build_tx_request(request, nonce).await?;
4715
4716 let transaction = typed_tx.into_impersonated();
4717
4718 self.ensure_typed_transaction_supported(&transaction)?;
4719
4720 let pending_transaction = PendingTransaction::with_impersonated(transaction, from);
4721
4722 self.add_pending_transaction(pending_transaction).await
4723 }
4724
4725 pub async fn txpool_inspect(&self) -> Result<TxpoolInspect> {
4732 node_info!("txpool_inspect");
4733 let mut inspect = TxpoolInspect::default();
4734
4735 fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> TxpoolInspectSummary {
4736 let tx = &tx.pending_transaction.transaction;
4737 let to = tx.to();
4738 let gas_price = tx.max_fee_per_gas();
4739 let value = tx.value();
4740 let gas = tx.gas_limit();
4741 TxpoolInspectSummary { to, value, gas, gas_price }
4742 }
4743
4744 for pending in self.pool.ready_transactions() {
4751 let entry = inspect.pending.entry(*pending.pending_transaction.sender()).or_default();
4752 let key = txpool_transaction_key(&pending.pending_transaction);
4753 entry.insert(key, convert(pending));
4754 }
4755 for queued in self.pool.pending_transactions() {
4756 let entry = inspect.queued.entry(*queued.pending_transaction.sender()).or_default();
4757 let key = txpool_transaction_key(&queued.pending_transaction);
4758 entry.insert(key, convert(queued));
4759 }
4760 Ok(inspect)
4761 }
4762
4763 pub async fn txpool_content(&self) -> Result<TxpoolContent<AnyRpcTransaction>> {
4770 node_info!("txpool_content");
4771 self.build_txpool_content(None)
4772 }
4773
4774 fn build_txpool_content(
4779 &self,
4780 filter: Option<Address>,
4781 ) -> Result<TxpoolContent<AnyRpcTransaction>> {
4782 let mut content = TxpoolContent::<AnyRpcTransaction>::default();
4783 fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> Result<AnyRpcTransaction> {
4784 let from = *tx.pending_transaction.sender();
4785 let tx = transaction_build(
4786 Some(tx.hash()),
4787 tx.pending_transaction.transaction.clone(),
4788 None,
4789 None,
4790 None,
4791 );
4792
4793 let WithOtherFields { inner: mut tx, other } = tx.0;
4794
4795 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
4798
4799 let tx = AnyRpcTransaction(WithOtherFields { inner: tx, other });
4800
4801 Ok(tx)
4802 }
4803
4804 for pending in self.pool.ready_transactions() {
4805 let sender = *pending.pending_transaction.sender();
4806 if filter.is_some_and(|from| from != sender) {
4807 continue;
4808 }
4809 let entry = content.pending.entry(sender).or_default();
4810 let key = txpool_transaction_key(&pending.pending_transaction);
4811 entry.insert(key, convert(pending)?);
4812 }
4813 for queued in self.pool.pending_transactions() {
4814 let sender = *queued.pending_transaction.sender();
4815 if filter.is_some_and(|from| from != sender) {
4816 continue;
4817 }
4818 let entry = content.queued.entry(sender).or_default();
4819 let key = txpool_transaction_key(&queued.pending_transaction);
4820 entry.insert(key, convert(queued)?);
4821 }
4822
4823 Ok(content)
4824 }
4825
4826 pub async fn txpool_content_from(
4834 &self,
4835 from: Address,
4836 ) -> Result<TxpoolContentFrom<AnyRpcTransaction>> {
4837 node_info!("txpool_contentFrom");
4838 let mut content = self.build_txpool_content(Some(from))?;
4839 Ok(content.remove_from(&from))
4840 }
4841}
4842
4843impl EthApi<FoundryNetwork> {
4844 async fn do_evm_mine(&self, opts: Option<MineOptions>) -> Result<u64> {
4846 let mut blocks_to_mine = 1u64;
4847
4848 if let Some(opts) = opts {
4849 let timestamp = match opts {
4850 MineOptions::Timestamp(timestamp) => timestamp,
4851 MineOptions::Options { timestamp, blocks } => {
4852 if let Some(blocks) = blocks {
4853 blocks_to_mine = blocks;
4854 }
4855 timestamp
4856 }
4857 };
4858 if let Some(timestamp) = timestamp {
4859 self.evm_set_next_block_timestamp(timestamp)?;
4861 }
4862 }
4863
4864 self.on_blocking_task(|this| async move {
4867 for _ in 0..blocks_to_mine {
4869 this.mine_one().await?;
4870 }
4871 Ok(())
4872 })
4873 .await?;
4874
4875 Ok(blocks_to_mine)
4876 }
4877
4878 async fn do_estimate_gas(
4879 &self,
4880 request: WithOtherFields<TransactionRequest>,
4881 block_number: Option<BlockId>,
4882 overrides: EvmOverrides,
4883 ) -> Result<u128> {
4884 let block_request = self.block_request(block_number).await?;
4885 if let BlockRequest::Number(number) = block_request
4887 && let Some(fork) = self.get_fork()
4888 && fork.predates_fork(number)
4889 {
4890 if overrides.has_state() || overrides.has_block() {
4891 return Err(BlockchainError::EvmOverrideError(
4892 "not available on past forked blocks".to_string(),
4893 ));
4894 }
4895 return Ok(fork.estimate_gas_raw(&request, Some(number.into())).await?);
4896 }
4897
4898 self.on_blocking_task(|this| async move {
4901 let request = this.parse_transaction_request(request)?;
4902 this.backend
4903 .with_database_at_and_context(
4904 Some(block_request),
4905 |state, mut block, monad_context| {
4906 let mut cache_db = CacheDB::new(state);
4907 if let Some(state_overrides) = overrides.state {
4908 apply_state_overrides(
4909 state_overrides.into_iter().collect(),
4910 &mut cache_db,
4911 )?;
4912 }
4913 if let Some(block_overrides) = overrides.block {
4914 cache_db.apply_block_overrides(*block_overrides, &mut block);
4915 }
4916 this.do_estimate_gas_with_state(request, &cache_db, block, monad_context)
4917 },
4918 )
4919 .await
4920 })
4921 .await
4922 }
4923
4924 async fn do_estimate_gas_typed(
4925 &self,
4926 request: FoundryTransactionRequest,
4927 block_number: Option<BlockId>,
4928 ) -> Result<u128> {
4929 let block_request = self.block_request(block_number).await?;
4930 self.on_blocking_task(|this| async move {
4931 this.backend
4932 .with_database_at_and_context(Some(block_request), |state, block, monad_context| {
4933 this.do_estimate_gas_with_state(request, &state, block, monad_context)
4934 })
4935 .await
4936 })
4937 .await
4938 }
4939
4940 fn transaction_priority(&self, tx: &FoundryTxEnvelope) -> TransactionPriority {
4942 self.transaction_order.read().priority(tx)
4943 }
4944
4945 pub fn full_pending_transactions(&self) -> UnboundedReceiver<AnyRpcTransaction> {
4947 let (tx, rx) = unbounded_channel();
4948 let mut hashes = self.new_ready_transactions();
4949
4950 let this = self.clone();
4951
4952 tokio::spawn(async move {
4953 while let Some(hash) = hashes.next().await {
4954 if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
4955 && tx.send(txn).is_err()
4956 {
4957 break;
4958 }
4959 }
4960 });
4961
4962 rx
4963 }
4964
4965 pub fn full_pending_transactions_filter(&self) -> mpsc::Receiver<AnyRpcTransaction> {
4970 let (tx, rx) = mpsc::channel(2048);
4972 let mut hashes = self.new_ready_transactions();
4973 let this = self.clone();
4974
4975 tokio::spawn(async move {
4976 while let Some(hash) = hashes.next().await {
4977 if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
4978 && tx.send(txn).await.is_err()
4979 {
4980 break;
4981 }
4982 }
4983 });
4984
4985 rx
4986 }
4987
4988 pub fn transaction_receipts_subscription(
4990 &self,
4991 filter: TransactionReceiptsParams,
4992 ) -> UnboundedReceiver<Vec<FoundryTxReceipt>> {
4993 let (tx, rx) = unbounded_channel();
4994 let mut blocks = self.new_block_notifications();
4995 let this = self.clone();
4996
4997 tokio::spawn(async move {
4998 let hash_filter = filter
5000 .transaction_hashes
5001 .filter(|hashes| !hashes.is_empty())
5002 .map(|hashes| hashes.into_iter().collect::<B256Set>());
5003
5004 loop {
5005 let notification = tokio::select! {
5006 biased;
5007 _ = tx.closed() => break,
5009 maybe_block = blocks.next() => match maybe_block {
5010 Some(block) => block,
5011 None => break,
5012 },
5013 };
5014
5015 let Some(block) = notification.as_new_block() else {
5016 continue;
5017 };
5018
5019 let receipts = match this.block_receipts(BlockId::hash(block.hash)).await {
5020 Ok(Some(mut receipts)) => {
5021 if let Some(hashes) = &hash_filter {
5022 receipts.retain(|receipt| hashes.contains(&receipt.transaction_hash()));
5023 }
5024 receipts
5025 }
5026 Ok(None) => continue,
5027 Err(err) => {
5028 trace!(target: "node", %err, "failed to build block receipts for subscription");
5029 continue;
5030 }
5031 };
5032
5033 if receipts.is_empty() {
5034 continue;
5035 }
5036
5037 if tx.send(receipts).is_err() {
5038 break;
5039 }
5040 }
5041 });
5042
5043 rx
5044 }
5045
5046 pub async fn mine_one(&self) -> Result<()> {
5048 let _mining = self.backend.lock_mining().await;
5049 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5050 let outcome = self.backend.mine_block_locked(transactions).await?;
5051
5052 trace!(target: "node", blocknumber = ?outcome.block_number, "mined block");
5053 if self.pool.on_mined_block(outcome) {
5054 self.miner.retry_ready_transactions();
5055 }
5056 Ok(())
5057 }
5058
5059 async fn pending_block(&self) -> Result<AnyRpcBlock> {
5061 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5062 let info = self.backend.pending_block(transactions).await?;
5063 Ok(self.backend.convert_block(info.block))
5064 }
5065
5066 async fn pending_block_full(&self) -> Result<Option<AnyRpcBlock>> {
5068 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5069 let BlockInfo { block, transactions, receipts: _ } =
5070 self.backend.pending_block(transactions).await?;
5071
5072 let mut partial_block = self.backend.convert_block(block.clone());
5073
5074 let mut block_transactions = Vec::with_capacity(block.body.transactions.len());
5075 let base_fee = self.backend.base_fee();
5076
5077 for info in transactions {
5078 let Some(tx) = block.body.transactions.get(info.transaction_index as usize).cloned()
5079 else {
5080 return Ok(None);
5081 };
5082
5083 let tx = transaction_build(
5084 Some(info.transaction_hash),
5085 tx,
5086 Some(&block),
5087 Some(info),
5088 Some(base_fee),
5089 );
5090 block_transactions.push(tx);
5091 }
5092
5093 partial_block.transactions = BlockTransactions::from(block_transactions);
5094
5095 Ok(Some(partial_block))
5096 }
5097
5098 async fn build_tx_request(
5101 &self,
5102 request: FoundryTransactionRequest,
5103 nonce: u64,
5104 ) -> Result<FoundryTypedTx> {
5105 self.build_tx_request_with_fee_defaults(request, nonce, None).await
5106 }
5107
5108 async fn build_tx_request_with_fee_defaults(
5109 &self,
5110 mut request: FoundryTransactionRequest,
5111 nonce: u64,
5112 fee_defaults: Option<TransactionFeeDefaults>,
5113 ) -> Result<FoundryTypedTx> {
5114 let from = request.from().or(self.accounts()?.first().copied());
5115 if let Some(from) = from {
5116 request.set_from(from);
5117 }
5118
5119 request.chain_id().is_none().then(|| request.set_chain_id(self.chain_id()));
5121 request.nonce().is_none().then(|| request.set_nonce(nonce));
5122 let is_tempo_batch =
5123 matches!(&request, FoundryTransactionRequest::Tempo(tx) if !tx.calls.is_empty());
5124 if request.kind().is_none() && !is_tempo_batch {
5125 request.set_kind(TxKind::default());
5126 }
5127 if request.gas_limit().is_none() {
5128 let fallback_gas_limit = {
5129 let evm_env = self.backend.evm_env().read();
5130 self.backend.fallback_tx_gas_limit(&evm_env)
5131 };
5132 let estimated_gas = self
5133 .do_estimate_gas_typed(request.clone(), None)
5134 .await
5135 .map(|v| v as u64)
5136 .unwrap_or_else(|_| {
5137 if is_simple_transfer_request(request.as_ref()) {
5138 MIN_TRANSACTION_GAS as u64
5139 } else {
5140 fallback_gas_limit
5141 }
5142 });
5143 request.set_gas_limit(estimated_gas);
5144 }
5145
5146 if let Err((tx_type, _)) = request.missing_keys() {
5148 let gas_price = || fee_defaults.map_or_else(|| self.gas_price(), |fees| fees.gas_price);
5149 if tx_type.is_legacy() || tx_type.is_eip2930() {
5150 request.gas_price().is_none().then(|| request.set_gas_price(gas_price()));
5151 }
5152 if tx_type.is_eip2930() {
5153 request
5154 .access_list()
5155 .is_none()
5156 .then(|| request.set_access_list(Default::default()));
5157 }
5158 if tx_type.is_eip1559()
5159 || tx_type.is_eip4844()
5160 || tx_type.is_eip7702()
5161 || tx_type.is_tempo()
5162 || tx_type.is_celo()
5163 {
5164 request
5165 .max_fee_per_gas()
5166 .is_none()
5167 .then(|| request.set_max_fee_per_gas(gas_price()));
5168 request
5169 .max_priority_fee_per_gas()
5170 .is_none()
5171 .then(|| request.set_max_priority_fee_per_gas(MIN_SUGGESTED_PRIORITY_FEE));
5172 }
5173 if tx_type.is_eip4844() {
5174 request.as_ref().max_fee_per_blob_gas().is_none().then(|| {
5175 let blob_gas_price = fee_defaults.map_or_else(
5176 || self.backend.fees().get_next_block_blob_base_fee_per_gas(),
5177 |fees| fees.blob_gas_price,
5178 );
5179 request.as_mut().set_max_fee_per_blob_gas(blob_gas_price)
5180 });
5181 }
5182 }
5183
5184 match request
5185 .build_unsigned()
5186 .map_err(|e| BlockchainError::InvalidTransactionRequest(e.to_string()))?
5187 {
5188 FoundryTypedTx::Eip4844(TxEip4844Variant::TxEip4844(_))
5189 if !self.backend.skip_blob_validation(from) =>
5190 {
5191 Err(BlockchainError::FailedToDecodeTransaction)
5193 }
5194 res => Ok(res),
5195 }
5196 }
5197
5198 async fn get_transaction_count(
5200 &self,
5201 address: Address,
5202 block_number: Option<BlockId>,
5203 ) -> Result<u64> {
5204 let block_request = self.block_request(block_number).await?;
5205
5206 if let BlockRequest::Number(number) = block_request
5207 && let Some(fork) = self.get_fork()
5208 && fork.predates_fork(number)
5209 {
5210 return Ok(fork.get_nonce(address, number).await?);
5211 }
5212
5213 self.backend.get_nonce(address, block_request).await
5214 }
5215
5216 async fn request_nonce(&self, request: &TransactionRequest, from: Address) -> Result<u64> {
5221 if let Some(nonce) = request.nonce {
5222 Ok(nonce)
5223 } else {
5224 self.get_transaction_count(from, Some(BlockId::pending())).await
5225 }
5226 }
5227
5228 async fn add_pending_transaction(
5230 &self,
5231 pending_transaction: PendingTransaction<FoundryTxEnvelope>,
5232 ) -> Result<TxHash> {
5233 let _mining = self.backend.lock_mining().await;
5234 self.backend.validate_pool_transaction(&pending_transaction).await?;
5235
5236 let from = *pending_transaction.sender();
5237 #[cfg(feature = "base")]
5238 let base_markers = self.eip8130_nonce_markers(&pending_transaction).await?;
5239 #[cfg(not(feature = "base"))]
5240 let base_markers = None;
5241
5242 let markers = if base_markers.is_some() {
5243 base_markers
5244 } else {
5245 self.tempo_nonce_markers(&pending_transaction).await?
5246 };
5247 let (requires, provides) = if let Some(markers) = markers {
5248 markers
5249 } else {
5250 let nonce = pending_transaction.transaction.nonce();
5251 let on_chain_nonce = self.backend.current_nonce(from).await?;
5252 (required_marker(nonce, on_chain_nonce, from), vec![to_marker(nonce, from)])
5253 };
5254
5255 debug_assert!(requires != provides);
5256 let priority = self.transaction_priority(&pending_transaction.transaction);
5257 let pool_transaction =
5258 PoolTransaction { requires, provides, pending_transaction, priority, is_replay: false };
5259 let tx = self.pool.add_transaction(pool_transaction)?;
5260 trace!(target: "node", "Added transaction: [{:?}] sender={:?}", tx.hash(), from);
5261 Ok(*tx.hash())
5262 }
5263
5264 async fn tempo_nonce_markers(
5266 &self,
5267 pending: &PendingTransaction<FoundryTxEnvelope>,
5268 ) -> Result<Option<(Vec<TxMarker>, Vec<TxMarker>)>> {
5269 let FoundryTxEnvelope::Tempo(signed) = pending.transaction.as_ref() else {
5270 return Ok(None);
5271 };
5272 let tx = signed.tx();
5273 if tx.nonce_key.is_zero() {
5274 return Ok(None);
5275 }
5276 if tx.nonce_key == U256::MAX {
5277 return Ok(Some((Vec::new(), vec![pending.hash().to_vec()])));
5278 }
5279
5280 let state_nonce = self.backend.tempo_nonce(*pending.sender(), tx.nonce_key, None).await?;
5281 if tx.nonce < state_nonce {
5282 return Err(InvalidTransactionError::NonceTooLow.into());
5283 }
5284
5285 let requires = if tx.nonce == state_nonce {
5286 Vec::new()
5287 } else {
5288 vec![tempo_nonce_marker(*pending.sender(), tx.nonce_key, tx.nonce - 1)]
5289 };
5290 let provides = vec![tempo_nonce_marker(*pending.sender(), tx.nonce_key, tx.nonce)];
5291 Ok(Some((requires, provides)))
5292 }
5293
5294 #[cfg(feature = "base")]
5297 async fn eip8130_nonce_markers(
5298 &self,
5299 pending: &PendingTransaction<FoundryTxEnvelope>,
5300 ) -> Result<Option<(Vec<TxMarker>, Vec<TxMarker>)>> {
5301 if let FoundryTxEnvelope::Eip8130(signed) = pending.transaction.as_ref() {
5302 let tx = signed.tx();
5303 let now = self.backend.eip8130_pool_timestamp_ms();
5304 signed
5305 .validate_admission_static(self.backend.chain_id().to())
5306 .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5307 signed
5308 .validate_timestamp(now)
5309 .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5310 if tx.nonce_key.is_zero() {
5311 let state_nonce = self.backend.current_nonce(*pending.sender()).await?;
5312 if tx.nonce_sequence < state_nonce {
5313 return Err(InvalidTransactionError::NonceTooLow.into());
5314 }
5315 let provides = vec![to_marker(tx.nonce_sequence, *pending.sender())];
5316 self.ensure_eip8130_replacement_price(pending, &provides)?;
5317 self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5318 return Ok(None);
5319 }
5320 if tx.nonce_key == Eip8130Constants::NONCE_KEY_MAX {
5321 let replay_id = tx.replay_id(*pending.sender());
5322 let slot = NonceManagerStorage::expiring_nonce_seen_slot(replay_id);
5323 let word =
5324 self.backend.storage_at(NonceManagerStorage::ADDRESS, slot, None).await?;
5325 let recorded_expiry = (Into::<U256>::into(word) & U256::from(u64::MAX)).to::<u64>();
5326 if recorded_expiry > now {
5327 return Err(BlockchainError::Eip8130TransactionRejected(
5328 "expiring nonce replay has already been recorded".to_string(),
5329 ));
5330 }
5331 let provides = vec![eip8130_replay_marker(replay_id)];
5332 self.ensure_eip8130_replacement_price(pending, &provides)?;
5333 self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5334 return Ok(Some((Vec::new(), provides)));
5335 }
5336
5337 let slot = NonceManagerStorage::nonce_slot(*pending.sender(), tx.nonce_key)
5338 .map_err(|error| BlockchainError::InvalidTransactionRequest(error.to_string()))?;
5339 let word = self.backend.storage_at(NonceManagerStorage::ADDRESS, slot, None).await?;
5340 let state_nonce = Eip8130Nonce::decode_channel_nonce(word.into()).to::<u64>();
5341 if tx.nonce_sequence < state_nonce {
5342 return Err(InvalidTransactionError::NonceTooLow.into());
5343 }
5344
5345 let requires = if tx.nonce_sequence == state_nonce {
5346 Vec::new()
5347 } else {
5348 vec![eip8130_channel_marker(*pending.sender(), tx.nonce_key, tx.nonce_sequence - 1)]
5349 };
5350 let provides =
5351 vec![eip8130_channel_marker(*pending.sender(), tx.nonce_key, tx.nonce_sequence)];
5352 self.ensure_eip8130_replacement_price(pending, &provides)?;
5353 self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5354 return Ok(Some((requires, provides)));
5355 }
5356
5357 Ok(None)
5358 }
5359
5360 #[cfg(feature = "base")]
5362 fn ensure_eip8130_replacement_price(
5363 &self,
5364 pending: &PendingTransaction<FoundryTxEnvelope>,
5365 provides: &[TxMarker],
5366 ) -> Result<()> {
5367 let Some(existing) = self.pool.transaction_with_markers(*pending.sender(), provides) else {
5368 return Ok(());
5369 };
5370 let FoundryTxEnvelope::Eip8130(incoming) = pending.transaction.as_ref() else {
5371 return Ok(());
5372 };
5373 let FoundryTxEnvelope::Eip8130(current) = existing.pending_transaction.transaction.as_ref()
5374 else {
5375 return Ok(());
5376 };
5377
5378 const PRICE_BUMP_PERCENT: u128 = 10;
5379 let bumped =
5380 |price: u128| price.saturating_mul(100 + PRICE_BUMP_PERCENT).saturating_add(99) / 100;
5381 if incoming.tx().max_fee_per_gas < bumped(current.tx().max_fee_per_gas)
5382 || incoming.tx().max_priority_fee_per_gas
5383 < bumped(current.tx().max_priority_fee_per_gas)
5384 {
5385 return Err(
5386 crate::eth::error::PoolError::ReplacementUnderpriced(*pending.hash()).into()
5387 );
5388 }
5389 Ok(())
5390 }
5391
5392 #[cfg(feature = "base")]
5394 async fn ensure_eip8130_payer_reservation(
5395 &self,
5396 pending: &PendingTransaction<FoundryTxEnvelope>,
5397 replacing_markers: &[TxMarker],
5398 ) -> Result<()> {
5399 let FoundryTxEnvelope::Eip8130(incoming) = pending.transaction.as_ref() else {
5400 return Ok(());
5401 };
5402 let payer = incoming.tx().payer.unwrap_or(*pending.sender());
5403 let incoming_cost = FeeCheck::max_fee_charge(
5404 incoming.tx().gas_limit,
5405 IntrinsicGas::max_payer_auth_cost(incoming)
5406 .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?,
5407 incoming.tx().max_fee_per_gas,
5408 );
5409 let mut reserved = U256::ZERO;
5410 for pooled in self.pool.all_transactions() {
5411 if pooled.provides == replacing_markers {
5412 continue;
5413 }
5414 let FoundryTxEnvelope::Eip8130(signed) =
5415 pooled.pending_transaction.transaction.as_ref()
5416 else {
5417 continue;
5418 };
5419 if signed.tx().payer.unwrap_or(*pooled.pending_transaction.sender()) != payer {
5420 continue;
5421 }
5422 let payer_auth = IntrinsicGas::max_payer_auth_cost(signed)
5423 .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5424 reserved = reserved.saturating_add(FeeCheck::max_fee_charge(
5425 signed.tx().gas_limit,
5426 payer_auth,
5427 signed.tx().max_fee_per_gas,
5428 ));
5429 }
5430 let balance = self.backend.get_account(payer).await?.balance;
5431 let required = reserved.saturating_add(incoming_cost);
5432 if balance < required {
5433 return Err(BlockchainError::Eip8130TransactionRejected(format!(
5434 "gas payer balance {balance} is below pending reservation {required}"
5435 )));
5436 }
5437 Ok(())
5438 }
5439
5440 fn ensure_typed_transaction_supported(&self, tx: &FoundryTxEnvelope) -> Result<()> {
5442 match &tx {
5443 FoundryTxEnvelope::Eip2930(_) => self.backend.ensure_eip2930_active(),
5444 FoundryTxEnvelope::Eip1559(_) => self.backend.ensure_eip1559_active(),
5445 FoundryTxEnvelope::Eip4844(_) => self.backend.ensure_eip4844_active(),
5446 FoundryTxEnvelope::Eip7702(_) => self.backend.ensure_eip7702_active(),
5447 #[cfg(any(feature = "base", feature = "optimism"))]
5448 FoundryTxEnvelope::Deposit(_) => self.backend.ensure_deposits_active(),
5449 #[cfg(feature = "optimism")]
5450 FoundryTxEnvelope::PostExec(_) => Err(BlockchainError::InvalidTransactionRequest(
5451 "not implemented for post-exec tx".to_string(),
5452 )),
5453 #[cfg(feature = "base")]
5454 FoundryTxEnvelope::Eip8130(_) => self.backend.ensure_base_eip8130_submission_active(),
5455 FoundryTxEnvelope::Celo(_) => self.backend.ensure_cip64_active(),
5456 FoundryTxEnvelope::Legacy(_) => Ok(()),
5457 FoundryTxEnvelope::Tempo(_) => self.backend.ensure_tempo_active(),
5458 }
5459 }
5460
5461 pub async fn anvil_set_fee_token(&self, user: Address, token: Address) -> Result<()> {
5467 node_info!("anvil_setFeeToken");
5468 self.ensure_tempo_mode()?;
5469 self.backend.set_fee_token(user, token).await?;
5470 Ok(())
5471 }
5472
5473 pub async fn anvil_set_validator_fee_token(
5479 &self,
5480 validator: Address,
5481 token: Address,
5482 ) -> Result<()> {
5483 node_info!("anvil_setValidatorFeeToken");
5484 self.ensure_tempo_mode()?;
5485 self.backend.set_validator_fee_token(validator, token).await?;
5486 Ok(())
5487 }
5488
5489 pub async fn anvil_set_fee_amm_liquidity(
5495 &self,
5496 user_token: Address,
5497 validator_token: Address,
5498 amount: U256,
5499 ) -> Result<()> {
5500 node_info!("anvil_setFeeAmmLiquidity");
5501 self.ensure_tempo_mode()?;
5502 self.backend.set_fee_amm_liquidity(user_token, validator_token, amount).await?;
5503 Ok(())
5504 }
5505
5506 fn ensure_tempo_mode(&self) -> Result<()> {
5508 if self.backend.is_tempo() { Ok(()) } else { Err(BlockchainError::RpcUnimplemented) }
5509 }
5510
5511 fn parse_transaction_request(
5512 &self,
5513 request: WithOtherFields<TransactionRequest>,
5514 ) -> Result<FoundryTransactionRequest> {
5515 self.backend.parse_transaction_request(request)
5516 }
5517
5518 async fn request_nonce_for_transaction(
5519 &self,
5520 request: &FoundryTransactionRequest,
5521 from: Address,
5522 ) -> Result<u64> {
5523 if let FoundryTransactionRequest::Tempo(request) = request
5524 && let Some(nonce_key) = request.nonce_key.filter(|key| !key.is_zero())
5525 {
5526 if let Some(nonce) = request.nonce() {
5527 return Ok(nonce);
5528 }
5529 let nonce = self.backend.tempo_nonce(from, nonce_key, None).await?;
5530 return Ok(nonce);
5531 }
5532 self.request_nonce(request.as_ref(), from).await
5533 }
5534}
5535
5536fn is_simple_transfer_request(request: &TransactionRequest) -> bool {
5537 request.to.as_ref().and_then(TxKind::to).is_some()
5538 && (request.input.input().is_none()
5539 || request.input.input().is_some_and(|data| data.is_empty()))
5540 && request.authorization_list.is_none()
5541 && request.access_list.is_none()
5542 && request.blob_versioned_hashes.is_none()
5543}
5544
5545fn required_marker(provided_nonce: u64, on_chain_nonce: u64, from: Address) -> Vec<TxMarker> {
5546 if provided_nonce == on_chain_nonce {
5547 return Vec::new();
5548 }
5549 let prev_nonce = provided_nonce.saturating_sub(1);
5550 if on_chain_nonce <= prev_nonce { vec![to_marker(prev_nonce, from)] } else { Vec::new() }
5551}
5552
5553fn tempo_nonce_marker(sender: Address, nonce_key: U256, nonce: u64) -> TxMarker {
5554 let mut marker = b"tempo-nonce".to_vec();
5555 marker.extend_from_slice(sender.as_slice());
5556 marker.extend_from_slice(&nonce_key.to_be_bytes::<32>());
5557 marker.extend_from_slice(&nonce.to_be_bytes());
5558 marker
5559}
5560
5561#[cfg(feature = "base")]
5562fn eip8130_channel_marker(sender: Address, nonce_key: U256, nonce_sequence: u64) -> TxMarker {
5563 let mut marker = b"base-eip8130-channel".to_vec();
5564 marker.extend_from_slice(sender.as_slice());
5565 marker.extend_from_slice(&nonce_key.to_be_bytes::<32>());
5566 marker.extend_from_slice(&nonce_sequence.to_be_bytes());
5567 marker
5568}
5569
5570#[cfg(feature = "base")]
5571fn eip8130_replay_marker(replay_id: B256) -> TxMarker {
5572 let mut marker = b"base-eip8130-replay".to_vec();
5573 marker.extend_from_slice(replay_id.as_slice());
5574 marker
5575}
5576
5577fn normalize_fee_payer_service_encoding(raw: &[u8]) -> Option<Vec<u8>> {
5587 let (tx_type, mut encoded_fields) = raw.split_first()?;
5588 if *tx_type != TEMPO_TX_TYPE_ID {
5589 return None;
5590 }
5591 let PayloadView::List(fields) = Header::decode_raw(&mut encoded_fields).ok()? else {
5592 return None;
5593 };
5594 if !encoded_fields.is_empty() {
5595 return None;
5596 }
5597 if fields.get(11).is_none_or(|field| *field != [0x00]) {
5599 return None;
5600 }
5601
5602 let marker = FEE_PAYER_SIGNATURE_MARKER;
5605 let mut marker_field = Vec::new();
5606 Header { list: true, payload_length: marker.rlp_rs_len() + marker.v().length() }
5607 .encode(&mut marker_field);
5608 marker.write_rlp_vrs(&mut marker_field, marker.v());
5609
5610 let mut payload = Vec::new();
5611 for (index, field) in fields.into_iter().enumerate() {
5612 if index == 11 {
5613 payload.extend_from_slice(&marker_field);
5614 } else {
5615 payload.extend_from_slice(field);
5616 }
5617 }
5618 let mut normalized = vec![TEMPO_TX_TYPE_ID];
5619 Header { list: true, payload_length: payload.len() }.encode(&mut normalized);
5620 normalized.extend_from_slice(&payload);
5621 Some(normalized)
5622}
5623
5624fn encode_rpc_transaction(transaction: &AnyRpcTransaction) -> Result<Bytes> {
5627 FoundryTxEnvelope::encode_rpc_2718(transaction)
5628 .map_err(|_| BlockchainError::UnsupportedTransactionEncoding(transaction.ty()))
5629}
5630
5631fn txpool_transaction_key(pending_transaction: &PendingTransaction<FoundryTxEnvelope>) -> String {
5632 match pending_transaction.transaction.as_ref() {
5633 #[cfg(feature = "base")]
5634 FoundryTxEnvelope::Eip8130(signed) if !signed.tx().nonce_key.is_zero() => {
5635 if signed.tx().nonce_key == Eip8130Constants::NONCE_KEY_MAX {
5636 return signed.tx().replay_id(*pending_transaction.sender()).to_string();
5637 }
5638 format!("{}:{}", signed.tx().nonce_key, signed.tx().nonce_sequence)
5639 }
5640 FoundryTxEnvelope::Tempo(tx) if !tx.tx().nonce_key.is_zero() => {
5641 let tx = tx.tx();
5642 format!("{}:{}", tx.nonce_key, tx.nonce)
5643 }
5644 _ => pending_transaction.nonce().to_string(),
5645 }
5646}
5647
5648fn convert_transact_out(out: &Option<Output>) -> Bytes {
5649 out.as_ref().map(Output::data).cloned().unwrap_or_default()
5650}
5651
5652fn ensure_return_ok(exit: InstructionResult, out: &Option<Output>) -> Result<Bytes> {
5654 let out = convert_transact_out(out);
5655 match exit {
5656 return_ok!() => Ok(out),
5657 return_revert!() => Err(InvalidTransactionError::Revert(Some(out)).into()),
5658 reason => Err(BlockchainError::EvmError(reason)),
5659 }
5660}
5661
5662fn execution_error(exit: InstructionResult) -> Option<String> {
5665 match SuccessOrHalt::<HaltReason>::from(exit) {
5666 SuccessOrHalt::Success(_) => None,
5667 SuccessOrHalt::Revert => Some("execution reverted".to_string()),
5668 SuccessOrHalt::Halt(reason) => Some(reason.to_string()),
5669 SuccessOrHalt::FatalExternalError => Some("fatal external error".to_string()),
5670 SuccessOrHalt::Internal(_) => Some("internal EVM error".to_string()),
5671 }
5672}
5673
5674enum GasEstimationCallResult {
5676 Success(u128),
5677 OutOfGas,
5678 Revert(Option<Bytes>),
5679 EvmError(InstructionResult),
5680}
5681
5682impl TryFrom<Result<(InstructionResult, Option<Output>, u128, State)>> for GasEstimationCallResult {
5686 type Error = BlockchainError;
5687
5688 fn try_from(res: Result<(InstructionResult, Option<Output>, u128, State)>) -> Result<Self> {
5689 match res {
5690 Err(BlockchainError::InvalidTransaction(InvalidTransactionError::GasTooHigh(_))) => {
5692 Ok(Self::OutOfGas)
5693 }
5694 Err(BlockchainError::Message(ref msg))
5696 if msg.contains("insufficient gas for intrinsic cost") =>
5697 {
5698 Ok(Self::OutOfGas)
5699 }
5700 Err(err) => Err(err),
5701 Ok((exit, output, gas, _)) => match exit {
5702 return_ok!() => Ok(Self::Success(gas)),
5703
5704 InstructionResult::Revert => {
5706 Ok(Self::Revert(Some(output.map(|o| o.into_data()).unwrap_or_default())))
5707 }
5708 InstructionResult::CallTooDeep
5709 | InstructionResult::OutOfFunds
5710 | InstructionResult::CreateInitCodeStartingEF00
5711 | InstructionResult::InvalidEOFInitCode
5712 | InstructionResult::InvalidExtDelegateCallTarget => Ok(Self::EvmError(exit)),
5713
5714 InstructionResult::OutOfGas
5716 | InstructionResult::MemoryOOG
5717 | InstructionResult::MemoryLimitOOG
5718 | InstructionResult::PrecompileOOG
5719 | InstructionResult::InvalidOperandOOG
5720 | InstructionResult::ReentrancySentryOOG => Ok(Self::OutOfGas),
5721
5722 InstructionResult::OpcodeNotFound
5724 | InstructionResult::CallNotAllowedInsideStatic
5725 | InstructionResult::StateChangeDuringStaticCall
5726 | InstructionResult::InvalidFEOpcode
5727 | InstructionResult::InvalidJump
5728 | InstructionResult::NotActivated
5729 | InstructionResult::StackUnderflow
5730 | InstructionResult::StackOverflow
5731 | InstructionResult::OutOfOffset
5732 | InstructionResult::CreateCollision
5733 | InstructionResult::OverflowPayment
5734 | InstructionResult::PrecompileError
5735 | InstructionResult::NonceOverflow
5736 | InstructionResult::CreateContractSizeLimit
5737 | InstructionResult::CreateContractStartingWithEF
5738 | InstructionResult::CreateInitCodeSizeLimit
5739 | InstructionResult::InvalidImmediateEncoding
5740 | InstructionResult::FatalExternalError => Ok(Self::EvmError(exit)),
5741 },
5742 }
5743 }
5744}
5745
5746fn merge_pre_fork_fee_history(
5748 response: &mut FeeHistory,
5749 rewards: &mut Vec<Vec<u128>>,
5750 pre: FeeHistory,
5751 fork_block: u64,
5752) {
5753 response.oldest_block = pre.oldest_block;
5755 let count = fork_block.checked_sub(pre.oldest_block).map_or(0, |count| count.saturating_add(1))
5756 as usize;
5757
5758 response.base_fee_per_gas.extend(pre.base_fee_per_gas.into_iter().take(count));
5760 response.gas_used_ratio.extend(pre.gas_used_ratio.into_iter().take(count));
5761 if let Some(reward) = pre.reward {
5762 rewards.extend(reward.into_iter().take(count));
5763 }
5764
5765 response.base_fee_per_blob_gas.extend(pre.base_fee_per_blob_gas.into_iter().take(count));
5767 response.base_fee_per_blob_gas.resize(count, 0);
5768 response.blob_gas_used_ratio.extend(pre.blob_gas_used_ratio.into_iter().take(count));
5769 response.blob_gas_used_ratio.resize(count, 0.0);
5770}
5771
5772fn reward_at_percentile(rewards: &[u128], percentile: f64) -> u128 {
5773 let index = (percentile * REWARD_PERCENTILE_RESOLUTION).round() as usize;
5774 rewards.get(index).copied().unwrap_or_default()
5775}
5776
5777#[cfg(test)]
5778mod tests {
5779 use super::*;
5780 use crate::{NodeConfig, spawn};
5781
5782 #[cfg(feature = "base")]
5783 #[tokio::test(flavor = "multi_thread")]
5784 async fn base_requests_are_rejected_without_execution() {
5785 let (api, _handle) = spawn(NodeConfig::test()).await;
5786 for request in [serde_json::json!({ "type": "0x79" }), serde_json::json!({ "calls": [[]] })]
5787 {
5788 let request = serde_json::from_value(request).unwrap();
5789 assert!(matches!(
5790 api.parse_transaction_request(request),
5791 Err(BlockchainError::BaseTransactionUnsupported)
5792 ));
5793 }
5794 }
5795
5796 #[tokio::test(flavor = "multi_thread")]
5797 async fn set_rpc_url_installs_context_equivalent_identity_with_new_instance() {
5798 let genesis_timestamp = 1_700_000_000u64;
5799 let (_origin_api, origin_handle) =
5800 spawn(NodeConfig::test().with_genesis_timestamp(Some(genesis_timestamp))).await;
5801 let (api, _handle) =
5802 spawn(NodeConfig::test().with_eth_rpc_url(Some(origin_handle.http_endpoint()))).await;
5803 let (target_api, target_handle) =
5804 spawn(NodeConfig::test().with_genesis_timestamp(Some(genesis_timestamp))).await;
5805 let target_url = target_handle.http_endpoint();
5806 let fork = api.backend.get_fork().unwrap();
5807 let identity_before = fork.config.read().endpoint_identity;
5808
5809 api.anvil_set_rpc_url(target_url.clone()).await.unwrap();
5810
5811 let fork = api.backend.get_fork().unwrap();
5812 let config = fork.config.read();
5813 assert!(config.endpoint_identity.context_eq(identity_before));
5814 assert_ne!(config.endpoint_identity.instance_id, identity_before.instance_id);
5815 assert_eq!(config.endpoint_identity.instance_id, Some(target_api.instance_id()));
5816 assert_eq!(config.eth_rpc_url(), Some(target_url.as_str()));
5817 }
5818
5819 #[tokio::test(flavor = "multi_thread")]
5820 async fn memory_reset_stages_live_fees_after_active_mining() {
5821 let (api, _handle) = spawn(NodeConfig::test()).await;
5822 api.backend.set_base_fee(123);
5823
5824 let mining = api.backend.lock_mining().await;
5827 let reset_api = api.clone();
5828 let reset = tokio::spawn(async move { reset_api.anvil_reset(None).await });
5829
5830 tokio::time::timeout(Duration::from_secs(5), async {
5831 while api.lifecycle_lock.try_read().is_ok() {
5832 tokio::task::yield_now().await;
5833 }
5834 })
5835 .await
5836 .unwrap();
5837
5838 api.backend.set_base_fee(456);
5839 drop(mining);
5840 tokio::time::timeout(Duration::from_secs(5), reset).await.unwrap().unwrap().unwrap();
5841
5842 assert_eq!(api.backend.evm_env().read().block_env.basefee, 456);
5843 assert_eq!(api.base_fee().unwrap(), Some(U256::from(crate::eth::fees::INITIAL_BASE_FEE)));
5844 }
5845
5846 #[tokio::test(flavor = "multi_thread")]
5848 async fn fee_history_is_complete_when_cache_entries_are_missing() {
5849 let (api, _handle) = spawn(NodeConfig::test()).await;
5850 let count = 10u64;
5851 api.anvil_mine(Some(U256::from(count)), None).await.unwrap();
5852
5853 tokio::time::timeout(Duration::from_secs(5), async {
5857 loop {
5858 if (1..=count).all(|number| api.fee_history_cache.lock().contains_key(&number)) {
5859 break;
5860 }
5861 tokio::task::yield_now().await;
5862 }
5863 })
5864 .await
5865 .unwrap();
5866 api.fee_history_cache.lock().clear();
5867
5868 let fee_history =
5869 api.fee_history(U256::from(count), BlockNumber::Latest, vec![50.0]).await.unwrap();
5870
5871 assert_eq!(fee_history.oldest_block, 1);
5872 assert_eq!(fee_history.gas_used_ratio.len(), count as usize);
5873 assert_eq!(fee_history.blob_gas_used_ratio.len(), count as usize);
5874 assert_eq!(fee_history.base_fee_per_gas.len(), count as usize + 1);
5875 assert_eq!(fee_history.base_fee_per_blob_gas.len(), count as usize + 1);
5876 let rewards = fee_history.reward.unwrap();
5877 assert_eq!(rewards.len(), count as usize);
5878 assert!(rewards.iter().all(|reward| reward.len() == 1));
5879 }
5880
5881 #[tokio::test(flavor = "multi_thread")]
5882 async fn fee_history_rejects_invalid_reward_percentiles() {
5883 let (api, _handle) = spawn(NodeConfig::test()).await;
5884
5885 for percentiles in [vec![-0.5], vec![100.5], vec![50.0, 25.0], vec![50.0, 50.0]] {
5886 let err =
5887 api.fee_history(U256::ONE, BlockNumber::Latest, percentiles).await.unwrap_err();
5888 assert!(matches!(
5889 err,
5890 BlockchainError::FeeHistory(FeeHistoryError::InvalidRewardPercentiles)
5891 ));
5892 }
5893
5894 for percentiles in [vec![], vec![0.0, 100.0]] {
5895 api.fee_history(U256::ONE, BlockNumber::Latest, percentiles).await.unwrap();
5896 }
5897 }
5898
5899 #[test]
5900 fn fractional_reward_percentiles_use_cache_resolution() {
5901 let rewards = (0..=200).collect::<Vec<_>>();
5902
5903 assert_eq!(reward_at_percentile(&rewards, 0.0), 0);
5904 assert_eq!(reward_at_percentile(&rewards, 0.5), 1);
5905 assert_eq!(reward_at_percentile(&rewards, 1.0), 2);
5906 assert_eq!(reward_at_percentile(&rewards, 100.0), 200);
5907 }
5908
5909 #[test]
5910 fn shortened_pre_fork_fee_history_uses_upstream_start() {
5911 let requested_lowest = 4;
5912 let fork_block = 10;
5913 let pre = FeeHistory {
5914 oldest_block: 5,
5915 base_fee_per_gas: vec![1; 7],
5916 gas_used_ratio: vec![0.0; 6],
5917 reward: Some(vec![vec![]; 6]),
5918 base_fee_per_blob_gas: vec![],
5919 blob_gas_used_ratio: vec![],
5920 };
5921
5922 let mut response = FeeHistory { oldest_block: requested_lowest, ..Default::default() };
5923 let mut rewards = Vec::new();
5924
5925 merge_pre_fork_fee_history(&mut response, &mut rewards, pre, fork_block);
5926
5927 assert_eq!(response.oldest_block, 5);
5928 assert_eq!(response.gas_used_ratio.len(), 6);
5929 assert_eq!(response.base_fee_per_gas.len(), 6);
5930 assert_eq!(response.blob_gas_used_ratio.len(), 6);
5931 assert_eq!(response.base_fee_per_blob_gas.len(), 6);
5932 assert_eq!(rewards.len(), 6);
5933 }
5934}