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