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