1use crate::{
2 db::Database,
3 interpreter::{
4 analysis::to_analysed, gas, return_ok, AccountLoad, Eip7702CodeLoad, InstructionResult,
5 InterpreterResult, SStoreResult, SelfDestructResult, StateLoad,
6 },
7 journaled_state::JournaledState,
8 primitives::{
9 AccessListItem, Account, Address, AnalysisKind, Bytecode, Bytes, CfgEnv, EVMError, Env,
10 Eof, HashSet, Spec,
11 SpecId::{self, *},
12 B256, EOF_MAGIC_BYTES, EOF_MAGIC_HASH, U256,
13 },
14 JournalCheckpoint,
15};
16use std::{boxed::Box, sync::Arc};
17
18#[derive(Debug)]
20pub struct InnerEvmContext<DB: Database> {
21 pub env: Box<Env>,
24 pub journaled_state: JournaledState,
26 pub db: DB,
28 pub error: Result<(), EVMError<DB::Error>>,
30 #[cfg(feature = "optimism")]
32 pub l1_block_info: Option<crate::optimism::L1BlockInfo>,
33}
34
35impl<DB: Database + Clone> Clone for InnerEvmContext<DB>
36where
37 DB::Error: Clone,
38{
39 fn clone(&self) -> Self {
40 Self {
41 env: self.env.clone(),
42 journaled_state: self.journaled_state.clone(),
43 db: self.db.clone(),
44 error: self.error.clone(),
45 #[cfg(feature = "optimism")]
46 l1_block_info: self.l1_block_info.clone(),
47 }
48 }
49}
50
51impl<DB: Database> InnerEvmContext<DB> {
52 pub fn new(db: DB) -> Self {
53 Self {
54 env: Box::default(),
55 journaled_state: JournaledState::new(SpecId::LATEST, HashSet::default()),
56 db,
57 error: Ok(()),
58 #[cfg(feature = "optimism")]
59 l1_block_info: None,
60 }
61 }
62
63 #[inline]
65 pub fn new_with_env(db: DB, env: Box<Env>) -> Self {
66 Self {
67 env,
68 journaled_state: JournaledState::new(SpecId::LATEST, HashSet::default()),
69 db,
70 error: Ok(()),
71 #[cfg(feature = "optimism")]
72 l1_block_info: None,
73 }
74 }
75
76 #[inline]
80 pub fn with_db<ODB: Database>(self, db: ODB) -> InnerEvmContext<ODB> {
81 InnerEvmContext {
82 env: self.env,
83 journaled_state: self.journaled_state,
84 db,
85 error: Ok(()),
86 #[cfg(feature = "optimism")]
87 l1_block_info: self.l1_block_info,
88 }
89 }
90
91 #[inline]
93 pub const fn spec_id(&self) -> SpecId {
94 self.journaled_state.spec
95 }
96
97 #[inline]
101 pub fn load_access_list(&mut self) -> Result<(), EVMError<DB::Error>> {
102 for AccessListItem {
103 address,
104 storage_keys,
105 } in self.env.tx.access_list.iter()
106 {
107 self.journaled_state.initial_account_load(
108 *address,
109 storage_keys.iter().map(|i| U256::from_be_bytes(i.0)),
110 &mut self.db,
111 )?;
112 }
113 Ok(())
114 }
115
116 #[inline]
118 pub fn env(&mut self) -> &mut Env {
119 &mut self.env
120 }
121
122 pub fn cfg(&self) -> &CfgEnv {
124 &self.env.cfg
125 }
126
127 #[inline]
129 pub fn take_error(&mut self) -> Result<(), EVMError<DB::Error>> {
130 core::mem::replace(&mut self.error, Ok(()))
131 }
132
133 #[inline]
135 pub fn block_hash(&mut self, number: u64) -> Result<B256, EVMError<DB::Error>> {
136 self.db.block_hash(number).map_err(EVMError::Database)
137 }
138
139 #[inline]
141 pub fn touch(&mut self, address: &Address) {
142 self.journaled_state.touch(address);
143 }
144
145 #[inline]
147 pub fn load_account(
148 &mut self,
149 address: Address,
150 ) -> Result<StateLoad<&mut Account>, EVMError<DB::Error>> {
151 self.journaled_state.load_account(address, &mut self.db)
152 }
153
154 #[inline]
158 pub fn load_account_delegated(
159 &mut self,
160 address: Address,
161 ) -> Result<AccountLoad, EVMError<DB::Error>> {
162 self.journaled_state
163 .load_account_delegated(address, &mut self.db)
164 }
165
166 #[inline]
168 pub fn balance(&mut self, address: Address) -> Result<StateLoad<U256>, EVMError<DB::Error>> {
169 self.journaled_state
170 .load_account(address, &mut self.db)
171 .map(|acc| acc.map(|a| a.info.balance))
172 }
173
174 #[inline]
178 pub fn code(
179 &mut self,
180 address: Address,
181 ) -> Result<Eip7702CodeLoad<Bytes>, EVMError<DB::Error>> {
182 let a = self.journaled_state.load_code(address, &mut self.db)?;
183 let code = a.info.code.as_ref().unwrap();
185 if code.is_eof() {
186 return Ok(Eip7702CodeLoad::new_not_delegated(
187 EOF_MAGIC_BYTES.clone(),
188 a.is_cold,
189 ));
190 }
191
192 if let Bytecode::Eip7702(code) = code {
193 let address = code.address();
194 let is_cold = a.is_cold;
195
196 let delegated_account = self.journaled_state.load_code(address, &mut self.db)?;
197
198 let delegated_code = delegated_account.info.code.as_ref().unwrap();
200
201 let bytes = if delegated_code.is_eof() {
202 EOF_MAGIC_BYTES.clone()
203 } else {
204 delegated_code.original_bytes()
205 };
206
207 return Ok(Eip7702CodeLoad::new(
208 StateLoad::new(bytes, is_cold),
209 delegated_account.is_cold,
210 ));
211 }
212
213 Ok(Eip7702CodeLoad::new_not_delegated(
214 code.original_bytes(),
215 a.is_cold,
216 ))
217 }
218
219 #[inline]
224 pub fn code_hash(
225 &mut self,
226 address: Address,
227 ) -> Result<Eip7702CodeLoad<B256>, EVMError<DB::Error>> {
228 let acc = self.journaled_state.load_code(address, &mut self.db)?;
229 if acc.is_empty() {
230 return Ok(Eip7702CodeLoad::new_not_delegated(B256::ZERO, acc.is_cold));
231 }
232 let code = acc.info.code.as_ref().unwrap();
234
235 if let Bytecode::Eip7702(code) = code {
237 let address = code.address();
238 let is_cold = acc.is_cold;
239
240 let delegated_account = self.journaled_state.load_code(address, &mut self.db)?;
241
242 let hash = if delegated_account.is_empty() {
243 B256::ZERO
244 } else if delegated_account.info.code.as_ref().unwrap().is_eof() {
245 EOF_MAGIC_HASH
246 } else {
247 delegated_account.info.code_hash
248 };
249
250 return Ok(Eip7702CodeLoad::new(
251 StateLoad::new(hash, is_cold),
252 delegated_account.is_cold,
253 ));
254 }
255
256 let hash = if code.is_eof() {
257 EOF_MAGIC_HASH
258 } else {
259 acc.info.code_hash
260 };
261
262 Ok(Eip7702CodeLoad::new_not_delegated(hash, acc.is_cold))
263 }
264
265 #[inline]
267 pub fn sload(
268 &mut self,
269 address: Address,
270 index: U256,
271 ) -> Result<StateLoad<U256>, EVMError<DB::Error>> {
272 self.journaled_state.sload(address, index, &mut self.db)
274 }
275
276 #[inline]
278 pub fn sstore(
279 &mut self,
280 address: Address,
281 index: U256,
282 value: U256,
283 ) -> Result<StateLoad<SStoreResult>, EVMError<DB::Error>> {
284 self.journaled_state
285 .sstore(address, index, value, &mut self.db)
286 }
287
288 #[inline]
290 pub fn tload(&mut self, address: Address, index: U256) -> U256 {
291 self.journaled_state.tload(address, index)
292 }
293
294 #[inline]
296 pub fn tstore(&mut self, address: Address, index: U256, value: U256) {
297 self.journaled_state.tstore(address, index, value)
298 }
299
300 #[inline]
302 pub fn selfdestruct(
303 &mut self,
304 address: Address,
305 target: Address,
306 ) -> Result<StateLoad<SelfDestructResult>, EVMError<DB::Error>> {
307 self.journaled_state
308 .selfdestruct(address, target, &mut self.db)
309 }
310
311 pub fn eofcreate_return<SPEC: Spec>(
313 &mut self,
314 interpreter_result: &mut InterpreterResult,
315 address: Address,
316 journal_checkpoint: JournalCheckpoint,
317 ) {
318 if interpreter_result.result != InstructionResult::ReturnContract {
326 self.journaled_state.checkpoint_revert(journal_checkpoint);
327 return;
328 }
329
330 if interpreter_result.output.len() > self.cfg().max_code_size() {
331 self.journaled_state.checkpoint_revert(journal_checkpoint);
332 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
333 return;
334 }
335
336 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
338 if !interpreter_result.gas.record_cost(gas_for_code) {
339 self.journaled_state.checkpoint_revert(journal_checkpoint);
340 interpreter_result.result = InstructionResult::OutOfGas;
341 return;
342 }
343
344 self.journaled_state.checkpoint_commit();
346
347 let bytecode =
349 Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified");
350
351 self.journaled_state
353 .set_code(address, Bytecode::Eof(Arc::new(bytecode)));
354 }
355
356 #[inline]
358 pub fn call_return(
359 &mut self,
360 interpreter_result: &InterpreterResult,
361 journal_checkpoint: JournalCheckpoint,
362 ) {
363 if matches!(interpreter_result.result, return_ok!()) {
365 self.journaled_state.checkpoint_commit();
366 } else {
367 self.journaled_state.checkpoint_revert(journal_checkpoint);
368 }
369 }
370
371 #[inline]
373 pub fn create_return<SPEC: Spec>(
374 &mut self,
375 interpreter_result: &mut InterpreterResult,
376 address: Address,
377 journal_checkpoint: JournalCheckpoint,
378 ) {
379 if !matches!(interpreter_result.result, return_ok!()) {
381 self.journaled_state.checkpoint_revert(journal_checkpoint);
382 return;
383 }
384 if SPEC::enabled(LONDON) && interpreter_result.output.first() == Some(&0xEF) {
389 self.journaled_state.checkpoint_revert(journal_checkpoint);
390 interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
391 return;
392 }
393
394 if SPEC::enabled(SPURIOUS_DRAGON)
397 && interpreter_result.output.len() > self.cfg().max_code_size()
398 {
399 self.journaled_state.checkpoint_revert(journal_checkpoint);
400 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
401 return;
402 }
403 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
404 if !interpreter_result.gas.record_cost(gas_for_code) {
405 if SPEC::enabled(HOMESTEAD) {
410 self.journaled_state.checkpoint_revert(journal_checkpoint);
411 interpreter_result.result = InstructionResult::OutOfGas;
412 return;
413 } else {
414 interpreter_result.output = Bytes::new();
415 }
416 }
417 self.journaled_state.checkpoint_commit();
419
420 let bytecode = match self.env.cfg.perf_analyse_created_bytecodes {
422 AnalysisKind::Raw => Bytecode::new_legacy(interpreter_result.output.clone()),
423 AnalysisKind::Analyse => {
424 to_analysed(Bytecode::new_legacy(interpreter_result.output.clone()))
425 }
426 };
427
428 self.journaled_state.set_code(address, bytecode);
430
431 interpreter_result.result = InstructionResult::Return;
432 }
433}