1use super::{
2 backend::mem::{BlockRequest, DatabaseRef, State},
3 sign::build_impersonated,
4};
5use crate::{
6 ClientFork, LoggingManager, Miner, MiningMode, StorageInfo,
7 eth::{
8 backend::{
9 self,
10 db::SerializableState,
11 mem::{MIN_CREATE_GAS, MIN_TRANSACTION_GAS},
12 notifications::NewBlockNotifications,
13 validate::TransactionValidator,
14 },
15 error::{
16 BlockchainError, FeeHistoryError, InvalidTransactionError, Result, ToRpcResponseResult,
17 },
18 fees::{FeeDetails, FeeHistoryCache, MIN_SUGGESTED_PRIORITY_FEE},
19 macros::node_info,
20 miner::FixedBlockTimeMiner,
21 pool::{
22 Pool,
23 transactions::{
24 PoolTransaction, TransactionOrder, TransactionPriority, TxMarker, to_marker,
25 },
26 },
27 sign::{self, Signer},
28 },
29 filter::{EthFilter, Filters, LogsFilter},
30 mem::transaction_build,
31};
32use alloy_consensus::{
33 Blob, BlockHeader, Transaction, TrieAccount, TxEip4844Variant, transaction::Recovered,
34};
35use alloy_dyn_abi::TypedData;
36use alloy_eips::{
37 eip2718::Encodable2718,
38 eip7910::{EthConfig, EthForkConfig},
39};
40use alloy_evm::overrides::{OverrideBlockHashes, apply_state_overrides};
41use alloy_network::{
42 AnyRpcBlock, AnyRpcTransaction, BlockResponse, Network, NetworkTransactionBuilder,
43 ReceiptResponse, TransactionBuilder, TransactionBuilder4844, TransactionResponse,
44 eip2718::Decodable2718,
45};
46use alloy_primitives::{
47 Address, B64, B256, Bytes, TxHash, TxKind, U64, U256,
48 map::{HashMap, HashSet},
49};
50use alloy_rpc_types::{
51 AccessListResult, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,
52 EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, Work,
53 anvil::{
54 ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo,
55 },
56 request::TransactionRequest,
57 simulate::{SimulatePayload, SimulatedBlock},
58 state::{AccountOverride, EvmOverrides, StateOverridesBuilder},
59 trace::{
60 filter::TraceFilter,
61 geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult},
62 parity::{LocalizedTransactionTrace, TraceResultsWithTransactionHash, TraceType},
63 },
64 txpool::{TxpoolContent, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus},
65};
66use alloy_rpc_types_eth::FillTransaction;
67use alloy_serde::WithOtherFields;
68use alloy_sol_types::{SolCall, SolValue, sol};
69use alloy_transport::TransportErrorKind;
70use anvil_core::{
71 eth::{
72 EthRequest,
73 block::BlockInfo,
74 transaction::{MaybeImpersonatedTransaction, PendingTransaction},
75 },
76 types::{ReorgOptions, TransactionData},
77};
78use anvil_rpc::{error::RpcError, response::ResponseResult};
79use foundry_common::{
80 provider::ProviderBuilder,
81 version::{COMMIT_SHA, SEMVER_VERSION},
82};
83use foundry_evm::decode::RevertDecoder;
84use foundry_primitives::{
85 FoundryNetwork, FoundryReceiptEnvelope, FoundryTransactionRequest, FoundryTxEnvelope,
86 FoundryTxReceipt, FoundryTxType, FoundryTypedTx, PaymentLaneClassification, PaymentLaneReason,
87};
88use futures::{
89 StreamExt, TryFutureExt,
90 channel::{mpsc::Receiver, oneshot},
91};
92use parking_lot::RwLock;
93use revm::{
94 context::{BlockEnv, Cfg},
95 context_interface::{
96 block::BlobExcessGasAndPrice,
97 result::{HaltReason, Output},
98 },
99 database::CacheDB,
100 interpreter::{InstructionResult, SuccessOrHalt, return_ok, return_revert},
101 primitives::eip7702::PER_EMPTY_ACCOUNT_COST,
102};
103use std::{sync::Arc, time::Duration};
104use tempo_chainspec::hardfork::TempoHardfork;
105use tokio::{
106 sync::mpsc::{UnboundedReceiver, unbounded_channel},
107 try_join,
108};
109
110pub const CLIENT_VERSION: &str = concat!("anvil/v", env!("CARGO_PKG_VERSION"));
112
113pub struct EthApi<N: Network> {
117 pool: Arc<Pool<N::TxEnvelope>>,
119 pub backend: Arc<backend::mem::Backend<N>>,
122 is_mining: bool,
124 signers: Arc<Vec<Box<dyn Signer<N>>>>,
126 fee_history_cache: FeeHistoryCache,
128 fee_history_limit: u64,
130 miner: Miner<N::TxEnvelope>,
135 logger: LoggingManager,
137 filters: Filters<N>,
139 transaction_order: Arc<RwLock<TransactionOrder>>,
141 net_listening: bool,
143 instance_id: Arc<RwLock<B256>>,
145}
146
147impl<N: Network> Clone for EthApi<N> {
148 fn clone(&self) -> Self {
149 Self {
150 pool: self.pool.clone(),
151 backend: self.backend.clone(),
152 is_mining: self.is_mining,
153 signers: self.signers.clone(),
154 fee_history_cache: self.fee_history_cache.clone(),
155 fee_history_limit: self.fee_history_limit,
156 miner: self.miner.clone(),
157 logger: self.logger.clone(),
158 filters: self.filters.clone(),
159 transaction_order: self.transaction_order.clone(),
160 net_listening: self.net_listening,
161 instance_id: self.instance_id.clone(),
162 }
163 }
164}
165
166impl<N: Network> EthApi<N> {
169 #[expect(clippy::too_many_arguments)]
171 pub fn new(
172 pool: Arc<Pool<N::TxEnvelope>>,
173 backend: Arc<backend::mem::Backend<N>>,
174 signers: Arc<Vec<Box<dyn Signer<N>>>>,
175 fee_history_cache: FeeHistoryCache,
176 fee_history_limit: u64,
177 miner: Miner<N::TxEnvelope>,
178 logger: LoggingManager,
179 filters: Filters<N>,
180 transactions_order: TransactionOrder,
181 ) -> Self {
182 Self {
183 pool,
184 backend,
185 is_mining: true,
186 signers,
187 fee_history_cache,
188 fee_history_limit,
189 miner,
190 logger,
191 filters,
192 net_listening: true,
193 transaction_order: Arc::new(RwLock::new(transactions_order)),
194 instance_id: Arc::new(RwLock::new(B256::random())),
195 }
196 }
197
198 pub fn gas_price(&self) -> u128 {
200 if self.backend.is_eip1559() {
201 if self.backend.is_min_priority_fee_enforced() {
202 (self.backend.base_fee() as u128).saturating_add(self.lowest_suggestion_tip())
203 } else {
204 self.backend.base_fee() as u128
205 }
206 } else {
207 self.backend.fees().raw_gas_price()
208 }
209 }
210
211 fn lowest_suggestion_tip(&self) -> u128 {
215 let block_number = self.backend.best_number();
216 let latest_cached_block = self.fee_history_cache.lock().get(&block_number).cloned();
217
218 match latest_cached_block {
219 Some(block) => block.rewards.iter().copied().min(),
220 None => self.fee_history_cache.lock().values().flat_map(|b| b.rewards.clone()).min(),
221 }
222 .map(|fee| fee.max(MIN_SUGGESTED_PRIORITY_FEE))
223 .unwrap_or(MIN_SUGGESTED_PRIORITY_FEE)
224 }
225
226 pub fn anvil_get_auto_mine(&self) -> Result<bool> {
230 node_info!("anvil_getAutomine");
231 Ok(self.miner.is_auto_mine())
232 }
233
234 pub fn anvil_get_interval_mining(&self) -> Result<Option<u64>> {
238 node_info!("anvil_getIntervalMining");
239 Ok(self.miner.get_interval())
240 }
241
242 pub async fn anvil_set_auto_mine(&self, enable_automine: bool) -> Result<()> {
247 node_info!("evm_setAutomine");
248 if self.miner.is_auto_mine() {
249 if enable_automine {
250 return Ok(());
251 }
252 self.miner.set_mining_mode(MiningMode::None);
253 } else if enable_automine {
254 let listener = self.pool.add_ready_listener();
255 let mode = MiningMode::instant(1_000, listener);
256 self.miner.set_mining_mode(mode);
257 }
258 Ok(())
259 }
260
261 pub fn anvil_set_interval_mining(&self, secs: u64) -> Result<()> {
265 node_info!("evm_setIntervalMining");
266 let mining_mode = if secs == 0 {
267 MiningMode::None
268 } else {
269 let block_time = Duration::from_secs(secs);
270
271 self.backend.update_interval_mine_block_time(block_time);
273
274 MiningMode::FixedBlockTime(FixedBlockTimeMiner::new(block_time))
275 };
276 self.miner.set_mining_mode(mining_mode);
277 Ok(())
278 }
279
280 pub async fn anvil_drop_transaction(&self, tx_hash: B256) -> Result<Option<B256>> {
284 node_info!("anvil_dropTransaction");
285 Ok(self.pool.drop_transaction(tx_hash).map(|tx| tx.hash()))
286 }
287
288 pub async fn anvil_drop_all_transactions(&self) -> Result<()> {
292 node_info!("anvil_dropAllTransactions");
293 self.pool.clear();
294 Ok(())
295 }
296
297 pub async fn anvil_set_chain_id(&self, chain_id: u64) -> Result<()> {
298 node_info!("anvil_setChainId");
299 self.backend.set_chain_id(chain_id);
300 Ok(())
301 }
302
303 pub async fn anvil_set_balance(&self, address: Address, balance: U256) -> Result<()> {
307 node_info!("anvil_setBalance");
308 self.backend.set_balance(address, balance).await?;
309 Ok(())
310 }
311
312 pub async fn anvil_set_code(&self, address: Address, code: Bytes) -> Result<()> {
316 node_info!("anvil_setCode");
317 self.backend.set_code(address, code).await?;
318 Ok(())
319 }
320
321 pub async fn anvil_set_nonce(&self, address: Address, nonce: U256) -> Result<()> {
325 node_info!("anvil_setNonce");
326 self.backend.set_nonce(address, nonce).await?;
327 Ok(())
328 }
329
330 pub async fn anvil_set_storage_at(
334 &self,
335 address: Address,
336 slot: U256,
337 val: B256,
338 ) -> Result<bool> {
339 node_info!("anvil_setStorageAt");
340 self.backend.set_storage_at(address, slot, val).await?;
341 Ok(true)
342 }
343
344 pub async fn anvil_set_logging(&self, enable: bool) -> Result<()> {
348 node_info!("anvil_setLoggingEnabled");
349 self.logger.set_enabled(enable);
350 Ok(())
351 }
352
353 pub async fn anvil_set_min_gas_price(&self, gas: U256) -> Result<()> {
357 node_info!("anvil_setMinGasPrice");
358 if self.backend.is_eip1559() {
359 return Err(RpcError::invalid_params(
360 "anvil_setMinGasPrice is not supported when EIP-1559 is active",
361 )
362 .into());
363 }
364 self.backend.set_gas_price(gas.saturating_to());
365 Ok(())
366 }
367
368 pub async fn anvil_set_next_block_base_fee_per_gas(&self, basefee: U256) -> Result<()> {
372 node_info!("anvil_setNextBlockBaseFeePerGas");
373 if !self.backend.is_eip1559() {
374 return Err(RpcError::invalid_params(
375 "anvil_setNextBlockBaseFeePerGas is only supported when EIP-1559 is active",
376 )
377 .into());
378 }
379 self.backend.set_base_fee(basefee.saturating_to());
380 Ok(())
381 }
382
383 pub async fn anvil_set_coinbase(&self, address: Address) -> Result<()> {
387 node_info!("anvil_setCoinbase");
388 self.backend.set_coinbase(address);
389 Ok(())
390 }
391
392 pub async fn anvil_node_info(&self) -> Result<NodeInfo> {
396 node_info!("anvil_nodeInfo");
397
398 let evm_env = self.backend.evm_env().read();
399 let fork_config = self.backend.get_fork();
400 let tx_order = self.transaction_order.read();
401 let hard_fork = self.backend.hardfork().name();
402
403 Ok(NodeInfo {
404 current_block_number: self.backend.best_number(),
405 current_block_timestamp: evm_env.block_env.timestamp.saturating_to(),
406 current_block_hash: self.backend.best_hash(),
407 hard_fork,
408 transaction_order: match *tx_order {
409 TransactionOrder::Fifo => "fifo".to_string(),
410 TransactionOrder::Fees => "fees".to_string(),
411 },
412 environment: NodeEnvironment {
413 base_fee: self.backend.base_fee() as u128,
414 chain_id: self.backend.chain_id().to::<u64>(),
415 gas_limit: self.backend.gas_limit(),
416 gas_price: self.gas_price(),
417 },
418 fork_config: fork_config
419 .map(|fork| {
420 let config = fork.config.read();
421
422 NodeForkConfig {
423 fork_url: config.eth_rpc_url().map(|s| s.to_string()),
424 fork_block_number: Some(config.block_number),
425 fork_retry_backoff: Some(config.backoff.as_millis()),
426 }
427 })
428 .unwrap_or_default(),
429 network: self.backend.is_tempo().then(|| "tempo".to_string()),
430 })
431 }
432
433 pub async fn anvil_metadata(&self) -> Result<Metadata> {
437 node_info!("anvil_metadata");
438 let fork_config = self.backend.get_fork();
439
440 Ok(Metadata {
441 client_version: CLIENT_VERSION.to_string(),
442 client_semver: Some(SEMVER_VERSION.to_string()),
443 client_commit_sha: Some(COMMIT_SHA.to_string()),
444 chain_id: self.backend.chain_id().to::<u64>(),
445 latest_block_hash: self.backend.best_hash(),
446 latest_block_number: self.backend.best_number(),
447 instance_id: *self.instance_id.read(),
448 forked_network: fork_config.map(|cfg| ForkedNetwork {
449 chain_id: cfg.chain_id(),
450 fork_block_number: cfg.block_number(),
451 fork_block_hash: cfg.block_hash(),
452 }),
453 snapshots: self.backend.list_state_snapshots(),
454 })
455 }
456
457 pub async fn anvil_remove_pool_transactions(&self, address: Address) -> Result<()> {
458 node_info!("anvil_removePoolTransactions");
459 self.pool.remove_transactions_by_address(address);
460 Ok(())
461 }
462
463 pub async fn evm_snapshot(&self) -> Result<U256> {
467 node_info!("evm_snapshot");
468 Ok(self.backend.create_state_snapshot().await)
469 }
470
471 pub async fn evm_increase_time(&self, seconds: U256) -> Result<i64> {
475 node_info!("evm_increaseTime");
476 Ok(self.backend.time().increase_time(seconds.try_into().unwrap_or(u64::MAX)) as i64)
477 }
478
479 pub fn evm_set_next_block_timestamp(&self, seconds: u64) -> Result<()> {
483 node_info!("evm_setNextBlockTimestamp");
484 self.backend.time().set_next_block_timestamp(seconds)
485 }
486
487 pub fn evm_set_time(&self, timestamp: u64) -> Result<u64> {
496 node_info!("evm_setTime");
497 let now = self.backend.time().current_call_timestamp();
498 self.backend.time().reset(timestamp);
499
500 let offset = timestamp.saturating_sub(now);
502 Ok(offset)
503 }
504
505 pub fn evm_set_block_gas_limit(&self, gas_limit: U256) -> Result<bool> {
509 node_info!("evm_setBlockGasLimit");
510 self.backend.set_gas_limit(gas_limit.saturating_to());
511 Ok(true)
512 }
513
514 pub fn evm_set_block_timestamp_interval(&self, seconds: u64) -> Result<()> {
518 node_info!("anvil_setBlockTimestampInterval");
519 self.backend.time().set_block_timestamp_interval(seconds);
520 Ok(())
521 }
522
523 pub fn evm_remove_block_timestamp_interval(&self) -> Result<bool> {
527 node_info!("anvil_removeBlockTimestampInterval");
528 Ok(self.backend.time().remove_block_timestamp_interval())
529 }
530
531 pub async fn anvil_set_rpc_url(&self, url: String) -> Result<()> {
535 node_info!("anvil_setRpcUrl");
536 if let Some(fork) = self.backend.get_fork() {
537 let mut config = fork.config.write();
538 let new_provider = Arc::new(
540 ProviderBuilder::new(&url).max_retry(10).initial_backoff(1000).build().map_err(
541 |_| {
542 TransportErrorKind::custom_str(
543 format!("Failed to parse invalid url {url}").as_str(),
544 )
545 },
546 )?, );
549 config.provider = new_provider;
550 trace!(target: "backend", "Updated fork rpc from \"{}\" to \"{}\"", config.eth_rpc_url().unwrap_or("none"), url);
551 config.fork_urls = vec![url.clone()];
552 }
553 self.backend.node_config.write().await.fork_urls = vec![url];
555 Ok(())
556 }
557
558 pub async fn txpool_status(&self) -> Result<TxpoolStatus> {
564 node_info!("txpool_status");
565 Ok(self.pool.txpool_status())
566 }
567
568 async fn on_blocking_task<C, F, R>(&self, c: C) -> Result<R>
570 where
571 C: FnOnce(Self) -> F,
572 F: Future<Output = Result<R>> + Send + 'static,
573 R: Send + 'static,
574 {
575 let (tx, rx) = oneshot::channel();
576 let this = self.clone();
577 let f = c(this);
578 tokio::task::spawn_blocking(move || {
579 tokio::runtime::Handle::current().block_on(async move {
580 let res = f.await;
581 let _ = tx.send(res);
582 })
583 });
584 rx.await.map_err(|_| BlockchainError::Internal("blocking task panicked".to_string()))?
585 }
586
587 pub fn set_transaction_order(&self, order: TransactionOrder) {
589 *self.transaction_order.write() = order;
590 }
591
592 pub fn chain_id(&self) -> u64 {
594 self.backend.chain_id().to::<u64>()
595 }
596
597 pub fn get_fork(&self) -> Option<ClientFork> {
599 self.backend.get_fork()
600 }
601
602 pub fn instance_id(&self) -> B256 {
604 *self.instance_id.read()
605 }
606
607 pub fn reset_instance_id(&self) {
609 *self.instance_id.write() = B256::random();
610 }
611
612 #[expect(clippy::borrowed_box)]
614 pub fn get_signer(&self, address: Address) -> Option<&Box<dyn Signer<N>>> {
615 self.signers.iter().find(|signer| signer.is_signer_for(address))
616 }
617
618 pub fn new_ready_transactions(&self) -> Receiver<TxHash> {
620 self.pool.add_ready_listener()
621 }
622
623 pub fn is_fork(&self) -> bool {
625 self.backend.is_fork()
626 }
627
628 pub async fn state_root(&self) -> Option<B256> {
630 self.backend.get_db().read().await.maybe_state_root()
631 }
632
633 pub fn is_impersonated(&self, addr: Address) -> bool {
635 self.backend.cheats().is_impersonated(addr)
636 }
637
638 pub fn storage_info(&self) -> StorageInfo<N> {
640 StorageInfo::new(Arc::clone(&self.backend))
641 }
642
643 #[allow(clippy::large_stack_frames)]
645 pub fn anvil_get_blob_by_versioned_hash(
646 &self,
647 hash: B256,
648 ) -> Result<Option<alloy_consensus::Blob>> {
649 node_info!("anvil_getBlobByHash");
650 Ok(self.backend.get_blob_by_versioned_hash(hash)?)
651 }
652
653 pub fn anvil_get_blobs_by_block_id(
655 &self,
656 block_id: impl Into<BlockId>,
657 versioned_hashes: Vec<B256>,
658 ) -> Result<Option<Vec<Blob>>> {
659 node_info!("anvil_getBlobsByBlockId");
660 Ok(self.backend.get_blobs_by_block_id(block_id, versioned_hashes)?)
661 }
662
663 pub fn anvil_get_genesis_time(&self) -> Result<u64> {
667 node_info!("anvil_getGenesisTime");
668 Ok(self.backend.genesis_time())
669 }
670
671 pub async fn anvil_reset(&self, forking: Option<Forking>) -> Result<()> {
677 self.reset_instance_id();
678 node_info!("anvil_reset");
679 if let Some(forking) = forking {
680 self.backend.reset_fork(forking).await?;
682 } else {
683 self.backend.reset_to_in_mem().await?;
685 }
686 self.pool.clear();
688 Ok(())
689 }
690
691 pub async fn evm_revert(&self, id: U256) -> Result<bool> {
696 node_info!("evm_revert");
697 self.backend.revert_state_snapshot(id).await
698 }
699
700 pub async fn anvil_impersonate_account(&self, address: Address) -> Result<()> {
704 node_info!("anvil_impersonateAccount");
705 self.backend.impersonate(address);
706 Ok(())
707 }
708
709 pub async fn anvil_stop_impersonating_account(&self, address: Address) -> Result<()> {
713 node_info!("anvil_stopImpersonatingAccount");
714 self.backend.stop_impersonating(address);
715 Ok(())
716 }
717
718 pub async fn anvil_auto_impersonate_account(&self, enabled: bool) -> Result<()> {
722 node_info!("anvil_autoImpersonateAccount");
723 self.backend.auto_impersonate_account(enabled);
724 Ok(())
725 }
726
727 pub async fn anvil_impersonate_signature(
729 &self,
730 signature: Bytes,
731 address: Address,
732 ) -> Result<()> {
733 node_info!("anvil_impersonateSignature");
734 self.backend.impersonate_signature(signature, address).await
735 }
736
737 pub fn new_block_notifications(&self) -> NewBlockNotifications {
739 self.backend.new_block_notifications()
740 }
741
742 pub fn client_version(&self) -> Result<String> {
746 node_info!("web3_clientVersion");
747 Ok(CLIENT_VERSION.to_string())
748 }
749
750 pub fn sha3(&self, bytes: Bytes) -> Result<String> {
754 node_info!("web3_sha3");
755 let hash = alloy_primitives::keccak256(bytes.as_ref());
756 Ok(alloy_primitives::hex::encode_prefixed(&hash[..]))
757 }
758
759 pub fn protocol_version(&self) -> Result<u64> {
763 node_info!("eth_protocolVersion");
764 Ok(1)
765 }
766
767 pub fn hashrate(&self) -> Result<U256> {
771 node_info!("eth_hashrate");
772 Ok(U256::ZERO)
773 }
774
775 pub fn author(&self) -> Result<Address> {
779 node_info!("eth_coinbase");
780 Ok(self.backend.coinbase())
781 }
782
783 pub fn is_mining(&self) -> Result<bool> {
787 node_info!("eth_mining");
788 Ok(self.is_mining)
789 }
790
791 pub fn eth_chain_id(&self) -> Result<Option<U64>> {
797 node_info!("eth_chainId");
798 Ok(Some(self.backend.chain_id().to::<U64>()))
799 }
800
801 pub fn network_id(&self) -> Result<Option<String>> {
805 node_info!("eth_networkId");
806 let chain_id = self.backend.chain_id().to::<u64>();
807 Ok(Some(format!("{chain_id}")))
808 }
809
810 pub fn net_listening(&self) -> Result<bool> {
814 node_info!("net_listening");
815 Ok(self.net_listening)
816 }
817
818 fn eth_gas_price(&self) -> Result<U256> {
820 node_info!("eth_gasPrice");
821 Ok(U256::from(self.gas_price()))
822 }
823
824 pub fn excess_blob_gas_and_price(&self) -> Result<Option<BlobExcessGasAndPrice>> {
826 Ok(self.backend.excess_blob_gas_and_price())
827 }
828
829 pub fn gas_max_priority_fee_per_gas(&self) -> Result<U256> {
834 self.max_priority_fee_per_gas()
835 }
836
837 pub fn blob_base_fee(&self) -> Result<U256> {
841 Ok(U256::from(self.backend.fees().base_fee_per_blob_gas()))
842 }
843
844 pub fn gas_limit(&self) -> U256 {
846 U256::from(self.backend.gas_limit())
847 }
848
849 pub fn accounts(&self) -> Result<Vec<Address>> {
853 node_info!("eth_accounts");
854 let mut unique = HashSet::new();
855 let mut accounts: Vec<Address> = Vec::new();
856 for signer in self.signers.iter() {
857 accounts.extend(signer.accounts().into_iter().filter(|acc| unique.insert(*acc)));
858 }
859 accounts.extend(
860 self.backend
861 .cheats()
862 .impersonated_accounts()
863 .into_iter()
864 .filter(|acc| unique.insert(*acc)),
865 );
866 Ok(accounts.into_iter().collect())
867 }
868
869 pub fn block_number(&self) -> Result<U256> {
873 node_info!("eth_blockNumber");
874 Ok(U256::from(self.backend.best_number()))
875 }
876
877 pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
881 node_info!("eth_getBlockByHash");
882 self.backend.block_by_hash(hash).await
883 }
884
885 pub async fn block_by_hash_full(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
889 node_info!("eth_getBlockByHash");
890 self.backend.block_by_hash_full(hash).await
891 }
892
893 pub async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
897 node_info!("eth_getBlockTransactionCountByHash");
898 let block = self.backend.block_by_hash(hash).await?;
899 let txs = block.map(|b| match b.transactions() {
900 BlockTransactions::Full(txs) => U256::from(txs.len()),
901 BlockTransactions::Hashes(txs) => U256::from(txs.len()),
902 BlockTransactions::Uncle => U256::from(0),
903 });
904 Ok(txs)
905 }
906
907 pub async fn block_uncles_count_by_hash(&self, hash: B256) -> Result<U256> {
911 node_info!("eth_getUncleCountByBlockHash");
912 let block =
913 self.backend.block_by_hash(hash).await?.ok_or(BlockchainError::BlockNotFound)?;
914 Ok(U256::from(block.uncles.len()))
915 }
916
917 pub async fn block_uncles_count_by_number(&self, block_number: BlockNumber) -> Result<U256> {
921 node_info!("eth_getUncleCountByBlockNumber");
922 let block = self
923 .backend
924 .block_by_number(block_number)
925 .await?
926 .ok_or(BlockchainError::BlockNotFound)?;
927 Ok(U256::from(block.uncles.len()))
928 }
929
930 pub async fn sign_typed_data(
934 &self,
935 _address: Address,
936 _data: serde_json::Value,
937 ) -> Result<String> {
938 node_info!("eth_signTypedData");
939 Err(BlockchainError::RpcUnimplemented)
940 }
941
942 pub async fn sign_typed_data_v3(
946 &self,
947 _address: Address,
948 _data: serde_json::Value,
949 ) -> Result<String> {
950 node_info!("eth_signTypedData_v3");
951 Err(BlockchainError::RpcUnimplemented)
952 }
953
954 pub async fn sign_typed_data_v4(&self, address: Address, data: &TypedData) -> Result<String> {
958 node_info!("eth_signTypedData_v4");
959 let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
960 let signature = signer.sign_typed_data(address, data).await?;
961 let signature = alloy_primitives::hex::encode(signature.as_bytes());
962 Ok(format!("0x{signature}"))
963 }
964
965 pub async fn sign(&self, address: Address, content: impl AsRef<[u8]>) -> Result<String> {
969 node_info!("eth_sign");
970 let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
971 let signature =
972 alloy_primitives::hex::encode(signer.sign(address, content.as_ref()).await?.as_bytes());
973 Ok(format!("0x{signature}"))
974 }
975
976 pub async fn transaction_by_block_hash_and_index(
980 &self,
981 hash: B256,
982 index: Index,
983 ) -> Result<Option<AnyRpcTransaction>> {
984 node_info!("eth_getTransactionByBlockHashAndIndex");
985 self.backend.transaction_by_block_hash_and_index(hash, index).await
986 }
987
988 pub async fn transaction_by_block_number_and_index(
992 &self,
993 block: BlockNumber,
994 idx: Index,
995 ) -> Result<Option<AnyRpcTransaction>> {
996 node_info!("eth_getTransactionByBlockNumberAndIndex");
997 self.backend.transaction_by_block_number_and_index(block, idx).await
998 }
999
1000 pub async fn uncle_by_block_hash_and_index(
1004 &self,
1005 block_hash: B256,
1006 idx: Index,
1007 ) -> Result<Option<AnyRpcBlock>> {
1008 node_info!("eth_getUncleByBlockHashAndIndex");
1009 let number =
1010 self.backend.ensure_block_number(Some(BlockId::Hash(block_hash.into()))).await?;
1011 if let Some(fork) = self.get_fork()
1012 && fork.predates_fork_inclusive(number)
1013 {
1014 return Ok(fork.uncle_by_block_hash_and_index(block_hash, idx.into()).await?);
1015 }
1016 Ok(None)
1018 }
1019
1020 pub async fn uncle_by_block_number_and_index(
1024 &self,
1025 block_number: BlockNumber,
1026 idx: Index,
1027 ) -> Result<Option<AnyRpcBlock>> {
1028 node_info!("eth_getUncleByBlockNumberAndIndex");
1029 let number = self.backend.ensure_block_number(Some(BlockId::Number(block_number))).await?;
1030 if let Some(fork) = self.get_fork()
1031 && fork.predates_fork_inclusive(number)
1032 {
1033 return Ok(fork.uncle_by_block_number_and_index(number, idx.into()).await?);
1034 }
1035 Ok(None)
1037 }
1038
1039 pub fn work(&self) -> Result<Work> {
1043 node_info!("eth_getWork");
1044 Err(BlockchainError::RpcUnimplemented)
1045 }
1046
1047 pub fn syncing(&self) -> Result<bool> {
1051 node_info!("eth_syncing");
1052 Ok(false)
1053 }
1054
1055 pub fn config(&self) -> Result<EthConfig> {
1066 node_info!("eth_config");
1067 Ok(EthConfig {
1068 current: EthForkConfig {
1069 activation_time: 0,
1070 blob_schedule: self.backend.blob_params(),
1071 chain_id: self.backend.chain_id().to::<u64>(),
1072 fork_id: Bytes::from_static(&[0; 4]),
1073 precompiles: self.backend.precompiles(),
1074 system_contracts: self.backend.system_contracts(),
1075 },
1076 next: None,
1077 last: None,
1078 })
1079 }
1080
1081 pub fn submit_work(&self, _: B64, _: B256, _: B256) -> Result<bool> {
1085 node_info!("eth_submitWork");
1086 Err(BlockchainError::RpcUnimplemented)
1087 }
1088
1089 pub fn submit_hashrate(&self, _: U256, _: B256) -> Result<bool> {
1093 node_info!("eth_submitHashrate");
1094 Err(BlockchainError::RpcUnimplemented)
1095 }
1096
1097 pub async fn fee_history(
1101 &self,
1102 block_count: U256,
1103 newest_block: BlockNumber,
1104 reward_percentiles: Vec<f64>,
1105 ) -> Result<FeeHistory> {
1106 node_info!("eth_feeHistory");
1107 let number = self.backend.convert_block_number(Some(newest_block));
1110
1111 if let Some(fork) = self.get_fork() {
1113 if fork.predates_fork_inclusive(number) {
1116 return fork
1117 .fee_history(block_count.to(), BlockNumber::Number(number), &reward_percentiles)
1118 .await
1119 .map_err(BlockchainError::AlloyForkProvider);
1120 }
1121 }
1122
1123 const MAX_BLOCK_COUNT: u64 = 1024u64;
1124 let block_count = block_count.saturating_to::<u64>().min(MAX_BLOCK_COUNT);
1125
1126 let highest = number;
1128 let lowest = highest.saturating_sub(block_count.saturating_sub(1));
1129
1130 if lowest < self.backend.best_number().saturating_sub(self.fee_history_limit) {
1132 return Err(FeeHistoryError::InvalidBlockRange.into());
1133 }
1134
1135 let mut response = FeeHistory {
1136 oldest_block: lowest,
1137 base_fee_per_gas: Vec::new(),
1138 gas_used_ratio: Vec::new(),
1139 reward: Some(Default::default()),
1140 base_fee_per_blob_gas: Default::default(),
1141 blob_gas_used_ratio: Default::default(),
1142 };
1143 let mut rewards = Vec::new();
1144
1145 {
1146 let fee_history = self.fee_history_cache.lock();
1147
1148 for n in lowest..=highest {
1150 if let Some(block) = fee_history.get(&n) {
1152 response.base_fee_per_gas.push(block.base_fee);
1153 response.base_fee_per_blob_gas.push(block.base_fee_per_blob_gas.unwrap_or(0));
1154 response.blob_gas_used_ratio.push(block.blob_gas_used_ratio);
1155 response.gas_used_ratio.push(block.gas_used_ratio);
1156
1157 if !reward_percentiles.is_empty() {
1159 let mut block_rewards = Vec::new();
1160 let resolution_per_percentile: f64 = 2.0;
1161 for p in &reward_percentiles {
1162 let p = p.clamp(0.0, 100.0);
1163 let index = ((p.round() / 2f64) * 2f64) * resolution_per_percentile;
1164 let reward = block.rewards.get(index as usize).map_or(0, |r| *r);
1165 block_rewards.push(reward);
1166 }
1167 rewards.push(block_rewards);
1168 }
1169 }
1170 }
1171 }
1172
1173 response.reward = Some(rewards);
1174
1175 response.base_fee_per_gas.push(self.backend.fees().base_fee() as u128);
1180
1181 response.base_fee_per_blob_gas.push(self.backend.fees().base_fee_per_blob_gas());
1185
1186 Ok(response)
1187 }
1188
1189 pub fn max_priority_fee_per_gas(&self) -> Result<U256> {
1196 node_info!("eth_maxPriorityFeePerGas");
1197 Ok(U256::from(self.lowest_suggestion_tip()))
1198 }
1199
1200 pub async fn debug_code_by_hash(
1204 &self,
1205 hash: B256,
1206 block_id: Option<BlockId>,
1207 ) -> Result<Option<Bytes>> {
1208 node_info!("debug_codeByHash");
1209 self.backend.debug_code_by_hash(hash, block_id).await
1210 }
1211
1212 pub async fn debug_db_get(&self, key: String) -> Result<Option<Bytes>> {
1217 node_info!("debug_dbGet");
1218 self.backend.debug_db_get(key).await
1219 }
1220
1221 pub async fn trace_transaction(&self, tx_hash: B256) -> Result<Vec<LocalizedTransactionTrace>> {
1225 node_info!("trace_transaction");
1226 self.backend.trace_transaction(tx_hash).await
1227 }
1228
1229 pub async fn trace_block(&self, block: BlockNumber) -> Result<Vec<LocalizedTransactionTrace>> {
1233 node_info!("trace_block");
1234 self.backend.trace_block(block).await
1235 }
1236
1237 pub async fn trace_filter(
1241 &self,
1242 filter: TraceFilter,
1243 ) -> Result<Vec<LocalizedTransactionTrace>> {
1244 node_info!("trace_filter");
1245 self.backend.trace_filter(filter).await
1246 }
1247
1248 pub async fn trace_replay_block_transactions(
1252 &self,
1253 block: BlockNumber,
1254 trace_types: HashSet<TraceType>,
1255 ) -> Result<Vec<TraceResultsWithTransactionHash>> {
1256 node_info!("trace_replayBlockTransactions");
1257 self.backend.trace_replay_block_transactions(block, trace_types).await
1258 }
1259}
1260
1261impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> EthApi<N> {
1262 pub async fn serialized_state(
1264 &self,
1265 preserve_historical_states: bool,
1266 ) -> Result<SerializableState> {
1267 self.backend.serialized_state(preserve_historical_states).await
1268 }
1269}
1270
1271impl EthApi<FoundryNetwork> {
1274 pub async fn anvil_dump_state(
1279 &self,
1280 preserve_historical_states: Option<bool>,
1281 ) -> Result<Bytes> {
1282 node_info!("anvil_dumpState");
1283 self.backend.dump_state(preserve_historical_states.unwrap_or(false)).await
1284 }
1285
1286 pub async fn anvil_load_state(&self, buf: Bytes) -> Result<bool> {
1291 node_info!("anvil_loadState");
1292 self.backend.load_state_bytes(buf).await
1293 }
1294
1295 async fn block_request(
1296 &self,
1297 block_number: Option<BlockId>,
1298 ) -> Result<BlockRequest<FoundryTxEnvelope>> {
1299 let block_request = match block_number {
1300 Some(BlockId::Number(BlockNumber::Pending)) => {
1301 let pending_txs = self.pool.ready_transactions().collect();
1302 BlockRequest::Pending(pending_txs)
1303 }
1304 _ => {
1305 let number = self.backend.ensure_block_number(block_number).await?;
1306 BlockRequest::Number(number)
1307 }
1308 };
1309 Ok(block_request)
1310 }
1311
1312 pub async fn anvil_add_balance(&self, address: Address, balance: U256) -> Result<()> {
1316 node_info!("anvil_addBalance");
1317 let current_balance = self.backend.get_balance(address, None).await?;
1318 self.backend.set_balance(address, current_balance.saturating_add(balance)).await?;
1319 Ok(())
1320 }
1321
1322 pub async fn anvil_rollback(&self, depth: Option<u64>) -> Result<()> {
1333 node_info!("anvil_rollback");
1334 let depth = depth.unwrap_or(1);
1335
1336 let current_height = self.backend.best_number();
1338 let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(
1339 RpcError::invalid_params(format!(
1340 "Rollback depth must not exceed current chain height: current height {current_height}, depth {depth}"
1341 )),
1342 ))?;
1343
1344 let common_block =
1346 self.backend.get_block(common_height).ok_or(BlockchainError::BlockNotFound)?;
1347
1348 self.backend.rollback(common_block).await?;
1349 Ok(())
1350 }
1351
1352 fn do_estimate_gas_with_state(
1356 &self,
1357 mut request: WithOtherFields<TransactionRequest>,
1358 state: &dyn DatabaseRef,
1359 block_env: BlockEnv,
1360 ) -> Result<u128> {
1361 let fees = FeeDetails::new(
1362 request.gas_price,
1363 request.max_fee_per_gas,
1364 request.max_priority_fee_per_gas,
1365 request.max_fee_per_blob_gas,
1366 )?
1367 .or_zero_fees();
1368
1369 let mut highest_gas_limit = request.gas.map_or(block_env.gas_limit.into(), |g| g as u128);
1372
1373 let is_tempo_aa_tx =
1376 self.backend.is_tempo() && request.other.get("feeToken").is_some_and(|v| !v.is_null());
1377
1378 let gas_price = fees.gas_price.unwrap_or_default();
1379 if !is_tempo_aa_tx && let Some(from) = request.from {
1384 let mut available_funds = self.backend.get_balance_with_state(state, from)?;
1385 if let Some(value) = request.value {
1386 if value > available_funds {
1387 return Err(InvalidTransactionError::InsufficientFunds.into());
1388 }
1389 available_funds -= value;
1391 }
1392 if gas_price > 0 {
1393 let allowance =
1395 available_funds.checked_div(U256::from(gas_price)).unwrap_or_default();
1396 highest_gas_limit = std::cmp::min(highest_gas_limit, allowance.saturating_to());
1397 }
1398 }
1399
1400 if !self.backend.is_tempo() {
1405 let to = request.to.as_ref().and_then(TxKind::to);
1406
1407 let maybe_transfer = (request.input.input().is_none()
1409 || request.input.input().is_some_and(|data| data.is_empty()))
1410 && request.authorization_list.is_none()
1411 && request.access_list.is_none()
1412 && request.blob_versioned_hashes.is_none();
1413
1414 if maybe_transfer
1415 && highest_gas_limit >= MIN_TRANSACTION_GAS
1416 && let Some(to) = to
1417 && let Ok(target_code) = self.backend.get_code_with_state(&state, *to)
1418 && target_code.as_ref().is_empty()
1419 {
1420 return Ok(MIN_TRANSACTION_GAS);
1421 }
1422 }
1423
1424 let mut call_to_estimate = request.clone();
1425 call_to_estimate.gas = Some(highest_gas_limit as u64);
1426
1427 let ethres =
1429 self.backend.call_with_state(&state, call_to_estimate, fees.clone(), block_env.clone());
1430
1431 let gas_used = match ethres.try_into()? {
1432 GasEstimationCallResult::Success(gas) => Ok(gas),
1433 GasEstimationCallResult::OutOfGas => {
1434 Err(InvalidTransactionError::BasicOutOfGas(highest_gas_limit).into())
1435 }
1436 GasEstimationCallResult::Revert(output) => {
1437 Err(InvalidTransactionError::Revert(output).into())
1438 }
1439 GasEstimationCallResult::EvmError(err) => {
1440 warn!(target: "node", "estimation failed due to {:?}", err);
1441 Err(BlockchainError::EvmError(err))
1442 }
1443 }?;
1444
1445 let mut lowest_gas_limit = determine_base_gas_by_kind(&request);
1452
1453 let mut mid_gas_limit =
1455 std::cmp::min(gas_used * 3, (highest_gas_limit + lowest_gas_limit) / 2);
1456
1457 while (highest_gas_limit - lowest_gas_limit) > 1 {
1459 request.gas = Some(mid_gas_limit as u64);
1460 let ethres = self.backend.call_with_state(
1461 &state,
1462 request.clone(),
1463 fees.clone(),
1464 block_env.clone(),
1465 );
1466
1467 match ethres.try_into()? {
1468 GasEstimationCallResult::Success(_) => {
1469 highest_gas_limit = mid_gas_limit;
1473 }
1474 GasEstimationCallResult::OutOfGas
1475 | GasEstimationCallResult::Revert(_)
1476 | GasEstimationCallResult::EvmError(_) => {
1477 lowest_gas_limit = mid_gas_limit;
1484 }
1485 };
1486 mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
1488 }
1489
1490 trace!(target : "node", "Estimated Gas for call {:?}", highest_gas_limit);
1491
1492 Ok(highest_gas_limit)
1493 }
1494
1495 #[allow(clippy::large_stack_frames)]
1497 pub async fn execute(&self, request: EthRequest) -> ResponseResult {
1498 trace!(target: "rpc::api", "executing eth request");
1499 let response = match request.clone() {
1500 EthRequest::EthProtocolVersion(()) => self.protocol_version().to_rpc_result(),
1501 EthRequest::Web3ClientVersion(()) => self.client_version().to_rpc_result(),
1502 EthRequest::Web3Sha3(content) => self.sha3(content).to_rpc_result(),
1503 EthRequest::EthGetAccount(addr, block) => {
1504 self.get_account(addr, block).await.to_rpc_result()
1505 }
1506 EthRequest::EthGetAccountInfo(addr, block) => {
1507 self.get_account_info(addr, block).await.to_rpc_result()
1508 }
1509 EthRequest::EthGetBalance(addr, block) => {
1510 self.balance(addr, block).await.to_rpc_result()
1511 }
1512 EthRequest::EthGetTransactionByHash(hash) => {
1513 self.transaction_by_hash(hash).await.to_rpc_result()
1514 }
1515 EthRequest::EthSendTransaction(request) => {
1516 self.send_transaction(*request).await.to_rpc_result()
1517 }
1518 EthRequest::EthSendTransactionSync(request) => {
1519 self.send_transaction_sync(*request).await.to_rpc_result()
1520 }
1521 EthRequest::EthChainId(_) => self.eth_chain_id().to_rpc_result(),
1522 EthRequest::EthNetworkId(_) => self.network_id().to_rpc_result(),
1523 EthRequest::NetListening(_) => self.net_listening().to_rpc_result(),
1524 EthRequest::EthHashrate(()) => self.hashrate().to_rpc_result(),
1525 EthRequest::EthGasPrice(_) => self.eth_gas_price().to_rpc_result(),
1526 EthRequest::EthMaxPriorityFeePerGas(_) => {
1527 self.gas_max_priority_fee_per_gas().to_rpc_result()
1528 }
1529 EthRequest::EthBlobBaseFee(_) => self.blob_base_fee().to_rpc_result(),
1530 EthRequest::EthAccounts(_) => self.accounts().to_rpc_result(),
1531 EthRequest::EthBlockNumber(_) => self.block_number().to_rpc_result(),
1532 EthRequest::EthCoinbase(()) => self.author().to_rpc_result(),
1533 EthRequest::EthGetStorageAt(addr, slot, block) => {
1534 self.storage_at(addr, slot, block).await.to_rpc_result()
1535 }
1536 EthRequest::EthGetStorageValues(requests, block) => {
1537 self.storage_values(requests, block).await.to_rpc_result()
1538 }
1539 EthRequest::EthGetBlockByHash(hash, full) => {
1540 if full {
1541 self.block_by_hash_full(hash).await.to_rpc_result()
1542 } else {
1543 self.block_by_hash(hash).await.to_rpc_result()
1544 }
1545 }
1546 EthRequest::EthGetBlockByNumber(num, full) => {
1547 if full {
1548 self.block_by_number_full(num).await.to_rpc_result()
1549 } else {
1550 self.block_by_number(num).await.to_rpc_result()
1551 }
1552 }
1553 EthRequest::EthGetTransactionCount(addr, block) => {
1554 self.transaction_count(addr, block).await.to_rpc_result()
1555 }
1556 EthRequest::EthGetTransactionCountByHash(hash) => {
1557 self.block_transaction_count_by_hash(hash).await.to_rpc_result()
1558 }
1559 EthRequest::EthGetTransactionCountByNumber(num) => {
1560 self.block_transaction_count_by_number(num).await.to_rpc_result()
1561 }
1562 EthRequest::EthGetUnclesCountByHash(hash) => {
1563 self.block_uncles_count_by_hash(hash).await.to_rpc_result()
1564 }
1565 EthRequest::EthGetUnclesCountByNumber(num) => {
1566 self.block_uncles_count_by_number(num).await.to_rpc_result()
1567 }
1568 EthRequest::EthGetCodeAt(addr, block) => {
1569 self.get_code(addr, block).await.to_rpc_result()
1570 }
1571 EthRequest::EthGetProof(addr, keys, block) => {
1572 self.get_proof(addr, keys, block).await.to_rpc_result()
1573 }
1574 EthRequest::EthSign(addr, content) => self.sign(addr, content).await.to_rpc_result(),
1575 EthRequest::PersonalSign(content, addr) => {
1576 self.sign(addr, content).await.to_rpc_result()
1577 }
1578 EthRequest::EthSignTransaction(request) => {
1579 self.sign_transaction(*request).await.to_rpc_result()
1580 }
1581 EthRequest::EthSignTypedData(addr, data) => {
1582 self.sign_typed_data(addr, data).await.to_rpc_result()
1583 }
1584 EthRequest::EthSignTypedDataV3(addr, data) => {
1585 self.sign_typed_data_v3(addr, data).await.to_rpc_result()
1586 }
1587 EthRequest::EthSignTypedDataV4(addr, data) => {
1588 self.sign_typed_data_v4(addr, &data).await.to_rpc_result()
1589 }
1590 EthRequest::EthSendRawTransaction(tx) => {
1591 self.send_raw_transaction(tx).await.to_rpc_result()
1592 }
1593 EthRequest::EthSendRawTransactionSync(tx) => {
1594 self.send_raw_transaction_sync(tx).await.to_rpc_result()
1595 }
1596 EthRequest::AnvilClassifyTransaction(tx) => {
1597 self.anvil_classify_transaction(tx).to_rpc_result()
1598 }
1599 EthRequest::EthCall(call, block, state_override, block_overrides) => self
1600 .call(call, block, EvmOverrides::new(state_override, block_overrides))
1601 .await
1602 .to_rpc_result(),
1603 EthRequest::EthSimulateV1(simulation, block) => {
1604 self.simulate_v1(simulation, block).await.to_rpc_result()
1605 }
1606 EthRequest::EthCreateAccessList(call, block) => {
1607 self.create_access_list(call, block).await.to_rpc_result()
1608 }
1609 EthRequest::EthEstimateGas(call, block, state_override, block_overrides) => self
1610 .estimate_gas(call, block, EvmOverrides::new(state_override, block_overrides))
1611 .await
1612 .to_rpc_result(),
1613 EthRequest::EthFillTransaction(request) => {
1614 self.fill_transaction(request).await.to_rpc_result()
1615 }
1616 EthRequest::EthGetRawTransactionByHash(hash) => {
1617 self.raw_transaction(hash).await.to_rpc_result()
1618 }
1619 EthRequest::GetBlobByHash(hash) => {
1620 self.anvil_get_blob_by_versioned_hash(hash).to_rpc_result()
1621 }
1622 EthRequest::GetBlobByTransactionHash(hash) => {
1623 self.anvil_get_blob_by_tx_hash(hash).to_rpc_result()
1624 }
1625 EthRequest::GetGenesisTime(()) => self.anvil_get_genesis_time().to_rpc_result(),
1626 EthRequest::EthGetRawTransactionByBlockHashAndIndex(hash, index) => {
1627 self.raw_transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
1628 }
1629 EthRequest::EthGetRawTransactionByBlockNumberAndIndex(num, index) => {
1630 self.raw_transaction_by_block_number_and_index(num, index).await.to_rpc_result()
1631 }
1632 EthRequest::EthGetTransactionByBlockHashAndIndex(hash, index) => {
1633 self.transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
1634 }
1635 EthRequest::EthGetTransactionByBlockNumberAndIndex(num, index) => {
1636 self.transaction_by_block_number_and_index(num, index).await.to_rpc_result()
1637 }
1638 EthRequest::EthGetTransactionReceipt(tx) => {
1639 self.transaction_receipt(tx).await.to_rpc_result()
1640 }
1641 EthRequest::EthGetBlockReceipts(number) => {
1642 self.block_receipts(number).await.to_rpc_result()
1643 }
1644 EthRequest::EthGetUncleByBlockHashAndIndex(hash, index) => {
1645 self.uncle_by_block_hash_and_index(hash, index).await.to_rpc_result()
1646 }
1647 EthRequest::EthGetUncleByBlockNumberAndIndex(num, index) => {
1648 self.uncle_by_block_number_and_index(num, index).await.to_rpc_result()
1649 }
1650 EthRequest::EthGetLogs(filter) => self.logs(filter).await.to_rpc_result(),
1651 EthRequest::EthGetWork(_) => self.work().to_rpc_result(),
1652 EthRequest::EthSyncing(_) => self.syncing().to_rpc_result(),
1653 EthRequest::EthConfig(_) => self.config().to_rpc_result(),
1654 EthRequest::EthSubmitWork(nonce, pow, digest) => {
1655 self.submit_work(nonce, pow, digest).to_rpc_result()
1656 }
1657 EthRequest::EthSubmitHashRate(rate, id) => {
1658 self.submit_hashrate(rate, id).to_rpc_result()
1659 }
1660 EthRequest::EthFeeHistory(count, newest, reward_percentiles) => {
1661 self.fee_history(count, newest, reward_percentiles).await.to_rpc_result()
1662 }
1663 EthRequest::DebugGetRawTransaction(hash) => {
1665 self.raw_transaction(hash).await.to_rpc_result()
1666 }
1667 EthRequest::DebugTraceTransaction(tx, opts) => {
1669 self.debug_trace_transaction(tx, opts).await.to_rpc_result()
1670 }
1671 EthRequest::DebugTraceCall(tx, block, opts) => {
1673 self.debug_trace_call(tx, block, opts).await.to_rpc_result()
1674 }
1675 EthRequest::DebugCodeByHash(hash, block) => {
1676 self.debug_code_by_hash(hash, block).await.to_rpc_result()
1677 }
1678 EthRequest::DebugDbGet(key) => self.debug_db_get(key).await.to_rpc_result(),
1679 EthRequest::DebugTraceBlockByHash(block_hash, opts) => {
1680 self.debug_trace_block_by_hash(block_hash, opts).await.to_rpc_result()
1681 }
1682 EthRequest::DebugTraceBlockByNumber(block_number, opts) => {
1683 self.debug_trace_block_by_number(block_number, opts).await.to_rpc_result()
1684 }
1685 EthRequest::TraceTransaction(tx) => self.trace_transaction(tx).await.to_rpc_result(),
1686 EthRequest::TraceBlock(block) => self.trace_block(block).await.to_rpc_result(),
1687 EthRequest::TraceFilter(filter) => self.trace_filter(filter).await.to_rpc_result(),
1688 EthRequest::TraceReplayBlockTransactions(block, trace_types) => {
1689 self.trace_replay_block_transactions(block, trace_types).await.to_rpc_result()
1690 }
1691 EthRequest::ImpersonateAccount(addr) => {
1692 self.anvil_impersonate_account(addr).await.to_rpc_result()
1693 }
1694 EthRequest::StopImpersonatingAccount(addr) => {
1695 self.anvil_stop_impersonating_account(addr).await.to_rpc_result()
1696 }
1697 EthRequest::AutoImpersonateAccount(enable) => {
1698 self.anvil_auto_impersonate_account(enable).await.to_rpc_result()
1699 }
1700 EthRequest::ImpersonateSignature(signature, address) => {
1701 self.anvil_impersonate_signature(signature, address).await.to_rpc_result()
1702 }
1703 EthRequest::GetAutoMine(()) => self.anvil_get_auto_mine().to_rpc_result(),
1704 EthRequest::Mine(blocks, interval) => {
1705 self.anvil_mine(blocks, interval).await.to_rpc_result()
1706 }
1707 EthRequest::SetAutomine(enabled) => {
1708 self.anvil_set_auto_mine(enabled).await.to_rpc_result()
1709 }
1710 EthRequest::SetIntervalMining(interval) => {
1711 self.anvil_set_interval_mining(interval).to_rpc_result()
1712 }
1713 EthRequest::GetIntervalMining(()) => self.anvil_get_interval_mining().to_rpc_result(),
1714 EthRequest::DropTransaction(tx) => {
1715 self.anvil_drop_transaction(tx).await.to_rpc_result()
1716 }
1717 EthRequest::DropAllTransactions() => {
1718 self.anvil_drop_all_transactions().await.to_rpc_result()
1719 }
1720 EthRequest::Reset(fork) => {
1721 self.anvil_reset(fork.and_then(|p| p.params)).await.to_rpc_result()
1722 }
1723 EthRequest::SetBalance(addr, val) => {
1724 self.anvil_set_balance(addr, val).await.to_rpc_result()
1725 }
1726 EthRequest::AddBalance(addr, val) => {
1727 self.anvil_add_balance(addr, val).await.to_rpc_result()
1728 }
1729 EthRequest::DealERC20(addr, token_addr, val) => {
1730 self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result()
1731 }
1732 EthRequest::SetERC20Allowance(owner, spender, token_addr, val) => self
1733 .anvil_set_erc20_allowance(owner, spender, token_addr, val)
1734 .await
1735 .to_rpc_result(),
1736 EthRequest::SetCode(addr, code) => {
1737 self.anvil_set_code(addr, code).await.to_rpc_result()
1738 }
1739 EthRequest::SetNonce(addr, nonce) => {
1740 self.anvil_set_nonce(addr, nonce).await.to_rpc_result()
1741 }
1742 EthRequest::SetStorageAt(addr, slot, val) => {
1743 self.anvil_set_storage_at(addr, slot, val).await.to_rpc_result()
1744 }
1745 EthRequest::SetCoinbase(addr) => self.anvil_set_coinbase(addr).await.to_rpc_result(),
1746 EthRequest::SetChainId(id) => self.anvil_set_chain_id(id).await.to_rpc_result(),
1747 EthRequest::SetLogging(log) => self.anvil_set_logging(log).await.to_rpc_result(),
1748 EthRequest::SetMinGasPrice(gas) => {
1749 self.anvil_set_min_gas_price(gas).await.to_rpc_result()
1750 }
1751 EthRequest::SetNextBlockBaseFeePerGas(gas) => {
1752 self.anvil_set_next_block_base_fee_per_gas(gas).await.to_rpc_result()
1753 }
1754 EthRequest::DumpState(preserve_historical_states) => self
1755 .anvil_dump_state(preserve_historical_states.and_then(|s| s.params))
1756 .await
1757 .to_rpc_result(),
1758 EthRequest::LoadState(buf) => self.anvil_load_state(buf).await.to_rpc_result(),
1759 EthRequest::NodeInfo(_) => self.anvil_node_info().await.to_rpc_result(),
1760 EthRequest::AnvilMetadata(_) => self.anvil_metadata().await.to_rpc_result(),
1761 EthRequest::EvmSnapshot(_) => self.evm_snapshot().await.to_rpc_result(),
1762 EthRequest::EvmRevert(id) => self.evm_revert(id).await.to_rpc_result(),
1763 EthRequest::EvmIncreaseTime(time) => self.evm_increase_time(time).await.to_rpc_result(),
1764 EthRequest::EvmSetNextBlockTimeStamp(time) => {
1765 if time >= U256::from(u64::MAX) {
1766 return ResponseResult::Error(RpcError::invalid_params(
1767 "The timestamp is too big",
1768 ));
1769 }
1770 let time = time.to::<u64>();
1771 self.evm_set_next_block_timestamp(time).to_rpc_result()
1772 }
1773 EthRequest::EvmSetTime(timestamp) => {
1774 if timestamp >= U256::from(u64::MAX) {
1775 return ResponseResult::Error(RpcError::invalid_params(
1776 "The timestamp is too big",
1777 ));
1778 }
1779 let raw = timestamp.to::<u64>();
1783 let time = if raw > 1_000_000_000_000 {
1784 Duration::from_millis(raw).as_secs()
1785 } else {
1786 raw
1787 };
1788 self.evm_set_time(time).to_rpc_result()
1789 }
1790 EthRequest::EvmSetBlockGasLimit(gas_limit) => {
1791 self.evm_set_block_gas_limit(gas_limit).to_rpc_result()
1792 }
1793 EthRequest::EvmSetBlockTimeStampInterval(time) => {
1794 self.evm_set_block_timestamp_interval(time).to_rpc_result()
1795 }
1796 EthRequest::EvmRemoveBlockTimeStampInterval(()) => {
1797 self.evm_remove_block_timestamp_interval().to_rpc_result()
1798 }
1799 EthRequest::EvmMine(mine) => {
1800 self.evm_mine(mine.and_then(|p| p.params)).await.to_rpc_result()
1801 }
1802 EthRequest::EvmMineDetailed(mine) => {
1803 self.evm_mine_detailed(mine.and_then(|p| p.params)).await.to_rpc_result()
1804 }
1805 EthRequest::SetRpcUrl(url) => self.anvil_set_rpc_url(url).await.to_rpc_result(),
1806 EthRequest::EthSendUnsignedTransaction(tx) => {
1807 self.eth_send_unsigned_transaction(*tx).await.to_rpc_result()
1808 }
1809 EthRequest::EthNewFilter(filter) => self.new_filter(filter).await.to_rpc_result(),
1810 EthRequest::EthGetFilterChanges(id) => self.get_filter_changes(&id).await,
1811 EthRequest::EthNewBlockFilter(_) => self.new_block_filter().await.to_rpc_result(),
1812 EthRequest::EthNewPendingTransactionFilter(_) => {
1813 self.new_pending_transaction_filter().await.to_rpc_result()
1814 }
1815 EthRequest::EthGetFilterLogs(id) => self.get_filter_logs(&id).await.to_rpc_result(),
1816 EthRequest::EthUninstallFilter(id) => self.uninstall_filter(&id).await.to_rpc_result(),
1817 EthRequest::TxPoolStatus(_) => self.txpool_status().await.to_rpc_result(),
1818 EthRequest::TxPoolInspect(_) => self.txpool_inspect().await.to_rpc_result(),
1819 EthRequest::TxPoolContent(_) => self.txpool_content().await.to_rpc_result(),
1820 EthRequest::ErigonGetHeaderByNumber(num) => {
1821 self.erigon_get_header_by_number(num).await.to_rpc_result()
1822 }
1823 EthRequest::OtsGetApiLevel(_) => self.ots_get_api_level().await.to_rpc_result(),
1824 EthRequest::OtsGetInternalOperations(hash) => {
1825 self.ots_get_internal_operations(hash).await.to_rpc_result()
1826 }
1827 EthRequest::OtsHasCode(addr, num) => self.ots_has_code(addr, num).await.to_rpc_result(),
1828 EthRequest::OtsTraceTransaction(hash) => {
1829 self.ots_trace_transaction(hash).await.to_rpc_result()
1830 }
1831 EthRequest::OtsGetTransactionError(hash) => {
1832 self.ots_get_transaction_error(hash).await.to_rpc_result()
1833 }
1834 EthRequest::OtsGetBlockDetails(num) => {
1835 self.ots_get_block_details(num).await.to_rpc_result()
1836 }
1837 EthRequest::OtsGetBlockDetailsByHash(hash) => {
1838 self.ots_get_block_details_by_hash(hash).await.to_rpc_result()
1839 }
1840 EthRequest::OtsGetBlockTransactions(num, page, page_size) => {
1841 self.ots_get_block_transactions(num, page, page_size).await.to_rpc_result()
1842 }
1843 EthRequest::OtsSearchTransactionsBefore(address, num, page_size) => {
1844 self.ots_search_transactions_before(address, num, page_size).await.to_rpc_result()
1845 }
1846 EthRequest::OtsSearchTransactionsAfter(address, num, page_size) => {
1847 self.ots_search_transactions_after(address, num, page_size).await.to_rpc_result()
1848 }
1849 EthRequest::OtsGetTransactionBySenderAndNonce(address, nonce) => {
1850 self.ots_get_transaction_by_sender_and_nonce(address, nonce).await.to_rpc_result()
1851 }
1852 EthRequest::EthGetTransactionBySenderAndNonce(sender, nonce) => {
1853 self.transaction_by_sender_and_nonce(sender, nonce).await.to_rpc_result()
1854 }
1855 EthRequest::OtsGetContractCreator(address) => {
1856 self.ots_get_contract_creator(address).await.to_rpc_result()
1857 }
1858 EthRequest::RemovePoolTransactions(address) => {
1859 self.anvil_remove_pool_transactions(address).await.to_rpc_result()
1860 }
1861 EthRequest::Reorg(reorg_options) => {
1862 self.anvil_reorg(reorg_options).await.to_rpc_result()
1863 }
1864 EthRequest::Rollback(depth) => self.anvil_rollback(depth).await.to_rpc_result(),
1865 EthRequest::SetFeeToken(user, token) => {
1866 self.anvil_set_fee_token(user, token).await.to_rpc_result()
1867 }
1868 EthRequest::SetValidatorFeeToken(validator, token) => {
1869 self.anvil_set_validator_fee_token(validator, token).await.to_rpc_result()
1870 }
1871 EthRequest::SetFeeAmmLiquidity(user_token, validator_token, amount) => self
1872 .anvil_set_fee_amm_liquidity(user_token, validator_token, amount)
1873 .await
1874 .to_rpc_result(),
1875 };
1876
1877 if let ResponseResult::Error(err) = &response {
1878 node_info!("\nRPC request failed:");
1879 node_info!(" Request: {:?}", request);
1880 node_info!(" Error: {}\n", err);
1881 }
1882
1883 response
1884 }
1885
1886 fn sign_request(&self, from: &Address, typed_tx: FoundryTypedTx) -> Result<FoundryTxEnvelope> {
1887 match typed_tx {
1888 #[cfg(feature = "optimism")]
1889 FoundryTypedTx::Deposit(_) => return Ok(build_impersonated(typed_tx)),
1890 _ => {
1891 for signer in self.signers.iter() {
1892 if signer.accounts().contains(from) {
1893 return signer.sign_transaction_from(from, typed_tx);
1894 }
1895 }
1896 }
1897 }
1898 Err(BlockchainError::NoSignerAvailable)
1899 }
1900
1901 async fn inner_raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
1902 match self.pool.get_transaction(hash) {
1903 Some(tx) => Ok(Some(tx.transaction.encoded_2718().into())),
1904 None => match self.backend.transaction_by_hash(hash).await? {
1905 Some(tx) => Ok(Some(tx.as_ref().encoded_2718().into())),
1906 None => Ok(None),
1907 },
1908 }
1909 }
1910
1911 pub async fn balance(&self, address: Address, block_number: Option<BlockId>) -> Result<U256> {
1915 node_info!("eth_getBalance");
1916 let block_request = self.block_request(block_number).await?;
1917
1918 if let BlockRequest::Number(number) = block_request
1920 && let Some(fork) = self.get_fork()
1921 && fork.predates_fork(number)
1922 {
1923 return Ok(fork.get_balance(address, number).await?);
1924 }
1925
1926 self.backend.get_balance(address, Some(block_request)).await
1927 }
1928
1929 pub async fn get_account(
1933 &self,
1934 address: Address,
1935 block_number: Option<BlockId>,
1936 ) -> Result<TrieAccount> {
1937 node_info!("eth_getAccount");
1938 let block_request = self.block_request(block_number).await?;
1939
1940 if let BlockRequest::Number(number) = block_request
1942 && let Some(fork) = self.get_fork()
1943 && fork.predates_fork(number)
1944 {
1945 return Ok(fork.get_account(address, number).await?);
1946 }
1947
1948 self.backend.get_account_at_block(address, Some(block_request)).await
1949 }
1950
1951 pub async fn get_account_info(
1955 &self,
1956 address: Address,
1957 block_number: Option<BlockId>,
1958 ) -> Result<alloy_rpc_types::eth::AccountInfo> {
1959 node_info!("eth_getAccountInfo");
1960
1961 if let Some(fork) = self.get_fork() {
1962 let block_request = self.block_request(block_number).await?;
1963 if let BlockRequest::Number(number) = block_request {
1965 trace!(target: "node", "get_account_info: fork block {}, requested block {number}", fork.block_number());
1966 return if fork.predates_fork(number) {
1967 let balance = fork.get_balance(address, number).map_err(BlockchainError::from);
1970 let code = fork.get_code(address, number).map_err(BlockchainError::from);
1971 let nonce = self.get_transaction_count(address, Some(number.into()));
1972 let (balance, code, nonce) = try_join!(balance, code, nonce)?;
1973
1974 Ok(alloy_rpc_types::eth::AccountInfo { balance, nonce, code })
1975 } else {
1976 let account_info = self.backend.get_account(address).await?;
1979 let code = self.backend.get_code(address, Some(block_request)).await?;
1980 Ok(alloy_rpc_types::eth::AccountInfo {
1981 balance: account_info.balance,
1982 nonce: account_info.nonce,
1983 code,
1984 })
1985 };
1986 }
1987 }
1988
1989 let account = self.get_account(address, block_number);
1990 let code = self.get_code(address, block_number);
1991 let (account, code) = try_join!(account, code)?;
1992 Ok(alloy_rpc_types::eth::AccountInfo {
1993 balance: account.balance,
1994 nonce: account.nonce,
1995 code,
1996 })
1997 }
1998 pub async fn storage_at(
2002 &self,
2003 address: Address,
2004 index: U256,
2005 block_number: Option<BlockId>,
2006 ) -> Result<B256> {
2007 node_info!("eth_getStorageAt");
2008 let block_request = self.block_request(block_number).await?;
2009
2010 if let BlockRequest::Number(number) = block_request
2012 && let Some(fork) = self.get_fork()
2013 && fork.predates_fork(number)
2014 {
2015 return Ok(B256::from(
2016 fork.storage_at(address, index, Some(BlockNumber::Number(number))).await?,
2017 ));
2018 }
2019
2020 self.backend.storage_at(address, index, Some(block_request)).await
2021 }
2022
2023 pub async fn storage_values(
2027 &self,
2028 requests: HashMap<Address, Vec<B256>>,
2029 block_number: Option<BlockId>,
2030 ) -> Result<HashMap<Address, Vec<B256>>> {
2031 node_info!("eth_getStorageValues");
2032
2033 let total_slots: usize = requests.values().map(|s| s.len()).sum();
2034 if total_slots > 1024 {
2035 return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
2036 "total slot count {total_slots} exceeds limit 1024"
2037 ))));
2038 }
2039
2040 let block_request = self.block_request(block_number).await?;
2041
2042 if let BlockRequest::Number(number) = block_request
2044 && let Some(fork) = self.get_fork()
2045 && fork.predates_fork(number)
2046 {
2047 let mut result: HashMap<Address, Vec<B256>> = HashMap::default();
2048 for (address, slots) in requests {
2049 let mut values = Vec::with_capacity(slots.len());
2050 for slot in &slots {
2051 let val = fork
2052 .storage_at(address, (*slot).into(), Some(BlockNumber::Number(number)))
2053 .await?;
2054 values.push(B256::from(val));
2055 }
2056 result.insert(address, values);
2057 }
2058 return Ok(result);
2059 }
2060
2061 self.backend.storage_values(requests, Some(block_request)).await
2062 }
2063
2064 pub async fn block_by_number(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2068 node_info!("eth_getBlockByNumber");
2069 if number == BlockNumber::Pending {
2070 return Ok(Some(self.pending_block().await));
2071 }
2072
2073 self.backend.block_by_number(number).await
2074 }
2075
2076 pub async fn block_by_number_full(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2080 node_info!("eth_getBlockByNumber");
2081 if number == BlockNumber::Pending {
2082 return Ok(self.pending_block_full().await);
2083 }
2084 self.backend.block_by_number_full(number).await
2085 }
2086
2087 pub async fn transaction_count(
2094 &self,
2095 address: Address,
2096 block_number: Option<BlockId>,
2097 ) -> Result<U256> {
2098 node_info!("eth_getTransactionCount");
2099 self.get_transaction_count(address, block_number).await.map(U256::from)
2100 }
2101
2102 pub async fn block_transaction_count_by_number(
2106 &self,
2107 block_number: BlockNumber,
2108 ) -> Result<Option<U256>> {
2109 node_info!("eth_getBlockTransactionCountByNumber");
2110 let block_request = self.block_request(Some(block_number.into())).await?;
2111 if let BlockRequest::Pending(txs) = block_request {
2112 let block = self.backend.pending_block(txs).await;
2113 return Ok(Some(U256::from(block.block.body.transactions.len())));
2114 }
2115 let block = self.backend.block_by_number(block_number).await?;
2116 let txs = block.map(|b| match b.transactions() {
2117 BlockTransactions::Full(txs) => U256::from(txs.len()),
2118 BlockTransactions::Hashes(txs) => U256::from(txs.len()),
2119 BlockTransactions::Uncle => U256::from(0),
2120 });
2121 Ok(txs)
2122 }
2123
2124 pub async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {
2128 node_info!("eth_getCode");
2129 let block_request = self.block_request(block_number).await?;
2130 if let BlockRequest::Number(number) = block_request
2132 && let Some(fork) = self.get_fork()
2133 && fork.predates_fork(number)
2134 {
2135 return Ok(fork.get_code(address, number).await?);
2136 }
2137 self.backend.get_code(address, Some(block_request)).await
2138 }
2139
2140 pub async fn get_proof(
2145 &self,
2146 address: Address,
2147 keys: Vec<B256>,
2148 block_number: Option<BlockId>,
2149 ) -> Result<EIP1186AccountProofResponse> {
2150 node_info!("eth_getProof");
2151 let block_request = self.block_request(block_number).await?;
2152
2153 if let BlockRequest::Number(number) = block_request
2156 && let Some(fork) = self.get_fork()
2157 && fork.predates_fork_inclusive(number)
2158 {
2159 return Ok(fork.get_proof(address, keys, Some(number.into())).await?);
2160 }
2161
2162 let proof = self.backend.prove_account_at(address, keys, Some(block_request)).await?;
2163 Ok(proof)
2164 }
2165
2166 pub async fn sign_transaction(
2170 &self,
2171 request: WithOtherFields<TransactionRequest>,
2172 ) -> Result<String> {
2173 node_info!("eth_signTransaction");
2174
2175 let from = request.from.map(Ok).unwrap_or_else(|| {
2176 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
2177 })?;
2178
2179 let (nonce, _) = self.request_nonce(&request, from).await?;
2180
2181 let request = self.build_tx_request(request, nonce).await?;
2182
2183 let signed_transaction = self.sign_request(&from, request)?.encoded_2718();
2184 Ok(alloy_primitives::hex::encode_prefixed(signed_transaction))
2185 }
2186
2187 pub async fn send_transaction(
2191 &self,
2192 request: WithOtherFields<TransactionRequest>,
2193 ) -> Result<TxHash> {
2194 node_info!("eth_sendTransaction");
2195
2196 let from = request.from.map(Ok).unwrap_or_else(|| {
2197 self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
2198 })?;
2199 let (nonce, on_chain_nonce) = self.request_nonce(&request, from).await?;
2200
2201 let typed_tx = self.build_tx_request(request, nonce).await?;
2202
2203 let pending_transaction = if self.is_impersonated(from) {
2205 let transaction = sign::build_impersonated(typed_tx);
2206 self.ensure_typed_transaction_supported(&transaction)?;
2207 trace!(target : "node", ?from, "eth_sendTransaction: impersonating");
2208 PendingTransaction::with_impersonated(transaction, from)
2209 } else {
2210 let transaction = self.sign_request(&from, typed_tx)?;
2211 self.ensure_typed_transaction_supported(&transaction)?;
2212 PendingTransaction::new(transaction)?
2213 };
2214 self.backend.validate_pool_transaction(&pending_transaction).await?;
2216
2217 let (requires, provides) = if let Some((requires, provides)) =
2218 tempo_parallel_nonce_markers(&pending_transaction)
2219 {
2220 (requires, provides)
2221 } else {
2222 (required_marker(nonce, on_chain_nonce, from), vec![to_marker(nonce, from)])
2223 };
2224
2225 self.add_pending_transaction(pending_transaction, requires, provides)
2226 }
2227
2228 async fn await_transaction_inclusion(&self, hash: TxHash) -> Result<FoundryTxReceipt> {
2230 let mut stream = self.new_block_notifications();
2231 if let Some(receipt) = self.backend.transaction_receipt(hash).await? {
2233 return Ok(receipt);
2234 }
2235 while let Some(notification) = stream.next().await {
2236 if let Some(block) = self.backend.get_block_by_hash(notification.hash)
2237 && block.body.transactions.iter().any(|tx| tx.hash() == hash)
2238 && let Some(receipt) = self.backend.transaction_receipt(hash).await?
2239 {
2240 return Ok(receipt);
2241 }
2242 }
2243
2244 Err(BlockchainError::Message("Failed to await transaction inclusion".to_string()))
2245 }
2246
2247 async fn check_transaction_inclusion(&self, hash: TxHash) -> Result<FoundryTxReceipt> {
2249 const TIMEOUT_DURATION: Duration = Duration::from_secs(30);
2250 tokio::time::timeout(TIMEOUT_DURATION, self.await_transaction_inclusion(hash))
2251 .await
2252 .unwrap_or_else(|_elapsed| {
2253 Err(BlockchainError::TransactionConfirmationTimeout {
2254 hash,
2255 duration: TIMEOUT_DURATION,
2256 })
2257 })
2258 }
2259
2260 pub async fn send_transaction_sync(
2264 &self,
2265 request: WithOtherFields<TransactionRequest>,
2266 ) -> Result<FoundryTxReceipt> {
2267 node_info!("eth_sendTransactionSync");
2268 let hash = self.send_transaction(request).await?;
2269
2270 let receipt = self.check_transaction_inclusion(hash).await?;
2271
2272 Ok(receipt)
2273 }
2274
2275 pub async fn send_raw_transaction(&self, tx: Bytes) -> Result<TxHash> {
2279 node_info!("eth_sendRawTransaction");
2280 let mut data = tx.as_ref();
2281 if data.is_empty() {
2282 return Err(BlockchainError::EmptyRawTransactionData);
2283 }
2284
2285 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
2286 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
2287
2288 self.ensure_typed_transaction_supported(&transaction)?;
2289
2290 if self.backend.is_tempo() && TempoHardfork::from(self.backend.hardfork()).is_t5() {
2291 let classification = transaction.classify_t5_payment_lane();
2292 trace!(target: "node", tx = ?transaction.hash(), ?classification, "classified transaction lane");
2293 }
2294
2295 let pending_transaction = PendingTransaction::new(transaction)?;
2296
2297 self.backend.validate_pool_transaction(&pending_transaction).await?;
2299
2300 let from = *pending_transaction.sender();
2301 let priority = self.transaction_priority(&pending_transaction.transaction);
2302
2303 let (requires, provides) = if let Some((requires, provides)) =
2305 tempo_parallel_nonce_markers(&pending_transaction)
2306 {
2307 (requires, provides)
2308 } else {
2309 let on_chain_nonce = self.backend.current_nonce(from).await?;
2310 let nonce = pending_transaction.transaction.nonce();
2311 (required_marker(nonce, on_chain_nonce, from), vec![to_marker(nonce, from)])
2312 };
2313
2314 let pool_transaction =
2315 PoolTransaction { requires, provides, pending_transaction, priority };
2316
2317 let tx = self.pool.add_transaction(pool_transaction)?;
2318 trace!(target: "node", "Added transaction: [{:?}] sender={:?}", tx.hash(), from);
2319 Ok(*tx.hash())
2320 }
2321
2322 pub fn anvil_classify_transaction(&self, tx: Bytes) -> Result<PaymentLaneClassification> {
2324 node_info!("anvil_classifyTransaction");
2325 let mut data = tx.as_ref();
2326 if data.is_empty() {
2327 return Err(BlockchainError::EmptyRawTransactionData);
2328 }
2329
2330 let transaction = FoundryTxEnvelope::decode_2718(&mut data)
2331 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
2332
2333 Ok(self.classify_transaction_envelope(&transaction))
2334 }
2335
2336 fn classify_transaction_envelope(
2337 &self,
2338 transaction: &FoundryTxEnvelope,
2339 ) -> PaymentLaneClassification {
2340 if !self.backend.is_tempo() {
2341 return PaymentLaneClassification::general(PaymentLaneReason::NotTempo);
2342 }
2343
2344 if !TempoHardfork::from(self.backend.hardfork()).is_t5() {
2345 return PaymentLaneClassification::general(PaymentLaneReason::T5NotActive);
2346 }
2347
2348 transaction.classify_t5_payment_lane()
2349 }
2350
2351 pub async fn send_raw_transaction_sync(&self, tx: Bytes) -> Result<FoundryTxReceipt> {
2355 node_info!("eth_sendRawTransactionSync");
2356
2357 let hash = self.send_raw_transaction(tx).await?;
2358 let receipt = self.check_transaction_inclusion(hash).await?;
2359
2360 Ok(receipt)
2361 }
2362
2363 pub async fn call(
2367 &self,
2368 request: WithOtherFields<TransactionRequest>,
2369 block_number: Option<BlockId>,
2370 overrides: EvmOverrides,
2371 ) -> Result<Bytes> {
2372 node_info!("eth_call");
2373 let block_request = self.block_request(block_number).await?;
2374 if let BlockRequest::Number(number) = block_request
2376 && let Some(fork) = self.get_fork()
2377 && fork.predates_fork(number)
2378 {
2379 if overrides.has_state() || overrides.has_block() {
2380 return Err(BlockchainError::EvmOverrideError(
2381 "not available on past forked blocks".to_string(),
2382 ));
2383 }
2384 return Ok(fork.call(&request, Some(number.into())).await?);
2385 }
2386
2387 let fees = FeeDetails::new(
2388 request.gas_price,
2389 request.max_fee_per_gas,
2390 request.max_priority_fee_per_gas,
2391 request.max_fee_per_blob_gas,
2392 )?
2393 .or_zero_fees();
2394 self.on_blocking_task(|this| async move {
2397 let (exit, out, gas, _) =
2398 this.backend.call(request, fees, Some(block_request), overrides).await?;
2399 trace!(target : "node", "Call status {:?}, gas {}", exit, gas);
2400
2401 ensure_return_ok(exit, &out)
2402 })
2403 .await
2404 }
2405
2406 pub async fn simulate_v1(
2407 &self,
2408 request: SimulatePayload,
2409 block_number: Option<BlockId>,
2410 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
2411 node_info!("eth_simulateV1");
2412 let block_request = self.block_request(block_number).await?;
2413 if let BlockRequest::Number(number) = block_request
2415 && let Some(fork) = self.get_fork()
2416 && fork.predates_fork(number)
2417 {
2418 return Ok(fork.simulate_v1(&request, Some(number.into())).await?);
2419 }
2420
2421 self.on_blocking_task(|this| async move {
2424 let simulated_blocks = this.backend.simulate(request, Some(block_request)).await?;
2425 trace!(target : "node", "Simulate status {:?}", simulated_blocks);
2426
2427 Ok(simulated_blocks)
2428 })
2429 .await
2430 }
2431
2432 pub async fn create_access_list(
2446 &self,
2447 mut request: WithOtherFields<TransactionRequest>,
2448 block_number: Option<BlockId>,
2449 ) -> Result<AccessListResult> {
2450 node_info!("eth_createAccessList");
2451 let block_request = self.block_request(block_number).await?;
2452 if let BlockRequest::Number(number) = block_request
2454 && let Some(fork) = self.get_fork()
2455 && fork.predates_fork(number)
2456 {
2457 return Ok(fork.create_access_list(&request, Some(number.into())).await?);
2458 }
2459
2460 self.backend
2461 .with_database_at(Some(block_request), |state, block_env| {
2462 let (_, _, _, access_list) = self.backend.build_access_list_with_state(
2463 &state,
2464 request.clone(),
2465 FeeDetails::zero(),
2466 block_env.clone(),
2467 )?;
2468
2469 request.access_list = Some(access_list.clone());
2474 let (exit, _, gas_used, _) =
2475 self.backend.call_with_state(&state, request, FeeDetails::zero(), block_env)?;
2476
2477 Ok(AccessListResult {
2478 access_list,
2479 gas_used: U256::from(gas_used),
2480 error: execution_error(exit),
2481 })
2482 })
2483 .await?
2484 }
2485
2486 pub async fn estimate_gas(
2491 &self,
2492 request: WithOtherFields<TransactionRequest>,
2493 block_number: Option<BlockId>,
2494 overrides: EvmOverrides,
2495 ) -> Result<U256> {
2496 node_info!("eth_estimateGas");
2497 self.do_estimate_gas(
2498 request,
2499 block_number.or_else(|| Some(BlockNumber::Pending.into())),
2500 overrides,
2501 )
2502 .await
2503 .map(U256::from)
2504 }
2505
2506 pub async fn fill_transaction(
2513 &self,
2514 mut request: WithOtherFields<TransactionRequest>,
2515 ) -> Result<FillTransaction<AnyRpcTransaction>> {
2516 node_info!("eth_fillTransaction");
2517
2518 let from = match request.as_ref().from() {
2519 Some(from) => from,
2520 None => self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)?,
2521 };
2522
2523 let nonce = if let Some(nonce) = request.as_ref().nonce() {
2524 nonce
2525 } else {
2526 self.request_nonce(&request, from).await?.0
2527 };
2528
2529 if request.as_ref().gas_limit().is_none() {
2531 let estimated_gas =
2532 self.estimate_gas(request.clone(), None, EvmOverrides::default()).await?;
2533 request.as_mut().set_gas_limit(estimated_gas.to());
2534 }
2535
2536 let typed_tx = self.build_tx_request(request, nonce).await?;
2537 let tx = build_impersonated(typed_tx);
2538
2539 let raw = tx.encoded_2718().into();
2540
2541 let mut tx =
2542 transaction_build(None, MaybeImpersonatedTransaction::new(tx), None, None, None);
2543
2544 tx.0.inner.inner = Recovered::new_unchecked(tx.0.inner.inner.into_inner(), from);
2547
2548 Ok(FillTransaction { raw, tx })
2549 }
2550
2551 pub fn anvil_get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<Blob>>> {
2553 node_info!("anvil_getBlobsByTransactionHash");
2554 Ok(self.backend.get_blob_by_tx_hash(hash)?)
2555 }
2556
2557 pub async fn transaction_by_hash(&self, hash: B256) -> Result<Option<AnyRpcTransaction>> {
2564 node_info!("eth_getTransactionByHash");
2565 let mut tx = self.pool.get_transaction(hash).map(|pending| {
2566 let from = *pending.sender();
2567 let tx = transaction_build(
2568 Some(*pending.hash()),
2569 pending.transaction,
2570 None,
2571 None,
2572 Some(self.backend.base_fee()),
2573 );
2574
2575 let WithOtherFields { inner: mut tx, other } = tx.0;
2576 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
2579
2580 AnyRpcTransaction(WithOtherFields { inner: tx, other })
2581 });
2582 if tx.is_none() {
2583 tx = self.backend.transaction_by_hash(hash).await?
2584 }
2585
2586 Ok(tx)
2587 }
2588
2589 pub async fn transaction_by_sender_and_nonce(
2596 &self,
2597 sender: Address,
2598 nonce: U256,
2599 ) -> Result<Option<AnyRpcTransaction>> {
2600 node_info!("eth_getTransactionBySenderAndNonce");
2601
2602 for pending_tx in self.pool.ready_transactions().chain(self.pool.pending_transactions()) {
2604 if U256::from(pending_tx.pending_transaction.nonce()) == nonce
2605 && *pending_tx.pending_transaction.sender() == sender
2606 {
2607 let tx = transaction_build(
2608 Some(*pending_tx.pending_transaction.hash()),
2609 pending_tx.pending_transaction.transaction.clone(),
2610 None,
2611 None,
2612 Some(self.backend.base_fee()),
2613 );
2614
2615 let WithOtherFields { inner: mut tx, other } = tx.0;
2616 let from = *pending_tx.pending_transaction.sender();
2619 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
2620
2621 return Ok(Some(AnyRpcTransaction(WithOtherFields { inner: tx, other })));
2622 }
2623 }
2624
2625 let highest_nonce = self.transaction_count(sender, None).await?.saturating_to::<u64>();
2626 let target_nonce = nonce.saturating_to::<u64>();
2627
2628 if target_nonce >= highest_nonce {
2630 return Ok(None);
2631 }
2632
2633 let latest_block = self.backend.best_number();
2635 if latest_block == 0 {
2636 return Ok(None);
2637 }
2638
2639 let mut low = 1u64;
2641 let mut high = latest_block;
2642
2643 while low <= high {
2644 let mid = low + (high - low) / 2;
2645 let mid_nonce =
2646 self.transaction_count(sender, Some(mid.into())).await?.saturating_to::<u64>();
2647
2648 if mid_nonce > target_nonce {
2649 high = mid - 1;
2650 } else {
2651 low = mid + 1;
2652 }
2653 }
2654
2655 let target_block = low;
2657 if target_block <= latest_block
2658 && let Some(txs) =
2659 self.backend.mined_transactions_by_block_number(target_block.into()).await
2660 {
2661 for tx in txs {
2662 if tx.from() == sender && tx.nonce() == target_nonce {
2663 return Ok(Some(tx));
2664 }
2665 }
2666 }
2667
2668 Ok(None)
2669 }
2670
2671 pub async fn transaction_receipt(&self, hash: B256) -> Result<Option<FoundryTxReceipt>> {
2675 node_info!("eth_getTransactionReceipt");
2676 self.backend.transaction_receipt(hash).await
2677 }
2678
2679 pub async fn block_receipts(&self, number: BlockId) -> Result<Option<Vec<FoundryTxReceipt>>> {
2683 node_info!("eth_getBlockReceipts");
2684 self.backend.block_receipts(number).await
2685 }
2686
2687 pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>> {
2691 node_info!("eth_getLogs");
2692 self.backend.logs(filter).await
2693 }
2694
2695 pub async fn new_filter(&self, filter: Filter) -> Result<String> {
2699 node_info!("eth_newFilter");
2700 let historic = if filter.block_option.get_from_block().is_some() {
2703 self.backend.logs(filter.clone()).await?
2704 } else {
2705 vec![]
2706 };
2707 let filter = EthFilter::Logs(Box::new(LogsFilter {
2708 blocks: self.new_block_notifications(),
2709 storage: self.storage_info(),
2710 filter: FilteredParams::new(Some(filter)),
2711 historic: Some(historic),
2712 }));
2713 Ok(self.filters.add_filter(filter).await)
2714 }
2715
2716 pub async fn new_block_filter(&self) -> Result<String> {
2720 node_info!("eth_newBlockFilter");
2721 let filter = EthFilter::Blocks(self.new_block_notifications());
2722 Ok(self.filters.add_filter(filter).await)
2723 }
2724
2725 pub async fn new_pending_transaction_filter(&self) -> Result<String> {
2729 node_info!("eth_newPendingTransactionFilter");
2730 let filter = EthFilter::PendingTransactions(self.new_ready_transactions());
2731 Ok(self.filters.add_filter(filter).await)
2732 }
2733
2734 pub async fn get_filter_changes(&self, id: &str) -> ResponseResult {
2738 node_info!("eth_getFilterChanges");
2739 self.filters.get_filter_changes(id).await
2740 }
2741
2742 pub async fn get_filter_logs(&self, id: &str) -> Result<Vec<Log>> {
2746 node_info!("eth_getFilterLogs");
2747 if let Some(filter) = self.filters.get_log_filter(id).await {
2748 self.backend.logs(filter).await
2749 } else {
2750 Err(BlockchainError::FilterNotFound)
2751 }
2752 }
2753
2754 pub async fn uninstall_filter(&self, id: &str) -> Result<bool> {
2756 node_info!("eth_uninstallFilter");
2757 Ok(self.filters.uninstall_filter(id).await.is_some())
2758 }
2759
2760 pub async fn raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
2764 node_info!("debug_getRawTransaction");
2765 self.inner_raw_transaction(hash).await
2766 }
2767
2768 pub async fn raw_transaction_by_block_hash_and_index(
2772 &self,
2773 block_hash: B256,
2774 index: Index,
2775 ) -> Result<Option<Bytes>> {
2776 node_info!("eth_getRawTransactionByBlockHashAndIndex");
2777 match self.backend.transaction_by_block_hash_and_index(block_hash, index).await? {
2778 Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
2779 None => Ok(None),
2780 }
2781 }
2782
2783 pub async fn raw_transaction_by_block_number_and_index(
2787 &self,
2788 block_number: BlockNumber,
2789 index: Index,
2790 ) -> Result<Option<Bytes>> {
2791 node_info!("eth_getRawTransactionByBlockNumberAndIndex");
2792 match self.backend.transaction_by_block_number_and_index(block_number, index).await? {
2793 Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
2794 None => Ok(None),
2795 }
2796 }
2797
2798 pub async fn debug_trace_transaction(
2802 &self,
2803 tx_hash: B256,
2804 opts: GethDebugTracingOptions,
2805 ) -> Result<GethTrace> {
2806 node_info!("debug_traceTransaction");
2807 self.backend.debug_trace_transaction(tx_hash, opts).await
2808 }
2809
2810 pub async fn debug_trace_block_by_hash(
2814 &self,
2815 block_hash: B256,
2816 opts: GethDebugTracingOptions,
2817 ) -> Result<Vec<TraceResult>> {
2818 node_info!("debug_traceBlockByHash");
2819 self.backend.debug_trace_block_by_hash(block_hash, opts).await
2820 }
2821
2822 pub async fn debug_trace_block_by_number(
2826 &self,
2827 block_number: BlockNumber,
2828 opts: GethDebugTracingOptions,
2829 ) -> Result<Vec<TraceResult>> {
2830 node_info!("debug_traceBlockByNumber");
2831 self.backend.debug_trace_block_by_number(block_number, opts).await
2832 }
2833
2834 pub async fn debug_trace_call(
2838 &self,
2839 request: WithOtherFields<TransactionRequest>,
2840 block_number: Option<BlockId>,
2841 opts: GethDebugTracingCallOptions,
2842 ) -> Result<GethTrace> {
2843 node_info!("debug_traceCall");
2844 let block_request = self.block_request(block_number).await?;
2845 let fees = FeeDetails::new(
2846 request.gas_price,
2847 request.max_fee_per_gas,
2848 request.max_priority_fee_per_gas,
2849 request.max_fee_per_blob_gas,
2850 )?
2851 .or_zero_fees();
2852
2853 let result: std::result::Result<GethTrace, BlockchainError> =
2854 self.backend.call_with_tracing(request, fees, Some(block_request), opts).await;
2855 result
2856 }
2857}
2858
2859impl EthApi<FoundryNetwork> {
2862 pub async fn anvil_mine(&self, num_blocks: Option<U256>, interval: Option<U256>) -> Result<()> {
2866 node_info!("anvil_mine");
2867 let interval = interval.map(|i| i.saturating_to::<u64>());
2868 let blocks = num_blocks.unwrap_or(U256::from(1));
2869 if blocks.is_zero() {
2870 return Ok(());
2871 }
2872
2873 self.on_blocking_task(|this| async move {
2874 for _ in 0..blocks.saturating_to::<u64>() {
2876 if let Some(interval) = interval {
2878 this.backend.time().increase_time(interval);
2879 }
2880 this.mine_one().await;
2881 }
2882 Ok(())
2883 })
2884 .await?;
2885
2886 Ok(())
2887 }
2888
2889 async fn find_erc20_storage_slot(
2906 &self,
2907 token_address: Address,
2908 calldata: Bytes,
2909 expected_value: U256,
2910 ) -> Result<B256> {
2911 let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone());
2912
2913 let access_list_result =
2915 self.create_access_list(WithOtherFields::new(tx.clone()), None).await?;
2916 let access_list = access_list_result.access_list;
2917
2918 for item in access_list.0 {
2921 if item.address != token_address {
2922 continue;
2923 };
2924 for slot in &item.storage_keys {
2925 let account_override = AccountOverride::default().with_state_diff(std::iter::once(
2926 (*slot, B256::from(expected_value.to_be_bytes())),
2927 ));
2928
2929 let state_override = StateOverridesBuilder::default()
2930 .append(token_address, account_override)
2931 .build();
2932
2933 let evm_override = EvmOverrides::state(Some(state_override));
2934
2935 let Ok(result) =
2936 self.call(WithOtherFields::new(tx.clone()), None, evm_override).await
2937 else {
2938 continue;
2940 };
2941
2942 let Ok(result_value) = U256::abi_decode(&result) else {
2943 continue;
2945 };
2946
2947 if result_value == expected_value {
2948 return Ok(*slot);
2949 }
2950 }
2951 }
2952
2953 Err(BlockchainError::Message("Unable to find storage slot".to_string()))
2954 }
2955
2956 pub async fn anvil_deal_erc20(
2960 &self,
2961 address: Address,
2962 token_address: Address,
2963 balance: U256,
2964 ) -> Result<()> {
2965 node_info!("anvil_dealERC20");
2966
2967 sol! {
2968 #[sol(rpc)]
2969 contract IERC20 {
2970 function balanceOf(address target) external view returns (uint256);
2971 }
2972 }
2973
2974 let calldata = IERC20::balanceOfCall { target: address }.abi_encode().into();
2975
2976 let slot =
2978 self.find_erc20_storage_slot(token_address, calldata, balance).await.map_err(|_| {
2979 BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string())
2980 })?;
2981
2982 self.anvil_set_storage_at(
2984 token_address,
2985 U256::from_be_bytes(slot.0),
2986 B256::from(balance.to_be_bytes()),
2987 )
2988 .await?;
2989
2990 Ok(())
2991 }
2992
2993 pub async fn anvil_set_erc20_allowance(
2997 &self,
2998 owner: Address,
2999 spender: Address,
3000 token_address: Address,
3001 amount: U256,
3002 ) -> Result<()> {
3003 node_info!("anvil_setERC20Allowance");
3004
3005 sol! {
3006 #[sol(rpc)]
3007 contract IERC20 {
3008 function allowance(address owner, address spender) external view returns (uint256);
3009 }
3010 }
3011
3012 let calldata = IERC20::allowanceCall { owner, spender }.abi_encode().into();
3013
3014 let slot =
3016 self.find_erc20_storage_slot(token_address, calldata, amount).await.map_err(|_| {
3017 BlockchainError::Message("Unable to set ERC20 allowance, no slot found".to_string())
3018 })?;
3019
3020 self.anvil_set_storage_at(
3022 token_address,
3023 U256::from_be_bytes(slot.0),
3024 B256::from(amount.to_be_bytes()),
3025 )
3026 .await?;
3027
3028 Ok(())
3029 }
3030
3031 pub async fn anvil_reorg(&self, options: ReorgOptions) -> Result<()> {
3045 node_info!("anvil_reorg");
3046 let depth = options.depth;
3047 let tx_block_pairs = options.tx_block_pairs;
3048
3049 let current_height = self.backend.best_number();
3051 let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(
3052 RpcError::invalid_params(format!(
3053 "Reorg depth must not exceed current chain height: current height {current_height}, depth {depth}"
3054 )),
3055 ))?;
3056
3057 let common_block =
3059 self.backend.get_block(common_height).ok_or(BlockchainError::BlockNotFound)?;
3060
3061 let block_pool_txs = if tx_block_pairs.is_empty() {
3064 HashMap::default()
3065 } else {
3066 let mut pairs = tx_block_pairs;
3067
3068 if let Some((_, num)) = pairs.iter().find(|(_, num)| *num >= depth) {
3070 return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
3071 "Block number for reorg tx will exceed the reorged chain height. Block number {num} must not exceed (depth-1) {}",
3072 depth - 1
3073 ))));
3074 }
3075
3076 pairs.sort_by_key(|a| a.1);
3078
3079 let mut nonces: HashMap<Address, u64> = HashMap::default();
3082
3083 let mut txs: HashMap<u64, Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>> =
3084 HashMap::default();
3085 for pair in pairs {
3086 let (tx_data, block_index) = pair;
3087
3088 let pending = match tx_data {
3089 TransactionData::Raw(bytes) => {
3090 let mut data = bytes.as_ref();
3091 let decoded = FoundryTxEnvelope::decode_2718(&mut data)
3092 .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3093 PendingTransaction::new(decoded)?
3094 }
3095
3096 TransactionData::JSON(request) => {
3097 let from = request.from.map(Ok).unwrap_or_else(|| {
3098 self.accounts()?
3099 .first()
3100 .copied()
3101 .ok_or(BlockchainError::NoSignerAvailable)
3102 })?;
3103
3104 let curr_nonce = nonces.entry(from).or_insert(
3106 self.get_transaction_count(
3107 from,
3108 Some(common_block.header.number().into()),
3109 )
3110 .await?,
3111 );
3112
3113 let typed_tx = self.build_tx_request(request.into(), *curr_nonce).await?;
3115
3116 *curr_nonce += 1;
3118
3119 if self.is_impersonated(from) {
3121 let transaction = sign::build_impersonated(typed_tx);
3122 self.ensure_typed_transaction_supported(&transaction)?;
3123 PendingTransaction::with_impersonated(transaction, from)
3124 } else {
3125 let transaction = self.sign_request(&from, typed_tx)?;
3126 self.ensure_typed_transaction_supported(&transaction)?;
3127 PendingTransaction::new(transaction)?
3128 }
3129 }
3130 };
3131
3132 let pooled = PoolTransaction::new(pending);
3133 txs.entry(block_index).or_default().push(Arc::new(pooled));
3134 }
3135
3136 txs
3137 };
3138
3139 self.backend.reorg(depth, block_pool_txs, common_block).await?;
3140 Ok(())
3141 }
3142
3143 pub async fn evm_mine(&self, opts: Option<MineOptions>) -> Result<String> {
3150 node_info!("evm_mine");
3151
3152 self.do_evm_mine(opts).await?;
3153
3154 Ok("0x0".to_string())
3155 }
3156
3157 pub async fn evm_mine_detailed(&self, opts: Option<MineOptions>) -> Result<Vec<AnyRpcBlock>> {
3167 node_info!("evm_mine_detailed");
3168
3169 let mined_blocks = self.do_evm_mine(opts).await?;
3170
3171 let mut blocks = Vec::with_capacity(mined_blocks as usize);
3172
3173 let latest = self.backend.best_number();
3174 for offset in (0..mined_blocks).rev() {
3175 let block_num = latest - offset;
3176 if let Some(mut block) =
3177 self.backend.block_by_number_full(BlockNumber::Number(block_num)).await?
3178 {
3179 let block_txs = match block.transactions_mut() {
3180 BlockTransactions::Full(txs) => txs,
3181 BlockTransactions::Hashes(_) | BlockTransactions::Uncle => unreachable!(),
3182 };
3183 for tx in block_txs.iter_mut() {
3184 if let Some(receipt) = self.backend.mined_transaction_receipt(tx.tx_hash())
3185 && let Some(output) = receipt.out
3186 {
3187 if !receipt.inner.as_ref().status()
3189 && let Some(reason) = RevertDecoder::new().maybe_decode(&output, None)
3190 {
3191 tx.other.insert(
3192 "revertReason".to_string(),
3193 serde_json::to_value(reason).expect("Infallible"),
3194 );
3195 }
3196 tx.other.insert(
3197 "output".to_string(),
3198 serde_json::to_value(output).expect("Infallible"),
3199 );
3200 }
3201 }
3202 block.transactions = BlockTransactions::Full(block_txs.clone());
3203 blocks.push(block);
3204 }
3205 }
3206
3207 Ok(blocks)
3208 }
3209
3210 pub async fn eth_send_unsigned_transaction(
3214 &self,
3215 request: WithOtherFields<TransactionRequest>,
3216 ) -> Result<TxHash> {
3217 node_info!("eth_sendUnsignedTransaction");
3218 let from = request.from.ok_or(BlockchainError::NoSignerAvailable)?;
3220
3221 let (nonce, on_chain_nonce) = self.request_nonce(&request, from).await?;
3222
3223 let typed_tx = self.build_tx_request(request, nonce).await?;
3224
3225 let transaction = sign::build_impersonated(typed_tx);
3226
3227 self.ensure_typed_transaction_supported(&transaction)?;
3228
3229 let pending_transaction = PendingTransaction::with_impersonated(transaction, from);
3230
3231 self.backend.validate_pool_transaction(&pending_transaction).await?;
3233
3234 let (requires, provides) = if let Some((requires, provides)) =
3235 tempo_parallel_nonce_markers(&pending_transaction)
3236 {
3237 (requires, provides)
3238 } else {
3239 (required_marker(nonce, on_chain_nonce, from), vec![to_marker(nonce, from)])
3240 };
3241
3242 self.add_pending_transaction(pending_transaction, requires, provides)
3243 }
3244
3245 pub async fn txpool_inspect(&self) -> Result<TxpoolInspect> {
3252 node_info!("txpool_inspect");
3253 let mut inspect = TxpoolInspect::default();
3254
3255 fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> TxpoolInspectSummary {
3256 let tx = &tx.pending_transaction.transaction;
3257 let to = tx.to();
3258 let gas_price = tx.max_fee_per_gas();
3259 let value = tx.value();
3260 let gas = tx.gas_limit();
3261 TxpoolInspectSummary { to, value, gas, gas_price }
3262 }
3263
3264 for pending in self.pool.ready_transactions() {
3271 let entry = inspect.pending.entry(*pending.pending_transaction.sender()).or_default();
3272 let key = txpool_transaction_key(&pending.pending_transaction);
3273 entry.insert(key, convert(pending));
3274 }
3275 for queued in self.pool.pending_transactions() {
3276 let entry = inspect.queued.entry(*queued.pending_transaction.sender()).or_default();
3277 let key = txpool_transaction_key(&queued.pending_transaction);
3278 entry.insert(key, convert(queued));
3279 }
3280 Ok(inspect)
3281 }
3282
3283 pub async fn txpool_content(&self) -> Result<TxpoolContent<AnyRpcTransaction>> {
3290 node_info!("txpool_content");
3291 let mut content = TxpoolContent::<AnyRpcTransaction>::default();
3292 fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> Result<AnyRpcTransaction> {
3293 let from = *tx.pending_transaction.sender();
3294 let tx = transaction_build(
3295 Some(tx.hash()),
3296 tx.pending_transaction.transaction.clone(),
3297 None,
3298 None,
3299 None,
3300 );
3301
3302 let WithOtherFields { inner: mut tx, other } = tx.0;
3303
3304 tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3307
3308 let tx = AnyRpcTransaction(WithOtherFields { inner: tx, other });
3309
3310 Ok(tx)
3311 }
3312
3313 for pending in self.pool.ready_transactions() {
3314 let entry = content.pending.entry(*pending.pending_transaction.sender()).or_default();
3315 let key = txpool_transaction_key(&pending.pending_transaction);
3316 entry.insert(key, convert(pending)?);
3317 }
3318 for queued in self.pool.pending_transactions() {
3319 let entry = content.queued.entry(*queued.pending_transaction.sender()).or_default();
3320 let key = txpool_transaction_key(&queued.pending_transaction);
3321 entry.insert(key, convert(queued)?);
3322 }
3323
3324 Ok(content)
3325 }
3326}
3327
3328impl EthApi<FoundryNetwork> {
3329 async fn do_evm_mine(&self, opts: Option<MineOptions>) -> Result<u64> {
3331 let mut blocks_to_mine = 1u64;
3332
3333 if let Some(opts) = opts {
3334 let timestamp = match opts {
3335 MineOptions::Timestamp(timestamp) => timestamp,
3336 MineOptions::Options { timestamp, blocks } => {
3337 if let Some(blocks) = blocks {
3338 blocks_to_mine = blocks;
3339 }
3340 timestamp
3341 }
3342 };
3343 if let Some(timestamp) = timestamp {
3344 self.evm_set_next_block_timestamp(timestamp)?;
3346 }
3347 }
3348
3349 self.on_blocking_task(|this| async move {
3352 for _ in 0..blocks_to_mine {
3354 this.mine_one().await;
3355 }
3356 Ok(())
3357 })
3358 .await?;
3359
3360 Ok(blocks_to_mine)
3361 }
3362
3363 async fn do_estimate_gas(
3364 &self,
3365 request: WithOtherFields<TransactionRequest>,
3366 block_number: Option<BlockId>,
3367 overrides: EvmOverrides,
3368 ) -> Result<u128> {
3369 let block_request = self.block_request(block_number).await?;
3370 if let BlockRequest::Number(number) = block_request
3372 && let Some(fork) = self.get_fork()
3373 && fork.predates_fork(number)
3374 {
3375 if overrides.has_state() || overrides.has_block() {
3376 return Err(BlockchainError::EvmOverrideError(
3377 "not available on past forked blocks".to_string(),
3378 ));
3379 }
3380 return Ok(fork.estimate_gas(&request, Some(number.into())).await?);
3381 }
3382
3383 self.on_blocking_task(|this| async move {
3386 this.backend
3387 .with_database_at(Some(block_request), |state, mut block| {
3388 let mut cache_db = CacheDB::new(state);
3389 if let Some(state_overrides) = overrides.state {
3390 apply_state_overrides(
3391 state_overrides.into_iter().collect(),
3392 &mut cache_db,
3393 )?;
3394 }
3395 if let Some(block_overrides) = overrides.block {
3396 cache_db.apply_block_overrides(*block_overrides, &mut block);
3397 }
3398 this.do_estimate_gas_with_state(request, &cache_db, block)
3399 })
3400 .await?
3401 })
3402 .await
3403 }
3404
3405 fn transaction_priority(&self, tx: &FoundryTxEnvelope) -> TransactionPriority {
3407 self.transaction_order.read().priority(tx)
3408 }
3409
3410 pub fn full_pending_transactions(&self) -> UnboundedReceiver<AnyRpcTransaction> {
3412 let (tx, rx) = unbounded_channel();
3413 let mut hashes = self.new_ready_transactions();
3414
3415 let this = self.clone();
3416
3417 tokio::spawn(async move {
3418 while let Some(hash) = hashes.next().await {
3419 if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
3420 && tx.send(txn).is_err()
3421 {
3422 break;
3423 }
3424 }
3425 });
3426
3427 rx
3428 }
3429
3430 pub async fn mine_one(&self) {
3432 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
3433 let outcome = self.backend.mine_block(transactions).await;
3434
3435 trace!(target: "node", blocknumber = ?outcome.block_number, "mined block");
3436 self.pool.on_mined_block(outcome);
3437 }
3438
3439 async fn pending_block(&self) -> AnyRpcBlock {
3441 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
3442 let info = self.backend.pending_block(transactions).await;
3443 self.backend.convert_block(info.block)
3444 }
3445
3446 async fn pending_block_full(&self) -> Option<AnyRpcBlock> {
3448 let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
3449 let BlockInfo { block, transactions, receipts: _ } =
3450 self.backend.pending_block(transactions).await;
3451
3452 let mut partial_block = self.backend.convert_block(block.clone());
3453
3454 let mut block_transactions = Vec::with_capacity(block.body.transactions.len());
3455 let base_fee = self.backend.base_fee();
3456
3457 for info in transactions {
3458 let tx = block.body.transactions.get(info.transaction_index as usize)?.clone();
3459
3460 let tx = transaction_build(
3461 Some(info.transaction_hash),
3462 tx,
3463 Some(&block),
3464 Some(info),
3465 Some(base_fee),
3466 );
3467 block_transactions.push(tx);
3468 }
3469
3470 partial_block.transactions = BlockTransactions::from(block_transactions);
3471
3472 Some(partial_block)
3473 }
3474
3475 async fn build_tx_request(
3478 &self,
3479 request: WithOtherFields<TransactionRequest>,
3480 nonce: u64,
3481 ) -> Result<FoundryTypedTx> {
3482 let mut request = Into::<FoundryTransactionRequest>::into(request);
3483 let from = request.from().or(self.accounts()?.first().copied());
3484 if let Some(from) = from {
3485 request.set_from(from);
3486 }
3487
3488 request.chain_id().is_none().then(|| request.set_chain_id(self.chain_id()));
3490 request.nonce().is_none().then(|| request.set_nonce(nonce));
3491 request.kind().is_none().then(|| request.set_kind(TxKind::default()));
3492 if request.gas_limit().is_none() {
3493 let fallback_gas_limit = {
3494 let evm_env = self.backend.evm_env().read();
3495 let block_gas_limit = evm_env.block_env.gas_limit;
3496 if evm_env.cfg_env.tx_gas_limit_cap.is_none() {
3497 block_gas_limit.min(evm_env.cfg_env().tx_gas_limit_cap())
3498 } else {
3499 block_gas_limit
3500 }
3501 };
3502 let estimated_gas = self
3503 .do_estimate_gas(request.as_ref().clone().into(), None, EvmOverrides::default())
3504 .await
3505 .map(|v| v as u64)
3506 .unwrap_or_else(|_| {
3507 if is_simple_transfer_request(request.as_ref()) {
3508 MIN_TRANSACTION_GAS as u64
3509 } else {
3510 fallback_gas_limit
3511 }
3512 });
3513 request.set_gas_limit(estimated_gas);
3514 }
3515
3516 if let Err((tx_type, _)) = request.missing_keys() {
3518 if matches!(tx_type, FoundryTxType::Legacy | FoundryTxType::Eip2930) {
3519 request.gas_price().is_none().then(|| request.set_gas_price(self.gas_price()));
3520 }
3521 if tx_type == FoundryTxType::Eip2930 {
3522 request
3523 .access_list()
3524 .is_none()
3525 .then(|| request.set_access_list(Default::default()));
3526 }
3527 if matches!(
3528 tx_type,
3529 FoundryTxType::Eip1559
3530 | FoundryTxType::Eip4844
3531 | FoundryTxType::Eip7702
3532 | FoundryTxType::Tempo
3533 ) {
3534 request
3535 .max_fee_per_gas()
3536 .is_none()
3537 .then(|| request.set_max_fee_per_gas(self.gas_price()));
3538 request
3539 .max_priority_fee_per_gas()
3540 .is_none()
3541 .then(|| request.set_max_priority_fee_per_gas(MIN_SUGGESTED_PRIORITY_FEE));
3542 }
3543 if tx_type == FoundryTxType::Eip4844 {
3544 request.as_ref().max_fee_per_blob_gas().is_none().then(|| {
3545 request.as_mut().set_max_fee_per_blob_gas(
3546 self.backend.fees().get_next_block_blob_base_fee_per_gas(),
3547 )
3548 });
3549 }
3550 }
3551
3552 match request
3553 .build_unsigned()
3554 .map_err(|e| BlockchainError::InvalidTransactionRequest(e.to_string()))?
3555 {
3556 FoundryTypedTx::Eip4844(TxEip4844Variant::TxEip4844(_))
3557 if !self.backend.skip_blob_validation(from) =>
3558 {
3559 Err(BlockchainError::FailedToDecodeTransaction)
3561 }
3562 res => Ok(res),
3563 }
3564 }
3565
3566 async fn get_transaction_count(
3568 &self,
3569 address: Address,
3570 block_number: Option<BlockId>,
3571 ) -> Result<u64> {
3572 let block_request = self.block_request(block_number).await?;
3573
3574 if let BlockRequest::Number(number) = block_request
3575 && let Some(fork) = self.get_fork()
3576 && fork.predates_fork(number)
3577 {
3578 return Ok(fork.get_nonce(address, number).await?);
3579 }
3580
3581 self.backend.get_nonce(address, block_request).await
3582 }
3583
3584 async fn request_nonce(
3592 &self,
3593 request: &TransactionRequest,
3594 from: Address,
3595 ) -> Result<(u64, u64)> {
3596 let highest_nonce =
3597 self.get_transaction_count(from, Some(BlockId::Number(BlockNumber::Pending))).await?;
3598 let nonce = request.nonce.unwrap_or(highest_nonce);
3599
3600 Ok((nonce, highest_nonce))
3601 }
3602
3603 fn add_pending_transaction(
3605 &self,
3606 pending_transaction: PendingTransaction<FoundryTxEnvelope>,
3607 requires: Vec<TxMarker>,
3608 provides: Vec<TxMarker>,
3609 ) -> Result<TxHash> {
3610 debug_assert!(requires != provides);
3611 let from = *pending_transaction.sender();
3612 let priority = self.transaction_priority(&pending_transaction.transaction);
3613 let pool_transaction =
3614 PoolTransaction { requires, provides, pending_transaction, priority };
3615 let tx = self.pool.add_transaction(pool_transaction)?;
3616 trace!(target: "node", "Added transaction: [{:?}] sender={:?}", tx.hash(), from);
3617 Ok(*tx.hash())
3618 }
3619
3620 fn ensure_typed_transaction_supported(&self, tx: &FoundryTxEnvelope) -> Result<()> {
3622 match &tx {
3623 FoundryTxEnvelope::Eip2930(_) => self.backend.ensure_eip2930_active(),
3624 FoundryTxEnvelope::Eip1559(_) => self.backend.ensure_eip1559_active(),
3625 FoundryTxEnvelope::Eip4844(_) => self.backend.ensure_eip4844_active(),
3626 FoundryTxEnvelope::Eip7702(_) => self.backend.ensure_eip7702_active(),
3627 #[cfg(feature = "optimism")]
3628 FoundryTxEnvelope::Deposit(_) => self.backend.ensure_op_deposits_active(),
3629 #[cfg(feature = "optimism")]
3630 FoundryTxEnvelope::PostExec(_) => Err(BlockchainError::InvalidTransactionRequest(
3631 "not implemented for post-exec tx".to_string(),
3632 )),
3633 FoundryTxEnvelope::Legacy(_) => Ok(()),
3634 FoundryTxEnvelope::Tempo(_) => self.backend.ensure_tempo_active(),
3635 }
3636 }
3637
3638 pub async fn anvil_set_fee_token(&self, user: Address, token: Address) -> Result<()> {
3644 node_info!("anvil_setFeeToken");
3645 if !self.backend.is_tempo() {
3646 return Err(BlockchainError::RpcUnimplemented);
3647 }
3648 self.backend.set_fee_token(user, token).await?;
3649 Ok(())
3650 }
3651
3652 pub async fn anvil_set_validator_fee_token(
3658 &self,
3659 validator: Address,
3660 token: Address,
3661 ) -> Result<()> {
3662 node_info!("anvil_setValidatorFeeToken");
3663 if !self.backend.is_tempo() {
3664 return Err(BlockchainError::RpcUnimplemented);
3665 }
3666 self.backend.set_validator_fee_token(validator, token).await?;
3667 Ok(())
3668 }
3669
3670 pub async fn anvil_set_fee_amm_liquidity(
3676 &self,
3677 user_token: Address,
3678 validator_token: Address,
3679 amount: U256,
3680 ) -> Result<()> {
3681 node_info!("anvil_setFeeAmmLiquidity");
3682 if !self.backend.is_tempo() {
3683 return Err(BlockchainError::RpcUnimplemented);
3684 }
3685 self.backend.set_fee_amm_liquidity(user_token, validator_token, amount).await?;
3686 Ok(())
3687 }
3688}
3689
3690fn is_simple_transfer_request(request: &TransactionRequest) -> bool {
3691 request.to.as_ref().and_then(TxKind::to).is_some()
3692 && (request.input.input().is_none()
3693 || request.input.input().is_some_and(|data| data.is_empty()))
3694 && request.authorization_list.is_none()
3695 && request.access_list.is_none()
3696 && request.blob_versioned_hashes.is_none()
3697}
3698
3699fn required_marker(provided_nonce: u64, on_chain_nonce: u64, from: Address) -> Vec<TxMarker> {
3700 if provided_nonce == on_chain_nonce {
3701 return Vec::new();
3702 }
3703 let prev_nonce = provided_nonce.saturating_sub(1);
3704 if on_chain_nonce <= prev_nonce { vec![to_marker(prev_nonce, from)] } else { Vec::new() }
3705}
3706
3707fn tempo_parallel_nonce_markers(
3708 pending_transaction: &PendingTransaction<FoundryTxEnvelope>,
3709) -> Option<(Vec<TxMarker>, Vec<TxMarker>)> {
3710 pending_transaction
3713 .transaction
3714 .as_ref()
3715 .has_nonzero_tempo_nonce_key()
3716 .then(|| (vec![], vec![pending_transaction.hash().to_vec()]))
3717}
3718
3719fn txpool_transaction_key(pending_transaction: &PendingTransaction<FoundryTxEnvelope>) -> String {
3720 match pending_transaction.transaction.as_ref() {
3721 FoundryTxEnvelope::Tempo(tx) if !tx.tx().nonce_key.is_zero() => {
3722 let tx = tx.tx();
3723 format!("{}:{}", tx.nonce_key, tx.nonce)
3724 }
3725 _ => pending_transaction.nonce().to_string(),
3726 }
3727}
3728
3729fn convert_transact_out(out: &Option<Output>) -> Bytes {
3730 match out {
3731 None => Default::default(),
3732 Some(Output::Call(out)) => out.to_vec().into(),
3733 Some(Output::Create(out, _)) => out.to_vec().into(),
3734 }
3735}
3736
3737fn ensure_return_ok(exit: InstructionResult, out: &Option<Output>) -> Result<Bytes> {
3739 let out = convert_transact_out(out);
3740 match exit {
3741 return_ok!() => Ok(out),
3742 return_revert!() => Err(InvalidTransactionError::Revert(Some(out)).into()),
3743 reason => Err(BlockchainError::EvmError(reason)),
3744 }
3745}
3746
3747fn execution_error(exit: InstructionResult) -> Option<String> {
3750 match SuccessOrHalt::<HaltReason>::from(exit) {
3751 SuccessOrHalt::Success(_) => None,
3752 SuccessOrHalt::Revert => Some("execution reverted".to_string()),
3753 SuccessOrHalt::Halt(reason) => Some(reason.to_string()),
3754 SuccessOrHalt::FatalExternalError => Some("fatal external error".to_string()),
3755 SuccessOrHalt::Internal(_) => Some("internal EVM error".to_string()),
3756 }
3757}
3758
3759fn determine_base_gas_by_kind(request: &WithOtherFields<TransactionRequest>) -> u128 {
3761 match request.kind() {
3762 Some(TxKind::Call(_)) => {
3763 MIN_TRANSACTION_GAS
3764 + request.inner().authorization_list.as_ref().map_or(0, |auths_list| {
3765 auths_list.len() as u128 * PER_EMPTY_ACCOUNT_COST as u128
3766 })
3767 }
3768 Some(TxKind::Create) => MIN_CREATE_GAS,
3769 None => MIN_CREATE_GAS,
3771 }
3772}
3773
3774enum GasEstimationCallResult {
3776 Success(u128),
3777 OutOfGas,
3778 Revert(Option<Bytes>),
3779 EvmError(InstructionResult),
3780}
3781
3782impl TryFrom<Result<(InstructionResult, Option<Output>, u128, State)>> for GasEstimationCallResult {
3786 type Error = BlockchainError;
3787
3788 fn try_from(res: Result<(InstructionResult, Option<Output>, u128, State)>) -> Result<Self> {
3789 match res {
3790 Err(BlockchainError::InvalidTransaction(InvalidTransactionError::GasTooHigh(_))) => {
3792 Ok(Self::OutOfGas)
3793 }
3794 Err(BlockchainError::Message(ref msg))
3796 if msg.contains("insufficient gas for intrinsic cost") =>
3797 {
3798 Ok(Self::OutOfGas)
3799 }
3800 Err(err) => Err(err),
3801 Ok((exit, output, gas, _)) => match exit {
3802 return_ok!() => Ok(Self::Success(gas)),
3803
3804 InstructionResult::Revert => {
3806 Ok(Self::Revert(Some(output.map(|o| o.into_data()).unwrap_or_default())))
3807 }
3808 InstructionResult::CallTooDeep
3809 | InstructionResult::OutOfFunds
3810 | InstructionResult::CreateInitCodeStartingEF00
3811 | InstructionResult::InvalidEOFInitCode
3812 | InstructionResult::InvalidExtDelegateCallTarget => Ok(Self::EvmError(exit)),
3813
3814 InstructionResult::OutOfGas
3816 | InstructionResult::MemoryOOG
3817 | InstructionResult::MemoryLimitOOG
3818 | InstructionResult::PrecompileOOG
3819 | InstructionResult::InvalidOperandOOG
3820 | InstructionResult::ReentrancySentryOOG => Ok(Self::OutOfGas),
3821
3822 InstructionResult::OpcodeNotFound
3824 | InstructionResult::CallNotAllowedInsideStatic
3825 | InstructionResult::StateChangeDuringStaticCall
3826 | InstructionResult::InvalidFEOpcode
3827 | InstructionResult::InvalidJump
3828 | InstructionResult::NotActivated
3829 | InstructionResult::StackUnderflow
3830 | InstructionResult::StackOverflow
3831 | InstructionResult::OutOfOffset
3832 | InstructionResult::CreateCollision
3833 | InstructionResult::OverflowPayment
3834 | InstructionResult::PrecompileError
3835 | InstructionResult::NonceOverflow
3836 | InstructionResult::CreateContractSizeLimit
3837 | InstructionResult::CreateContractStartingWithEF
3838 | InstructionResult::CreateInitCodeSizeLimit
3839 | InstructionResult::InvalidImmediateEncoding
3840 | InstructionResult::FatalExternalError => Ok(Self::EvmError(exit)),
3841 },
3842 }
3843 }
3844}