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