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,
13 db::SerializableState,
14 mem::{MIN_CREATE_GAS, MIN_TRANSACTION_GAS},
15 notifications::ChainNotifications,
16 validate::TransactionValidator,
17 },
18 error::{
19 BlockchainError, FeeHistoryError, InvalidTransactionError, Result, ToRpcResponseResult,
20 },
21 fees::{
22 FeeDetails, FeeHistoryCache, FeeHistoryCacheItem, MIN_SUGGESTED_PRIORITY_FEE,
23 REWARD_PERCENTILE_RESOLUTION, create_fee_history_cache_item,
24 },
25 macros::node_info,
26 miner::FixedBlockTimeMiner,
27 pool::{
28 Pool,
29 transactions::{
30 PoolTransaction, TransactionOrder, TransactionPriority, TxMarker, to_marker,
31 },
32 },
33 sign::Signer,
34 },
35 filter::{EthFilter, Filters, LogsFilter},
36 mem::transaction_build,
37};
38use alloy_consensus::{
39 Blob, BlockHeader, Transaction, TrieAccount, TxEip4844Variant, TxReceipt, Typed2718,
40 transaction::{Recovered, SignerRecoverable},
41};
42use alloy_dyn_abi::TypedData;
43use alloy_eips::{
44 eip2718::{EIP4844_TX_TYPE_ID, Encodable2718},
45 eip7910::{EthConfig, EthForkConfig},
46};
47use alloy_evm::overrides::{OverrideBlockHashes, apply_state_overrides};
48use alloy_network::{
49 AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, BlockResponse, Network,
50 NetworkTransactionBuilder, ReceiptResponse, TransactionBuilder, TransactionBuilder4844,
51 TransactionResponse, eip2718::Decodable2718,
52};
53use alloy_primitives::{
54 Address, B64, B256, Bytes, TxHash, TxKind, U64, U256,
55 map::{AddressSet, B256Set, HashMap, HashSet},
56};
57use alloy_rlp::{Encodable, Header, PayloadView};
58use alloy_rpc_types::{
59 AccessListResult, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,
60 EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, Work,
61 anvil::{
62 ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo,
63 },
64 debug::ExecutionWitness,
65 erc4337::TransactionConditional,
66 pubsub::TransactionReceiptsParams,
67 request::TransactionRequest,
68 simulate::{MAX_SIMULATE_BLOCKS, SimulatePayload, SimulatedBlock},
69 state::{AccountOverride, EvmOverrides, StateOverride, StateOverridesBuilder},
70 trace::{
71 filter::TraceFilter,
72 geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult},
73 opcode::{BlockOpcodeGas, TransactionOpcodeGas},
74 parity::{
75 LocalizedTransactionTrace, TraceResults, TraceResultsWithTransactionHash, TraceType,
76 },
77 },
78 txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus},
79};
80use alloy_rpc_types_eth::{AccountInfo, Bundle, EthCallResponse, FillTransaction, StateContext};
81use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse};
82use alloy_serde::WithOtherFields;
83use alloy_sol_types::{SolCall, SolValue, sol};
84use anvil_core::{
85 eth::{
86 EthRequest,
87 block::{BlockInfo, canonical_block},
88 transaction::{MaybeImpersonatedTransaction, PendingTransaction},
89 },
90 types::{ReorgOptions, TransactionData},
91};
92use anvil_rpc::{
93 error::{ErrorCode, RpcError},
94 response::ResponseResult,
95};
96use foundry_common::{
97 provider::redact_url,
98 tempo::{PaymentLaneClassification, PaymentLaneReason, classify_payment_lane},
99 version::{COMMIT_SHA, SEMVER_VERSION},
100};
101use foundry_evm::decode::RevertDecoder;
102use foundry_primitives::{
103 FoundryNetwork, FoundryReceiptEnvelope, FoundryTransactionRequest, FoundryTxEnvelope,
104 FoundryTxReceipt, FoundryTxType, FoundryTypedTx,
105};
106use futures::{
107 StreamExt, TryFutureExt,
108 channel::{mpsc::Receiver, oneshot},
109};
110use parking_lot::RwLock;
111use revm::{
112 context::BlockEnv,
113 context_interface::{
114 block::BlobExcessGasAndPrice,
115 result::{HaltReason, Output},
116 },
117 database::CacheDB,
118 interpreter::{InstructionResult, SuccessOrHalt, return_ok, return_revert},
119 primitives::eip7702::PER_EMPTY_ACCOUNT_COST,
120};
121use std::{sync::Arc, time::Duration};
122use tempo_hardfork::TempoHardfork;
123use tempo_primitives::{AASigned, TEMPO_TX_TYPE_ID, transaction::FEE_PAYER_SIGNATURE_MARKER};
124use tokio::{
125 sync::mpsc::{self, UnboundedReceiver, unbounded_channel},
126 try_join,
127};
128
129pub const CLIENT_VERSION: &str = concat!("anvil/v", env!("CARGO_PKG_VERSION"));
131
132pub struct EthApi<N: Network> {
136 pool: Arc<Pool<N::TxEnvelope>>,
138 pub backend: Arc<backend::mem::Backend<N>>,
141 is_mining: bool,
143 signers: Arc<Vec<Box<dyn Signer<N>>>>,
145 fee_history_cache: FeeHistoryCache,
147 fee_history_limit: u64,
149 miner: Miner<N::TxEnvelope>,
154 logger: LoggingManager,
156 filters: Filters<N>,
158 transaction_order: Arc<RwLock<TransactionOrder>>,
160 net_listening: bool,
162 instance_id: Arc<RwLock<B256>>,
164 lifecycle_lock: Arc<tokio::sync::RwLock<()>>,
166 reset_lock: Arc<tokio::sync::Mutex<()>>,
168}
169
170impl<N: Network> Clone for EthApi<N> {
171 fn clone(&self) -> Self {
172 Self {
173 pool: self.pool.clone(),
174 backend: self.backend.clone(),
175 is_mining: self.is_mining,
176 signers: self.signers.clone(),
177 fee_history_cache: self.fee_history_cache.clone(),
178 fee_history_limit: self.fee_history_limit,
179 miner: self.miner.clone(),
180 logger: self.logger.clone(),
181 filters: self.filters.clone(),
182 transaction_order: self.transaction_order.clone(),
183 net_listening: self.net_listening,
184 instance_id: self.instance_id.clone(),
185 lifecycle_lock: self.lifecycle_lock.clone(),
186 reset_lock: self.reset_lock.clone(),
187 }
188 }
189}
190
191impl<N: Network> EthApi<N> {
194 #[expect(clippy::too_many_arguments)]
196 pub fn new(
197 pool: Arc<Pool<N::TxEnvelope>>,
198 backend: Arc<backend::mem::Backend<N>>,
199 signers: Arc<Vec<Box<dyn Signer<N>>>>,
200 fee_history_cache: FeeHistoryCache,
201 fee_history_limit: u64,
202 miner: Miner<N::TxEnvelope>,
203 logger: LoggingManager,
204 filters: Filters<N>,
205 transactions_order: TransactionOrder,
206 ) -> Self {
207 Self {
208 pool,
209 backend,
210 is_mining: true,
211 signers,
212 fee_history_cache,
213 fee_history_limit,
214 miner,
215 logger,
216 filters,
217 net_listening: true,
218 transaction_order: Arc::new(RwLock::new(transactions_order)),
219 instance_id: Arc::new(RwLock::new(B256::random())),
220 lifecycle_lock: Arc::new(tokio::sync::RwLock::new(())),
221 reset_lock: Arc::new(tokio::sync::Mutex::new(())),
222 }
223 }
224
225 pub fn gas_price(&self) -> u128 {
227 if self.backend.is_eip1559() {
228 if self.backend.is_min_priority_fee_enforced() {
229 (self.backend.base_fee() as u128).saturating_add(self.lowest_suggestion_tip())
230 } else {
231 self.backend.base_fee() as u128
232 }
233 } else {
234 self.backend.fees().raw_gas_price()
235 }
236 }
237
238 fn lowest_suggestion_tip(&self) -> u128 {
242 let block_number = self.backend.best_number();
243 let cache = self.fee_history_cache.lock();
244 let latest_tip = self
245 .backend
246 .get_block_with_hash(block_number)
247 .and_then(|(_, hash)| cache.get(&block_number).filter(|item| item.block_hash == hash))
248 .and_then(|item| item.rewards.iter().copied().min());
249
250 latest_tip
251 .or_else(|| {
252 cache
253 .iter()
254 .filter(|(number, item)| {
255 self.backend
256 .get_block_with_hash(**number)
257 .is_some_and(|(_, hash)| item.block_hash == hash)
258 })
259 .flat_map(|(_, item)| item.rewards.iter().copied())
260 .min()
261 })
262 .map(|fee| fee.max(MIN_SUGGESTED_PRIORITY_FEE))
263 .unwrap_or(MIN_SUGGESTED_PRIORITY_FEE)
264 }
265
266 pub fn anvil_get_auto_mine(&self) -> Result<bool> {
270 node_info!("anvil_getAutomine");
271 Ok(self.miner.is_auto_mine())
272 }
273
274 pub fn anvil_get_interval_mining(&self) -> Result<Option<u64>> {
278 node_info!("anvil_getIntervalMining");
279 Ok(self.miner.get_interval())
280 }
281
282 pub async fn anvil_set_auto_mine(&self, enable_automine: bool) -> Result<()> {
287 node_info!("evm_setAutomine");
288 if self.miner.is_auto_mine() {
289 if enable_automine {
290 return Ok(());
291 }
292 self.miner.set_mining_mode(MiningMode::None);
293 } else if enable_automine {
294 let listener = self.pool.add_ready_listener();
295 let mode = MiningMode::instant(1_000, listener);
296 self.miner.set_mining_mode(mode);
297 }
298 Ok(())
299 }
300
301 pub fn anvil_set_interval_mining(&self, secs: u64) -> Result<()> {
305 node_info!("evm_setIntervalMining");
306 let mining_mode = if secs == 0 {
307 MiningMode::None
308 } else {
309 let block_time = Duration::from_secs(secs);
310
311 self.backend.update_interval_mine_block_time(block_time);
313
314 MiningMode::FixedBlockTime(FixedBlockTimeMiner::new(block_time))
315 };
316 self.miner.set_mining_mode(mining_mode);
317 Ok(())
318 }
319
320 pub async fn anvil_drop_transaction(&self, tx_hash: B256) -> Result<Option<B256>> {
324 node_info!("anvil_dropTransaction");
325 Ok(self.pool.drop_transaction(tx_hash).map(|tx| tx.hash()))
326 }
327
328 pub async fn anvil_drop_all_transactions(&self) -> Result<()> {
332 node_info!("anvil_dropAllTransactions");
333 self.pool.clear();
334 Ok(())
335 }
336
337 pub async fn debug_clear_txpool(&self) -> Result<()> {
341 node_info!("debug_clearTxpool");
342 self.pool.clear();
343 Ok(())
344 }
345
346 pub async fn anvil_set_chain_id(&self, chain_id: u64) -> Result<()> {
347 node_info!("anvil_setChainId");
348 self.backend.set_chain_id(chain_id);
349 Ok(())
350 }
351
352 pub async fn anvil_set_balance(&self, address: Address, balance: U256) -> Result<()> {
356 node_info!("anvil_setBalance");
357 self.backend.set_balance(address, balance).await?;
358 Ok(())
359 }
360
361 pub async fn anvil_set_code(&self, address: Address, code: Bytes) -> Result<()> {
365 node_info!("anvil_setCode");
366 self.backend.set_code(address, code).await?;
367 Ok(())
368 }
369
370 pub async fn anvil_set_nonce(&self, address: Address, nonce: U256) -> Result<()> {
374 node_info!("anvil_setNonce");
375 self.backend.set_nonce(address, nonce).await?;
376 Ok(())
377 }
378
379 pub async fn anvil_set_storage_at(
383 &self,
384 address: Address,
385 slot: U256,
386 val: B256,
387 ) -> Result<bool> {
388 node_info!("anvil_setStorageAt");
389 self.backend.set_storage_at(address, slot, val).await?;
390 Ok(true)
391 }
392
393 pub async fn anvil_set_logging(&self, enable: bool) -> Result<()> {
397 node_info!("anvil_setLoggingEnabled");
398 self.logger.set_enabled(enable);
399 Ok(())
400 }
401
402 pub async fn anvil_set_min_gas_price(&self, gas: U256) -> Result<()> {
406 node_info!("anvil_setMinGasPrice");
407 if self.backend.is_eip1559() {
408 return Err(RpcError::invalid_params(
409 "anvil_setMinGasPrice is not supported when EIP-1559 is active",
410 )
411 .into());
412 }
413 self.backend.set_gas_price(gas.saturating_to());
414 Ok(())
415 }
416
417 pub async fn anvil_set_next_block_base_fee_per_gas(&self, basefee: U256) -> Result<()> {
421 node_info!("anvil_setNextBlockBaseFeePerGas");
422 if !self.backend.is_eip1559() {
423 return Err(RpcError::invalid_params(
424 "anvil_setNextBlockBaseFeePerGas is only supported when EIP-1559 is active",
425 )
426 .into());
427 }
428 self.backend.set_base_fee(basefee.saturating_to());
429 Ok(())
430 }
431
432 pub async fn anvil_set_coinbase(&self, address: Address) -> Result<()> {
436 node_info!("anvil_setCoinbase");
437 self.backend.set_coinbase(address);
438 Ok(())
439 }
440
441 pub async fn anvil_set_next_block_prevrandao(&self, prevrandao: B256) -> Result<()> {
448 node_info!("anvil_setNextBlockPrevRandao");
449 self.backend.set_next_block_prevrandao(prevrandao);
450 Ok(())
451 }
452
453 pub async fn anvil_node_info(&self) -> Result<NodeInfo> {
457 node_info!("anvil_nodeInfo");
458 let _lifecycle = self.lifecycle_lock.read().await;
459
460 let evm_env = self.backend.evm_env().read();
461 let fork_config = self.backend.get_fork();
462 let tx_order = self.transaction_order.read();
463 let hard_fork = self.backend.hardfork().name();
464
465 Ok(NodeInfo {
466 current_block_number: self.backend.best_number(),
467 current_block_timestamp: evm_env.block_env.timestamp.saturating_to(),
468 current_block_hash: self.backend.best_hash(),
469 hard_fork,
470 transaction_order: match *tx_order {
471 TransactionOrder::Fifo => "fifo".to_string(),
472 TransactionOrder::Fees => "fees".to_string(),
473 },
474 environment: NodeEnvironment {
475 base_fee: self.backend.base_fee() as u128,
476 chain_id: self.backend.chain_id().to::<u64>(),
477 gas_limit: self.backend.gas_limit(),
478 gas_price: self.gas_price(),
479 },
480 fork_config: fork_config
481 .map(|fork| {
482 let config = fork.config.read();
483
484 NodeForkConfig {
485 fork_url: config.eth_rpc_url().map(|s| s.to_string()),
486 fork_block_number: Some(config.block_number),
487 fork_retry_backoff: Some(config.backoff.as_millis()),
488 }
489 })
490 .unwrap_or_default(),
491 network: Some(self.backend.execution_profile_name().to_string()),
494 })
495 }
496
497 pub async fn anvil_metadata(&self) -> Result<Metadata> {
501 node_info!("anvil_metadata");
502 let _lifecycle = self.lifecycle_lock.read().await;
503 let fork_config = self.backend.get_fork();
504
505 Ok(Metadata {
506 client_version: CLIENT_VERSION.to_string(),
507 client_semver: Some(SEMVER_VERSION.to_string()),
508 client_commit_sha: Some(COMMIT_SHA.to_string()),
509 chain_id: self.backend.chain_id().to::<u64>(),
510 latest_block_hash: self.backend.best_hash(),
511 latest_block_number: self.backend.best_number(),
512 instance_id: *self.instance_id.read(),
513 forked_network: fork_config.map(|cfg| ForkedNetwork {
514 chain_id: cfg.chain_id(),
515 fork_block_number: cfg.block_number(),
516 fork_block_hash: cfg.block_hash(),
517 }),
518 snapshots: self.backend.list_state_snapshots(),
519 })
520 }
521
522 pub async fn anvil_remove_pool_transactions(&self, address: Address) -> Result<()> {
523 node_info!("anvil_removePoolTransactions");
524 self.pool.remove_transactions_by_address(address);
525 Ok(())
526 }
527
528 pub async fn evm_snapshot(&self) -> Result<U256> {
532 node_info!("evm_snapshot");
533 let _lifecycle = self.lifecycle_lock.read().await;
534 let _mining = self.backend.lock_mining().await;
535 Ok(self.backend.create_state_snapshot().await)
536 }
537
538 pub async fn evm_increase_time(&self, seconds: U256) -> Result<i64> {
542 node_info!("evm_increaseTime");
543 Ok(self.backend.time().increase_time(seconds.try_into().unwrap_or(u64::MAX)) as i64)
544 }
545
546 pub fn evm_set_next_block_timestamp(&self, seconds: u64) -> Result<()> {
550 node_info!("evm_setNextBlockTimestamp");
551 self.backend.time().set_next_block_timestamp(seconds)
552 }
553
554 pub fn evm_set_time(&self, timestamp: u64) -> Result<u64> {
563 node_info!("evm_setTime");
564 let now = self.backend.time().current_call_timestamp();
565 self.backend.time().set_time(timestamp);
566
567 let offset = timestamp.saturating_sub(now);
569 Ok(offset)
570 }
571
572 pub fn evm_set_block_gas_limit(&self, gas_limit: U256) -> Result<bool> {
576 node_info!("evm_setBlockGasLimit");
577 self.backend.set_gas_limit(gas_limit.saturating_to());
578 Ok(true)
579 }
580
581 pub fn evm_set_block_timestamp_interval(&self, seconds: u64) -> Result<()> {
585 node_info!("anvil_setBlockTimestampInterval");
586 self.backend.time().set_block_timestamp_interval(seconds);
587 Ok(())
588 }
589
590 pub fn evm_remove_block_timestamp_interval(&self) -> Result<bool> {
594 node_info!("anvil_removeBlockTimestampInterval");
595 Ok(self.backend.time().remove_block_timestamp_interval())
596 }
597
598 pub async fn anvil_set_rpc_url(&self, url: String) -> Result<()> {
602 node_info!("anvil_setRpcUrl");
603 let _reset = self.reset_lock.lock().await;
604 let staged_fork = if let Some(fork) = self.backend.get_fork() {
605 let mut validation_config = self.backend.node_config.read().await.clone();
606 let (expected_identity, block_number, block_hash) = {
607 let config = fork.config.read();
608 (config.endpoint_identity, config.block_number, config.block_hash)
609 };
610 validation_config.fork_chain_id = None;
613 let (provider, endpoint_identity) = validation_config
614 .replacement_fork_provider(
615 &url,
616 expected_identity,
617 block_number,
618 block_hash,
619 self.instance_id(),
620 )
621 .await?;
622 Some((fork, provider, endpoint_identity))
623 } else {
624 None
625 };
626
627 let _lifecycle = self.lifecycle_lock.write().await;
628 let _mining = self.backend.lock_mining().await;
629 let mut node_config = self.backend.node_config.write().await;
630 if let Some((fork, provider, endpoint_identity)) = staged_fork {
631 let mut config = fork.config.write();
632 trace!(target: "backend", "Updated fork rpc from \"{}\" to \"{}\"", config.eth_rpc_url().map(redact_url).unwrap_or_else(|| "none".to_string()), redact_url(&url));
633 config.provider = provider;
634 config.fork_urls = vec![url.clone()];
635 config.fork_chain_id = None;
636 config.endpoint_identity = endpoint_identity;
637 node_config.fork_endpoint_is_anvil = endpoint_identity.is_authoritative();
638 }
639 node_config.fork_urls = vec![url];
641 node_config.fork_chain_id = None;
642 Ok(())
643 }
644
645 pub async fn txpool_status(&self) -> Result<TxpoolStatus> {
651 node_info!("txpool_status");
652 Ok(self.pool.txpool_status())
653 }
654
655 async fn on_blocking_task<C, F, R>(&self, c: C) -> Result<R>
657 where
658 C: FnOnce(Self) -> F,
659 F: Future<Output = Result<R>> + Send + 'static,
660 R: Send + 'static,
661 {
662 let (tx, rx) = oneshot::channel();
663 let this = self.clone();
664 let f = c(this);
665 tokio::task::spawn_blocking(move || {
666 tokio::runtime::Handle::current().block_on(async move {
667 let res = f.await;
668 let _ = tx.send(res);
669 })
670 });
671 rx.await.map_err(|_| BlockchainError::Internal("blocking task panicked".to_string()))?
672 }
673
674 pub fn set_transaction_order(&self, order: TransactionOrder) {
676 *self.transaction_order.write() = order;
677 }
678
679 pub fn chain_id(&self) -> u64 {
681 self.backend.chain_id().to::<u64>()
682 }
683
684 pub fn get_fork(&self) -> Option<ClientFork> {
686 self.backend.get_fork()
687 }
688
689 pub fn instance_id(&self) -> B256 {
691 *self.instance_id.read()
692 }
693
694 pub fn reset_instance_id(&self) {
696 *self.instance_id.write() = B256::random();
697 }
698
699 #[expect(clippy::borrowed_box)]
701 pub fn get_signer(&self, address: Address) -> Option<&Box<dyn Signer<N>>> {
702 self.signers.iter().find(|signer| signer.is_signer_for(address))
703 }
704
705 pub fn new_ready_transactions(&self) -> Receiver<TxHash> {
707 self.pool.add_ready_listener()
708 }
709
710 pub fn is_fork(&self) -> bool {
712 self.backend.is_fork()
713 }
714
715 pub async fn state_root(&self) -> Option<B256> {
717 self.backend.get_db().read().await.maybe_state_root()
718 }
719
720 pub fn is_impersonated(&self, addr: Address) -> bool {
722 self.backend.cheats().is_impersonated(addr)
723 }
724
725 pub fn storage_info(&self) -> StorageInfo<N> {
727 StorageInfo::new(Arc::clone(&self.backend))
728 }
729
730 #[allow(clippy::large_stack_frames)]
732 pub fn anvil_get_blob_by_versioned_hash(
733 &self,
734 hash: B256,
735 ) -> Result<Option<alloy_consensus::Blob>> {
736 node_info!("anvil_getBlobByHash");
737 Ok(self.backend.get_blob_by_versioned_hash(hash)?)
738 }
739
740 pub fn anvil_get_blobs_by_block_id(
742 &self,
743 block_id: impl Into<BlockId>,
744 versioned_hashes: Vec<B256>,
745 ) -> Result<Option<Vec<Blob>>> {
746 node_info!("anvil_getBlobsByBlockId");
747 Ok(self.backend.get_blobs_by_block_id(block_id, versioned_hashes)?)
748 }
749
750 pub fn anvil_get_genesis_time(&self) -> Result<u64> {
754 node_info!("anvil_getGenesisTime");
755 Ok(self.backend.genesis_time())
756 }
757
758 pub fn anvil_get_last_block_wall_time(&self) -> Result<u64> {
762 node_info!("anvil_getLastBlockWallTime");
763 Ok(self.backend.time().last_block_wall_time())
764 }
765
766 pub async fn anvil_reset(&self, forking: Option<Forking>) -> Result<()> {
772 node_info!("anvil_reset");
773 let _reset = self.reset_lock.lock().await;
774 if let Some(forking) = forking {
775 let staged = self.backend.prepare_fork_reset(forking, self.instance_id()).await?;
776 let _lifecycle = self.lifecycle_lock.write().await;
777 let _mining = self.backend.lock_mining().await;
779 self.backend.commit_fork_reset(staged).await?;
780 self.reset_instance_id();
781 self.pool.clear();
782 self.fee_history_cache.lock().clear();
783 } else {
784 let _lifecycle = self.lifecycle_lock.write().await;
785 let _mining = self.backend.lock_mining().await;
788 let staged = self.backend.prepare_memory_reset().await?;
789 self.backend.commit_memory_reset(staged).await?;
790 self.reset_instance_id();
791 self.pool.clear();
792 self.fee_history_cache.lock().clear();
793 }
794 Ok(())
795 }
796
797 pub async fn evm_revert(&self, id: U256) -> Result<bool> {
802 node_info!("evm_revert");
803 let _lifecycle = self.lifecycle_lock.read().await;
804 let _mining = self.backend.lock_mining().await;
805 self.backend.revert_state_snapshot(id).await
806 }
807
808 pub async fn anvil_impersonate_account(&self, address: Address) -> Result<()> {
812 node_info!("anvil_impersonateAccount");
813 self.backend.impersonate(address);
814 Ok(())
815 }
816
817 pub async fn anvil_stop_impersonating_account(&self, address: Address) -> Result<()> {
821 node_info!("anvil_stopImpersonatingAccount");
822 self.backend.stop_impersonating(address);
823 Ok(())
824 }
825
826 pub async fn anvil_auto_impersonate_account(&self, enabled: bool) -> Result<()> {
830 node_info!("anvil_autoImpersonateAccount");
831 self.backend.auto_impersonate_account(enabled);
832 Ok(())
833 }
834
835 pub async fn anvil_impersonate_signature(
837 &self,
838 signature: Bytes,
839 address: Address,
840 ) -> Result<()> {
841 node_info!("anvil_impersonateSignature");
842 self.backend.impersonate_signature(signature, address).await
843 }
844
845 pub fn new_block_notifications(&self) -> ChainNotifications {
848 self.backend.new_block_notifications()
849 }
850
851 pub fn client_version(&self) -> Result<String> {
855 node_info!("web3_clientVersion");
856 Ok(CLIENT_VERSION.to_string())
857 }
858
859 pub fn sha3(&self, bytes: Bytes) -> Result<String> {
863 node_info!("web3_sha3");
864 let hash = alloy_primitives::keccak256(bytes.as_ref());
865 Ok(alloy_primitives::hex::encode_prefixed(&hash[..]))
866 }
867
868 pub fn protocol_version(&self) -> Result<u64> {
872 node_info!("eth_protocolVersion");
873 Ok(1)
874 }
875
876 pub fn hashrate(&self) -> Result<U256> {
880 node_info!("eth_hashrate");
881 Ok(U256::ZERO)
882 }
883
884 pub fn author(&self) -> Result<Address> {
888 node_info!("eth_coinbase");
889 Ok(self.backend.coinbase())
890 }
891
892 pub fn is_mining(&self) -> Result<bool> {
896 node_info!("eth_mining");
897 Ok(self.is_mining)
898 }
899
900 pub fn eth_chain_id(&self) -> Result<Option<U64>> {
906 node_info!("eth_chainId");
907 Ok(Some(self.backend.chain_id().to::<U64>()))
908 }
909
910 pub fn network_id(&self) -> Result<Option<String>> {
914 node_info!("eth_networkId");
915 let chain_id = self.backend.chain_id().to::<u64>();
916 Ok(Some(format!("{chain_id}")))
917 }
918
919 pub fn net_listening(&self) -> Result<bool> {
923 node_info!("net_listening");
924 Ok(self.net_listening)
925 }
926
927 fn eth_gas_price(&self) -> Result<U256> {
929 node_info!("eth_gasPrice");
930 Ok(U256::from(self.gas_price()))
931 }
932
933 pub fn base_fee(&self) -> Result<Option<U256>> {
937 node_info!("eth_baseFee");
938 Ok(self.backend.is_eip1559().then(|| U256::from(self.backend.base_fee())))
939 }
940
941 pub fn excess_blob_gas_and_price(&self) -> Result<Option<BlobExcessGasAndPrice>> {
943 Ok(self.backend.excess_blob_gas_and_price())
944 }
945
946 pub fn gas_max_priority_fee_per_gas(&self) -> Result<U256> {
951 self.max_priority_fee_per_gas()
952 }
953
954 pub fn blob_base_fee(&self) -> Result<U256> {
958 Ok(U256::from(self.backend.fees().base_fee_per_blob_gas()))
959 }
960
961 pub fn gas_limit(&self) -> U256 {
963 U256::from(self.backend.gas_limit())
964 }
965
966 pub fn accounts(&self) -> Result<Vec<Address>> {
970 node_info!("eth_accounts");
971 let mut unique = AddressSet::default();
972 let mut accounts: Vec<Address> = Vec::new();
973 for signer in self.signers.iter() {
974 accounts.extend(signer.accounts().into_iter().filter(|acc| unique.insert(*acc)));
975 }
976 accounts.extend(
977 self.backend
978 .cheats()
979 .impersonated_accounts()
980 .into_iter()
981 .filter(|acc| unique.insert(*acc)),
982 );
983 Ok(accounts.into_iter().collect())
984 }
985
986 pub fn block_number(&self) -> Result<U256> {
990 node_info!("eth_blockNumber");
991 Ok(U256::from(self.backend.best_number()))
992 }
993
994 pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
998 node_info!("eth_getBlockByHash");
999 self.backend.block_by_hash(hash).await
1000 }
1001
1002 pub async fn header_by_hash(
1006 &self,
1007 hash: B256,
1008 ) -> Result<Option<WithOtherFields<AnyRpcHeader>>> {
1009 node_info!("eth_getHeaderByHash");
1010 Ok(self.backend.block_by_hash(hash).await?.map(|block| {
1011 let WithOtherFields { inner: block, other } = block.0;
1012 WithOtherFields { inner: block.header, other }
1013 }))
1014 }
1015
1016 pub async fn block_by_hash_full(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
1020 node_info!("eth_getBlockByHash");
1021 self.backend.block_by_hash_full(hash).await
1022 }
1023
1024 pub async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
1028 node_info!("eth_getBlockTransactionCountByHash");
1029 let block = self.backend.block_by_hash(hash).await?;
1030 let txs = block.map(|b| match b.transactions() {
1031 BlockTransactions::Full(txs) => U256::from(txs.len()),
1032 BlockTransactions::Hashes(txs) => U256::from(txs.len()),
1033 BlockTransactions::Uncle => U256::from(0),
1034 });
1035 Ok(txs)
1036 }
1037
1038 pub async fn block_uncles_count_by_hash(&self, hash: B256) -> Result<U256> {
1042 node_info!("eth_getUncleCountByBlockHash");
1043 let block =
1044 self.backend.block_by_hash(hash).await?.ok_or(BlockchainError::BlockNotFound)?;
1045 Ok(U256::from(block.uncles.len()))
1046 }
1047
1048 pub async fn block_uncles_count_by_number(&self, block_number: BlockNumber) -> Result<U256> {
1052 node_info!("eth_getUncleCountByBlockNumber");
1053 let block = self
1054 .backend
1055 .block_by_number(block_number)
1056 .await?
1057 .ok_or(BlockchainError::BlockNotFound)?;
1058 Ok(U256::from(block.uncles.len()))
1059 }
1060
1061 pub async fn sign_typed_data(
1065 &self,
1066 _address: Address,
1067 _data: serde_json::Value,
1068 ) -> Result<String> {
1069 node_info!("eth_signTypedData");
1070 Err(BlockchainError::RpcUnimplemented)
1071 }
1072
1073 pub async fn sign_typed_data_v3(
1077 &self,
1078 _address: Address,
1079 _data: serde_json::Value,
1080 ) -> Result<String> {
1081 node_info!("eth_signTypedData_v3");
1082 Err(BlockchainError::RpcUnimplemented)
1083 }
1084
1085 pub async fn sign_typed_data_v4(&self, address: Address, data: &TypedData) -> Result<String> {
1089 node_info!("eth_signTypedData_v4");
1090 let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
1091 let signature = signer.sign_typed_data(address, data).await?;
1092 let signature = alloy_primitives::hex::encode(signature.as_bytes());
1093 Ok(format!("0x{signature}"))
1094 }
1095
1096 pub async fn sign(&self, address: Address, content: impl AsRef<[u8]>) -> Result<String> {
1100 node_info!("eth_sign");
1101 let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
1102 let signature =
1103 alloy_primitives::hex::encode(signer.sign(address, content.as_ref()).await?.as_bytes());
1104 Ok(format!("0x{signature}"))
1105 }
1106
1107 pub async fn transaction_by_block_hash_and_index(
1111 &self,
1112 hash: B256,
1113 index: Index,
1114 ) -> Result<Option<AnyRpcTransaction>> {
1115 node_info!("eth_getTransactionByBlockHashAndIndex");
1116 self.backend.transaction_by_block_hash_and_index(hash, index).await
1117 }
1118
1119 pub async fn uncle_by_block_hash_and_index(
1123 &self,
1124 block_hash: B256,
1125 idx: Index,
1126 ) -> Result<Option<AnyRpcBlock>> {
1127 node_info!("eth_getUncleByBlockHashAndIndex");
1128 let number =
1129 self.backend.ensure_block_number(Some(BlockId::Hash(block_hash.into()))).await?;
1130 if let Some(fork) = self.get_fork()
1131 && fork.predates_fork_inclusive(number)
1132 {
1133 return Ok(fork.uncle_by_block_hash_and_index(block_hash, idx.into()).await?);
1134 }
1135 Ok(None)
1137 }
1138
1139 pub async fn uncle_by_block_number_and_index(
1143 &self,
1144 block_number: BlockNumber,
1145 idx: Index,
1146 ) -> Result<Option<AnyRpcBlock>> {
1147 node_info!("eth_getUncleByBlockNumberAndIndex");
1148 let number = self.backend.ensure_block_number(Some(BlockId::Number(block_number))).await?;
1149 if let Some(fork) = self.get_fork()
1150 && fork.predates_fork_inclusive(number)
1151 {
1152 return Ok(fork.uncle_by_block_number_and_index(number, idx.into()).await?);
1153 }
1154 Ok(None)
1156 }
1157
1158 pub fn work(&self) -> Result<Work> {
1162 node_info!("eth_getWork");
1163 Err(BlockchainError::RpcUnimplemented)
1164 }
1165
1166 pub fn syncing(&self) -> Result<bool> {
1170 node_info!("eth_syncing");
1171 Ok(false)
1172 }
1173
1174 pub fn config(&self) -> Result<EthConfig> {
1185 node_info!("eth_config");
1186 Ok(EthConfig {
1187 current: EthForkConfig {
1188 activation_time: 0,
1189 blob_schedule: self.backend.blob_params(),
1190 chain_id: self.backend.chain_id().to::<u64>(),
1191 fork_id: Bytes::from_static(&[0; 4]),
1192 precompiles: self.backend.precompiles(),
1193 system_contracts: self.backend.system_contracts(),
1194 },
1195 next: None,
1196 last: None,
1197 })
1198 }
1199
1200 pub fn submit_work(&self, _: B64, _: B256, _: B256) -> Result<bool> {
1204 node_info!("eth_submitWork");
1205 Err(BlockchainError::RpcUnimplemented)
1206 }
1207
1208 pub fn submit_hashrate(&self, _: U256, _: B256) -> Result<bool> {
1212 node_info!("eth_submitHashrate");
1213 Err(BlockchainError::RpcUnimplemented)
1214 }
1215
1216 pub async fn fee_history(
1220 &self,
1221 block_count: U256,
1222 newest_block: BlockNumber,
1223 reward_percentiles: Vec<f64>,
1224 ) -> Result<FeeHistory>
1225 where
1226 N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log>,
1227 {
1228 node_info!("eth_feeHistory");
1229
1230 if reward_percentiles.iter().any(|p| !(0.0..=100.0).contains(p))
1231 || reward_percentiles.windows(2).any(|pair| pair[0] >= pair[1])
1232 {
1233 return Err(FeeHistoryError::InvalidRewardPercentiles.into());
1234 }
1235
1236 let number = self.backend.convert_block_number(Some(newest_block));
1239
1240 let fork = self.get_fork();
1245 let fork_block = fork.as_ref().map(|fork| fork.block_number());
1246
1247 if let (Some(fork), Some(fork_block)) = (fork.as_ref(), fork_block) {
1249 if number <= fork_block {
1252 return fork
1253 .fee_history(block_count.to(), BlockNumber::Number(number), &reward_percentiles)
1254 .await
1255 .map_err(BlockchainError::AlloyForkProvider);
1256 }
1257 }
1258
1259 const MAX_BLOCK_COUNT: u64 = 1024u64;
1260 let block_count = block_count.saturating_to::<u64>().min(MAX_BLOCK_COUNT);
1261
1262 let highest = number;
1264 let lowest = highest.saturating_sub(block_count.saturating_sub(1));
1265
1266 if lowest < self.backend.best_number().saturating_sub(self.fee_history_limit) {
1268 return Err(FeeHistoryError::InvalidBlockRange.into());
1269 }
1270
1271 let mut response = FeeHistory {
1272 oldest_block: lowest,
1273 base_fee_per_gas: Vec::new(),
1274 gas_used_ratio: Vec::new(),
1275 reward: Some(Default::default()),
1276 base_fee_per_blob_gas: Default::default(),
1277 blob_gas_used_ratio: Default::default(),
1278 };
1279 let mut rewards = Vec::new();
1280
1281 let local_lowest = if let (Some(fork), Some(fork_block)) = (fork.as_ref(), fork_block) {
1288 if lowest <= fork_block {
1289 let count_pre = fork_block - lowest + 1;
1290 let pre = fork
1291 .fee_history(count_pre, BlockNumber::Number(fork_block), &reward_percentiles)
1292 .await
1293 .map_err(BlockchainError::AlloyForkProvider)?;
1294 merge_pre_fork_fee_history(&mut response, &mut rewards, pre, fork_block);
1295 fork_block + 1
1297 } else {
1298 lowest
1299 }
1300 } else {
1301 lowest
1302 };
1303
1304 {
1305 let storage_info = self.storage_info();
1306 let blob_params = self.backend.blob_params();
1307
1308 let cached: Vec<Option<FeeHistoryCacheItem>> = {
1312 let cache = self.fee_history_cache.lock();
1313 (local_lowest..=highest).map(|n| cache.get(&n).cloned()).collect()
1314 };
1315
1316 let mut warmed: Vec<(u64, FeeHistoryCacheItem)> = Vec::new();
1322 let mut items: Vec<FeeHistoryCacheItem> = Vec::with_capacity(cached.len());
1323 for (cached_item, n) in cached.into_iter().zip(local_lowest..=highest) {
1324 let hash = self
1325 .backend
1326 .block_hash_by_number(n)
1327 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1328 let item = match cached_item {
1329 Some(item) if item.block_hash == hash => item,
1330 _ => {
1331 let block = self
1332 .backend
1333 .get_block_by_hash(hash)
1334 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1335 let header = block.header;
1336 let (item, block_number) = create_fee_history_cache_item(
1337 hash,
1338 &header,
1339 &storage_info,
1340 blob_params,
1341 );
1342 let block_number = block_number
1346 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1347 warmed.push((block_number, item.clone()));
1348 item
1349 }
1350 };
1351 items.push(item);
1352 }
1353
1354 if !warmed.is_empty() {
1357 let mut cache = self.fee_history_cache.lock();
1358 for (block_number, item) in warmed {
1359 cache.insert(block_number, item);
1360 }
1361 while cache.len() as u64 > self.fee_history_limit {
1362 cache.pop_first();
1363 }
1364 }
1365
1366 for item in items {
1367 response.base_fee_per_gas.push(item.base_fee);
1368 response.base_fee_per_blob_gas.push(item.base_fee_per_blob_gas.unwrap_or(0));
1369 response.blob_gas_used_ratio.push(item.blob_gas_used_ratio);
1370 response.gas_used_ratio.push(item.gas_used_ratio);
1371
1372 if !reward_percentiles.is_empty() {
1374 let mut block_rewards = Vec::new();
1375 for p in &reward_percentiles {
1376 block_rewards.push(reward_at_percentile(&item.rewards, *p));
1377 }
1378 rewards.push(block_rewards);
1379 }
1380 }
1381 }
1382
1383 response.reward = Some(rewards);
1384
1385 let next_number = highest
1390 .checked_add(1)
1391 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(highest)))?;
1392 let (next_base_fee, next_blob_base_fee) = self
1393 .backend
1394 .fee_history_next_fees(highest)
1395 .await
1396 .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(next_number)))?;
1397 response.base_fee_per_gas.push(next_base_fee);
1398 response.base_fee_per_blob_gas.push(next_blob_base_fee);
1399
1400 Ok(response)
1401 }
1402
1403 pub fn max_priority_fee_per_gas(&self) -> Result<U256> {
1410 node_info!("eth_maxPriorityFeePerGas");
1411 Ok(U256::from(self.lowest_suggestion_tip()))
1412 }
1413
1414 pub async fn debug_code_by_hash(
1418 &self,
1419 hash: B256,
1420 block_id: Option<BlockId>,
1421 ) -> Result<Option<Bytes>> {
1422 node_info!("debug_codeByHash");
1423 self.backend.debug_code_by_hash(hash, block_id).await
1424 }
1425
1426 pub async fn debug_db_get(&self, key: String) -> Result<Option<Bytes>> {
1431 node_info!("debug_dbGet");
1432 self.backend.debug_db_get(key).await
1433 }
1434
1435 pub fn debug_get_modified_accounts_by_number(
1437 &self,
1438 _start_number: u64,
1439 _end_number: u64,
1440 ) -> Result<()> {
1441 node_info!("debug_getModifiedAccountsByNumber");
1442 Ok(())
1443 }
1444
1445 pub fn debug_free_os_memory(&self) -> Result<()> {
1447 node_info!("debug_freeOSMemory");
1448 Ok(())
1449 }
1450
1451 pub async fn trace_call(
1455 &self,
1456 request: WithOtherFields<TransactionRequest>,
1457 mut trace_types: HashSet<TraceType>,
1458 block_id: Option<BlockId>,
1459 ) -> Result<TraceResults>
1460 where
1461 N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope>,
1462 {
1463 node_info!("trace_call");
1464 if trace_types.is_empty() {
1465 trace_types.insert(TraceType::Trace);
1466 }
1467
1468 let block_id = block_id.unwrap_or_default();
1469 let block_request = match &block_id {
1470 BlockId::Number(BlockNumber::Pending) => {
1471 let pending_txs = self.pool.ready_transactions().collect();
1472 BlockRequest::Pending(pending_txs)
1473 }
1474 _ => {
1475 let number = self.backend.ensure_block_number(Some(block_id)).await?;
1476 BlockRequest::Number(number)
1477 }
1478 };
1479 let inner = request.as_ref();
1480 let fees = FeeDetails::new(
1481 inner.gas_price,
1482 inner.max_fee_per_gas,
1483 inner.max_priority_fee_per_gas,
1484 inner.max_fee_per_blob_gas,
1485 )?
1486 .or_zero_fees();
1487
1488 self.backend.trace_call(request, fees, trace_types, block_request, block_id).await
1489 }
1490
1491 pub async fn trace_transaction(&self, tx_hash: B256) -> Result<Vec<LocalizedTransactionTrace>> {
1495 node_info!("trace_transaction");
1496 self.backend.trace_transaction(tx_hash).await
1497 }
1498
1499 pub async fn trace_block(&self, block: BlockNumber) -> Result<Vec<LocalizedTransactionTrace>> {
1503 node_info!("trace_block");
1504 self.backend.trace_block(block).await
1505 }
1506
1507 pub async fn trace_filter(
1511 &self,
1512 filter: TraceFilter,
1513 ) -> Result<Vec<LocalizedTransactionTrace>> {
1514 node_info!("trace_filter");
1515 self.backend.trace_filter(filter).await
1516 }
1517
1518 pub async fn trace_get(
1522 &self,
1523 hash: B256,
1524 indices: Vec<Index>,
1525 ) -> Result<Option<LocalizedTransactionTrace>> {
1526 node_info!("trace_get");
1527 self.backend.trace_get(hash, indices).await
1528 }
1529
1530 pub async fn trace_replay_block_transactions(
1534 &self,
1535 block: BlockNumber,
1536 trace_types: HashSet<TraceType>,
1537 ) -> Result<Vec<TraceResultsWithTransactionHash>> {
1538 node_info!("trace_replayBlockTransactions");
1539 self.backend.trace_replay_block_transactions(block, trace_types).await
1540 }
1541
1542 pub async fn trace_replay_transaction(
1546 &self,
1547 transaction: B256,
1548 trace_types: HashSet<TraceType>,
1549 ) -> Result<TraceResults> {
1550 node_info!("trace_replayTransaction");
1551 self.backend.trace_replay_transaction(transaction, trace_types).await
1552 }
1553}
1554
1555impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> EthApi<N> {
1556 pub async fn serialized_state(
1558 &self,
1559 preserve_historical_states: bool,
1560 ) -> Result<SerializableState> {
1561 self.backend.serialized_state(preserve_historical_states).await
1562 }
1563}
1564
1565impl EthApi<FoundryNetwork> {
1568 pub async fn transaction_by_block_number_and_index(
1572 &self,
1573 block: BlockNumber,
1574 idx: Index,
1575 ) -> Result<Option<AnyRpcTransaction>> {
1576 node_info!("eth_getTransactionByBlockNumberAndIndex");
1577 if block == BlockNumber::Pending {
1578 return Ok(self.pending_block_full().await.and_then(|block| {
1579 let WithOtherFields { inner: block, .. } = block.0;
1580 block.transactions.into_transactions().nth(idx.into())
1581 }));
1582 }
1583
1584 self.backend.transaction_by_block_number_and_index(block, idx).await
1585 }
1586
1587 pub async fn anvil_dump_state(
1592 &self,
1593 preserve_historical_states: Option<bool>,
1594 ) -> Result<Bytes> {
1595 node_info!("anvil_dumpState");
1596 self.backend.dump_state(preserve_historical_states.unwrap_or(false)).await
1597 }
1598
1599 pub async fn anvil_load_state(&self, buf: Bytes) -> Result<bool> {
1604 node_info!("anvil_loadState");
1605 self.backend.load_state_bytes(buf).await
1606 }
1607
1608 async fn block_request(
1609 &self,
1610 block_number: Option<BlockId>,
1611 ) -> Result<BlockRequest<FoundryTxEnvelope>> {
1612 let block_request = match block_number {
1613 Some(BlockId::Number(BlockNumber::Pending)) => {
1614 let pending_txs = self.pool.ready_transactions().collect();
1615 BlockRequest::Pending(pending_txs)
1616 }
1617 _ => {
1618 let number = self.backend.ensure_block_number(block_number).await?;
1619 BlockRequest::Number(number)
1620 }
1621 };
1622 Ok(block_request)
1623 }
1624
1625 pub async fn debug_account_info_at(
1629 &self,
1630 block_id: BlockId,
1631 tx_index: Index,
1632 address: Address,
1633 ) -> Result<Option<AccountInfo>> {
1634 node_info!("debug_accountInfoAt");
1635 self.backend.debug_account_info_at(block_id, tx_index, address).await
1636 }
1637
1638 pub async fn debug_execution_witness(&self, block: BlockNumber) -> Result<ExecutionWitness> {
1644 node_info!("debug_executionWitness");
1645 self.backend.debug_execution_witness(block).await
1646 }
1647
1648 pub async fn trace_transaction_opcode_gas(
1652 &self,
1653 tx_hash: B256,
1654 ) -> Result<Option<TransactionOpcodeGas>> {
1655 node_info!("trace_transactionOpcodeGas");
1656 self.backend.trace_transaction_opcode_gas(tx_hash).await
1657 }
1658
1659 pub async fn trace_block_opcode_gas(
1663 &self,
1664 block_id: BlockId,
1665 ) -> Result<Option<BlockOpcodeGas>> {
1666 node_info!("trace_blockOpcodeGas");
1667 self.backend.trace_block_opcode_gas(block_id).await
1668 }
1669
1670 pub async fn trace_raw_transaction(
1674 &self,
1675 tx: Bytes,
1676 trace_types: HashSet<TraceType>,
1677 block_number: Option<BlockId>,
1678 ) -> Result<TraceResults> {
1679 node_info!("trace_rawTransaction");
1680
1681 let mut data = tx.as_ref();
1682 if data.is_empty() {
1683 return Err(BlockchainError::EmptyRawTransactionData);
1684 }
1685
1686 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
1687 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
1688 self.ensure_typed_transaction_supported(&transaction)?;
1689
1690 let pending_transaction = PendingTransaction::new(transaction)?;
1691 let block_request = self.block_request(block_number).await?;
1692
1693 self.backend
1694 .trace_raw_transaction(pending_transaction, trace_types, Some(block_request))
1695 .await
1696 }
1697
1698 pub async fn anvil_add_balance(&self, address: Address, balance: U256) -> Result<()> {
1702 node_info!("anvil_addBalance");
1703 let current_balance = self.backend.get_balance(address, None).await?;
1704 self.backend.set_balance(address, current_balance.saturating_add(balance)).await?;
1705 Ok(())
1706 }
1707
1708 pub async fn anvil_rollback(&self, depth: Option<u64>) -> Result<()> {
1719 node_info!("anvil_rollback");
1720 let depth = depth.unwrap_or(1);
1721
1722 let current_height = self.backend.best_number();
1724 let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(
1725 RpcError::invalid_params(format!(
1726 "Rollback depth must not exceed current chain height: current height {current_height}, depth {depth}"
1727 )),
1728 ))?;
1729
1730 let common_block =
1732 self.backend.get_block(common_height).ok_or(BlockchainError::BlockNotFound)?;
1733
1734 self.backend.rollback(common_block).await?;
1735 Ok(())
1736 }
1737
1738 fn do_estimate_gas_with_state(
1742 &self,
1743 request: FoundryTransactionRequest,
1744 state: &dyn DatabaseRef,
1745 block_env: BlockEnv,
1746 monad_context: Option<MonadReplayContext>,
1747 ) -> Result<u128> {
1748 let inner = request.as_ref();
1749 let fees = FeeDetails::new(
1750 inner.gas_price,
1751 inner.max_fee_per_gas,
1752 inner.max_priority_fee_per_gas,
1753 inner.max_fee_per_blob_gas,
1754 )?
1755 .or_zero_fees();
1756
1757 let mut highest_gas_limit = inner.gas.map_or(block_env.gas_limit.into(), |g| g as u128);
1760
1761 let is_tempo_aa_tx = self.backend.is_tempo() && request.is_tempo();
1764 let is_tempo_keychain = matches!(
1765 &request,
1766 FoundryTransactionRequest::Tempo(request) if request.key_id.is_some()
1767 );
1768
1769 let gas_price = fees.gas_price.unwrap_or_default();
1770 if !is_tempo_aa_tx && let Some(from) = inner.from {
1775 let mut available_funds = self.backend.get_balance_with_state(state, from)?;
1776 if let Some(value) = inner.value {
1777 if value > available_funds {
1778 return Err(InvalidTransactionError::InsufficientFunds.into());
1779 }
1780 available_funds -= value;
1782 }
1783 if gas_price > 0 {
1784 let allowance =
1786 available_funds.checked_div(U256::from(gas_price)).unwrap_or_default();
1787 highest_gas_limit = std::cmp::min(highest_gas_limit, allowance.saturating_to());
1788 }
1789 }
1790
1791 if !self.backend.is_tempo() {
1796 let to = inner.to.as_ref().and_then(TxKind::to);
1797
1798 let maybe_transfer = (inner.input.input().is_none()
1800 || inner.input.input().is_some_and(|data| data.is_empty()))
1801 && inner.authorization_list.is_none()
1802 && inner.access_list.is_none()
1803 && inner.blob_versioned_hashes.is_none();
1804
1805 if maybe_transfer
1806 && highest_gas_limit >= MIN_TRANSACTION_GAS
1807 && let Some(to) = to
1808 && let Ok(target_code) = self.backend.get_code_with_state(&state, *to)
1809 && target_code.as_ref().is_empty()
1810 {
1811 return Ok(MIN_TRANSACTION_GAS);
1812 }
1813 }
1814
1815 let ethres = self.backend.call_with_state_typed_gas_limit(
1817 &state,
1818 request.clone(),
1819 fees.clone(),
1820 block_env.clone(),
1821 GasEstimateCallOptions::new(
1822 highest_gas_limit as u64,
1823 is_tempo_keychain,
1824 monad_context.clone(),
1825 ),
1826 );
1827
1828 let gas_used = match ethres.try_into()? {
1829 GasEstimationCallResult::Success(gas) => Ok(gas),
1830 GasEstimationCallResult::OutOfGas => {
1831 Err(InvalidTransactionError::BasicOutOfGas(highest_gas_limit).into())
1832 }
1833 GasEstimationCallResult::Revert(output) => {
1834 Err(InvalidTransactionError::Revert(output).into())
1835 }
1836 GasEstimationCallResult::EvmError(err) => {
1837 warn!(target: "node", "estimation failed due to {:?}", err);
1838 Err(BlockchainError::EvmError(err))
1839 }
1840 }?;
1841
1842 let mut lowest_gas_limit = determine_base_gas_by_kind(&request);
1849
1850 let mut mid_gas_limit =
1852 std::cmp::min(gas_used * 3, (highest_gas_limit + lowest_gas_limit) / 2);
1853
1854 while (highest_gas_limit - lowest_gas_limit) > 1 {
1856 let ethres = self.backend.call_with_state_typed_gas_limit(
1857 &state,
1858 request.clone(),
1859 fees.clone(),
1860 block_env.clone(),
1861 GasEstimateCallOptions::new(
1862 mid_gas_limit as u64,
1863 is_tempo_keychain,
1864 monad_context.clone(),
1865 ),
1866 );
1867
1868 match ethres.try_into()? {
1869 GasEstimationCallResult::Success(_) => {
1870 highest_gas_limit = mid_gas_limit;
1874 }
1875 GasEstimationCallResult::OutOfGas
1876 | GasEstimationCallResult::Revert(_)
1877 | GasEstimationCallResult::EvmError(_) => {
1878 lowest_gas_limit = mid_gas_limit;
1885 }
1886 };
1887 mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
1889 }
1890
1891 trace!(target : "node", "Estimated Gas for call {:?}", highest_gas_limit);
1892
1893 Ok(highest_gas_limit)
1894 }
1895
1896 #[allow(clippy::large_stack_frames)]
1898 pub async fn execute(&self, request: EthRequest) -> ResponseResult {
1899 trace!(target: "rpc::api", "executing eth request");
1900 let _lifecycle = if matches!(
1905 &request,
1906 EthRequest::Reset(_)
1907 | EthRequest::SetRpcUrl(_)
1908 | EthRequest::NodeInfo(_)
1909 | EthRequest::AnvilMetadata(_)
1910 | EthRequest::EvmSnapshot(_)
1911 | EthRequest::EvmRevert(_)
1912 ) {
1913 None
1914 } else {
1915 Some(self.lifecycle_lock.read().await)
1916 };
1917 let response = match request.clone() {
1918 EthRequest::EthProtocolVersion(()) => self.protocol_version().to_rpc_result(),
1919 EthRequest::Web3ClientVersion(()) => self.client_version().to_rpc_result(),
1920 EthRequest::Web3Sha3(content) => self.sha3(content).to_rpc_result(),
1921 EthRequest::EthGetAccount(addr, block) => {
1922 self.get_account(addr, block).await.to_rpc_result()
1923 }
1924 EthRequest::EthGetAccountInfo(addr, block) => {
1925 self.get_account_info(addr, block).await.to_rpc_result()
1926 }
1927 EthRequest::EthGetBalance(addr, block) => {
1928 self.balance(addr, block).await.to_rpc_result()
1929 }
1930 EthRequest::EthGetTransactionByHash(hash) => {
1931 self.transaction_by_hash(hash).await.to_rpc_result()
1932 }
1933 EthRequest::EthPendingTransactions(_) => {
1934 self.pending_transactions().await.to_rpc_result()
1935 }
1936 EthRequest::EthSendTransaction(request) => {
1937 self.send_transaction(*request).await.to_rpc_result()
1938 }
1939 EthRequest::EthResend(request, gas_price, gas_limit) => {
1940 self.resend_transaction(*request, gas_price, gas_limit).await.to_rpc_result()
1941 }
1942 EthRequest::EthSendTransactionSync(request) => {
1943 self.send_transaction_sync(*request).await.to_rpc_result()
1944 }
1945 EthRequest::EthChainId(_) => self.eth_chain_id().to_rpc_result(),
1946 EthRequest::EthNetworkId(_) => self.network_id().to_rpc_result(),
1947 EthRequest::NetListening(_) => self.net_listening().to_rpc_result(),
1948 EthRequest::EthHashrate(()) => self.hashrate().to_rpc_result(),
1949 EthRequest::EthGasPrice(_) => self.eth_gas_price().to_rpc_result(),
1950 EthRequest::EthBaseFee(_) => self.base_fee().to_rpc_result(),
1951 EthRequest::EthMaxPriorityFeePerGas(_) => {
1952 self.gas_max_priority_fee_per_gas().to_rpc_result()
1953 }
1954 EthRequest::EthBlobBaseFee(_) => self.blob_base_fee().to_rpc_result(),
1955 EthRequest::EthAccounts(_) => self.accounts().to_rpc_result(),
1956 EthRequest::EthBlockNumber(_) => self.block_number().to_rpc_result(),
1957 EthRequest::EthCoinbase(()) => self.author().to_rpc_result(),
1958 EthRequest::EthGetStorageAt(addr, slot, block) => {
1959 self.storage_at(addr, slot, block).await.to_rpc_result()
1960 }
1961 EthRequest::EthGetStorageValues(requests, block) => {
1962 self.storage_values(requests, block).await.to_rpc_result()
1963 }
1964 EthRequest::EthGetBlockByHash(hash, full) => {
1965 if full {
1966 self.block_by_hash_full(hash).await.to_rpc_result()
1967 } else {
1968 self.block_by_hash(hash).await.to_rpc_result()
1969 }
1970 }
1971 EthRequest::EthGetHeaderByHash(hash) => self.header_by_hash(hash).await.to_rpc_result(),
1972 EthRequest::EthGetBlockByNumber(num, full) => {
1973 if full {
1974 self.block_by_number_full(num).await.to_rpc_result()
1975 } else {
1976 self.block_by_number(num).await.to_rpc_result()
1977 }
1978 }
1979 EthRequest::EthGetHeaderByNumber(num) => {
1980 self.header_by_number(num).await.to_rpc_result()
1981 }
1982 EthRequest::EthGetBlockAccessList(block_id) => {
1983 self.block_access_list(block_id).await.to_rpc_result()
1984 }
1985 EthRequest::EthGetBlockAccessListByBlockHash(block_hash) => {
1986 self.block_access_list_by_hash(block_hash).await.to_rpc_result()
1987 }
1988 EthRequest::EthGetBlockAccessListByBlockNumber(block_number) => {
1989 self.block_access_list_by_number(block_number).await.to_rpc_result()
1990 }
1991 EthRequest::EthGetBlockAccessListRaw(block_id) => {
1992 self.block_access_list_raw(block_id).await.to_rpc_result()
1993 }
1994 EthRequest::EthGetTransactionCount(addr, block) => {
1995 self.transaction_count(addr, block).await.to_rpc_result()
1996 }
1997 EthRequest::EthGetTransactionCountByHash(hash) => {
1998 self.block_transaction_count_by_hash(hash).await.to_rpc_result()
1999 }
2000 EthRequest::EthGetTransactionCountByNumber(num) => {
2001 self.block_transaction_count_by_number(num).await.to_rpc_result()
2002 }
2003 EthRequest::EthGetUnclesCountByHash(hash) => {
2004 self.block_uncles_count_by_hash(hash).await.to_rpc_result()
2005 }
2006 EthRequest::EthGetUnclesCountByNumber(num) => {
2007 self.block_uncles_count_by_number(num).await.to_rpc_result()
2008 }
2009 EthRequest::EthGetCodeAt(addr, block) => {
2010 self.get_code(addr, block).await.to_rpc_result()
2011 }
2012 EthRequest::EthGetProof(addr, keys, block) => {
2013 self.get_proof(addr, keys, block).await.to_rpc_result()
2014 }
2015 EthRequest::EthSign(addr, content) => self.sign(addr, content).await.to_rpc_result(),
2016 EthRequest::PersonalSign(content, addr) => {
2017 self.sign(addr, content).await.to_rpc_result()
2018 }
2019 EthRequest::EthSignTransaction(request) => {
2020 self.sign_transaction(*request).await.to_rpc_result()
2021 }
2022 EthRequest::EthSignTypedData(addr, data) => {
2023 self.sign_typed_data(addr, data).await.to_rpc_result()
2024 }
2025 EthRequest::EthSignTypedDataV3(addr, data) => {
2026 self.sign_typed_data_v3(addr, data).await.to_rpc_result()
2027 }
2028 EthRequest::EthSignTypedDataV4(addr, data) => {
2029 self.sign_typed_data_v4(addr, &data).await.to_rpc_result()
2030 }
2031 EthRequest::EthSendRawTransaction(tx) => {
2032 self.send_raw_transaction(tx).await.to_rpc_result()
2033 }
2034 EthRequest::EthSendRawTransactionSync(tx, timeout_ms) => {
2035 self.send_raw_transaction_sync(tx, timeout_ms).await.to_rpc_result()
2036 }
2037 EthRequest::EthSendRawTransactionConditional(tx, condition) => {
2038 self.send_raw_transaction_conditional(tx, condition).await.to_rpc_result()
2039 }
2040 EthRequest::EthSignRawTransaction(tx) => {
2041 self.sign_raw_transaction(tx).await.to_rpc_result()
2042 }
2043 EthRequest::AnvilClassifyTransaction(tx) => {
2044 self.anvil_classify_transaction(tx).to_rpc_result()
2045 }
2046 EthRequest::EthCall(call, block, state_override, block_overrides) => self
2047 .call(call, block, EvmOverrides::new(state_override, block_overrides))
2048 .await
2049 .to_rpc_result(),
2050 EthRequest::EthCallMany(bundles, state_context, state_override) => {
2051 self.call_many(bundles, state_context, state_override).await.to_rpc_result()
2052 }
2053 EthRequest::EthCallBundle(bundle) => self.call_bundle(bundle).await.to_rpc_result(),
2054 EthRequest::EthSimulateV1(simulation, block) => {
2055 self.simulate_v1_raw(simulation, block).await.to_rpc_result()
2056 }
2057 EthRequest::EthCreateAccessList(call, block, state_override) => {
2058 self.create_access_list(call, block, state_override).await.to_rpc_result()
2059 }
2060 EthRequest::EthEstimateGas(call, block, state_override, block_overrides) => self
2061 .estimate_gas(call, block, EvmOverrides::new(state_override, block_overrides))
2062 .await
2063 .to_rpc_result(),
2064 EthRequest::EthFillTransaction(request) => {
2065 self.fill_transaction(request).await.to_rpc_result()
2066 }
2067 EthRequest::EthGetRawTransactionByHash(hash) => {
2068 self.raw_transaction(hash).await.to_rpc_result()
2069 }
2070 EthRequest::GetBlobByHash(hash) => {
2071 self.anvil_get_blob_by_versioned_hash(hash).to_rpc_result()
2072 }
2073 EthRequest::GetBlobByTransactionHash(hash) => {
2074 self.anvil_get_blob_by_tx_hash(hash).to_rpc_result()
2075 }
2076 EthRequest::GetGenesisTime(()) => self.anvil_get_genesis_time().to_rpc_result(),
2077 EthRequest::GetLastBlockWallTime(()) => {
2078 self.anvil_get_last_block_wall_time().to_rpc_result()
2079 }
2080 EthRequest::EthGetRawTransactionByBlockHashAndIndex(hash, index) => {
2081 self.raw_transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
2082 }
2083 EthRequest::EthGetRawTransactionByBlockNumberAndIndex(num, index) => {
2084 self.raw_transaction_by_block_number_and_index(num, index).await.to_rpc_result()
2085 }
2086 EthRequest::EthGetTransactionByBlockHashAndIndex(hash, index) => {
2087 self.transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
2088 }
2089 EthRequest::EthGetTransactionByBlockNumberAndIndex(num, index) => {
2090 self.transaction_by_block_number_and_index(num, index).await.to_rpc_result()
2091 }
2092 EthRequest::EthGetTransactionReceipt(tx) => {
2093 self.transaction_receipt(tx).await.to_rpc_result()
2094 }
2095 EthRequest::EthGetBlockReceipts(number) => {
2096 self.block_receipts(number).await.to_rpc_result()
2097 }
2098 EthRequest::EthGetUncleByBlockHashAndIndex(hash, index) => {
2099 self.uncle_by_block_hash_and_index(hash, index).await.to_rpc_result()
2100 }
2101 EthRequest::EthGetUncleByBlockNumberAndIndex(num, index) => {
2102 self.uncle_by_block_number_and_index(num, index).await.to_rpc_result()
2103 }
2104 EthRequest::EthGetLogs(filter) => self.logs(filter).await.to_rpc_result(),
2105 EthRequest::EthGetWork(_) => self.work().to_rpc_result(),
2106 EthRequest::EthSyncing(_) => self.syncing().to_rpc_result(),
2107 EthRequest::EthConfig(_) => self.config().to_rpc_result(),
2108 EthRequest::EthSubmitWork(nonce, pow, digest) => {
2109 self.submit_work(nonce, pow, digest).to_rpc_result()
2110 }
2111 EthRequest::EthSubmitHashRate(rate, id) => {
2112 self.submit_hashrate(rate, id).to_rpc_result()
2113 }
2114 EthRequest::EthFeeHistory(count, newest, reward_percentiles) => {
2115 self.fee_history(count, newest, reward_percentiles).await.to_rpc_result()
2116 }
2117 EthRequest::DebugGetRawTransaction(hash) => {
2119 self.raw_transaction(hash).await.to_rpc_result()
2120 }
2121 EthRequest::DebugGetRawReceipts(block) => {
2122 self.raw_receipts(block).await.to_rpc_result()
2123 }
2124 EthRequest::DebugGetRawTransactions(block) => {
2125 self.raw_transactions(block).await.to_rpc_result()
2126 }
2127 EthRequest::DebugGetRawHeader(block) => self.raw_header(block).await.to_rpc_result(),
2128 EthRequest::DebugGetRawBlock(block) => self.raw_block(block).await.to_rpc_result(),
2129 EthRequest::DebugClearTxpool(_) => self.debug_clear_txpool().await.to_rpc_result(),
2131 EthRequest::DebugTraceTransaction(tx, opts) => {
2133 self.debug_trace_transaction(tx, opts).await.to_rpc_result()
2134 }
2135 EthRequest::DebugTraceCall(tx, block, opts) => {
2137 self.debug_trace_call(tx, block, opts).await.to_rpc_result()
2138 }
2139 EthRequest::DebugCodeByHash(hash, block) => {
2140 self.debug_code_by_hash(hash, block).await.to_rpc_result()
2141 }
2142 EthRequest::DebugDbGet(key) => self.debug_db_get(key).await.to_rpc_result(),
2143 EthRequest::DebugGetModifiedAccountsByNumber(start_number, end_number) => {
2144 self.debug_get_modified_accounts_by_number(start_number, end_number).to_rpc_result()
2145 }
2146 EthRequest::DebugFreeOsMemory(()) => self.debug_free_os_memory().to_rpc_result(),
2147 EthRequest::DebugAccountInfoAt(block_id, tx_index, address) => {
2148 self.debug_account_info_at(block_id, tx_index, address).await.to_rpc_result()
2149 }
2150 EthRequest::DebugExecutionWitness(block) => {
2151 self.debug_execution_witness(block).await.to_rpc_result()
2152 }
2153 EthRequest::DebugTraceBlock(rlp_block, opts) => {
2154 self.debug_trace_block(rlp_block, opts).await.to_rpc_result()
2155 }
2156 EthRequest::DebugTraceBlockByHash(block_hash, opts) => {
2157 self.debug_trace_block_by_hash(block_hash, opts).await.to_rpc_result()
2158 }
2159 EthRequest::DebugTraceBlockByNumber(block_number, opts) => {
2160 self.debug_trace_block_by_number(block_number, opts).await.to_rpc_result()
2161 }
2162 EthRequest::TraceCall(tx, trace_types, block) => {
2163 self.trace_call(tx, trace_types, block).await.to_rpc_result()
2164 }
2165 EthRequest::TraceTransaction(tx) => self.trace_transaction(tx).await.to_rpc_result(),
2166 EthRequest::TraceBlock(block) => self.trace_block(block).await.to_rpc_result(),
2167 EthRequest::TraceFilter(filter) => self.trace_filter(filter).await.to_rpc_result(),
2168 EthRequest::TraceGet(hash, indices) => {
2169 self.trace_get(hash, indices).await.to_rpc_result()
2170 }
2171 EthRequest::TraceReplayBlockTransactions(block, trace_types) => {
2172 self.trace_replay_block_transactions(block, trace_types).await.to_rpc_result()
2173 }
2174 EthRequest::TraceReplayTransaction(transaction, trace_types) => {
2175 self.trace_replay_transaction(transaction, trace_types).await.to_rpc_result()
2176 }
2177 EthRequest::TraceTransactionOpcodeGas(tx_hash) => {
2178 self.trace_transaction_opcode_gas(tx_hash).await.to_rpc_result()
2179 }
2180 EthRequest::TraceBlockOpcodeGas(block_id) => {
2181 self.trace_block_opcode_gas(block_id).await.to_rpc_result()
2182 }
2183 EthRequest::TraceRawTransaction(tx, trace_types, block_number) => {
2184 self.trace_raw_transaction(tx, trace_types, block_number).await.to_rpc_result()
2185 }
2186 EthRequest::TraceCallMany(calls, block_number) => {
2187 self.trace_call_many(calls, block_number).await.to_rpc_result()
2188 }
2189 EthRequest::ImpersonateAccount(addr) => {
2190 self.anvil_impersonate_account(addr).await.to_rpc_result()
2191 }
2192 EthRequest::StopImpersonatingAccount(addr) => {
2193 self.anvil_stop_impersonating_account(addr).await.to_rpc_result()
2194 }
2195 EthRequest::AutoImpersonateAccount(enable) => {
2196 self.anvil_auto_impersonate_account(enable).await.to_rpc_result()
2197 }
2198 EthRequest::ImpersonateSignature(signature, address) => {
2199 self.anvil_impersonate_signature(signature, address).await.to_rpc_result()
2200 }
2201 EthRequest::GetAutoMine(()) => self.anvil_get_auto_mine().to_rpc_result(),
2202 EthRequest::Mine(blocks, interval) => {
2203 self.anvil_mine(blocks, interval).await.to_rpc_result()
2204 }
2205 EthRequest::SetAutomine(enabled) => {
2206 self.anvil_set_auto_mine(enabled).await.to_rpc_result()
2207 }
2208 EthRequest::SetIntervalMining(interval) => {
2209 self.anvil_set_interval_mining(interval).to_rpc_result()
2210 }
2211 EthRequest::GetIntervalMining(()) => self.anvil_get_interval_mining().to_rpc_result(),
2212 EthRequest::DropTransaction(tx) => {
2213 self.anvil_drop_transaction(tx).await.to_rpc_result()
2214 }
2215 EthRequest::DropAllTransactions() => {
2216 self.anvil_drop_all_transactions().await.to_rpc_result()
2217 }
2218 EthRequest::Reset(fork) => {
2219 self.anvil_reset(fork.and_then(|p| p.params)).await.to_rpc_result()
2220 }
2221 EthRequest::SetBalance(addr, val) => {
2222 self.anvil_set_balance(addr, val).await.to_rpc_result()
2223 }
2224 EthRequest::AddBalance(addr, val) => {
2225 self.anvil_add_balance(addr, val).await.to_rpc_result()
2226 }
2227 EthRequest::DealERC20(addr, token_addr, val) => {
2228 self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result()
2229 }
2230 EthRequest::DealTIP20(addr, token_addr, val) => {
2231 self.anvil_deal_tip20(addr, token_addr, val).await.to_rpc_result()
2232 }
2233 EthRequest::SetERC20Allowance(owner, spender, token_addr, val) => self
2234 .anvil_set_erc20_allowance(owner, spender, token_addr, val)
2235 .await
2236 .to_rpc_result(),
2237 EthRequest::SetCode(addr, code) => {
2238 self.anvil_set_code(addr, code).await.to_rpc_result()
2239 }
2240 EthRequest::SetNonce(addr, nonce) => {
2241 self.anvil_set_nonce(addr, nonce).await.to_rpc_result()
2242 }
2243 EthRequest::SetStorageAt(addr, slot, val) => {
2244 self.anvil_set_storage_at(addr, slot, val).await.to_rpc_result()
2245 }
2246 EthRequest::SetCoinbase(addr) => self.anvil_set_coinbase(addr).await.to_rpc_result(),
2247 EthRequest::SetNextBlockPrevRandao(prevrandao) => {
2248 self.anvil_set_next_block_prevrandao(prevrandao).await.to_rpc_result()
2249 }
2250 EthRequest::SetChainId(id) => self.anvil_set_chain_id(id).await.to_rpc_result(),
2251 EthRequest::SetLogging(log) => self.anvil_set_logging(log).await.to_rpc_result(),
2252 EthRequest::SetMinGasPrice(gas) => {
2253 self.anvil_set_min_gas_price(gas).await.to_rpc_result()
2254 }
2255 EthRequest::SetNextBlockBaseFeePerGas(gas) => {
2256 self.anvil_set_next_block_base_fee_per_gas(gas).await.to_rpc_result()
2257 }
2258 EthRequest::DumpState(preserve_historical_states) => self
2259 .anvil_dump_state(preserve_historical_states.and_then(|s| s.params))
2260 .await
2261 .to_rpc_result(),
2262 EthRequest::LoadState(buf) => self.anvil_load_state(buf).await.to_rpc_result(),
2263 EthRequest::NodeInfo(_) => self.anvil_node_info().await.to_rpc_result(),
2264 EthRequest::AnvilMetadata(_) => self.anvil_metadata().await.to_rpc_result(),
2265 EthRequest::EvmSnapshot(_) => self.evm_snapshot().await.to_rpc_result(),
2266 EthRequest::EvmRevert(id) => self.evm_revert(id).await.to_rpc_result(),
2267 EthRequest::EvmIncreaseTime(time) => self.evm_increase_time(time).await.to_rpc_result(),
2268 EthRequest::EvmSetNextBlockTimeStamp(time) => {
2269 if time >= U256::from(u64::MAX) {
2270 return ResponseResult::Error(RpcError::invalid_params(
2271 "The timestamp is too big",
2272 ));
2273 }
2274 let time = time.to::<u64>();
2275 self.evm_set_next_block_timestamp(time).to_rpc_result()
2276 }
2277 EthRequest::EvmSetTime(timestamp) => {
2278 if timestamp >= U256::from(u64::MAX) {
2279 return ResponseResult::Error(RpcError::invalid_params(
2280 "The timestamp is too big",
2281 ));
2282 }
2283 let raw = timestamp.to::<u64>();
2287 let time = if raw > 1_000_000_000_000 {
2288 Duration::from_millis(raw).as_secs()
2289 } else {
2290 raw
2291 };
2292 self.evm_set_time(time).to_rpc_result()
2293 }
2294 EthRequest::EvmSetBlockGasLimit(gas_limit) => {
2295 self.evm_set_block_gas_limit(gas_limit).to_rpc_result()
2296 }
2297 EthRequest::EvmSetBlockTimeStampInterval(time) => {
2298 self.evm_set_block_timestamp_interval(time).to_rpc_result()
2299 }
2300 EthRequest::EvmRemoveBlockTimeStampInterval(()) => {
2301 self.evm_remove_block_timestamp_interval().to_rpc_result()
2302 }
2303 EthRequest::EvmMine(mine) => {
2304 self.evm_mine(mine.and_then(|p| p.params)).await.to_rpc_result()
2305 }
2306 EthRequest::EvmMineDetailed(mine) => {
2307 self.evm_mine_detailed(mine.and_then(|p| p.params)).await.to_rpc_result()
2308 }
2309 EthRequest::SetRpcUrl(url) => self.anvil_set_rpc_url(url).await.to_rpc_result(),
2310 EthRequest::EthSendUnsignedTransaction(tx) => {
2311 self.eth_send_unsigned_transaction(*tx).await.to_rpc_result()
2312 }
2313 EthRequest::EthNewFilter(filter) => self.new_filter(filter).await.to_rpc_result(),
2314 EthRequest::EthGetFilterChanges(id) => self.get_filter_changes(&id).await,
2315 EthRequest::EthNewBlockFilter(_) => self.new_block_filter().await.to_rpc_result(),
2316 EthRequest::EthNewPendingTransactionFilter(full) => {
2317 self.new_pending_transaction_filter(full.unwrap_or(false)).await.to_rpc_result()
2318 }
2319 EthRequest::EthGetFilterLogs(id) => self.get_filter_logs(&id).await.to_rpc_result(),
2320 EthRequest::EthUninstallFilter(id) => self.uninstall_filter(&id).await.to_rpc_result(),
2321 EthRequest::TxPoolStatus(_) => self.txpool_status().await.to_rpc_result(),
2322 EthRequest::TxPoolInspect(_) => self.txpool_inspect().await.to_rpc_result(),
2323 EthRequest::TxPoolContent(_) => self.txpool_content().await.to_rpc_result(),
2324 EthRequest::TxPoolContentFrom(from) => {
2325 self.txpool_content_from(from).await.to_rpc_result()
2326 }
2327 EthRequest::ErigonGetHeaderByNumber(num) => {
2328 self.erigon_get_header_by_number(num).await.to_rpc_result()
2329 }
2330 EthRequest::OtsGetApiLevel(_) => self.ots_get_api_level().await.to_rpc_result(),
2331 EthRequest::OtsGetInternalOperations(hash) => {
2332 self.ots_get_internal_operations(hash).await.to_rpc_result()
2333 }
2334 EthRequest::OtsHasCode(addr, num) => self.ots_has_code(addr, num).await.to_rpc_result(),
2335 EthRequest::OtsTraceTransaction(hash) => {
2336 self.ots_trace_transaction(hash).await.to_rpc_result()
2337 }
2338 EthRequest::OtsGetTransactionError(hash) => {
2339 self.ots_get_transaction_error(hash).await.to_rpc_result()
2340 }
2341 EthRequest::OtsGetBlockDetails(num) => {
2342 self.ots_get_block_details(num).await.to_rpc_result()
2343 }
2344 EthRequest::OtsGetBlockDetailsByHash(hash) => {
2345 self.ots_get_block_details_by_hash(hash).await.to_rpc_result()
2346 }
2347 EthRequest::OtsGetBlockTransactions(num, page, page_size) => {
2348 self.ots_get_block_transactions(num, page, page_size).await.to_rpc_result()
2349 }
2350 EthRequest::OtsSearchTransactionsBefore(address, num, page_size) => {
2351 self.ots_search_transactions_before(address, num, page_size).await.to_rpc_result()
2352 }
2353 EthRequest::OtsSearchTransactionsAfter(address, num, page_size) => {
2354 self.ots_search_transactions_after(address, num, page_size).await.to_rpc_result()
2355 }
2356 EthRequest::OtsGetTransactionBySenderAndNonce(address, nonce) => {
2357 self.ots_get_transaction_by_sender_and_nonce(address, nonce).await.to_rpc_result()
2358 }
2359 EthRequest::EthGetTransactionBySenderAndNonce(sender, nonce) => {
2360 self.transaction_by_sender_and_nonce(sender, nonce).await.to_rpc_result()
2361 }
2362 EthRequest::OtsGetContractCreator(address) => {
2363 self.ots_get_contract_creator(address).await.to_rpc_result()
2364 }
2365 EthRequest::RemovePoolTransactions(address) => {
2366 self.anvil_remove_pool_transactions(address).await.to_rpc_result()
2367 }
2368 EthRequest::Reorg(reorg_options) => {
2369 self.anvil_reorg(reorg_options).await.to_rpc_result()
2370 }
2371 EthRequest::Rollback(depth) => self.anvil_rollback(depth).await.to_rpc_result(),
2372 EthRequest::SetFeeToken(user, token) => {
2373 self.anvil_set_fee_token(user, token).await.to_rpc_result()
2374 }
2375 EthRequest::SetValidatorFeeToken(validator, token) => {
2376 self.anvil_set_validator_fee_token(validator, token).await.to_rpc_result()
2377 }
2378 EthRequest::SetFeeAmmLiquidity(user_token, validator_token, amount) => self
2379 .anvil_set_fee_amm_liquidity(user_token, validator_token, amount)
2380 .await
2381 .to_rpc_result(),
2382 };
2383
2384 if let ResponseResult::Error(err) = &response {
2385 node_info!("\nRPC request failed:");
2386 node_info!(" Request: {:?}", request);
2387 node_info!(" Error: {}\n", err);
2388 }
2389
2390 response
2391 }
2392
2393 fn sign_request(&self, from: &Address, typed_tx: FoundryTypedTx) -> Result<FoundryTxEnvelope> {
2394 match typed_tx {
2395 #[cfg(feature = "optimism")]
2396 FoundryTypedTx::Deposit(_) => return Ok(typed_tx.into_impersonated()),
2397 _ => {
2398 for signer in self.signers.iter() {
2399 if signer.accounts().contains(from) {
2400 return signer.sign_transaction_from(from, typed_tx);
2401 }
2402 }
2403 }
2404 }
2405 Err(BlockchainError::NoSignerAvailable)
2406 }
2407
2408 async fn inner_raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
2409 match self.pool.get_transaction(hash) {
2410 Some(tx) => Ok(Some(tx.transaction.encoded_2718().into())),
2411 None => match self.backend.transaction_by_hash(hash).await? {
2412 Some(tx) => encode_rpc_transaction(&tx).map(Some),
2413 None => Ok(None),
2414 },
2415 }
2416 }
2417
2418 pub async fn balance(&self, address: Address, block_number: Option<BlockId>) -> Result<U256> {
2422 node_info!("eth_getBalance");
2423 let block_request = self.block_request(block_number).await?;
2424
2425 if let BlockRequest::Number(number) = block_request
2427 && let Some(fork) = self.get_fork()
2428 && fork.predates_fork(number)
2429 {
2430 return Ok(fork.get_balance(address, number).await?);
2431 }
2432
2433 self.backend.get_balance(address, Some(block_request)).await
2434 }
2435
2436 pub async fn get_account(
2440 &self,
2441 address: Address,
2442 block_number: Option<BlockId>,
2443 ) -> Result<TrieAccount> {
2444 node_info!("eth_getAccount");
2445 let block_request = self.block_request(block_number).await?;
2446
2447 if let BlockRequest::Number(number) = block_request
2449 && let Some(fork) = self.get_fork()
2450 && fork.predates_fork(number)
2451 {
2452 return Ok(fork.get_account(address, number).await?);
2453 }
2454
2455 self.backend.get_account_at_block(address, Some(block_request)).await
2456 }
2457
2458 pub async fn get_account_info(
2462 &self,
2463 address: Address,
2464 block_number: Option<BlockId>,
2465 ) -> Result<alloy_rpc_types::eth::AccountInfo> {
2466 node_info!("eth_getAccountInfo");
2467
2468 if let Some(fork) = self.get_fork() {
2469 let block_request = self.block_request(block_number).await?;
2470 if let BlockRequest::Number(number) = block_request {
2472 trace!(target: "node", "get_account_info: fork block {}, requested block {number}", fork.block_number());
2473 return if fork.predates_fork(number) {
2474 let balance = fork.get_balance(address, number).map_err(BlockchainError::from);
2477 let code = fork.get_code(address, number).map_err(BlockchainError::from);
2478 let nonce = self.get_transaction_count(address, Some(number.into()));
2479 let (balance, code, nonce) = try_join!(balance, code, nonce)?;
2480
2481 Ok(alloy_rpc_types::eth::AccountInfo { balance, nonce, code })
2482 } else {
2483 let account_info = self.backend.get_account(address).await?;
2486 let code = self.backend.get_code(address, Some(block_request)).await?;
2487 Ok(alloy_rpc_types::eth::AccountInfo {
2488 balance: account_info.balance,
2489 nonce: account_info.nonce,
2490 code,
2491 })
2492 };
2493 }
2494 }
2495
2496 let account = self.get_account(address, block_number);
2497 let code = self.get_code(address, block_number);
2498 let (account, code) = try_join!(account, code)?;
2499 Ok(alloy_rpc_types::eth::AccountInfo {
2500 balance: account.balance,
2501 nonce: account.nonce,
2502 code,
2503 })
2504 }
2505 pub async fn storage_at(
2509 &self,
2510 address: Address,
2511 index: U256,
2512 block_number: Option<BlockId>,
2513 ) -> Result<B256> {
2514 node_info!("eth_getStorageAt");
2515 let block_request = self.block_request(block_number).await?;
2516
2517 if let BlockRequest::Number(number) = block_request
2519 && let Some(fork) = self.get_fork()
2520 && fork.predates_fork(number)
2521 {
2522 return Ok(B256::from(
2523 fork.storage_at(address, index, Some(BlockNumber::Number(number))).await?,
2524 ));
2525 }
2526
2527 self.backend.storage_at(address, index, Some(block_request)).await
2528 }
2529
2530 pub async fn storage_values(
2534 &self,
2535 requests: HashMap<Address, Vec<B256>>,
2536 block_number: Option<BlockId>,
2537 ) -> Result<HashMap<Address, Vec<B256>>> {
2538 node_info!("eth_getStorageValues");
2539
2540 let total_slots: usize = requests.values().map(|s| s.len()).sum();
2541 if total_slots > 1024 {
2542 return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
2543 "total slot count {total_slots} exceeds limit 1024"
2544 ))));
2545 }
2546
2547 let block_request = self.block_request(block_number).await?;
2548
2549 if let BlockRequest::Number(number) = block_request
2551 && let Some(fork) = self.get_fork()
2552 && fork.predates_fork(number)
2553 {
2554 let mut result: HashMap<Address, Vec<B256>> = HashMap::default();
2555 for (address, slots) in requests {
2556 let mut values = Vec::with_capacity(slots.len());
2557 for slot in &slots {
2558 let val = fork
2559 .storage_at(address, (*slot).into(), Some(BlockNumber::Number(number)))
2560 .await?;
2561 values.push(B256::from(val));
2562 }
2563 result.insert(address, values);
2564 }
2565 return Ok(result);
2566 }
2567
2568 self.backend.storage_values(requests, Some(block_request)).await
2569 }
2570
2571 pub async fn block_by_number(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2575 node_info!("eth_getBlockByNumber");
2576 if number == BlockNumber::Pending {
2577 return Ok(Some(self.pending_block().await));
2578 }
2579
2580 self.backend.block_by_number(number).await
2581 }
2582
2583 pub async fn header_by_number(
2587 &self,
2588 number: BlockNumber,
2589 ) -> Result<Option<WithOtherFields<AnyRpcHeader>>> {
2590 node_info!("eth_getHeaderByNumber");
2591 if number == BlockNumber::Pending {
2592 let WithOtherFields { inner: block, other } = self.pending_block().await.0;
2593 return Ok(Some(WithOtherFields { inner: block.header, other }));
2594 }
2595
2596 Ok(self.backend.block_by_number(number).await?.map(|block| {
2597 let WithOtherFields { inner: block, other } = block.0;
2598 WithOtherFields { inner: block.header, other }
2599 }))
2600 }
2601
2602 pub async fn block_by_number_full(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2606 node_info!("eth_getBlockByNumber");
2607 if number == BlockNumber::Pending {
2608 return Ok(self.pending_block_full().await);
2609 }
2610 self.backend.block_by_number_full(number).await
2611 }
2612
2613 pub async fn block_access_list(&self, block_id: BlockId) -> Result<Option<serde_json::Value>> {
2617 node_info!("eth_getBlockAccessList");
2618 let block_request = self.block_request(Some(block_id)).await?;
2619 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2620
2621 if let Some(fork) = self.get_fork()
2622 && fork.predates_fork_inclusive(number)
2623 {
2624 return Ok(fork.block_access_list(block_id).await?);
2625 }
2626
2627 Ok(None)
2628 }
2629
2630 pub async fn block_access_list_by_hash(
2634 &self,
2635 block_hash: B256,
2636 ) -> Result<Option<serde_json::Value>> {
2637 node_info!("eth_getBlockAccessListByBlockHash");
2638 let Some(fork) = self.get_fork() else { return Ok(None) };
2639
2640 if let Some(block) = self.backend.get_block_by_hash(block_hash)
2643 && !fork.predates_fork_inclusive(block.header.number)
2644 {
2645 return Ok(None);
2646 }
2647
2648 Ok(fork.block_access_list_by_hash(block_hash).await?)
2649 }
2650
2651 pub async fn block_access_list_by_number(
2655 &self,
2656 block_number: BlockNumber,
2657 ) -> Result<Option<serde_json::Value>> {
2658 node_info!("eth_getBlockAccessListByBlockNumber");
2659 let block_request = self.block_request(Some(BlockId::Number(block_number))).await?;
2660 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2661
2662 if let Some(fork) = self.get_fork()
2663 && fork.predates_fork_inclusive(number)
2664 {
2665 return Ok(fork.block_access_list_by_number(block_number).await?);
2666 }
2667
2668 Ok(None)
2669 }
2670
2671 pub async fn block_access_list_raw(&self, block_id: BlockId) -> Result<Option<Bytes>> {
2675 node_info!("eth_getBlockAccessListRaw");
2676 let block_request = self.block_request(Some(block_id)).await?;
2677 let BlockRequest::Number(number) = block_request else { return Ok(None) };
2678
2679 if let Some(fork) = self.get_fork()
2680 && fork.predates_fork_inclusive(number)
2681 {
2682 return Ok(fork.block_access_list_raw(block_id).await?);
2683 }
2684
2685 Ok(None)
2686 }
2687
2688 pub async fn transaction_count(
2695 &self,
2696 address: Address,
2697 block_number: Option<BlockId>,
2698 ) -> Result<U256> {
2699 node_info!("eth_getTransactionCount");
2700 self.get_transaction_count(address, block_number).await.map(U256::from)
2701 }
2702
2703 pub async fn block_transaction_count_by_number(
2707 &self,
2708 block_number: BlockNumber,
2709 ) -> Result<Option<U256>> {
2710 node_info!("eth_getBlockTransactionCountByNumber");
2711 let block_request = self.block_request(Some(block_number.into())).await?;
2712 if let BlockRequest::Pending(txs) = block_request {
2713 let block = self.backend.pending_block(txs).await;
2714 return Ok(Some(U256::from(block.block.body.transactions.len())));
2715 }
2716 let block = self.backend.block_by_number(block_number).await?;
2717 let txs = block.map(|b| match b.transactions() {
2718 BlockTransactions::Full(txs) => U256::from(txs.len()),
2719 BlockTransactions::Hashes(txs) => U256::from(txs.len()),
2720 BlockTransactions::Uncle => U256::from(0),
2721 });
2722 Ok(txs)
2723 }
2724
2725 pub async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {
2729 node_info!("eth_getCode");
2730 let block_request = self.block_request(block_number).await?;
2731 if let BlockRequest::Number(number) = block_request
2733 && let Some(fork) = self.get_fork()
2734 && fork.predates_fork(number)
2735 {
2736 return Ok(fork.get_code(address, number).await?);
2737 }
2738 self.backend.get_code(address, Some(block_request)).await
2739 }
2740
2741 pub async fn get_proof(
2746 &self,
2747 address: Address,
2748 keys: Vec<B256>,
2749 block_number: Option<BlockId>,
2750 ) -> Result<EIP1186AccountProofResponse> {
2751 node_info!("eth_getProof");
2752 let block_request = self.block_request(block_number).await?;
2753
2754 if let BlockRequest::Number(number) = block_request
2757 && let Some(fork) = self.get_fork()
2758 && fork.predates_fork_inclusive(number)
2759 {
2760 return Ok(fork.get_proof(address, keys, Some(number.into())).await?);
2761 }
2762
2763 let proof = self.backend.prove_account_at(address, keys, Some(block_request)).await?;
2764 Ok(proof)
2765 }
2766
2767 pub async fn sign_transaction(
2771 &self,
2772 request: WithOtherFields<TransactionRequest>,
2773 ) -> Result<String> {
2774 node_info!("eth_signTransaction");
2775 let request = self.parse_transaction_request(request)?;
2776
2777 let from = request.from().map(Ok).unwrap_or_else(|| {
2778 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
2779 })?;
2780
2781 let (nonce, _) = self.request_nonce_for_transaction(&request, from).await?;
2782
2783 let request = self.build_tx_request(request, nonce).await?;
2784
2785 let signed_transaction = self.sign_request(&from, request)?.encoded_2718();
2786 Ok(alloy_primitives::hex::encode_prefixed(signed_transaction))
2787 }
2788
2789 pub async fn send_transaction(
2793 &self,
2794 request: WithOtherFields<TransactionRequest>,
2795 ) -> Result<TxHash> {
2796 node_info!("eth_sendTransaction");
2797 let request = self.parse_transaction_request(request)?;
2798
2799 let from = request.from().map(Ok).unwrap_or_else(|| {
2800 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
2801 })?;
2802 let (nonce, on_chain_nonce) = self.request_nonce_for_transaction(&request, from).await?;
2803
2804 let typed_tx = self.build_tx_request(request, nonce).await?;
2805
2806 let pending_transaction = if self.is_impersonated(from) {
2808 let transaction = typed_tx.into_impersonated();
2809 self.ensure_typed_transaction_supported(&transaction)?;
2810 trace!(target : "node", ?from, "eth_sendTransaction: impersonating");
2811 PendingTransaction::with_impersonated(transaction, from)
2812 } else {
2813 let transaction = self.sign_request(&from, typed_tx)?;
2814 self.ensure_typed_transaction_supported(&transaction)?;
2815 PendingTransaction::new(transaction)?
2816 };
2817 self.backend.validate_pool_transaction(&pending_transaction).await?;
2819
2820 let (requires, provides) = nonce_markers(&pending_transaction, nonce, on_chain_nonce, from);
2821
2822 self.add_pending_transaction(pending_transaction, requires, provides)
2823 }
2824
2825 pub async fn resend_transaction(
2829 &self,
2830 request: WithOtherFields<TransactionRequest>,
2831 gas_price: Option<U256>,
2832 gas_limit: Option<U64>,
2833 ) -> Result<TxHash> {
2834 node_info!("eth_resend");
2835 let mut request = self.parse_transaction_request(request)?;
2836
2837 let from = request.from().map(Ok).unwrap_or_else(|| {
2838 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
2839 })?;
2840 let nonce = request.nonce().ok_or_else(|| {
2841 BlockchainError::InvalidTransactionRequest(
2842 "missing transaction nonce in transaction spec".to_string(),
2843 )
2844 })?;
2845
2846 if !self.pool.contains_sender_nonce(from, nonce) {
2847 return Err(BlockchainError::TransactionNotFound);
2848 }
2849
2850 if let Some(gas_price) = gas_price.filter(|gas_price| !gas_price.is_zero()) {
2851 request.set_gas_price(gas_price.saturating_to());
2852 }
2853
2854 if let Some(gas_limit) = gas_limit.filter(|gas_limit| *gas_limit != U64::ZERO) {
2855 request.set_gas_limit(gas_limit.to());
2856 }
2857
2858 let typed_tx = self.build_tx_request(request, nonce).await?;
2859
2860 let pending_transaction = if self.is_impersonated(from) {
2861 let transaction = typed_tx.into_impersonated();
2862 self.ensure_typed_transaction_supported(&transaction)?;
2863 trace!(target : "node", ?from, "eth_resend: impersonating");
2864 PendingTransaction::with_impersonated(transaction, from)
2865 } else {
2866 let transaction = self.sign_request(&from, typed_tx)?;
2867 self.ensure_typed_transaction_supported(&transaction)?;
2868 PendingTransaction::new(transaction)?
2869 };
2870
2871 self.backend.validate_pool_transaction(&pending_transaction).await?;
2872
2873 let on_chain_nonce = self.backend.current_nonce(from).await?;
2874 let (requires, provides) = nonce_markers(&pending_transaction, nonce, on_chain_nonce, from);
2875
2876 self.add_pending_transaction(pending_transaction, requires, provides)
2877 }
2878
2879 async fn await_transaction_inclusion(&self, hash: TxHash) -> Result<FoundryTxReceipt> {
2881 let mut stream = self.new_block_notifications();
2882 if let Some(receipt) = self.backend.transaction_receipt(hash).await? {
2884 return Ok(receipt);
2885 }
2886 while let Some(notification) = stream.next().await {
2887 if let Some(new_block) = notification.as_new_block()
2888 && let Some(block) = self.backend.get_block_by_hash(new_block.hash)
2889 && block.body.transactions.iter().any(|tx| tx.hash() == hash)
2890 && let Some(receipt) = self.backend.transaction_receipt(hash).await?
2891 {
2892 return Ok(receipt);
2893 }
2894 }
2895
2896 Err(BlockchainError::Message("Failed to await transaction inclusion".to_string()))
2897 }
2898
2899 fn transaction_confirmation_timeout(timeout_ms: Option<u64>) -> Duration {
2900 const TIMEOUT_DURATION: Duration = Duration::from_secs(30);
2901 timeout_ms
2902 .filter(|timeout_ms| *timeout_ms > 0)
2903 .map(Duration::from_millis)
2904 .map(|timeout| timeout.min(TIMEOUT_DURATION))
2905 .unwrap_or(TIMEOUT_DURATION)
2906 }
2907
2908 async fn check_transaction_inclusion(
2910 &self,
2911 hash: TxHash,
2912 timeout_ms: Option<u64>,
2913 ) -> Result<FoundryTxReceipt> {
2914 let timeout_duration = Self::transaction_confirmation_timeout(timeout_ms);
2915 tokio::time::timeout(timeout_duration, self.await_transaction_inclusion(hash))
2916 .await
2917 .unwrap_or_else(|_elapsed| {
2918 Err(BlockchainError::TransactionConfirmationTimeout {
2919 hash,
2920 duration: timeout_duration,
2921 })
2922 })
2923 }
2924
2925 pub async fn send_transaction_sync(
2929 &self,
2930 request: WithOtherFields<TransactionRequest>,
2931 ) -> Result<FoundryTxReceipt> {
2932 node_info!("eth_sendTransactionSync");
2933 let hash = self.send_transaction(request).await?;
2934
2935 let receipt = self.check_transaction_inclusion(hash, None).await?;
2936
2937 Ok(receipt)
2938 }
2939
2940 pub async fn send_raw_transaction(&self, tx: Bytes) -> Result<TxHash> {
2944 node_info!("eth_sendRawTransaction");
2945 if tx.is_empty() {
2946 return Err(BlockchainError::EmptyRawTransactionData);
2947 }
2948
2949 let service_encoded = if self.backend.is_tempo() {
2953 normalize_fee_payer_service_encoding(tx.as_ref())
2954 } else {
2955 None
2956 };
2957 let raw = service_encoded.map(Bytes::from).unwrap_or(tx);
2958
2959 let transaction = if raw.first() == Some(&EIP4844_TX_TYPE_ID) {
2960 let raw = raw.clone();
2963 tokio::task::spawn_blocking(move || FoundryTxEnvelope::decode_2718(&mut raw.as_ref()))
2964 .await
2965 .map_err(|_| {
2966 BlockchainError::Internal("transaction decoding task panicked".into())
2967 })?
2968 } else {
2969 FoundryTxEnvelope::decode_2718(&mut raw.as_ref())
2970 }
2971 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
2972
2973 self.ensure_typed_transaction_supported(&transaction)?;
2974
2975 let transaction = match transaction {
2976 FoundryTxEnvelope::Tempo(aa_tx)
2977 if self.backend.is_tempo()
2978 && aa_tx.tx().fee_payer_signature == Some(FEE_PAYER_SIGNATURE_MARKER) =>
2979 {
2980 FoundryTxEnvelope::Tempo(self.sponsor_sign_tempo_transaction(aa_tx).await?)
2981 }
2982 transaction => transaction,
2983 };
2984
2985 if self.backend.is_tempo() && TempoHardfork::from(self.backend.hardfork()).is_t5() {
2986 let classification = classify_payment_lane(raw.as_ref());
2987 trace!(target: "node", tx = ?transaction.hash(), ?classification, "classified transaction lane");
2988 }
2989
2990 let pending_transaction = PendingTransaction::new(transaction)?;
2991
2992 self.backend.validate_pool_transaction(&pending_transaction).await?;
2994
2995 let from = *pending_transaction.sender();
2996 let priority = self.transaction_priority(&pending_transaction.transaction);
2997
2998 let (requires, provides) = if let Some((requires, provides)) =
3000 tempo_parallel_nonce_markers(&pending_transaction)
3001 {
3002 (requires, provides)
3003 } else {
3004 let on_chain_nonce = self.backend.current_nonce(from).await?;
3005 let nonce = pending_transaction.transaction.nonce();
3006 (required_marker(nonce, on_chain_nonce, from), vec![to_marker(nonce, from)])
3007 };
3008
3009 let pool_transaction =
3010 PoolTransaction { requires, provides, pending_transaction, priority, is_replay: false };
3011
3012 let tx = self.pool.add_transaction(pool_transaction)?;
3013 trace!(target: "node", "Added transaction: [{:?}] sender={:?}", tx.hash(), from);
3014 Ok(*tx.hash())
3015 }
3016
3017 pub async fn send_raw_transaction_conditional(
3021 &self,
3022 tx: Bytes,
3023 _condition: TransactionConditional,
3024 ) -> Result<TxHash> {
3025 node_info!("eth_sendRawTransactionConditional");
3026 self.send_raw_transaction(tx).await
3027 }
3028
3029 pub fn anvil_classify_transaction(&self, tx: Bytes) -> Result<PaymentLaneClassification> {
3031 node_info!("anvil_classifyTransaction");
3032 let mut data = tx.as_ref();
3033 if data.is_empty() {
3034 return Err(BlockchainError::EmptyRawTransactionData);
3035 }
3036
3037 FoundryTxEnvelope::decode_2718(&mut data)
3038 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3039
3040 Ok(self.classify_transaction_lane(tx.as_ref()))
3041 }
3042
3043 fn classify_transaction_lane(&self, raw: &[u8]) -> PaymentLaneClassification {
3044 if !self.backend.is_tempo() {
3045 return PaymentLaneClassification::general(PaymentLaneReason::NotTempo);
3046 }
3047
3048 if !TempoHardfork::from(self.backend.hardfork()).is_t5() {
3049 return PaymentLaneClassification::general(PaymentLaneReason::T5NotActive);
3050 }
3051
3052 classify_payment_lane(raw)
3053 }
3054
3055 pub async fn send_raw_transaction_sync(
3059 &self,
3060 tx: Bytes,
3061 timeout_ms: Option<u64>,
3062 ) -> Result<FoundryTxReceipt> {
3063 node_info!("eth_sendRawTransactionSync");
3064
3065 let hash = self.send_raw_transaction(tx).await?;
3066 let receipt = self.check_transaction_inclusion(hash, timeout_ms).await?;
3067
3068 Ok(receipt)
3069 }
3070
3071 pub async fn sign_raw_transaction(&self, tx: Bytes) -> Result<Bytes> {
3080 node_info!("eth_signRawTransaction");
3081 if !self.backend.is_tempo() {
3082 return Err(BlockchainError::RpcUnimplemented);
3083 }
3084
3085 if tx.is_empty() {
3086 return Err(BlockchainError::EmptyRawTransactionData);
3087 }
3088
3089 let service_encoded = normalize_fee_payer_service_encoding(tx.as_ref());
3092 let mut data = service_encoded.as_deref().unwrap_or(tx.as_ref());
3093
3094 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
3095 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3096
3097 let FoundryTxEnvelope::Tempo(aa_tx) = transaction else {
3098 return Err(RpcError::invalid_params(
3099 "only Tempo (0x76) transactions can be fee-payer signed",
3100 )
3101 .into());
3102 };
3103
3104 let signed = self.sponsor_sign_tempo_transaction(aa_tx).await?;
3105 Ok(FoundryTxEnvelope::Tempo(signed).encoded_2718().into())
3106 }
3107
3108 async fn sponsor_sign_tempo_transaction(&self, tx: AASigned) -> Result<AASigned> {
3114 match tx.tx().fee_payer_signature {
3118 Some(FEE_PAYER_SIGNATURE_MARKER) => {}
3119 Some(_) => {
3120 return Err(
3121 RpcError::invalid_params("transaction is already fee-payer signed").into()
3122 );
3123 }
3124 None => {
3125 return Err(RpcError::invalid_params(
3126 "transaction does not request sponsorship; sign it with the fee payer \
3127 signature placeholder",
3128 )
3129 .into());
3130 }
3131 }
3132
3133 let sender = tx.recover_signer().map_err(|_| {
3134 BlockchainError::RpcError(RpcError::invalid_params(
3135 "transaction must be signed by the sender before fee-payer signing",
3136 ))
3137 })?;
3138
3139 let Some(sponsor) = self.backend.tempo_fee_payer().await else {
3140 return Err(RpcError::invalid_params("no Tempo fee payer account available").into());
3141 };
3142 if sponsor == sender {
3143 return Err(RpcError::invalid_params(format!(
3144 "Tempo fee payer {sponsor} must not equal the transaction sender"
3145 ))
3146 .into());
3147 }
3148 let signer = self.get_signer(sponsor).ok_or(BlockchainError::NoSignerAvailable)?;
3149
3150 let (mut tx, sender_signature, _) = tx.into_parts();
3151 if tx.fee_token.is_none() {
3155 tx.fee_token = Some(self.backend.tempo_user_fee_token(sponsor).await?);
3156 }
3157 let digest = tx.fee_payer_signature_hash(sender);
3158 tx.fee_payer_signature = Some(signer.sign_hash(sponsor, digest).await?);
3159
3160 Ok(tx.into_signed(sender_signature))
3161 }
3162
3163 pub async fn call(
3167 &self,
3168 request: WithOtherFields<TransactionRequest>,
3169 block_number: Option<BlockId>,
3170 overrides: EvmOverrides,
3171 ) -> Result<Bytes> {
3172 node_info!("eth_call");
3173 let block_request = self.block_request(block_number).await?;
3174 if let BlockRequest::Number(number) = block_request
3176 && let Some(fork) = self.get_fork()
3177 && fork.predates_fork(number)
3178 {
3179 if overrides.has_state() || overrides.has_block() {
3180 return Err(BlockchainError::EvmOverrideError(
3181 "not available on past forked blocks".to_string(),
3182 ));
3183 }
3184 return Ok(fork.call_raw(&request, Some(number.into())).await?);
3185 }
3186
3187 let fees = FeeDetails::new(
3188 request.gas_price,
3189 request.max_fee_per_gas,
3190 request.max_priority_fee_per_gas,
3191 request.max_fee_per_blob_gas,
3192 )?
3193 .or_zero_fees();
3194 self.on_blocking_task(|this| async move {
3197 let (exit, out, gas, _) =
3198 this.backend.call(request, fees, Some(block_request), overrides).await?;
3199 trace!(target : "node", "Call status {:?}, gas {}", exit, gas);
3200
3201 ensure_return_ok(exit, &out)
3202 })
3203 .await
3204 }
3205
3206 pub async fn call_many(
3207 &self,
3208 bundles: Vec<Bundle<WithOtherFields<TransactionRequest>>>,
3209 state_context: Option<StateContext>,
3210 state_override: Option<StateOverride>,
3211 ) -> Result<Vec<Vec<EthCallResponse>>> {
3212 node_info!("eth_callMany");
3213 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
3214 if transaction_index.is_some_and(|index| index.index().is_some()) {
3215 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3216 "transactionIndex is not supported for eth_callMany yet".to_string(),
3217 )));
3218 }
3219
3220 let block_request = self.block_request(block_number).await?;
3221 if let BlockRequest::Number(number) = block_request
3222 && let Some(fork) = self.get_fork()
3223 && fork.predates_fork(number)
3224 {
3225 return Ok(fork
3226 .call_many(
3227 bundles,
3228 Some(StateContext { transaction_index, block_number: Some(number.into()) }),
3229 state_override,
3230 )
3231 .await?);
3232 }
3233
3234 self.on_blocking_task(|this| async move {
3235 this.backend.call_many(bundles, Some(block_request), state_override).await
3236 })
3237 .await
3238 }
3239
3240 pub async fn call_bundle(&self, bundle: EthCallBundle) -> Result<EthCallBundleResponse> {
3244 node_info!("eth_callBundle");
3245 if bundle.txs.is_empty() {
3246 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3247 "bundle missing txs".to_string(),
3248 )));
3249 }
3250 if bundle.block_number == 0 {
3251 return Err(BlockchainError::RpcError(RpcError::invalid_params(
3252 "bundle missing blockNumber".to_string(),
3253 )));
3254 }
3255
3256 let block_request = self.block_request(Some(bundle.state_block_number.into())).await?;
3257 if let BlockRequest::Number(number) = block_request
3258 && let Some(fork) = self.get_fork()
3259 && fork.predates_fork(number)
3260 {
3261 return Ok(fork.call_bundle(bundle).await?);
3262 }
3263
3264 let transactions = bundle
3265 .txs
3266 .iter()
3267 .map(|raw| {
3268 let mut data = raw.as_ref();
3269 if data.is_empty() {
3270 return Err(BlockchainError::EmptyRawTransactionData);
3271 }
3272 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
3273 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3274 self.ensure_typed_transaction_supported(&transaction)?;
3275 PendingTransaction::new(transaction).map_err(Into::into)
3276 })
3277 .collect::<Result<Vec<_>>>()?;
3278
3279 self.on_blocking_task(|this| async move {
3280 this.backend.call_bundle(bundle, transactions, Some(block_request)).await
3281 })
3282 .await
3283 }
3284
3285 pub async fn simulate_v1(
3286 &self,
3287 request: SimulatePayload,
3288 block_number: Option<BlockId>,
3289 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
3290 self.simulate_v1_raw(preserve_simulation_request_fields(request), block_number).await
3291 }
3292
3293 pub(crate) async fn simulate_v1_raw(
3294 &self,
3295 mut request: SimulatePayload<WithOtherFields<TransactionRequest>>,
3296 block_number: Option<BlockId>,
3297 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
3298 const DEFAULT_BLOCK_INTERVAL_SECS: u64 = 12;
3299
3300 node_info!("eth_simulateV1");
3301 if request.block_state_calls.is_empty() {
3302 return Err(BlockchainError::RpcError(RpcError::invalid_params("empty input")));
3303 }
3304 if request.block_state_calls.len() > MAX_SIMULATE_BLOCKS as usize {
3305 return Err(BlockchainError::RpcError(RpcError {
3306 code: ErrorCode::ServerError(-38026),
3307 message: "too many blocks".into(),
3308 data: None,
3309 }));
3310 }
3311 let block_id = block_number;
3312 let block_request =
3313 self.block_request(block_number).await.map_err(|error| match error {
3314 BlockchainError::BlockOutOfRange(_, _) | BlockchainError::BlockNotFound => {
3315 BlockchainError::RpcError(RpcError {
3316 code: ErrorCode::ServerError(-32000),
3317 message: "header not found".into(),
3318 data: None,
3319 })
3320 }
3321 error => error,
3322 })?;
3323 let block_interval = self.backend.time().block_timestamp_interval().unwrap_or_else(|| {
3324 self.miner
3325 .block_interval()
3326 .map(|duration| {
3327 duration
3328 .as_secs()
3329 .saturating_add(u64::from(duration.subsec_nanos() != 0))
3330 .max(1)
3331 })
3332 .unwrap_or(DEFAULT_BLOCK_INTERVAL_SECS)
3333 });
3334
3335 if let BlockRequest::Number(number) = block_request
3337 && let Some(fork) = self.get_fork()
3338 && fork.predates_fork(number)
3339 {
3340 let block_id = match block_id {
3341 Some(BlockId::Hash(hash)) => BlockId::Hash(hash),
3342 _ => number.into(),
3343 };
3344 let base_block = fork.fetch_block(block_id).await?.ok_or_else(|| {
3345 BlockchainError::RpcError(RpcError {
3346 code: ErrorCode::ServerError(-32000),
3347 message: "header not found".into(),
3348 data: None,
3349 })
3350 })?;
3351 request.block_state_calls = sanitize_simulation_blocks(
3352 request.block_state_calls,
3353 base_block.header.number(),
3354 base_block.header.timestamp(),
3355 block_interval,
3356 )?;
3357 return Ok(fork.simulate_v1(&request, Some(base_block.header.hash.into())).await?);
3358 }
3359
3360 self.on_blocking_task(|this| async move {
3363 let simulated_blocks =
3364 this.backend.simulate_raw(request, Some(block_request), block_interval).await?;
3365 trace!(target : "node", "Simulate status {:?}", simulated_blocks);
3366
3367 Ok(simulated_blocks)
3368 })
3369 .await
3370 }
3371
3372 pub async fn create_access_list(
3386 &self,
3387 request: WithOtherFields<TransactionRequest>,
3388 block_number: Option<BlockId>,
3389 state_override: Option<StateOverride>,
3390 ) -> Result<AccessListResult> {
3391 node_info!("eth_createAccessList");
3392 let block_request = self.block_request(block_number).await?;
3393 if let BlockRequest::Number(number) = block_request
3395 && let Some(fork) = self.get_fork()
3396 && fork.predates_fork(number)
3397 {
3398 if state_override.is_some() {
3399 return Err(BlockchainError::EvmOverrideError(
3400 "not available on past forked blocks".to_string(),
3401 ));
3402 }
3403 return Ok(fork.create_access_list_raw(&request, Some(number.into())).await?);
3404 }
3405 let typed_request = self.parse_transaction_request(request.clone())?;
3406
3407 self.backend
3408 .with_database_at_and_context(Some(block_request), |state, block_env, monad_context| {
3409 let mut cache_db = CacheDB::new(state);
3410 if let Some(state_override) = state_override {
3411 apply_state_overrides(state_override.into_iter().collect(), &mut cache_db)?;
3412 }
3413
3414 let (_, _, _, access_list) =
3415 self.backend.build_access_list_with_state_and_context(
3416 &cache_db,
3417 request.clone(),
3418 FeeDetails::zero(),
3419 block_env.clone(),
3420 monad_context.clone(),
3421 )?;
3422
3423 let (exit, _, gas_used, _) = self.backend.call_with_state_typed_access_list(
3428 &cache_db,
3429 typed_request,
3430 FeeDetails::zero(),
3431 block_env,
3432 access_list.clone(),
3433 monad_context,
3434 )?;
3435
3436 Ok(AccessListResult {
3437 access_list,
3438 gas_used: U256::from(gas_used),
3439 error: execution_error(exit),
3440 })
3441 })
3442 .await
3443 }
3444
3445 pub async fn estimate_gas(
3450 &self,
3451 request: WithOtherFields<TransactionRequest>,
3452 block_number: Option<BlockId>,
3453 overrides: EvmOverrides,
3454 ) -> Result<U256> {
3455 node_info!("eth_estimateGas");
3456 self.do_estimate_gas(
3457 request,
3458 block_number.or_else(|| Some(BlockNumber::Pending.into())),
3459 overrides,
3460 )
3461 .await
3462 .map(U256::from)
3463 }
3464
3465 pub async fn fill_transaction(
3472 &self,
3473 request: WithOtherFields<TransactionRequest>,
3474 ) -> Result<FillTransaction<AnyRpcTransaction>> {
3475 node_info!("eth_fillTransaction");
3476 let mut request = self.parse_transaction_request(request)?;
3477
3478 let from = match request.from() {
3479 Some(from) => from,
3480 None => self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)?,
3481 };
3482
3483 let nonce = self.request_nonce_for_transaction(&request, from).await?.0;
3484
3485 if request.gas_limit().is_none() {
3487 let estimated_gas = self
3488 .do_estimate_gas_typed(request.clone(), Some(BlockNumber::Pending.into()))
3489 .await?;
3490 request.set_gas_limit(estimated_gas as u64);
3491 }
3492
3493 let typed_tx = self.build_tx_request(request, nonce).await?;
3494 let tx = typed_tx.into_impersonated();
3495
3496 let raw = tx.encoded_2718().into();
3497
3498 let mut tx =
3499 transaction_build(None, MaybeImpersonatedTransaction::new(tx), None, None, None);
3500
3501 tx.0.inner.inner = Recovered::new_unchecked(tx.0.inner.inner.into_inner(), from);
3504
3505 Ok(FillTransaction { raw, tx })
3506 }
3507
3508 pub fn anvil_get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<Blob>>> {
3510 node_info!("anvil_getBlobsByTransactionHash");
3511 Ok(self.backend.get_blob_by_tx_hash(hash)?)
3512 }
3513
3514 pub async fn transaction_by_hash(&self, hash: B256) -> Result<Option<AnyRpcTransaction>> {
3521 node_info!("eth_getTransactionByHash");
3522 let mut tx =
3523 self.pool.get_transaction(hash).map(|pending| self.build_pool_transaction(pending));
3524 if tx.is_none() {
3525 tx = self.backend.transaction_by_hash(hash).await?
3526 }
3527
3528 Ok(tx)
3529 }
3530
3531 fn build_pool_transaction(
3532 &self,
3533 pending: PendingTransaction<FoundryTxEnvelope>,
3534 ) -> AnyRpcTransaction {
3535 let from = *pending.sender();
3536 let tx = transaction_build(
3537 Some(*pending.hash()),
3538 pending.transaction,
3539 None,
3540 None,
3541 Some(self.backend.base_fee()),
3542 );
3543
3544 let WithOtherFields { inner: mut tx, other } = tx.0;
3545 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3548
3549 AnyRpcTransaction(WithOtherFields { inner: tx, other })
3550 }
3551
3552 pub async fn pending_transactions(&self) -> Result<Vec<AnyRpcTransaction>> {
3556 node_info!("eth_pendingTransactions");
3557 Ok(self
3558 .pool
3559 .ready_transactions()
3560 .map(|pending| self.build_pool_transaction(pending.pending_transaction.clone()))
3561 .collect())
3562 }
3563
3564 pub async fn transaction_by_sender_and_nonce(
3571 &self,
3572 sender: Address,
3573 nonce: U256,
3574 ) -> Result<Option<AnyRpcTransaction>> {
3575 node_info!("eth_getTransactionBySenderAndNonce");
3576
3577 for pending_tx in self.pool.ready_transactions().chain(self.pool.pending_transactions()) {
3579 if U256::from(pending_tx.pending_transaction.nonce()) == nonce
3580 && *pending_tx.pending_transaction.sender() == sender
3581 {
3582 let tx = transaction_build(
3583 Some(*pending_tx.pending_transaction.hash()),
3584 pending_tx.pending_transaction.transaction.clone(),
3585 None,
3586 None,
3587 Some(self.backend.base_fee()),
3588 );
3589
3590 let WithOtherFields { inner: mut tx, other } = tx.0;
3591 let from = *pending_tx.pending_transaction.sender();
3594 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3595
3596 return Ok(Some(AnyRpcTransaction(WithOtherFields { inner: tx, other })));
3597 }
3598 }
3599
3600 let highest_nonce = self.transaction_count(sender, None).await?.saturating_to::<u64>();
3601 let target_nonce = nonce.saturating_to::<u64>();
3602
3603 if target_nonce >= highest_nonce {
3605 return Ok(None);
3606 }
3607
3608 let latest_block = self.backend.best_number();
3610 if latest_block == 0 {
3611 return Ok(None);
3612 }
3613
3614 let mut low = 1u64;
3616 let mut high = latest_block;
3617
3618 while low <= high {
3619 let mid = low + (high - low) / 2;
3620 let mid_nonce =
3621 self.transaction_count(sender, Some(mid.into())).await?.saturating_to::<u64>();
3622
3623 if mid_nonce > target_nonce {
3624 high = mid - 1;
3625 } else {
3626 low = mid + 1;
3627 }
3628 }
3629
3630 let target_block = low;
3632 if target_block <= latest_block
3633 && let Some(txs) =
3634 self.backend.mined_transactions_by_block_number(target_block.into()).await
3635 {
3636 for tx in txs {
3637 if tx.from() == sender && tx.nonce() == target_nonce {
3638 return Ok(Some(tx));
3639 }
3640 }
3641 }
3642
3643 Ok(None)
3644 }
3645
3646 pub async fn transaction_receipt(&self, hash: B256) -> Result<Option<FoundryTxReceipt>> {
3650 node_info!("eth_getTransactionReceipt");
3651 self.backend.transaction_receipt(hash).await
3652 }
3653
3654 pub async fn block_receipts(&self, number: BlockId) -> Result<Option<Vec<FoundryTxReceipt>>> {
3658 node_info!("eth_getBlockReceipts");
3659 self.backend.block_receipts(number).await
3660 }
3661
3662 pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>> {
3666 node_info!("eth_getLogs");
3667 self.backend.logs(filter).await
3668 }
3669
3670 pub async fn new_filter(&self, filter: Filter) -> Result<String> {
3674 node_info!("eth_newFilter");
3675 let historic = if filter.block_option.get_from_block().is_some() {
3678 self.backend.logs(filter.clone()).await?
3679 } else {
3680 vec![]
3681 };
3682 let filter = EthFilter::Logs(Box::new(LogsFilter {
3683 blocks: self.new_block_notifications(),
3684 storage: self.storage_info(),
3685 filter: FilteredParams::new(Some(filter)),
3686 historic: Some(historic),
3687 }));
3688 Ok(self.filters.add_filter(filter).await)
3689 }
3690
3691 pub async fn new_block_filter(&self) -> Result<String> {
3695 node_info!("eth_newBlockFilter");
3696 let filter = EthFilter::Blocks(self.new_block_notifications());
3697 Ok(self.filters.add_filter(filter).await)
3698 }
3699
3700 pub async fn new_pending_transaction_filter(&self, full: bool) -> Result<String> {
3704 node_info!("eth_newPendingTransactionFilter");
3705 let filter = if full {
3706 EthFilter::FullPendingTransactions(self.full_pending_transactions_filter())
3707 } else {
3708 EthFilter::PendingTransactions(self.new_ready_transactions())
3709 };
3710 Ok(self.filters.add_filter(filter).await)
3711 }
3712
3713 pub async fn get_filter_changes(&self, id: &str) -> ResponseResult {
3717 node_info!("eth_getFilterChanges");
3718 self.filters.get_filter_changes(id).await
3719 }
3720
3721 pub async fn get_filter_logs(&self, id: &str) -> Result<Vec<Log>> {
3725 node_info!("eth_getFilterLogs");
3726 if let Some(filter) = self.filters.get_log_filter(id).await {
3727 self.backend.logs(filter).await
3728 } else {
3729 Err(BlockchainError::FilterNotFound)
3730 }
3731 }
3732
3733 pub async fn uninstall_filter(&self, id: &str) -> Result<bool> {
3735 node_info!("eth_uninstallFilter");
3736 Ok(self.filters.uninstall_filter(id).await.is_some())
3737 }
3738
3739 pub async fn raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
3743 node_info!("debug_getRawTransaction");
3744 self.inner_raw_transaction(hash).await
3745 }
3746
3747 pub async fn raw_receipts(&self, block: BlockId) -> Result<Vec<Bytes>> {
3751 node_info!("debug_getRawReceipts");
3752
3753 if let BlockRequest::Number(number) = self.block_request(Some(block)).await?
3755 && let Some(fork) = self.get_fork()
3756 && fork.predates_fork_inclusive(number)
3757 {
3758 let receipts = fork.block_receipts(number).await?.unwrap_or_default();
3759 return Ok(receipts
3760 .into_iter()
3761 .map(|receipt| {
3762 receipt.0.inner.inner.map_logs(|log| log.inner).encoded_2718().into()
3763 })
3764 .collect());
3765 }
3766
3767 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
3768 let receipts = self
3769 .backend
3770 .mined_receipts(block.header.hash_slow())
3771 .ok_or(BlockchainError::BlockNotFound)?;
3772 Ok(receipts.into_iter().map(|receipt| receipt.encoded_2718().into()).collect())
3773 }
3774
3775 pub async fn raw_transactions(&self, block: BlockId) -> Result<Vec<Bytes>> {
3779 node_info!("debug_getRawTransactions");
3780
3781 if let Some(block) = self.backend.get_block(block) {
3782 return Ok(block
3783 .body
3784 .transactions
3785 .into_iter()
3786 .map(|tx| tx.into_inner().into_canonical().encoded_2718().into())
3787 .collect());
3788 }
3789
3790 let Some(fork) = self.get_fork() else {
3793 return Ok(Vec::new());
3794 };
3795 let block = match block {
3796 BlockId::Number(BlockNumber::Pending) => None,
3797 BlockId::Number(number) => {
3798 let number = self.backend.convert_block_number(Some(number));
3799 if !fork.predates_fork_inclusive(number) {
3800 return Ok(Vec::new());
3801 }
3802 fork.block_by_number_full(number).await?
3803 }
3804 BlockId::Hash(hash) => fork
3805 .block_by_hash_full(hash.block_hash)
3806 .await?
3807 .filter(|block| fork.predates_fork_inclusive(block.header().number())),
3808 };
3809 let Some(block) = block else {
3810 return Ok(Vec::new());
3811 };
3812 let BlockTransactions::Full(txs) = block.transactions() else {
3813 return Err(BlockchainError::Internal(
3814 "fork provider returned a non-full block for a full block request".to_string(),
3815 ));
3816 };
3817 txs.iter().map(encode_rpc_transaction).collect()
3818 }
3819
3820 pub async fn raw_header(&self, block: BlockId) -> Result<Bytes> {
3824 node_info!("debug_getRawHeader");
3825 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
3826 Ok(alloy_rlp::encode(&block.header).into())
3827 }
3828
3829 pub async fn raw_block(&self, block: BlockId) -> Result<Bytes> {
3833 node_info!("debug_getRawBlock");
3834 let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
3835 Ok(alloy_rlp::encode(canonical_block(block)).into())
3836 }
3837
3838 pub async fn raw_transaction_by_block_hash_and_index(
3842 &self,
3843 block_hash: B256,
3844 index: Index,
3845 ) -> Result<Option<Bytes>> {
3846 node_info!("eth_getRawTransactionByBlockHashAndIndex");
3847 match self.backend.transaction_by_block_hash_and_index(block_hash, index).await? {
3848 Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
3849 None => Ok(None),
3850 }
3851 }
3852
3853 pub async fn raw_transaction_by_block_number_and_index(
3857 &self,
3858 block_number: BlockNumber,
3859 index: Index,
3860 ) -> Result<Option<Bytes>> {
3861 node_info!("eth_getRawTransactionByBlockNumberAndIndex");
3862 match self.transaction_by_block_number_and_index(block_number, index).await? {
3863 Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
3864 None => Ok(None),
3865 }
3866 }
3867
3868 pub async fn debug_trace_transaction(
3872 &self,
3873 tx_hash: B256,
3874 opts: GethDebugTracingOptions,
3875 ) -> Result<GethTrace> {
3876 node_info!("debug_traceTransaction");
3877 self.backend.debug_trace_transaction(tx_hash, opts).await
3878 }
3879
3880 pub async fn debug_trace_block(
3884 &self,
3885 rlp_block: Bytes,
3886 opts: GethDebugTracingOptions,
3887 ) -> Result<Vec<TraceResult>> {
3888 node_info!("debug_traceBlock");
3889 self.backend.debug_trace_block(rlp_block, opts).await
3890 }
3891
3892 pub async fn debug_trace_block_by_hash(
3896 &self,
3897 block_hash: B256,
3898 opts: GethDebugTracingOptions,
3899 ) -> Result<Vec<TraceResult>> {
3900 node_info!("debug_traceBlockByHash");
3901 self.backend.debug_trace_block_by_hash(block_hash, opts).await
3902 }
3903
3904 pub async fn debug_trace_block_by_number(
3908 &self,
3909 block_number: BlockNumber,
3910 opts: GethDebugTracingOptions,
3911 ) -> Result<Vec<TraceResult>> {
3912 node_info!("debug_traceBlockByNumber");
3913 self.backend.debug_trace_block_by_number(block_number, opts).await
3914 }
3915
3916 pub async fn debug_trace_call(
3920 &self,
3921 request: WithOtherFields<TransactionRequest>,
3922 block_number: Option<BlockId>,
3923 opts: GethDebugTracingCallOptions,
3924 ) -> Result<GethTrace> {
3925 node_info!("debug_traceCall");
3926 let block_request = self.block_request(block_number).await?;
3927 let fees = FeeDetails::new(
3928 request.gas_price,
3929 request.max_fee_per_gas,
3930 request.max_priority_fee_per_gas,
3931 request.max_fee_per_blob_gas,
3932 )?
3933 .or_zero_fees();
3934
3935 let result: std::result::Result<GethTrace, BlockchainError> =
3936 self.backend.call_with_tracing(request, fees, Some(block_request), opts).await;
3937 result
3938 }
3939
3940 pub async fn trace_call_many(
3944 &self,
3945 calls: Vec<(WithOtherFields<TransactionRequest>, HashSet<TraceType>)>,
3946 block_number: Option<BlockId>,
3947 ) -> Result<Vec<TraceResults>> {
3948 node_info!("trace_callMany");
3949 let block_number = block_number.unwrap_or(BlockId::Number(BlockNumber::Pending));
3950 let block_request = self.block_request(Some(block_number)).await?;
3951
3952 self.backend.trace_call_many(calls, Some(block_request)).await
3953 }
3954}
3955
3956impl EthApi<FoundryNetwork> {
3959 pub async fn anvil_mine(&self, num_blocks: Option<U256>, interval: Option<U256>) -> Result<()> {
3963 node_info!("anvil_mine");
3964 let interval = interval.map(|i| i.saturating_to::<u64>());
3965 let blocks = num_blocks.unwrap_or(U256::from(1));
3966 if blocks.is_zero() {
3967 return Ok(());
3968 }
3969
3970 self.on_blocking_task(|this| async move {
3971 for _ in 0..blocks.saturating_to::<u64>() {
3973 let pending_increase =
3975 interval.map(|interval| this.backend.time().apply_time_increase(interval));
3976 if let Err(error) = this.mine_one().await {
3977 if let Some(pending) = pending_increase {
3978 this.backend.time().revert_time_increase(pending);
3979 }
3980 return Err(error);
3981 }
3982 }
3983 Ok(())
3984 })
3985 .await?;
3986
3987 Ok(())
3988 }
3989
3990 async fn find_erc20_storage_slot(
4007 &self,
4008 token_address: Address,
4009 calldata: Bytes,
4010 expected_value: U256,
4011 ) -> Result<B256> {
4012 let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone());
4013
4014 let access_list_result =
4016 self.create_access_list(WithOtherFields::new(tx.clone()), None, None).await?;
4017 let access_list = access_list_result.access_list;
4018
4019 for item in access_list.0 {
4022 if item.address != token_address {
4023 continue;
4024 };
4025 for slot in &item.storage_keys {
4026 let account_override = AccountOverride::default().with_state_diff(std::iter::once(
4027 (*slot, B256::from(expected_value.to_be_bytes())),
4028 ));
4029
4030 let state_override = StateOverridesBuilder::default()
4031 .append(token_address, account_override)
4032 .build();
4033
4034 let evm_override = EvmOverrides::state(Some(state_override));
4035
4036 let Ok(result) =
4037 self.call(WithOtherFields::new(tx.clone()), None, evm_override).await
4038 else {
4039 continue;
4041 };
4042
4043 let Ok(result_value) = U256::abi_decode(&result) else {
4044 continue;
4046 };
4047
4048 if result_value == expected_value {
4049 return Ok(*slot);
4050 }
4051 }
4052 }
4053
4054 Err(BlockchainError::Message("Unable to find storage slot".to_string()))
4055 }
4056
4057 pub async fn anvil_deal_erc20(
4061 &self,
4062 address: Address,
4063 token_address: Address,
4064 balance: U256,
4065 ) -> Result<()> {
4066 node_info!("anvil_dealERC20");
4067
4068 if self.backend.is_tempo()
4069 && self.backend.try_set_tip20_balance(address, token_address, balance).await?
4070 {
4071 return Ok(());
4072 }
4073
4074 sol! {
4075 #[sol(rpc)]
4076 contract IERC20 {
4077 function balanceOf(address target) external view returns (uint256);
4078 }
4079 }
4080
4081 let calldata = IERC20::balanceOfCall { target: address }.abi_encode().into();
4082
4083 let slot =
4085 self.find_erc20_storage_slot(token_address, calldata, balance).await.map_err(|_| {
4086 BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string())
4087 })?;
4088
4089 self.anvil_set_storage_at(
4091 token_address,
4092 U256::from_be_bytes(slot.0),
4093 B256::from(balance.to_be_bytes()),
4094 )
4095 .await?;
4096
4097 Ok(())
4098 }
4099
4100 pub async fn anvil_deal_tip20(
4104 &self,
4105 address: Address,
4106 token_address: Address,
4107 balance: U256,
4108 ) -> Result<()> {
4109 node_info!("anvil_dealTIP20");
4110 self.ensure_tempo_mode()?;
4111 self.backend.set_tip20_balance(address, token_address, balance).await?;
4112 Ok(())
4113 }
4114
4115 pub async fn anvil_set_erc20_allowance(
4119 &self,
4120 owner: Address,
4121 spender: Address,
4122 token_address: Address,
4123 amount: U256,
4124 ) -> Result<()> {
4125 node_info!("anvil_setERC20Allowance");
4126
4127 sol! {
4128 #[sol(rpc)]
4129 contract IERC20 {
4130 function allowance(address owner, address spender) external view returns (uint256);
4131 }
4132 }
4133
4134 let calldata = IERC20::allowanceCall { owner, spender }.abi_encode().into();
4135
4136 let slot =
4138 self.find_erc20_storage_slot(token_address, calldata, amount).await.map_err(|_| {
4139 BlockchainError::Message("Unable to set ERC20 allowance, no slot found".to_string())
4140 })?;
4141
4142 self.anvil_set_storage_at(
4144 token_address,
4145 U256::from_be_bytes(slot.0),
4146 B256::from(amount.to_be_bytes()),
4147 )
4148 .await?;
4149
4150 Ok(())
4151 }
4152
4153 #[cfg(feature = "monad")]
4156 fn monad_protocol_reorg_transaction(
4157 &self,
4158 transaction: FoundryTxEnvelope,
4159 ) -> Option<PendingTransaction<FoundryTxEnvelope>> {
4160 if !self.backend.is_monad() {
4161 return None;
4162 }
4163
4164 let pending = PendingTransaction::with_sender(
4165 MaybeImpersonatedTransaction::new(transaction),
4166 monad_revm::staking::constants::SYSTEM_ADDRESS,
4167 );
4168 let tx_env: revm::context::TxEnv = crate::eth::backend::executor::build_tx_env_for_pending(
4169 &pending,
4170 self.backend.cheats(),
4171 );
4172 foundry_evm::core::evm::protocol_system_call(&tx_env)
4173 .is_ok_and(|call| call.is_some())
4174 .then_some(pending)
4175 }
4176
4177 pub async fn anvil_reorg(&self, options: ReorgOptions) -> Result<()> {
4191 node_info!("anvil_reorg");
4192 let depth = options.depth;
4193 let tx_block_pairs = options.tx_block_pairs;
4194
4195 let current_height = self.backend.best_number();
4197 let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(
4198 RpcError::invalid_params(format!(
4199 "Reorg depth must not exceed current chain height: current height {current_height}, depth {depth}"
4200 )),
4201 ))?;
4202
4203 let common_block =
4205 self.backend.get_block(common_height).ok_or(BlockchainError::BlockNotFound)?;
4206
4207 let block_pool_txs = if tx_block_pairs.is_empty() {
4210 HashMap::default()
4211 } else {
4212 let mut pairs = tx_block_pairs;
4213
4214 if let Some((_, num)) = pairs.iter().find(|(_, num)| *num >= depth) {
4216 return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
4217 "Block number for reorg tx will exceed the reorged chain height. Block number {num} must not exceed (depth-1) {}",
4218 depth - 1
4219 ))));
4220 }
4221
4222 pairs.sort_by_key(|a| a.1);
4224
4225 let mut nonces: HashMap<Address, u64> = HashMap::default();
4228
4229 let mut txs: HashMap<u64, Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>> =
4230 HashMap::default();
4231 for pair in pairs {
4232 let (tx_data, block_index) = pair;
4233
4234 let pending = match tx_data {
4235 TransactionData::Raw(bytes) => {
4236 let mut data = bytes.as_ref();
4237 let decoded = FoundryTxEnvelope::decode_2718(&mut data)
4238 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
4239 let protocol_pending = {
4240 #[cfg(feature = "monad")]
4241 {
4242 self.monad_protocol_reorg_transaction(decoded.clone())
4243 }
4244 #[cfg(not(feature = "monad"))]
4245 {
4246 None
4247 }
4248 };
4249 if let Some(pending) = protocol_pending {
4250 pending
4251 } else {
4252 PendingTransaction::new(decoded)?
4253 }
4254 }
4255
4256 TransactionData::JSON(request) => {
4257 let from = request.from.map(Ok).unwrap_or_else(|| {
4258 self.accounts()?
4259 .first()
4260 .copied()
4261 .ok_or(BlockchainError::NoSignerAvailable)
4262 })?;
4263
4264 let curr_nonce = nonces.entry(from).or_insert(
4266 self.get_transaction_count(
4267 from,
4268 Some(common_block.header.number().into()),
4269 )
4270 .await?,
4271 );
4272
4273 let typed_tx = self.build_tx_request(request.into(), *curr_nonce).await?;
4275
4276 *curr_nonce += 1;
4278
4279 let protocol_pending = {
4280 #[cfg(feature = "monad")]
4281 {
4282 if from == monad_revm::staking::constants::SYSTEM_ADDRESS {
4283 self.monad_protocol_reorg_transaction(
4284 typed_tx.clone().into_impersonated(),
4285 )
4286 } else {
4287 None
4288 }
4289 }
4290 #[cfg(not(feature = "monad"))]
4291 {
4292 None
4293 }
4294 };
4295 if let Some(pending) = protocol_pending {
4296 pending
4297 } else if self.is_impersonated(from) {
4298 let transaction = typed_tx.into_impersonated();
4299 self.ensure_typed_transaction_supported(&transaction)?;
4300 PendingTransaction::with_impersonated(transaction, from)
4301 } else {
4302 let transaction = self.sign_request(&from, typed_tx)?;
4303 self.ensure_typed_transaction_supported(&transaction)?;
4304 PendingTransaction::new(transaction)?
4305 }
4306 }
4307 };
4308
4309 let pooled = PoolTransaction::new(pending).with_replay();
4310 txs.entry(block_index).or_default().push(Arc::new(pooled));
4311 }
4312
4313 txs
4314 };
4315
4316 self.backend.reorg(depth, block_pool_txs, common_block).await?;
4317 Ok(())
4318 }
4319
4320 pub async fn evm_mine(&self, opts: Option<MineOptions>) -> Result<String> {
4327 node_info!("evm_mine");
4328
4329 self.do_evm_mine(opts).await?;
4330
4331 Ok("0x0".to_string())
4332 }
4333
4334 pub async fn evm_mine_detailed(&self, opts: Option<MineOptions>) -> Result<Vec<AnyRpcBlock>> {
4344 node_info!("evm_mine_detailed");
4345
4346 let mined_blocks = self.do_evm_mine(opts).await?;
4347
4348 let mut blocks = Vec::with_capacity(mined_blocks as usize);
4349
4350 let latest = self.backend.best_number();
4351 for offset in (0..mined_blocks).rev() {
4352 let block_num = latest - offset;
4353 if let Some(mut block) =
4354 self.backend.block_by_number_full(BlockNumber::Number(block_num)).await?
4355 {
4356 let block_txs = match block.transactions_mut() {
4357 BlockTransactions::Full(txs) => txs,
4358 BlockTransactions::Hashes(_) | BlockTransactions::Uncle => unreachable!(),
4359 };
4360 for tx in block_txs.iter_mut() {
4361 if let Some(receipt) = self.backend.mined_transaction_receipt(tx.tx_hash())
4362 && let Some(output) = receipt.out
4363 {
4364 if !receipt.inner.as_ref().status()
4366 && let Some(reason) = RevertDecoder::new().maybe_decode(&output, None)
4367 {
4368 tx.other.insert(
4369 "revertReason".to_string(),
4370 serde_json::to_value(reason).expect("Infallible"),
4371 );
4372 }
4373 tx.other.insert(
4374 "output".to_string(),
4375 serde_json::to_value(output).expect("Infallible"),
4376 );
4377 }
4378 }
4379 block.transactions = BlockTransactions::Full(block_txs.clone());
4380 blocks.push(block);
4381 }
4382 }
4383
4384 Ok(blocks)
4385 }
4386
4387 pub async fn eth_send_unsigned_transaction(
4391 &self,
4392 request: WithOtherFields<TransactionRequest>,
4393 ) -> Result<TxHash> {
4394 node_info!("eth_sendUnsignedTransaction");
4395 let request = self.parse_transaction_request(request)?;
4396 let from = request.from().ok_or(BlockchainError::NoSignerAvailable)?;
4398
4399 let (nonce, on_chain_nonce) = self.request_nonce_for_transaction(&request, from).await?;
4400
4401 let typed_tx = self.build_tx_request(request, nonce).await?;
4402
4403 let transaction = typed_tx.into_impersonated();
4404
4405 self.ensure_typed_transaction_supported(&transaction)?;
4406
4407 let pending_transaction = PendingTransaction::with_impersonated(transaction, from);
4408
4409 self.backend.validate_pool_transaction(&pending_transaction).await?;
4411
4412 let (requires, provides) = nonce_markers(&pending_transaction, nonce, on_chain_nonce, from);
4413
4414 self.add_pending_transaction(pending_transaction, requires, provides)
4415 }
4416
4417 pub async fn txpool_inspect(&self) -> Result<TxpoolInspect> {
4424 node_info!("txpool_inspect");
4425 let mut inspect = TxpoolInspect::default();
4426
4427 fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> TxpoolInspectSummary {
4428 let tx = &tx.pending_transaction.transaction;
4429 let to = tx.to();
4430 let gas_price = tx.max_fee_per_gas();
4431 let value = tx.value();
4432 let gas = tx.gas_limit();
4433 TxpoolInspectSummary { to, value, gas, gas_price }
4434 }
4435
4436 for pending in self.pool.ready_transactions() {
4443 let entry = inspect.pending.entry(*pending.pending_transaction.sender()).or_default();
4444 let key = txpool_transaction_key(&pending.pending_transaction);
4445 entry.insert(key, convert(pending));
4446 }
4447 for queued in self.pool.pending_transactions() {
4448 let entry = inspect.queued.entry(*queued.pending_transaction.sender()).or_default();
4449 let key = txpool_transaction_key(&queued.pending_transaction);
4450 entry.insert(key, convert(queued));
4451 }
4452 Ok(inspect)
4453 }
4454
4455 pub async fn txpool_content(&self) -> Result<TxpoolContent<AnyRpcTransaction>> {
4462 node_info!("txpool_content");
4463 self.build_txpool_content(None)
4464 }
4465
4466 fn build_txpool_content(
4471 &self,
4472 filter: Option<Address>,
4473 ) -> Result<TxpoolContent<AnyRpcTransaction>> {
4474 let mut content = TxpoolContent::<AnyRpcTransaction>::default();
4475 fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> Result<AnyRpcTransaction> {
4476 let from = *tx.pending_transaction.sender();
4477 let tx = transaction_build(
4478 Some(tx.hash()),
4479 tx.pending_transaction.transaction.clone(),
4480 None,
4481 None,
4482 None,
4483 );
4484
4485 let WithOtherFields { inner: mut tx, other } = tx.0;
4486
4487 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
4490
4491 let tx = AnyRpcTransaction(WithOtherFields { inner: tx, other });
4492
4493 Ok(tx)
4494 }
4495
4496 for pending in self.pool.ready_transactions() {
4497 let sender = *pending.pending_transaction.sender();
4498 if filter.is_some_and(|from| from != sender) {
4499 continue;
4500 }
4501 let entry = content.pending.entry(sender).or_default();
4502 let key = txpool_transaction_key(&pending.pending_transaction);
4503 entry.insert(key, convert(pending)?);
4504 }
4505 for queued in self.pool.pending_transactions() {
4506 let sender = *queued.pending_transaction.sender();
4507 if filter.is_some_and(|from| from != sender) {
4508 continue;
4509 }
4510 let entry = content.queued.entry(sender).or_default();
4511 let key = txpool_transaction_key(&queued.pending_transaction);
4512 entry.insert(key, convert(queued)?);
4513 }
4514
4515 Ok(content)
4516 }
4517
4518 pub async fn txpool_content_from(
4526 &self,
4527 from: Address,
4528 ) -> Result<TxpoolContentFrom<AnyRpcTransaction>> {
4529 node_info!("txpool_contentFrom");
4530 let mut content = self.build_txpool_content(Some(from))?;
4531 Ok(content.remove_from(&from))
4532 }
4533}
4534
4535impl EthApi<FoundryNetwork> {
4536 async fn do_evm_mine(&self, opts: Option<MineOptions>) -> Result<u64> {
4538 let mut blocks_to_mine = 1u64;
4539
4540 if let Some(opts) = opts {
4541 let timestamp = match opts {
4542 MineOptions::Timestamp(timestamp) => timestamp,
4543 MineOptions::Options { timestamp, blocks } => {
4544 if let Some(blocks) = blocks {
4545 blocks_to_mine = blocks;
4546 }
4547 timestamp
4548 }
4549 };
4550 if let Some(timestamp) = timestamp {
4551 self.evm_set_next_block_timestamp(timestamp)?;
4553 }
4554 }
4555
4556 self.on_blocking_task(|this| async move {
4559 for _ in 0..blocks_to_mine {
4561 this.mine_one().await?;
4562 }
4563 Ok(())
4564 })
4565 .await?;
4566
4567 Ok(blocks_to_mine)
4568 }
4569
4570 async fn do_estimate_gas(
4571 &self,
4572 request: WithOtherFields<TransactionRequest>,
4573 block_number: Option<BlockId>,
4574 overrides: EvmOverrides,
4575 ) -> Result<u128> {
4576 let block_request = self.block_request(block_number).await?;
4577 if let BlockRequest::Number(number) = block_request
4579 && let Some(fork) = self.get_fork()
4580 && fork.predates_fork(number)
4581 {
4582 if overrides.has_state() || overrides.has_block() {
4583 return Err(BlockchainError::EvmOverrideError(
4584 "not available on past forked blocks".to_string(),
4585 ));
4586 }
4587 return Ok(fork.estimate_gas_raw(&request, Some(number.into())).await?);
4588 }
4589
4590 self.on_blocking_task(|this| async move {
4593 let request = this.parse_transaction_request(request)?;
4594 this.backend
4595 .with_database_at_and_context(
4596 Some(block_request),
4597 |state, mut block, monad_context| {
4598 let mut cache_db = CacheDB::new(state);
4599 if let Some(state_overrides) = overrides.state {
4600 apply_state_overrides(
4601 state_overrides.into_iter().collect(),
4602 &mut cache_db,
4603 )?;
4604 }
4605 if let Some(block_overrides) = overrides.block {
4606 cache_db.apply_block_overrides(*block_overrides, &mut block);
4607 }
4608 this.do_estimate_gas_with_state(request, &cache_db, block, monad_context)
4609 },
4610 )
4611 .await
4612 })
4613 .await
4614 }
4615
4616 async fn do_estimate_gas_typed(
4617 &self,
4618 request: FoundryTransactionRequest,
4619 block_number: Option<BlockId>,
4620 ) -> Result<u128> {
4621 let block_request = self.block_request(block_number).await?;
4622 self.on_blocking_task(|this| async move {
4623 this.backend
4624 .with_database_at_and_context(Some(block_request), |state, block, monad_context| {
4625 this.do_estimate_gas_with_state(request, &state, block, monad_context)
4626 })
4627 .await
4628 })
4629 .await
4630 }
4631
4632 fn transaction_priority(&self, tx: &FoundryTxEnvelope) -> TransactionPriority {
4634 self.transaction_order.read().priority(tx)
4635 }
4636
4637 pub fn full_pending_transactions(&self) -> UnboundedReceiver<AnyRpcTransaction> {
4639 let (tx, rx) = unbounded_channel();
4640 let mut hashes = self.new_ready_transactions();
4641
4642 let this = self.clone();
4643
4644 tokio::spawn(async move {
4645 while let Some(hash) = hashes.next().await {
4646 if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
4647 && tx.send(txn).is_err()
4648 {
4649 break;
4650 }
4651 }
4652 });
4653
4654 rx
4655 }
4656
4657 pub fn full_pending_transactions_filter(&self) -> mpsc::Receiver<AnyRpcTransaction> {
4662 let (tx, rx) = mpsc::channel(2048);
4664 let mut hashes = self.new_ready_transactions();
4665 let this = self.clone();
4666
4667 tokio::spawn(async move {
4668 while let Some(hash) = hashes.next().await {
4669 if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
4670 && tx.send(txn).await.is_err()
4671 {
4672 break;
4673 }
4674 }
4675 });
4676
4677 rx
4678 }
4679
4680 pub fn transaction_receipts_subscription(
4682 &self,
4683 filter: TransactionReceiptsParams,
4684 ) -> UnboundedReceiver<Vec<FoundryTxReceipt>> {
4685 let (tx, rx) = unbounded_channel();
4686 let mut blocks = self.new_block_notifications();
4687 let this = self.clone();
4688
4689 tokio::spawn(async move {
4690 let hash_filter = filter
4692 .transaction_hashes
4693 .filter(|hashes| !hashes.is_empty())
4694 .map(|hashes| hashes.into_iter().collect::<B256Set>());
4695
4696 loop {
4697 let notification = tokio::select! {
4698 biased;
4699 _ = tx.closed() => break,
4701 maybe_block = blocks.next() => match maybe_block {
4702 Some(block) => block,
4703 None => break,
4704 },
4705 };
4706
4707 let Some(block) = notification.as_new_block() else {
4708 continue;
4709 };
4710
4711 let receipts = match this.block_receipts(BlockId::Hash(block.hash.into())).await {
4712 Ok(Some(mut receipts)) => {
4713 if let Some(hashes) = &hash_filter {
4714 receipts.retain(|receipt| hashes.contains(&receipt.transaction_hash()));
4715 }
4716 receipts
4717 }
4718 Ok(None) => continue,
4719 Err(err) => {
4720 trace!(target: "node", %err, "failed to build block receipts for subscription");
4721 continue;
4722 }
4723 };
4724
4725 if receipts.is_empty() {
4726 continue;
4727 }
4728
4729 if tx.send(receipts).is_err() {
4730 break;
4731 }
4732 }
4733 });
4734
4735 rx
4736 }
4737
4738 pub async fn mine_one(&self) -> Result<()> {
4740 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
4741 let outcome = self.backend.mine_block(transactions).await?;
4742
4743 trace!(target: "node", blocknumber = ?outcome.block_number, "mined block");
4744 self.pool.on_mined_block(outcome);
4745 Ok(())
4746 }
4747
4748 async fn pending_block(&self) -> AnyRpcBlock {
4750 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
4751 let info = self.backend.pending_block(transactions).await;
4752 self.backend.convert_block(info.block)
4753 }
4754
4755 async fn pending_block_full(&self) -> Option<AnyRpcBlock> {
4757 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
4758 let BlockInfo { block, transactions, receipts: _ } =
4759 self.backend.pending_block(transactions).await;
4760
4761 let mut partial_block = self.backend.convert_block(block.clone());
4762
4763 let mut block_transactions = Vec::with_capacity(block.body.transactions.len());
4764 let base_fee = self.backend.base_fee();
4765
4766 for info in transactions {
4767 let tx = block.body.transactions.get(info.transaction_index as usize)?.clone();
4768
4769 let tx = transaction_build(
4770 Some(info.transaction_hash),
4771 tx,
4772 Some(&block),
4773 Some(info),
4774 Some(base_fee),
4775 );
4776 block_transactions.push(tx);
4777 }
4778
4779 partial_block.transactions = BlockTransactions::from(block_transactions);
4780
4781 Some(partial_block)
4782 }
4783
4784 async fn build_tx_request(
4787 &self,
4788 mut request: FoundryTransactionRequest,
4789 nonce: u64,
4790 ) -> Result<FoundryTypedTx> {
4791 let from = request.from().or(self.accounts()?.first().copied());
4792 if let Some(from) = from {
4793 request.set_from(from);
4794 }
4795
4796 request.chain_id().is_none().then(|| request.set_chain_id(self.chain_id()));
4798 request.nonce().is_none().then(|| request.set_nonce(nonce));
4799 let is_tempo_batch =
4800 matches!(&request, FoundryTransactionRequest::Tempo(tx) if !tx.calls.is_empty());
4801 if request.kind().is_none() && !is_tempo_batch {
4802 request.set_kind(TxKind::default());
4803 }
4804 if request.gas_limit().is_none() {
4805 let fallback_gas_limit = {
4806 let evm_env = self.backend.evm_env().read();
4807 self.backend.fallback_tx_gas_limit(&evm_env)
4808 };
4809 let estimated_gas = self
4810 .do_estimate_gas_typed(request.clone(), None)
4811 .await
4812 .map(|v| v as u64)
4813 .unwrap_or_else(|_| {
4814 if is_simple_transfer_request(request.as_ref()) {
4815 MIN_TRANSACTION_GAS as u64
4816 } else {
4817 fallback_gas_limit
4818 }
4819 });
4820 request.set_gas_limit(estimated_gas);
4821 }
4822
4823 if let Err((tx_type, _)) = request.missing_keys() {
4825 if matches!(tx_type, FoundryTxType::Legacy | FoundryTxType::Eip2930) {
4826 request.gas_price().is_none().then(|| request.set_gas_price(self.gas_price()));
4827 }
4828 if tx_type == FoundryTxType::Eip2930 {
4829 request
4830 .access_list()
4831 .is_none()
4832 .then(|| request.set_access_list(Default::default()));
4833 }
4834 if matches!(
4835 tx_type,
4836 FoundryTxType::Eip1559
4837 | FoundryTxType::Eip4844
4838 | FoundryTxType::Eip7702
4839 | FoundryTxType::Tempo
4840 ) {
4841 request
4842 .max_fee_per_gas()
4843 .is_none()
4844 .then(|| request.set_max_fee_per_gas(self.gas_price()));
4845 request
4846 .max_priority_fee_per_gas()
4847 .is_none()
4848 .then(|| request.set_max_priority_fee_per_gas(MIN_SUGGESTED_PRIORITY_FEE));
4849 }
4850 if tx_type == FoundryTxType::Eip4844 {
4851 request.as_ref().max_fee_per_blob_gas().is_none().then(|| {
4852 request.as_mut().set_max_fee_per_blob_gas(
4853 self.backend.fees().get_next_block_blob_base_fee_per_gas(),
4854 )
4855 });
4856 }
4857 }
4858
4859 match request
4860 .build_unsigned()
4861 .map_err(|e| BlockchainError::InvalidTransactionRequest(e.to_string()))?
4862 {
4863 FoundryTypedTx::Eip4844(TxEip4844Variant::TxEip4844(_))
4864 if !self.backend.skip_blob_validation(from) =>
4865 {
4866 Err(BlockchainError::FailedToDecodeTransaction)
4868 }
4869 res => Ok(res),
4870 }
4871 }
4872
4873 async fn get_transaction_count(
4875 &self,
4876 address: Address,
4877 block_number: Option<BlockId>,
4878 ) -> Result<u64> {
4879 let block_request = self.block_request(block_number).await?;
4880
4881 if let BlockRequest::Number(number) = block_request
4882 && let Some(fork) = self.get_fork()
4883 && fork.predates_fork(number)
4884 {
4885 return Ok(fork.get_nonce(address, number).await?);
4886 }
4887
4888 self.backend.get_nonce(address, block_request).await
4889 }
4890
4891 async fn request_nonce(
4899 &self,
4900 request: &TransactionRequest,
4901 from: Address,
4902 ) -> Result<(u64, u64)> {
4903 let highest_nonce =
4904 self.get_transaction_count(from, Some(BlockId::Number(BlockNumber::Pending))).await?;
4905 let nonce = request.nonce.unwrap_or(highest_nonce);
4906
4907 Ok((nonce, highest_nonce))
4908 }
4909
4910 fn add_pending_transaction(
4912 &self,
4913 pending_transaction: PendingTransaction<FoundryTxEnvelope>,
4914 requires: Vec<TxMarker>,
4915 provides: Vec<TxMarker>,
4916 ) -> Result<TxHash> {
4917 debug_assert!(requires != provides);
4918 let from = *pending_transaction.sender();
4919 let priority = self.transaction_priority(&pending_transaction.transaction);
4920 let pool_transaction =
4921 PoolTransaction { requires, provides, pending_transaction, priority, is_replay: false };
4922 let tx = self.pool.add_transaction(pool_transaction)?;
4923 trace!(target: "node", "Added transaction: [{:?}] sender={:?}", tx.hash(), from);
4924 Ok(*tx.hash())
4925 }
4926
4927 fn ensure_typed_transaction_supported(&self, tx: &FoundryTxEnvelope) -> Result<()> {
4929 match &tx {
4930 FoundryTxEnvelope::Eip2930(_) => self.backend.ensure_eip2930_active(),
4931 FoundryTxEnvelope::Eip1559(_) => self.backend.ensure_eip1559_active(),
4932 FoundryTxEnvelope::Eip4844(_) => self.backend.ensure_eip4844_active(),
4933 FoundryTxEnvelope::Eip7702(_) => self.backend.ensure_eip7702_active(),
4934 #[cfg(feature = "optimism")]
4935 FoundryTxEnvelope::Deposit(_) => self.backend.ensure_op_deposits_active(),
4936 #[cfg(feature = "optimism")]
4937 FoundryTxEnvelope::PostExec(_) => Err(BlockchainError::InvalidTransactionRequest(
4938 "not implemented for post-exec tx".to_string(),
4939 )),
4940 FoundryTxEnvelope::Legacy(_) => Ok(()),
4941 FoundryTxEnvelope::Tempo(_) => self.backend.ensure_tempo_active(),
4942 }
4943 }
4944
4945 pub async fn anvil_set_fee_token(&self, user: Address, token: Address) -> Result<()> {
4951 node_info!("anvil_setFeeToken");
4952 self.ensure_tempo_mode()?;
4953 self.backend.set_fee_token(user, token).await?;
4954 Ok(())
4955 }
4956
4957 pub async fn anvil_set_validator_fee_token(
4963 &self,
4964 validator: Address,
4965 token: Address,
4966 ) -> Result<()> {
4967 node_info!("anvil_setValidatorFeeToken");
4968 self.ensure_tempo_mode()?;
4969 self.backend.set_validator_fee_token(validator, token).await?;
4970 Ok(())
4971 }
4972
4973 pub async fn anvil_set_fee_amm_liquidity(
4979 &self,
4980 user_token: Address,
4981 validator_token: Address,
4982 amount: U256,
4983 ) -> Result<()> {
4984 node_info!("anvil_setFeeAmmLiquidity");
4985 self.ensure_tempo_mode()?;
4986 self.backend.set_fee_amm_liquidity(user_token, validator_token, amount).await?;
4987 Ok(())
4988 }
4989
4990 fn ensure_tempo_mode(&self) -> Result<()> {
4992 if self.backend.is_tempo() { Ok(()) } else { Err(BlockchainError::RpcUnimplemented) }
4993 }
4994
4995 fn parse_transaction_request(
4996 &self,
4997 request: WithOtherFields<TransactionRequest>,
4998 ) -> Result<FoundryTransactionRequest> {
4999 self.backend.parse_transaction_request(request)
5000 }
5001
5002 async fn request_nonce_for_transaction(
5003 &self,
5004 request: &FoundryTransactionRequest,
5005 from: Address,
5006 ) -> Result<(u64, u64)> {
5007 if let FoundryTransactionRequest::Tempo(request) = request
5008 && let Some(nonce_key) = request.nonce_key.filter(|key| !key.is_zero())
5009 {
5010 if let Some(nonce) = request.nonce() {
5011 return Ok((nonce, 0));
5012 }
5013 let nonce = self.backend.tempo_nonce(from, nonce_key, None).await?;
5014 return Ok((nonce, 0));
5015 }
5016 self.request_nonce(request.as_ref(), from).await
5017 }
5018}
5019
5020fn is_simple_transfer_request(request: &TransactionRequest) -> bool {
5021 request.to.as_ref().and_then(TxKind::to).is_some()
5022 && (request.input.input().is_none()
5023 || request.input.input().is_some_and(|data| data.is_empty()))
5024 && request.authorization_list.is_none()
5025 && request.access_list.is_none()
5026 && request.blob_versioned_hashes.is_none()
5027}
5028
5029fn required_marker(provided_nonce: u64, on_chain_nonce: u64, from: Address) -> Vec<TxMarker> {
5030 if provided_nonce == on_chain_nonce {
5031 return Vec::new();
5032 }
5033 let prev_nonce = provided_nonce.saturating_sub(1);
5034 if on_chain_nonce <= prev_nonce { vec![to_marker(prev_nonce, from)] } else { Vec::new() }
5035}
5036
5037fn tempo_parallel_nonce_markers(
5038 pending_transaction: &PendingTransaction<FoundryTxEnvelope>,
5039) -> Option<(Vec<TxMarker>, Vec<TxMarker>)> {
5040 pending_transaction
5043 .transaction
5044 .as_ref()
5045 .has_nonzero_tempo_nonce_key()
5046 .then(|| (vec![], vec![pending_transaction.hash().to_vec()]))
5047}
5048
5049fn nonce_markers(
5052 pending_transaction: &PendingTransaction<FoundryTxEnvelope>,
5053 nonce: u64,
5054 on_chain_nonce: u64,
5055 from: Address,
5056) -> (Vec<TxMarker>, Vec<TxMarker>) {
5057 tempo_parallel_nonce_markers(pending_transaction).unwrap_or_else(|| {
5058 (required_marker(nonce, on_chain_nonce, from), vec![to_marker(nonce, from)])
5059 })
5060}
5061
5062fn normalize_fee_payer_service_encoding(raw: &[u8]) -> Option<Vec<u8>> {
5072 let (tx_type, mut encoded_fields) = raw.split_first()?;
5073 if *tx_type != TEMPO_TX_TYPE_ID {
5074 return None;
5075 }
5076 let PayloadView::List(fields) = Header::decode_raw(&mut encoded_fields).ok()? else {
5077 return None;
5078 };
5079 if !encoded_fields.is_empty() {
5080 return None;
5081 }
5082 if fields.get(11).is_none_or(|field| *field != [0x00]) {
5084 return None;
5085 }
5086
5087 let marker = FEE_PAYER_SIGNATURE_MARKER;
5090 let mut marker_field = Vec::new();
5091 Header { list: true, payload_length: marker.rlp_rs_len() + marker.v().length() }
5092 .encode(&mut marker_field);
5093 marker.write_rlp_vrs(&mut marker_field, marker.v());
5094
5095 let mut payload = Vec::new();
5096 for (index, field) in fields.into_iter().enumerate() {
5097 if index == 11 {
5098 payload.extend_from_slice(&marker_field);
5099 } else {
5100 payload.extend_from_slice(field);
5101 }
5102 }
5103 let mut normalized = vec![TEMPO_TX_TYPE_ID];
5104 Header { list: true, payload_length: payload.len() }.encode(&mut normalized);
5105 normalized.extend_from_slice(&payload);
5106 Some(normalized)
5107}
5108
5109fn encode_rpc_transaction(transaction: &AnyRpcTransaction) -> Result<Bytes> {
5112 FoundryTxEnvelope::encode_rpc_2718(transaction)
5113 .map_err(|_| BlockchainError::UnsupportedTransactionEncoding(transaction.ty()))
5114}
5115
5116fn txpool_transaction_key(pending_transaction: &PendingTransaction<FoundryTxEnvelope>) -> String {
5117 match pending_transaction.transaction.as_ref() {
5118 FoundryTxEnvelope::Tempo(tx) if !tx.tx().nonce_key.is_zero() => {
5119 let tx = tx.tx();
5120 format!("{}:{}", tx.nonce_key, tx.nonce)
5121 }
5122 _ => pending_transaction.nonce().to_string(),
5123 }
5124}
5125
5126fn convert_transact_out(out: &Option<Output>) -> Bytes {
5127 match out {
5128 None => Default::default(),
5129 Some(Output::Call(out)) => out.to_vec().into(),
5130 Some(Output::Create(out, _)) => out.to_vec().into(),
5131 }
5132}
5133
5134fn ensure_return_ok(exit: InstructionResult, out: &Option<Output>) -> Result<Bytes> {
5136 let out = convert_transact_out(out);
5137 match exit {
5138 return_ok!() => Ok(out),
5139 return_revert!() => Err(InvalidTransactionError::Revert(Some(out)).into()),
5140 reason => Err(BlockchainError::EvmError(reason)),
5141 }
5142}
5143
5144fn execution_error(exit: InstructionResult) -> Option<String> {
5147 match SuccessOrHalt::<HaltReason>::from(exit) {
5148 SuccessOrHalt::Success(_) => None,
5149 SuccessOrHalt::Revert => Some("execution reverted".to_string()),
5150 SuccessOrHalt::Halt(reason) => Some(reason.to_string()),
5151 SuccessOrHalt::FatalExternalError => Some("fatal external error".to_string()),
5152 SuccessOrHalt::Internal(_) => Some("internal EVM error".to_string()),
5153 }
5154}
5155
5156fn determine_base_gas_by_kind(request: &FoundryTransactionRequest) -> u128 {
5158 let inner = request.as_ref();
5159 let kind = match request {
5160 FoundryTransactionRequest::Tempo(request) => {
5161 request.calls.first().map(|call| call.to).or_else(|| inner.kind())
5162 }
5163 _ => inner.kind(),
5164 };
5165 match kind {
5166 Some(TxKind::Call(_)) => {
5167 MIN_TRANSACTION_GAS
5168 + inner.authorization_list.as_ref().map_or(0, |auths_list| {
5169 auths_list.len() as u128 * PER_EMPTY_ACCOUNT_COST as u128
5170 })
5171 }
5172 Some(TxKind::Create) => MIN_CREATE_GAS,
5173 None => MIN_CREATE_GAS,
5175 }
5176}
5177
5178enum GasEstimationCallResult {
5180 Success(u128),
5181 OutOfGas,
5182 Revert(Option<Bytes>),
5183 EvmError(InstructionResult),
5184}
5185
5186impl TryFrom<Result<(InstructionResult, Option<Output>, u128, State)>> for GasEstimationCallResult {
5190 type Error = BlockchainError;
5191
5192 fn try_from(res: Result<(InstructionResult, Option<Output>, u128, State)>) -> Result<Self> {
5193 match res {
5194 Err(BlockchainError::InvalidTransaction(InvalidTransactionError::GasTooHigh(_))) => {
5196 Ok(Self::OutOfGas)
5197 }
5198 Err(BlockchainError::Message(ref msg))
5200 if msg.contains("insufficient gas for intrinsic cost") =>
5201 {
5202 Ok(Self::OutOfGas)
5203 }
5204 Err(err) => Err(err),
5205 Ok((exit, output, gas, _)) => match exit {
5206 return_ok!() => Ok(Self::Success(gas)),
5207
5208 InstructionResult::Revert => {
5210 Ok(Self::Revert(Some(output.map(|o| o.into_data()).unwrap_or_default())))
5211 }
5212 InstructionResult::CallTooDeep
5213 | InstructionResult::OutOfFunds
5214 | InstructionResult::CreateInitCodeStartingEF00
5215 | InstructionResult::InvalidEOFInitCode
5216 | InstructionResult::InvalidExtDelegateCallTarget => Ok(Self::EvmError(exit)),
5217
5218 InstructionResult::OutOfGas
5220 | InstructionResult::MemoryOOG
5221 | InstructionResult::MemoryLimitOOG
5222 | InstructionResult::PrecompileOOG
5223 | InstructionResult::InvalidOperandOOG
5224 | InstructionResult::ReentrancySentryOOG => Ok(Self::OutOfGas),
5225
5226 InstructionResult::OpcodeNotFound
5228 | InstructionResult::CallNotAllowedInsideStatic
5229 | InstructionResult::StateChangeDuringStaticCall
5230 | InstructionResult::InvalidFEOpcode
5231 | InstructionResult::InvalidJump
5232 | InstructionResult::NotActivated
5233 | InstructionResult::StackUnderflow
5234 | InstructionResult::StackOverflow
5235 | InstructionResult::OutOfOffset
5236 | InstructionResult::CreateCollision
5237 | InstructionResult::OverflowPayment
5238 | InstructionResult::PrecompileError
5239 | InstructionResult::NonceOverflow
5240 | InstructionResult::CreateContractSizeLimit
5241 | InstructionResult::CreateContractStartingWithEF
5242 | InstructionResult::CreateInitCodeSizeLimit
5243 | InstructionResult::InvalidImmediateEncoding
5244 | InstructionResult::FatalExternalError => Ok(Self::EvmError(exit)),
5245 },
5246 }
5247 }
5248}
5249
5250fn merge_pre_fork_fee_history(
5252 response: &mut FeeHistory,
5253 rewards: &mut Vec<Vec<u128>>,
5254 pre: FeeHistory,
5255 fork_block: u64,
5256) {
5257 response.oldest_block = pre.oldest_block;
5259 let count = fork_block.checked_sub(pre.oldest_block).map_or(0, |count| count.saturating_add(1))
5260 as usize;
5261
5262 response.base_fee_per_gas.extend(pre.base_fee_per_gas.into_iter().take(count));
5264 response.gas_used_ratio.extend(pre.gas_used_ratio.into_iter().take(count));
5265 if let Some(reward) = pre.reward {
5266 rewards.extend(reward.into_iter().take(count));
5267 }
5268
5269 response.base_fee_per_blob_gas.extend(pre.base_fee_per_blob_gas.into_iter().take(count));
5271 response.base_fee_per_blob_gas.resize(count, 0);
5272 response.blob_gas_used_ratio.extend(pre.blob_gas_used_ratio.into_iter().take(count));
5273 response.blob_gas_used_ratio.resize(count, 0.0);
5274}
5275
5276fn reward_at_percentile(rewards: &[u128], percentile: f64) -> u128 {
5277 let index = (percentile * REWARD_PERCENTILE_RESOLUTION).round() as usize;
5278 rewards.get(index).copied().unwrap_or_default()
5279}
5280
5281#[cfg(test)]
5282mod tests {
5283 use super::*;
5284 use crate::{NodeConfig, spawn};
5285
5286 #[tokio::test(flavor = "multi_thread")]
5287 async fn set_rpc_url_installs_context_equivalent_identity_with_new_instance() {
5288 let genesis_timestamp = 1_700_000_000u64;
5289 let (_origin_api, origin_handle) =
5290 spawn(NodeConfig::test().with_genesis_timestamp(Some(genesis_timestamp))).await;
5291 let (api, _handle) =
5292 spawn(NodeConfig::test().with_eth_rpc_url(Some(origin_handle.http_endpoint()))).await;
5293 let (target_api, target_handle) =
5294 spawn(NodeConfig::test().with_genesis_timestamp(Some(genesis_timestamp))).await;
5295 let target_url = target_handle.http_endpoint();
5296 let fork = api.backend.get_fork().unwrap();
5297 let identity_before = fork.config.read().endpoint_identity;
5298
5299 api.anvil_set_rpc_url(target_url.clone()).await.unwrap();
5300
5301 let fork = api.backend.get_fork().unwrap();
5302 let config = fork.config.read();
5303 assert!(config.endpoint_identity.context_eq(identity_before));
5304 assert_ne!(config.endpoint_identity.instance_id, identity_before.instance_id);
5305 assert_eq!(config.endpoint_identity.instance_id, Some(target_api.instance_id()));
5306 assert_eq!(config.eth_rpc_url(), Some(target_url.as_str()));
5307 }
5308
5309 #[tokio::test(flavor = "multi_thread")]
5310 async fn memory_reset_stages_live_fees_after_active_mining() {
5311 let (api, _handle) = spawn(NodeConfig::test()).await;
5312 api.backend.set_base_fee(123);
5313
5314 let mining = api.backend.lock_mining().await;
5317 let reset_api = api.clone();
5318 let reset = tokio::spawn(async move { reset_api.anvil_reset(None).await });
5319
5320 tokio::time::timeout(Duration::from_secs(5), async {
5321 while api.lifecycle_lock.try_read().is_ok() {
5322 tokio::task::yield_now().await;
5323 }
5324 })
5325 .await
5326 .unwrap();
5327
5328 api.backend.set_base_fee(456);
5329 drop(mining);
5330 tokio::time::timeout(Duration::from_secs(5), reset).await.unwrap().unwrap().unwrap();
5331
5332 assert_eq!(api.backend.evm_env().read().block_env.basefee, 456);
5333 assert_eq!(api.base_fee().unwrap(), Some(U256::from(crate::eth::fees::INITIAL_BASE_FEE)));
5334 }
5335
5336 #[tokio::test(flavor = "multi_thread")]
5338 async fn fee_history_is_complete_when_cache_entries_are_missing() {
5339 let (api, _handle) = spawn(NodeConfig::test()).await;
5340 let count = 10u64;
5341 api.anvil_mine(Some(U256::from(count)), None).await.unwrap();
5342
5343 tokio::time::timeout(Duration::from_secs(5), async {
5347 loop {
5348 if (1..=count).all(|number| api.fee_history_cache.lock().contains_key(&number)) {
5349 break;
5350 }
5351 tokio::task::yield_now().await;
5352 }
5353 })
5354 .await
5355 .unwrap();
5356 api.fee_history_cache.lock().clear();
5357
5358 let fee_history =
5359 api.fee_history(U256::from(count), BlockNumber::Latest, vec![50.0]).await.unwrap();
5360
5361 assert_eq!(fee_history.oldest_block, 1);
5362 assert_eq!(fee_history.gas_used_ratio.len(), count as usize);
5363 assert_eq!(fee_history.blob_gas_used_ratio.len(), count as usize);
5364 assert_eq!(fee_history.base_fee_per_gas.len(), count as usize + 1);
5365 assert_eq!(fee_history.base_fee_per_blob_gas.len(), count as usize + 1);
5366 let rewards = fee_history.reward.unwrap();
5367 assert_eq!(rewards.len(), count as usize);
5368 assert!(rewards.iter().all(|reward| reward.len() == 1));
5369 }
5370
5371 #[tokio::test(flavor = "multi_thread")]
5372 async fn fee_history_rejects_invalid_reward_percentiles() {
5373 let (api, _handle) = spawn(NodeConfig::test()).await;
5374
5375 for percentiles in [vec![-0.5], vec![100.5], vec![50.0, 25.0], vec![50.0, 50.0]] {
5376 let err =
5377 api.fee_history(U256::from(1), BlockNumber::Latest, percentiles).await.unwrap_err();
5378 assert!(matches!(
5379 err,
5380 BlockchainError::FeeHistory(FeeHistoryError::InvalidRewardPercentiles)
5381 ));
5382 }
5383
5384 for percentiles in [vec![], vec![0.0, 100.0]] {
5385 api.fee_history(U256::from(1), BlockNumber::Latest, percentiles).await.unwrap();
5386 }
5387 }
5388
5389 #[test]
5390 fn fractional_reward_percentiles_use_cache_resolution() {
5391 let rewards = (0..=200).collect::<Vec<_>>();
5392
5393 assert_eq!(reward_at_percentile(&rewards, 0.0), 0);
5394 assert_eq!(reward_at_percentile(&rewards, 0.5), 1);
5395 assert_eq!(reward_at_percentile(&rewards, 1.0), 2);
5396 assert_eq!(reward_at_percentile(&rewards, 100.0), 200);
5397 }
5398
5399 #[test]
5400 fn shortened_pre_fork_fee_history_uses_upstream_start() {
5401 let requested_lowest = 4;
5402 let fork_block = 10;
5403 let pre = FeeHistory {
5404 oldest_block: 5,
5405 base_fee_per_gas: vec![1; 7],
5406 gas_used_ratio: vec![0.0; 6],
5407 reward: Some(vec![vec![]; 6]),
5408 base_fee_per_blob_gas: vec![],
5409 blob_gas_used_ratio: vec![],
5410 };
5411
5412 let mut response = FeeHistory { oldest_block: requested_lowest, ..Default::default() };
5413 let mut rewards = Vec::new();
5414
5415 merge_pre_fork_fee_history(&mut response, &mut rewards, pre, fork_block);
5416
5417 assert_eq!(response.oldest_block, 5);
5418 assert_eq!(response.gas_used_ratio.len(), 6);
5419 assert_eq!(response.base_fee_per_gas.len(), 6);
5420 assert_eq!(response.blob_gas_used_ratio.len(), 6);
5421 assert_eq!(response.base_fee_per_blob_gas.len(), 6);
5422 assert_eq!(rewards.len(), 6);
5423 }
5424}