anvil/eth/backend/executor/
optimism.rs1use alloy_consensus::{Eip658Value, Receipt, ReceiptWithBloom, Transaction};
4use alloy_eips::Encodable2718;
5use alloy_primitives::{Address, Log};
6use foundry_evm::hardfork::{FoundryHardfork, OpHardfork};
7use foundry_primitives::{FoundryReceiptEnvelope, FoundryTxEnvelope};
8use op_alloy_consensus::{OpDepositReceipt, OpDepositReceiptWithBloom};
9use op_revm::{L1BlockInfo, estimate_tx_compressed_size};
10use revm::{Database, context_interface::result::ExecutionResult, state::EvmState};
11
12use super::AnvilBlockExecutor;
13
14impl<E> AnvilBlockExecutor<E> {
15 pub(crate) fn set_optimism_hardfork(&mut self, hardfork: FoundryHardfork) {
17 self.optimism_jovian = OpHardfork::from(hardfork) >= OpHardfork::Jovian;
18 }
19}
20
21pub(crate) fn blob_gas_used<DB: Database>(
23 db: &mut DB,
24 tx: &FoundryTxEnvelope,
25 jovian: bool,
26) -> Result<u64, alloy_evm::block::BlockExecutionError> {
27 if !jovian || matches!(tx, FoundryTxEnvelope::Deposit(_)) {
28 return Ok(tx.blob_gas_used().unwrap_or_default());
29 }
30
31 let encoded = estimate_tx_compressed_size(tx.encoded_2718().as_ref()).saturating_div(1_000_000);
32 let scalar = L1BlockInfo::fetch_da_footprint_gas_scalar(db)
33 .map_err(alloy_evm::block::BlockExecutionError::other)?;
34 Ok(encoded.saturating_mul(u64::from(scalar)))
35}
36
37pub(crate) fn build_mined_deposit_receipt<H>(
39 result: ExecutionResult<H>,
40 state: &EvmState,
41 sender: Address,
42 cumulative_gas_used: u64,
43) -> FoundryReceiptEnvelope {
44 let deposit_nonce = state.get(&sender).map(|account| account.info.nonce);
45 build_deposit_receipt(result, cumulative_gas_used, deposit_nonce, deposit_nonce.map(|_| 1))
46}
47
48pub(crate) fn build_simulated_deposit_receipt<H>(
50 hardfork: FoundryHardfork,
51 caller_nonce: u64,
52 result: &ExecutionResult<H>,
53 logs: Vec<Log>,
54 cumulative_gas_used: u64,
55) -> FoundryReceiptEnvelope {
56 let hardfork = OpHardfork::from(hardfork);
57 let deposit_nonce = (hardfork >= OpHardfork::Regolith).then_some(caller_nonce);
58 let deposit_receipt_version = (hardfork >= OpHardfork::Canyon).then_some(1);
59 let receipt =
60 Receipt { status: Eip658Value::Eip658(result.is_success()), cumulative_gas_used, logs }
61 .with_bloom();
62 wrap_deposit_receipt(receipt, deposit_nonce, deposit_receipt_version)
63}
64
65fn build_deposit_receipt<H>(
66 result: ExecutionResult<H>,
67 cumulative_gas_used: u64,
68 deposit_nonce: Option<u64>,
69 deposit_receipt_version: Option<u64>,
70) -> FoundryReceiptEnvelope {
71 let receipt = Receipt {
72 status: Eip658Value::Eip658(result.is_success()),
73 cumulative_gas_used,
74 logs: result.into_logs(),
75 }
76 .with_bloom();
77 wrap_deposit_receipt(receipt, deposit_nonce, deposit_receipt_version)
78}
79
80fn wrap_deposit_receipt(
81 receipt: ReceiptWithBloom<Receipt>,
82 deposit_nonce: Option<u64>,
83 deposit_receipt_version: Option<u64>,
84) -> FoundryReceiptEnvelope {
85 FoundryReceiptEnvelope::Deposit(OpDepositReceiptWithBloom {
86 receipt: OpDepositReceipt {
87 inner: receipt.receipt,
88 deposit_nonce,
89 deposit_receipt_version,
90 },
91 logs_bloom: receipt.logs_bloom,
92 })
93}