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