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