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_eip8246_delayed_clear_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    fn is_amsterdam_eip8024_enabled(&self) -> bool {
471        self.cfg().is_amsterdam_eip8024_enabled()
472    }
473
474    fn block_number(&self) -> U256 {
475        self.block().number()
476    }
477
478    fn timestamp(&self) -> U256 {
479        U256::from(self.block().timestamp())
480    }
481
482    fn beneficiary(&self) -> Address {
483        self.block().beneficiary()
484    }
485
486    fn slot_num(&self) -> U256 {
487        U256::from(self.block().slot_num())
488    }
489
490    fn chain_id(&self) -> U256 {
491        U256::from(self.cfg().chain_id())
492    }
493
494    /* Transaction */
495
496    fn effective_gas_price(&self) -> U256 {
497        let basefee = self.block().basefee();
498        U256::from(self.tx().effective_gas_price(basefee as u128))
499    }
500
501    fn caller(&self) -> Address {
502        self.tx().caller()
503    }
504
505    fn blob_hash(&self, number: usize) -> Option<U256> {
506        let tx = &self.tx();
507        if tx.tx_type() != TransactionType::Eip4844 {
508            return None;
509        }
510        tx.blob_versioned_hashes()
511            .get(number)
512            .map(|t| U256::from_be_bytes(t.0))
513    }
514
515    /* Config */
516
517    fn max_initcode_size(&self) -> usize {
518        self.cfg().max_initcode_size()
519    }
520
521    /* Database */
522
523    fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
524        self.db_mut()
525            .block_hash(requested_number)
526            .map_err(|e| {
527                cold_path();
528                *self.error() = Err(e.into());
529            })
530            .ok()
531    }
532
533    /* Journal */
534
535    /// Gets the transient storage value of `address` at `index`.
536    fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
537        self.journal_mut().tload(address, index)
538    }
539
540    /// Sets the transient storage value of `address` at `index`.
541    fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
542        self.journal_mut().tstore(address, index, value)
543    }
544
545    /// Emits a log owned by `address` with given `LogData`.
546    fn log(&mut self, log: Log) {
547        self.journal_mut().log(log);
548    }
549
550    /// Marks `address` to be deleted, with funds transferred to `target`.
551    #[inline]
552    fn selfdestruct(
553        &mut self,
554        address: Address,
555        target: Address,
556        skip_cold_load: bool,
557    ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
558        self.journal_mut()
559            .selfdestruct(address, target, skip_cold_load)
560            .map_err(|e| {
561                cold_path();
562                let (ret, err) = e.into_parts();
563                if let Some(err) = err {
564                    *self.error() = Err(err.into());
565                }
566                ret
567            })
568    }
569
570    #[inline]
571    fn sstore_skip_cold_load(
572        &mut self,
573        address: Address,
574        key: StorageKey,
575        value: StorageValue,
576        skip_cold_load: bool,
577    ) -> Result<StateLoad<SStoreResult>, LoadError> {
578        self.journal_mut()
579            .sstore_skip_cold_load(address, key, value, skip_cold_load)
580            .map_err(|e| {
581                cold_path();
582                let (ret, err) = e.into_parts();
583                if let Some(err) = err {
584                    *self.error() = Err(err.into());
585                }
586                ret
587            })
588    }
589
590    #[inline]
591    fn sload_skip_cold_load(
592        &mut self,
593        address: Address,
594        key: StorageKey,
595        skip_cold_load: bool,
596    ) -> Result<StateLoad<StorageValue>, LoadError> {
597        self.journal_mut()
598            .sload_skip_cold_load(address, key, skip_cold_load)
599            .map_err(|e| {
600                cold_path();
601                let (ret, err) = e.into_parts();
602                if let Some(err) = err {
603                    *self.error() = Err(err.into());
604                }
605                ret
606            })
607    }
608
609    #[inline]
610    fn load_account_info_skip_cold_load(
611        &mut self,
612        address: Address,
613        load_code: bool,
614        skip_cold_load: bool,
615    ) -> Result<AccountInfoLoad<'_>, LoadError> {
616        match self.journaled_state.load_account_info_skip_cold_load(
617            address,
618            load_code,
619            skip_cold_load,
620        ) {
621            Ok(a) => Ok(a),
622            Err(e) => {
623                cold_path();
624                let (ret, err) = e.into_parts();
625                if let Some(err) = err {
626                    self.error = Err(err.into());
627                }
628                Err(ret)
629            }
630        }
631    }
632}