Skip to main content

revm_context/
context.rs

1//! This module contains [`Context`] struct and implements [`ContextTr`] trait for it.
2use crate::{block::BlockEnv, cfg::CfgEnv, journal::Journal, tx::TxEnv, LocalContext};
3use context_interface::{
4    cfg::GasParams,
5    context::{ContextError, ContextSetters, SStoreResult, SelfDestructResult, StateLoad},
6    host::LoadError,
7    journaled_state::AccountInfoLoad,
8    Block, Cfg, ContextTr, Host, JournalTr, LocalContextTr, Transaction, TransactionType,
9};
10use database_interface::{Database, DatabaseRef, EmptyDB, WrapDatabaseRef};
11use derive_where::derive_where;
12use primitives::{
13    hardfork::SpecId, hints_util::cold_path, Address, Log, StorageKey, StorageValue, B256, U256,
14};
15
16/// EVM context contains data that EVM needs for execution.
17#[derive_where(Clone, Debug; BLOCK, CFG, CHAIN, TX, DB, JOURNAL, <DB as Database>::Error, LOCAL)]
18pub struct Context<
19    BLOCK = BlockEnv,
20    TX = TxEnv,
21    CFG = CfgEnv,
22    DB: Database = EmptyDB,
23    JOURNAL: JournalTr<Database = DB> = Journal<DB>,
24    CHAIN = (),
25    LOCAL: LocalContextTr = LocalContext,
26> {
27    /// Block information.
28    pub block: BLOCK,
29    /// Transaction information.
30    pub tx: TX,
31    /// Configurations.
32    pub cfg: CFG,
33    /// EVM State with journaling support and database.
34    pub journaled_state: JOURNAL,
35    /// Inner context.
36    pub chain: CHAIN,
37    /// Local context that is filled by execution.
38    pub local: LOCAL,
39    /// Error that happened during execution.
40    pub error: Result<(), ContextError<DB::Error>>,
41}
42
43impl<
44        BLOCK: Block,
45        TX: Transaction,
46        DB: Database,
47        CFG: Cfg,
48        JOURNAL: JournalTr<Database = DB>,
49        CHAIN,
50        LOCAL: LocalContextTr,
51    > ContextTr for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
52{
53    type Block = BLOCK;
54    type Tx = TX;
55    type Cfg = CFG;
56    type Db = DB;
57    type Journal = JOURNAL;
58    type Chain = CHAIN;
59    type Local = LOCAL;
60
61    #[inline]
62    fn all(
63        &self,
64    ) -> (
65        &Self::Block,
66        &Self::Tx,
67        &Self::Cfg,
68        &Self::Db,
69        &Self::Journal,
70        &Self::Chain,
71        &Self::Local,
72    ) {
73        let block = &self.block;
74        let tx = &self.tx;
75        let cfg = &self.cfg;
76        let db = self.journaled_state.db();
77        let journal = &self.journaled_state;
78        let chain = &self.chain;
79        let local = &self.local;
80
81        (block, tx, cfg, db, journal, chain, local)
82    }
83
84    #[inline]
85    fn all_mut(
86        &mut self,
87    ) -> (
88        &Self::Block,
89        &Self::Tx,
90        &Self::Cfg,
91        &mut Self::Journal,
92        &mut Self::Chain,
93        &mut Self::Local,
94    ) {
95        let block = &self.block;
96        let tx = &self.tx;
97        let cfg = &self.cfg;
98        let journal = &mut self.journaled_state;
99        let chain = &mut self.chain;
100        let local = &mut self.local;
101
102        (block, tx, cfg, journal, chain, local)
103    }
104
105    #[inline]
106    fn error(&mut self) -> &mut Result<(), ContextError<<Self::Db as Database>::Error>> {
107        &mut self.error
108    }
109}
110
111impl<
112        BLOCK: Block,
113        TX: Transaction,
114        DB: Database,
115        CFG: Cfg,
116        JOURNAL: JournalTr<Database = DB>,
117        CHAIN,
118        LOCAL: LocalContextTr,
119    > ContextSetters for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
120{
121    fn set_tx(&mut self, tx: Self::Tx) {
122        self.tx = tx;
123    }
124
125    fn set_block(&mut self, block: Self::Block) {
126        self.block = block;
127    }
128}
129
130impl<
131        BLOCK: Block + Default,
132        TX: Transaction + Default,
133        DB: Database,
134        JOURNAL: JournalTr<Database = DB>,
135        CHAIN: Default,
136        LOCAL: LocalContextTr + Default,
137        SPEC: Default + Into<SpecId> + Clone,
138    > Context<BLOCK, TX, CfgEnv<SPEC>, DB, JOURNAL, CHAIN, LOCAL>
139{
140    /// Creates a new context with a new database type.
141    ///
142    /// This will create a new [`Journal`] object.
143    pub fn new(db: DB, spec: SPEC) -> Self {
144        let cfg = CfgEnv::new_with_spec(spec);
145        let mut journaled_state = JOURNAL::new(db);
146        journaled_state.set_spec_id(cfg.spec.clone().into());
147        journaled_state.set_eip7708_config(
148            cfg.amsterdam_eip7708_disabled,
149            cfg.amsterdam_eip7708_delayed_burn_disabled,
150        );
151        Self {
152            tx: TX::default(),
153            block: BLOCK::default(),
154            cfg,
155            local: LOCAL::default(),
156            journaled_state,
157            chain: Default::default(),
158            error: Ok(()),
159        }
160    }
161}
162
163impl<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
164where
165    BLOCK: Block,
166    TX: Transaction,
167    CFG: Cfg,
168    DB: Database,
169    JOURNAL: JournalTr<Database = DB>,
170    LOCAL: LocalContextTr,
171{
172    /// Creates a new context with a new journal type. New journal needs to have the same database type.
173    pub fn with_new_journal<OJOURNAL: JournalTr<Database = DB>>(
174        self,
175        mut journal: OJOURNAL,
176    ) -> Context<BLOCK, TX, CFG, DB, OJOURNAL, CHAIN, LOCAL> {
177        journal.set_spec_id(self.cfg.spec().into());
178        journal.set_eip7708_config(
179            self.cfg.is_eip7708_disabled(),
180            self.cfg.is_eip7708_delayed_burn_disabled(),
181        );
182        Context {
183            tx: self.tx,
184            block: self.block,
185            cfg: self.cfg,
186            journaled_state: journal,
187            local: self.local,
188            chain: self.chain,
189            error: Ok(()),
190        }
191    }
192
193    /// Creates a new context with a new database type.
194    ///
195    /// This will create a new [`Journal`] object.
196    pub fn with_db<ODB: Database>(
197        self,
198        db: ODB,
199    ) -> Context<BLOCK, TX, CFG, ODB, Journal<ODB>, CHAIN, LOCAL> {
200        let mut journaled_state = Journal::new(db);
201        journaled_state.set_spec_id(self.cfg.spec().into());
202        journaled_state.set_eip7708_config(
203            self.cfg.is_eip7708_disabled(),
204            self.cfg.is_eip7708_delayed_burn_disabled(),
205        );
206        Context {
207            tx: self.tx,
208            block: self.block,
209            cfg: self.cfg,
210            journaled_state,
211            local: self.local,
212            chain: self.chain,
213            error: Ok(()),
214        }
215    }
216
217    /// Creates a new context with a new `DatabaseRef` type.
218    pub fn with_ref_db<ODB: DatabaseRef>(
219        self,
220        db: ODB,
221    ) -> Context<BLOCK, TX, CFG, WrapDatabaseRef<ODB>, Journal<WrapDatabaseRef<ODB>>, CHAIN, LOCAL>
222    {
223        let mut journaled_state = Journal::new(WrapDatabaseRef(db));
224        journaled_state.set_spec_id(self.cfg.spec().into());
225        journaled_state.set_eip7708_config(
226            self.cfg.is_eip7708_disabled(),
227            self.cfg.is_eip7708_delayed_burn_disabled(),
228        );
229        Context {
230            tx: self.tx,
231            block: self.block,
232            cfg: self.cfg,
233            journaled_state,
234            local: self.local,
235            chain: self.chain,
236            error: Ok(()),
237        }
238    }
239
240    /// Creates a new context with a new block type.
241    pub fn with_block<OB: Block>(
242        self,
243        block: OB,
244    ) -> Context<OB, TX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
245        Context {
246            tx: self.tx,
247            block,
248            cfg: self.cfg,
249            journaled_state: self.journaled_state,
250            local: self.local,
251            chain: self.chain,
252            error: Ok(()),
253        }
254    }
255    /// Creates a new context with a new transaction type.
256    pub fn with_tx<OTX: Transaction>(
257        self,
258        tx: OTX,
259    ) -> Context<BLOCK, OTX, CFG, DB, JOURNAL, CHAIN, LOCAL> {
260        Context {
261            tx,
262            block: self.block,
263            cfg: self.cfg,
264            journaled_state: self.journaled_state,
265            local: self.local,
266            chain: self.chain,
267            error: Ok(()),
268        }
269    }
270
271    /// Creates a new context with a new chain type.
272    pub fn with_chain<OC>(self, chain: OC) -> Context<BLOCK, TX, CFG, DB, JOURNAL, OC, LOCAL> {
273        Context {
274            tx: self.tx,
275            block: self.block,
276            cfg: self.cfg,
277            journaled_state: self.journaled_state,
278            local: self.local,
279            chain,
280            error: Ok(()),
281        }
282    }
283
284    /// Creates a new context with a new chain type.
285    pub fn with_cfg<OCFG: Cfg>(
286        mut self,
287        cfg: OCFG,
288    ) -> Context<BLOCK, TX, OCFG, DB, JOURNAL, CHAIN, LOCAL> {
289        self.journaled_state.set_spec_id(cfg.spec().into());
290        self.journaled_state.set_eip7708_config(
291            cfg.is_eip7708_disabled(),
292            cfg.is_eip7708_delayed_burn_disabled(),
293        );
294        Context {
295            tx: self.tx,
296            block: self.block,
297            cfg,
298            journaled_state: self.journaled_state,
299            local: self.local,
300            chain: self.chain,
301            error: Ok(()),
302        }
303    }
304
305    /// Creates a new context with a new local context type.
306    pub fn with_local<OL: LocalContextTr>(
307        self,
308        local: OL,
309    ) -> Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, OL> {
310        Context {
311            tx: self.tx,
312            block: self.block,
313            cfg: self.cfg,
314            journaled_state: self.journaled_state,
315            local,
316            chain: self.chain,
317            error: Ok(()),
318        }
319    }
320
321    /// Modifies the context configuration.
322    #[must_use]
323    pub fn modify_cfg_chained<F>(mut self, f: F) -> Self
324    where
325        F: FnOnce(&mut CFG),
326    {
327        f(&mut self.cfg);
328        self.journaled_state.set_spec_id(self.cfg.spec().into());
329        self.journaled_state.set_eip7708_config(
330            self.cfg.is_eip7708_disabled(),
331            self.cfg.is_eip7708_delayed_burn_disabled(),
332        );
333        self
334    }
335
336    /// Modifies the context block.
337    #[must_use]
338    pub fn modify_block_chained<F>(mut self, f: F) -> Self
339    where
340        F: FnOnce(&mut BLOCK),
341    {
342        self.modify_block(f);
343        self
344    }
345
346    /// Modifies the context transaction.
347    #[must_use]
348    pub fn modify_tx_chained<F>(mut self, f: F) -> Self
349    where
350        F: FnOnce(&mut TX),
351    {
352        self.modify_tx(f);
353        self
354    }
355
356    /// Modifies the context chain.
357    #[must_use]
358    pub fn modify_chain_chained<F>(mut self, f: F) -> Self
359    where
360        F: FnOnce(&mut CHAIN),
361    {
362        self.modify_chain(f);
363        self
364    }
365
366    /// Modifies the context database.
367    #[must_use]
368    pub fn modify_db_chained<F>(mut self, f: F) -> Self
369    where
370        F: FnOnce(&mut DB),
371    {
372        self.modify_db(f);
373        self
374    }
375
376    /// Modifies the context journal.
377    #[must_use]
378    pub fn modify_journal_chained<F>(mut self, f: F) -> Self
379    where
380        F: FnOnce(&mut JOURNAL),
381    {
382        self.modify_journal(f);
383        self
384    }
385
386    /// Modifies the context block.
387    pub fn modify_block<F>(&mut self, f: F)
388    where
389        F: FnOnce(&mut BLOCK),
390    {
391        f(&mut self.block);
392    }
393
394    /// Modifies the context transaction.
395    pub fn modify_tx<F>(&mut self, f: F)
396    where
397        F: FnOnce(&mut TX),
398    {
399        f(&mut self.tx);
400    }
401
402    /// Modifies the context configuration.
403    pub fn modify_cfg<F>(&mut self, f: F)
404    where
405        F: FnOnce(&mut CFG),
406    {
407        f(&mut self.cfg);
408        self.journaled_state.set_spec_id(self.cfg.spec().into());
409        self.journaled_state.set_eip7708_config(
410            self.cfg.is_eip7708_disabled(),
411            self.cfg.is_eip7708_delayed_burn_disabled(),
412        );
413    }
414
415    /// Modifies the context chain.
416    pub fn modify_chain<F>(&mut self, f: F)
417    where
418        F: FnOnce(&mut CHAIN),
419    {
420        f(&mut self.chain);
421    }
422
423    /// Modifies the context database.
424    pub fn modify_db<F>(&mut self, f: F)
425    where
426        F: FnOnce(&mut DB),
427    {
428        f(self.journaled_state.db_mut());
429    }
430
431    /// Modifies the context journal.
432    pub fn modify_journal<F>(&mut self, f: F)
433    where
434        F: FnOnce(&mut JOURNAL),
435    {
436        f(&mut self.journaled_state);
437    }
438
439    /// Modifies the local context.
440    pub fn modify_local<F>(&mut self, f: F)
441    where
442        F: FnOnce(&mut LOCAL),
443    {
444        f(&mut self.local);
445    }
446}
447
448impl<
449        BLOCK: Block,
450        TX: Transaction,
451        CFG: Cfg,
452        DB: Database,
453        JOURNAL: JournalTr<Database = DB>,
454        CHAIN,
455        LOCAL: LocalContextTr,
456    > Host for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
457{
458    /* Block */
459
460    fn basefee(&self) -> U256 {
461        U256::from(self.block().basefee())
462    }
463
464    fn blob_gasprice(&self) -> U256 {
465        U256::from(self.block().blob_gasprice().unwrap_or(0))
466    }
467
468    fn gas_limit(&self) -> U256 {
469        U256::from(self.block().gas_limit())
470    }
471
472    fn difficulty(&self) -> U256 {
473        self.block().difficulty()
474    }
475
476    fn prevrandao(&self) -> Option<U256> {
477        self.block().prevrandao().map(|r| r.into())
478    }
479
480    #[inline]
481    fn gas_params(&self) -> &GasParams {
482        self.cfg().gas_params()
483    }
484
485    fn block_number(&self) -> U256 {
486        self.block().number()
487    }
488
489    fn timestamp(&self) -> U256 {
490        U256::from(self.block().timestamp())
491    }
492
493    fn beneficiary(&self) -> Address {
494        self.block().beneficiary()
495    }
496
497    fn slot_num(&self) -> U256 {
498        U256::from(self.block().slot_num())
499    }
500
501    fn chain_id(&self) -> U256 {
502        U256::from(self.cfg().chain_id())
503    }
504
505    /* Transaction */
506
507    fn effective_gas_price(&self) -> U256 {
508        let basefee = self.block().basefee();
509        U256::from(self.tx().effective_gas_price(basefee as u128))
510    }
511
512    fn caller(&self) -> Address {
513        self.tx().caller()
514    }
515
516    fn blob_hash(&self, number: usize) -> Option<U256> {
517        let tx = &self.tx();
518        if tx.tx_type() != TransactionType::Eip4844 {
519            return None;
520        }
521        tx.blob_versioned_hashes()
522            .get(number)
523            .map(|t| U256::from_be_bytes(t.0))
524    }
525
526    /* Config */
527
528    fn max_initcode_size(&self) -> usize {
529        self.cfg().max_initcode_size()
530    }
531
532    /* Database */
533
534    fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
535        self.db_mut()
536            .block_hash(requested_number)
537            .map_err(|e| {
538                cold_path();
539                *self.error() = Err(e.into());
540            })
541            .ok()
542    }
543
544    /* Journal */
545
546    /// Gets the transient storage value of `address` at `index`.
547    fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
548        self.journal_mut().tload(address, index)
549    }
550
551    /// Sets the transient storage value of `address` at `index`.
552    fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
553        self.journal_mut().tstore(address, index, value)
554    }
555
556    /// Emits a log owned by `address` with given `LogData`.
557    fn log(&mut self, log: Log) {
558        self.journal_mut().log(log);
559    }
560
561    /// Marks `address` to be deleted, with funds transferred to `target`.
562    #[inline]
563    fn selfdestruct(
564        &mut self,
565        address: Address,
566        target: Address,
567        skip_cold_load: bool,
568    ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
569        self.journal_mut()
570            .selfdestruct(address, target, skip_cold_load)
571            .map_err(|e| {
572                cold_path();
573                let (ret, err) = e.into_parts();
574                if let Some(err) = err {
575                    *self.error() = Err(err.into());
576                }
577                ret
578            })
579    }
580
581    #[inline]
582    fn sstore_skip_cold_load(
583        &mut self,
584        address: Address,
585        key: StorageKey,
586        value: StorageValue,
587        skip_cold_load: bool,
588    ) -> Result<StateLoad<SStoreResult>, LoadError> {
589        self.journal_mut()
590            .sstore_skip_cold_load(address, key, value, skip_cold_load)
591            .map_err(|e| {
592                cold_path();
593                let (ret, err) = e.into_parts();
594                if let Some(err) = err {
595                    *self.error() = Err(err.into());
596                }
597                ret
598            })
599    }
600
601    #[inline]
602    fn sload_skip_cold_load(
603        &mut self,
604        address: Address,
605        key: StorageKey,
606        skip_cold_load: bool,
607    ) -> Result<StateLoad<StorageValue>, LoadError> {
608        self.journal_mut()
609            .sload_skip_cold_load(address, key, skip_cold_load)
610            .map_err(|e| {
611                cold_path();
612                let (ret, err) = e.into_parts();
613                if let Some(err) = err {
614                    *self.error() = Err(err.into());
615                }
616                ret
617            })
618    }
619
620    #[inline]
621    fn load_account_info_skip_cold_load(
622        &mut self,
623        address: Address,
624        load_code: bool,
625        skip_cold_load: bool,
626    ) -> Result<AccountInfoLoad<'_>, LoadError> {
627        match self.journaled_state.load_account_info_skip_cold_load(
628            address,
629            load_code,
630            skip_cold_load,
631        ) {
632            Ok(a) => Ok(a),
633            Err(e) => {
634                cold_path();
635                let (ret, err) = e.into_parts();
636                if let Some(err) = err {
637                    self.error = Err(err.into());
638                }
639                Err(ret)
640            }
641        }
642    }
643}