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
43impl<
44        BLOCK: Block,
45        TX: Transaction,
46        DB: Database,
47        CFG: Cfg,
48        JOURNAL: JournalTr<Database = DB>,
49        CHAIN,
50        LOCAL: LocalContextTr,
51    > ContextTr for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
52{
53    type Block = BLOCK;
54    type Tx = TX;
55    type Cfg = CFG;
56    type Db = DB;
57    type Journal = JOURNAL;
58    type Chain = CHAIN;
59    type Local = LOCAL;
60
61    #[inline]
62    fn all(
63        &self,
64    ) -> (
65        &Self::Block,
66        &Self::Tx,
67        &Self::Cfg,
68        &Self::Db,
69        &Self::Journal,
70        &Self::Chain,
71        &Self::Local,
72    ) {
73        let block = &self.block;
74        let tx = &self.tx;
75        let cfg = &self.cfg;
76        let db = self.journaled_state.db();
77        let journal = &self.journaled_state;
78        let chain = &self.chain;
79        let local = &self.local;
80
81        (block, tx, cfg, db, journal, chain, local)
82    }
83
84    #[inline]
85    fn all_mut(
86        &mut self,
87    ) -> (
88        &Self::Block,
89        &Self::Tx,
90        &Self::Cfg,
91        &mut Self::Journal,
92        &mut Self::Chain,
93        &mut Self::Local,
94    ) {
95        let block = &self.block;
96        let tx = &self.tx;
97        let cfg = &self.cfg;
98        let journal = &mut self.journaled_state;
99        let chain = &mut self.chain;
100        let local = &mut self.local;
101
102        (block, tx, cfg, journal, chain, local)
103    }
104
105    #[inline]
106    fn error(&mut self) -> &mut Result<(), ContextError<<Self::Db as Database>::Error>> {
107        &mut self.error
108    }
109}
110
111impl<
112        BLOCK: Block,
113        TX: Transaction,
114        DB: Database,
115        CFG: Cfg,
116        JOURNAL: JournalTr<Database = DB>,
117        CHAIN,
118        LOCAL: LocalContextTr,
119    > ContextSetters for Context<BLOCK, TX, CFG, DB, JOURNAL, CHAIN, LOCAL>
120{
121    fn set_tx(&mut self, tx: Self::Tx) {
122        self.tx = tx;
123    }
124
125    fn set_block(&mut self, block: Self::Block) {
126        self.block = block;
127    }
128}
129
130impl<
131        BLOCK: Block + Default,
132        TX: Transaction + Default,
133        DB: Database,
134        JOURNAL: JournalTr<Database = DB>,
135        CHAIN: Default,
136        LOCAL: LocalContextTr + Default,
137        SPEC: Default + Into<SpecId> + Clone,
138    > Context<BLOCK, TX, CfgEnv<SPEC>, DB, JOURNAL, CHAIN, LOCAL>
139{
140    /// Creates a new context with a new database type.
141    ///
142    /// This will create a new [`Journal`] object.
143    pub fn new(db: DB, spec: SPEC) -> Self {
144        let mut journaled_state = JOURNAL::new(db);
145        journaled_state.set_spec_id(spec.clone().into());
146        Self {
147            tx: TX::default(),
148            block: BLOCK::default(),
149            cfg: CfgEnv::new_with_spec(spec),
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    #[inline]
454    fn gas_params(&self) -> &GasParams {
455        self.cfg().gas_params()
456    }
457
458    fn block_number(&self) -> U256 {
459        self.block().number()
460    }
461
462    fn timestamp(&self) -> U256 {
463        U256::from(self.block().timestamp())
464    }
465
466    fn beneficiary(&self) -> Address {
467        self.block().beneficiary()
468    }
469
470    fn chain_id(&self) -> U256 {
471        U256::from(self.cfg().chain_id())
472    }
473
474    /* Transaction */
475
476    fn effective_gas_price(&self) -> U256 {
477        let basefee = self.block().basefee();
478        U256::from(self.tx().effective_gas_price(basefee as u128))
479    }
480
481    fn caller(&self) -> Address {
482        self.tx().caller()
483    }
484
485    fn blob_hash(&self, number: usize) -> Option<U256> {
486        let tx = &self.tx();
487        if tx.tx_type() != TransactionType::Eip4844 {
488            return None;
489        }
490        tx.blob_versioned_hashes()
491            .get(number)
492            .map(|t| U256::from_be_bytes(t.0))
493    }
494
495    /* Config */
496
497    fn max_initcode_size(&self) -> usize {
498        self.cfg().max_initcode_size()
499    }
500
501    /* Database */
502
503    fn block_hash(&mut self, requested_number: u64) -> Option<B256> {
504        self.db_mut()
505            .block_hash(requested_number)
506            .map_err(|e| {
507                cold_path();
508                *self.error() = Err(e.into());
509            })
510            .ok()
511    }
512
513    /* Journal */
514
515    /// Gets the transient storage value of `address` at `index`.
516    fn tload(&mut self, address: Address, index: StorageKey) -> StorageValue {
517        self.journal_mut().tload(address, index)
518    }
519
520    /// Sets the transient storage value of `address` at `index`.
521    fn tstore(&mut self, address: Address, index: StorageKey, value: StorageValue) {
522        self.journal_mut().tstore(address, index, value)
523    }
524
525    /// Emits a log owned by `address` with given `LogData`.
526    fn log(&mut self, log: Log) {
527        self.journal_mut().log(log);
528    }
529
530    /// Marks `address` to be deleted, with funds transferred to `target`.
531    #[inline]
532    fn selfdestruct(
533        &mut self,
534        address: Address,
535        target: Address,
536        skip_cold_load: bool,
537    ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
538        self.journal_mut()
539            .selfdestruct(address, target, skip_cold_load)
540            .map_err(|e| {
541                cold_path();
542                let (ret, err) = e.into_parts();
543                if let Some(err) = err {
544                    *self.error() = Err(err.into());
545                }
546                ret
547            })
548    }
549
550    #[inline]
551    fn sstore_skip_cold_load(
552        &mut self,
553        address: Address,
554        key: StorageKey,
555        value: StorageValue,
556        skip_cold_load: bool,
557    ) -> Result<StateLoad<SStoreResult>, LoadError> {
558        self.journal_mut()
559            .sstore_skip_cold_load(address, key, value, 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 sload_skip_cold_load(
572        &mut self,
573        address: Address,
574        key: StorageKey,
575        skip_cold_load: bool,
576    ) -> Result<StateLoad<StorageValue>, LoadError> {
577        self.journal_mut()
578            .sload_skip_cold_load(address, key, skip_cold_load)
579            .map_err(|e| {
580                cold_path();
581                let (ret, err) = e.into_parts();
582                if let Some(err) = err {
583                    *self.error() = Err(err.into());
584                }
585                ret
586            })
587    }
588
589    #[inline]
590    fn load_account_info_skip_cold_load(
591        &mut self,
592        address: Address,
593        load_code: bool,
594        skip_cold_load: bool,
595    ) -> Result<AccountInfoLoad<'_>, LoadError> {
596        match self.journaled_state.load_account_info_skip_cold_load(
597            address,
598            load_code,
599            skip_cold_load,
600        ) {
601            Ok(a) => Ok(a),
602            Err(e) => {
603                cold_path();
604                let (ret, err) = e.into_parts();
605                if let Some(err) = err {
606                    self.error = Err(err.into());
607                }
608                Err(ret)
609            }
610        }
611    }
612}