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