reth_optimism_evm/
execute.rs
1use crate::{OpEvmConfig, OpRethReceiptBuilder};
4use alloc::sync::Arc;
5use reth_evm::execute::BasicBlockExecutorProvider;
6use reth_optimism_chainspec::OpChainSpec;
7
8#[derive(Debug)]
10pub struct OpExecutorProvider;
11
12impl OpExecutorProvider {
13 pub fn optimism(chain_spec: Arc<OpChainSpec>) -> BasicBlockExecutorProvider<OpEvmConfig> {
15 BasicBlockExecutorProvider::new(OpEvmConfig::new(
16 chain_spec,
17 OpRethReceiptBuilder::default(),
18 ))
19 }
20}
21
22#[cfg(test)]
23mod tests {
24 use super::*;
25 use crate::OpChainSpec;
26 use alloy_consensus::{Block, BlockBody, Header, SignableTransaction, TxEip1559};
27 use alloy_primitives::{b256, Address, Signature, StorageKey, StorageValue, U256};
28 use op_alloy_consensus::TxDeposit;
29 use op_revm::constants::L1_BLOCK_CONTRACT;
30 use reth_chainspec::MIN_TRANSACTION_GAS;
31 use reth_evm::execute::{BasicBlockExecutorProvider, BlockExecutorProvider, Executor};
32 use reth_optimism_chainspec::OpChainSpecBuilder;
33 use reth_optimism_primitives::{OpReceipt, OpTransactionSigned};
34 use reth_primitives_traits::{Account, RecoveredBlock};
35 use reth_revm::{database::StateProviderDatabase, test_utils::StateProviderTest};
36 use std::{collections::HashMap, str::FromStr};
37
38 fn create_op_state_provider() -> StateProviderTest {
39 let mut db = StateProviderTest::default();
40
41 let l1_block_contract_account =
42 Account { balance: U256::ZERO, bytecode_hash: None, nonce: 1 };
43
44 let mut l1_block_storage = HashMap::default();
45 l1_block_storage.insert(StorageKey::with_last_byte(1), StorageValue::from(1000000000));
47 l1_block_storage.insert(StorageKey::with_last_byte(5), StorageValue::from(188));
49 l1_block_storage.insert(StorageKey::with_last_byte(6), StorageValue::from(684000));
51 l1_block_storage.insert(
53 StorageKey::with_last_byte(3),
54 StorageValue::from_str(
55 "0x0000000000000000000000000000000000001db0000d27300000000000000005",
56 )
57 .unwrap(),
58 );
59
60 db.insert_account(L1_BLOCK_CONTRACT, l1_block_contract_account, None, l1_block_storage);
61
62 db
63 }
64
65 fn executor_provider(chain_spec: Arc<OpChainSpec>) -> BasicBlockExecutorProvider<OpEvmConfig> {
66 BasicBlockExecutorProvider::new(OpEvmConfig::new(
67 chain_spec,
68 OpRethReceiptBuilder::default(),
69 ))
70 }
71
72 #[test]
73 fn op_deposit_fields_pre_canyon() {
74 let header = Header {
75 timestamp: 1,
76 number: 1,
77 gas_limit: 1_000_000,
78 gas_used: 42_000,
79 receipts_root: b256!(
80 "0x83465d1e7d01578c0d609be33570f91242f013e9e295b0879905346abbd63731"
81 ),
82 ..Default::default()
83 };
84
85 let mut db = create_op_state_provider();
86
87 let addr = Address::ZERO;
88 let account = Account { balance: U256::MAX, ..Account::default() };
89 db.insert_account(addr, account, None, HashMap::default());
90
91 let chain_spec = Arc::new(OpChainSpecBuilder::base_mainnet().regolith_activated().build());
92
93 let tx: OpTransactionSigned = TxEip1559 {
94 chain_id: chain_spec.chain.id(),
95 nonce: 0,
96 gas_limit: MIN_TRANSACTION_GAS,
97 to: addr.into(),
98 ..Default::default()
99 }
100 .into_signed(Signature::test_signature())
101 .into();
102
103 let tx_deposit: OpTransactionSigned = TxDeposit {
104 from: addr,
105 to: addr.into(),
106 gas_limit: MIN_TRANSACTION_GAS,
107 ..Default::default()
108 }
109 .into();
110
111 let provider = executor_provider(chain_spec);
112 let mut executor = provider.executor(StateProviderDatabase::new(&db));
113
114 executor.with_state_mut(|state| {
116 state.load_cache_account(L1_BLOCK_CONTRACT).unwrap();
117 });
118
119 let output = executor
121 .execute(&RecoveredBlock::new_unhashed(
122 Block {
123 header,
124 body: BlockBody { transactions: vec![tx, tx_deposit], ..Default::default() },
125 },
126 vec![addr, addr],
127 ))
128 .unwrap();
129
130 let receipts = &output.receipts;
131 let tx_receipt = &receipts[0];
132 let deposit_receipt = &receipts[1];
133
134 assert!(!matches!(tx_receipt, OpReceipt::Deposit(_)));
135 let OpReceipt::Deposit(deposit_receipt) = deposit_receipt else {
137 panic!("expected deposit")
138 };
139 assert!(deposit_receipt.deposit_nonce.is_some());
140 assert!(deposit_receipt.deposit_receipt_version.is_none());
142 }
143
144 #[test]
145 fn op_deposit_fields_post_canyon() {
146 let header = Header {
148 timestamp: 2,
149 number: 1,
150 gas_limit: 1_000_000,
151 gas_used: 42_000,
152 receipts_root: b256!(
153 "0xfffc85c4004fd03c7bfbe5491fae98a7473126c099ac11e8286fd0013f15f908"
154 ),
155 ..Default::default()
156 };
157
158 let mut db = create_op_state_provider();
159 let addr = Address::ZERO;
160 let account = Account { balance: U256::MAX, ..Account::default() };
161
162 db.insert_account(addr, account, None, HashMap::default());
163
164 let chain_spec = Arc::new(OpChainSpecBuilder::base_mainnet().canyon_activated().build());
165
166 let tx: OpTransactionSigned = TxEip1559 {
167 chain_id: chain_spec.chain.id(),
168 nonce: 0,
169 gas_limit: MIN_TRANSACTION_GAS,
170 to: addr.into(),
171 ..Default::default()
172 }
173 .into_signed(Signature::test_signature())
174 .into();
175
176 let tx_deposit: OpTransactionSigned = TxDeposit {
177 from: addr,
178 to: addr.into(),
179 gas_limit: MIN_TRANSACTION_GAS,
180 ..Default::default()
181 }
182 .into();
183
184 let provider = executor_provider(chain_spec);
185 let mut executor = provider.executor(StateProviderDatabase::new(&db));
186
187 executor.with_state_mut(|state| {
189 state.load_cache_account(L1_BLOCK_CONTRACT).unwrap();
190 });
191
192 let output = executor
194 .execute(&RecoveredBlock::new_unhashed(
195 Block {
196 header,
197 body: BlockBody { transactions: vec![tx, tx_deposit], ..Default::default() },
198 },
199 vec![addr, addr],
200 ))
201 .expect("Executing a block while canyon is active should not fail");
202
203 let receipts = &output.receipts;
204 let tx_receipt = &receipts[0];
205 let deposit_receipt = &receipts[1];
206
207 assert!(!matches!(tx_receipt, OpReceipt::Deposit(_)));
209 let OpReceipt::Deposit(deposit_receipt) = deposit_receipt else {
210 panic!("expected deposit")
211 };
212 assert_eq!(deposit_receipt.deposit_receipt_version, Some(1));
213
214 assert!(deposit_receipt.deposit_nonce.is_some());
216 }
217}