trevm/fill/
traits.rs

1use crate::helpers::Ctx;
2use revm::{
3    context::{BlockEnv, CfgEnv, Evm, TxEnv},
4    Database,
5};
6use std::sync::Arc;
7
8/// Types that can fill the EVM transaction environment [`TxEnv`].
9pub trait Tx: Send + Sync {
10    /// Fill the transaction environment.
11    ///
12    /// ## Note:
13    ///
14    /// It is generally expected that the filler will fill (or at least
15    /// inspect) ALL fields of the transaction environment. This is because
16    /// the EVM will NOT clear the transaction environment between
17    /// transactions. If the filler does not fill a field, it will be left
18    /// unchanged from the previous transaction.
19    fn fill_tx_env(&self, tx_env: &mut TxEnv);
20
21    /// Fill the transaction environment on the EVM.
22    fn fill_tx<Db: Database, Insp, Inst, Prec, Frame>(
23        &self,
24        evm: &mut Evm<Ctx<Db>, Insp, Inst, Prec, Frame>,
25    ) where
26        Self: Sized,
27    {
28        evm.ctx.modify_tx(|tx_env| self.fill_tx_env(tx_env));
29    }
30}
31
32impl Tx for TxEnv {
33    fn fill_tx_env(&self, tx_env: &mut TxEnv) {
34        *tx_env = self.clone();
35    }
36}
37
38impl Tx for Arc<dyn Tx> {
39    fn fill_tx_env(&self, tx_env: &mut TxEnv) {
40        self.as_ref().fill_tx_env(tx_env);
41    }
42}
43
44impl Tx for Box<dyn Tx> {
45    fn fill_tx_env(&self, tx_env: &mut TxEnv) {
46        self.as_ref().fill_tx_env(tx_env);
47    }
48}
49
50impl<T> Tx for T
51where
52    T: Fn(&mut TxEnv) + Send + Sync,
53{
54    fn fill_tx_env(&self, tx_env: &mut TxEnv) {
55        self(tx_env);
56    }
57}
58
59/// Types that can fill the EVM block environment [`BlockEnv`].
60pub trait Block: Send + Sync {
61    /// Fill the block environment.
62    ///
63    /// ## Note:
64    ///
65    /// It is generally expected that the filler will fill (or at least
66    /// inspect) ALL fields of the block environment. This is because the EVM
67    /// will NOT clear the block environment between blocks. If the filler does
68    /// not fill a field, it will be left unchanged from the previous block.
69    fn fill_block_env(&self, block_env: &mut BlockEnv);
70
71    /// Fill the block environment on the EVM.
72    fn fill_block<Db: Database, Insp, Inst, Prec, Frame>(
73        &self,
74        evm: &mut Evm<Ctx<Db>, Insp, Inst, Prec, Frame>,
75    ) where
76        Self: Sized,
77    {
78        evm.ctx.modify_block(|block_env| self.fill_block_env(block_env));
79    }
80
81    /// Get the transaction count hint from the filler. This can be used for
82    /// memory pre-allocation during block execution.
83    fn tx_count_hint(&self) -> Option<usize> {
84        None
85    }
86}
87
88impl<T> Block for T
89where
90    T: Fn(&mut BlockEnv) + Send + Sync,
91{
92    fn fill_block_env(&self, block_env: &mut BlockEnv) {
93        self(block_env);
94    }
95}
96
97impl Block for BlockEnv {
98    fn fill_block_env(&self, block_env: &mut BlockEnv) {
99        *block_env = self.clone();
100    }
101}
102
103impl Block for Arc<dyn Block> {
104    fn fill_block_env(&self, block_env: &mut BlockEnv) {
105        self.as_ref().fill_block_env(block_env);
106    }
107}
108
109impl Block for Box<dyn Block> {
110    fn fill_block_env(&self, block_env: &mut BlockEnv) {
111        self.as_ref().fill_block_env(block_env);
112    }
113}
114
115/// Types that can fill the EVM configuration environment [`CfgEnv`].
116///
117/// Because the CFG env has quite a few conditionally compiled properties, it
118/// is recommended to use the default implementation of `fill_cfg_env` to ensure
119/// that fields are filled only when appropriate.
120///
121/// Note that the following properties on [`CfgEnv`] are feature-gated:
122/// - `kzg_settings` - gated by `c-kzg`
123/// - `memory_limit` - gated by `memory_limit`
124/// - `disable_balance_check` - gated by `optional_balance_check`
125/// - `disable_block_gas_limit` - gated by `optional_block_gas_limit`
126/// - `disable_eip3607` - gated by `optional_eip3607`
127/// - `disable_gas_refund` - gated by `optional_gas_refund`
128/// - `disable_base_fee` - gated by `optional_no_base_fee`
129/// - `disable_beneficiary_reward` - gated by `optional_beneficiary_reward`
130///
131/// Cfg fillers should consider these feature gates when implementing the trait.
132pub trait Cfg: Send + Sync {
133    /// Fill the configuration environment.
134    fn fill_cfg_env(&self, cfg_env: &mut CfgEnv);
135
136    /// Fill the configuration environment on the EVM.
137    fn fill_cfg<Db: Database, Insp, Inst, Prec, Frame>(
138        &self,
139        evm: &mut Evm<Ctx<Db>, Insp, Inst, Prec, Frame>,
140    ) where
141        Self: Sized,
142    {
143        evm.ctx.modify_cfg(|cfg_env| self.fill_cfg_env(cfg_env));
144    }
145}
146
147impl Cfg for Arc<dyn Cfg> {
148    fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) {
149        self.as_ref().fill_cfg_env(cfg_env);
150    }
151}
152
153impl Cfg for CfgEnv {
154    fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) {
155        *cfg_env = self.clone();
156    }
157}
158
159impl Cfg for Box<dyn Cfg> {
160    fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) {
161        self.as_ref().fill_cfg_env(cfg_env);
162    }
163}
164
165impl<T> Cfg for T
166where
167    T: Fn(&mut CfgEnv) + Send + Sync,
168{
169    fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) {
170        self(cfg_env);
171    }
172}
173
174#[cfg(test)]
175mod test {
176    use alloy::{
177        consensus::constants::GWEI_TO_WEI,
178        primitives::{B256, U256},
179    };
180    use revm::{
181        context::{BlockEnv, CfgEnv},
182        context_interface::block::BlobExcessGasAndPrice,
183    };
184
185    use super::*;
186
187    #[allow(dead_code)]
188    fn object_safety(cfg: Box<dyn Cfg>, block: Box<dyn Block>, tx: Box<dyn Tx>) {
189        crate::test_utils::test_trevm().fill_cfg(&cfg).fill_block(&block).fill_tx(&tx);
190
191        unimplemented!("compilation check only")
192    }
193
194    impl Block for () {
195        fn fill_block_env(&self, block_env: &mut BlockEnv) {
196            let BlockEnv {
197                number,
198                beneficiary,
199                timestamp,
200                gas_limit,
201                basefee,
202                difficulty,
203                prevrandao,
204                blob_excess_gas_and_price,
205            } = block_env;
206            *number = U256::ONE;
207            *beneficiary = Default::default();
208            *timestamp = U256::from(1720450148u64); // Time when I was writing the test code
209            *gas_limit = 30_000_000;
210            *basefee = 5 * GWEI_TO_WEI;
211
212            let diff = B256::repeat_byte(0xab);
213            *prevrandao = Some(diff);
214            *difficulty = U256::from_be_bytes(diff.into());
215
216            *blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(
217                1_000_000,
218                revm::primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE,
219            ));
220        }
221
222        fn tx_count_hint(&self) -> Option<usize> {
223            None
224        }
225    }
226
227    impl Cfg for () {
228        fn fill_cfg_env(&self, cfg_env: &mut CfgEnv) {
229            let CfgEnv { chain_id, .. } = cfg_env;
230            *chain_id = 1;
231        }
232    }
233}