Skip to main content

foundry_evm_core/
env.rs

1use std::fmt::Debug;
2
3pub use alloy_evm::EvmEnv;
4use alloy_primitives::{Address, B256, Bytes, U256};
5use revm::{
6    Context, Database,
7    context::{Block, BlockEnv, Cfg, CfgEnv, Transaction, TxEnv},
8    context_interface::{ContextTr, transaction::AccessList},
9    inspector::JournalExt,
10    primitives::{TxKind, hardfork::SpecId},
11};
12
13use crate::backend::{DatabaseExt, JournaledState};
14
15/// Extension of [`Block`] with mutable setters, allowing EVM-agnostic mutation of block fields.
16pub trait FoundryBlock: Block {
17    /// Sets the block number.
18    fn set_number(&mut self, number: U256);
19
20    /// Sets the beneficiary (coinbase) address.
21    fn set_beneficiary(&mut self, beneficiary: Address);
22
23    /// Sets the block timestamp.
24    fn set_timestamp(&mut self, timestamp: U256);
25
26    /// Sets the gas limit.
27    fn set_gas_limit(&mut self, gas_limit: u64);
28
29    /// Sets the base fee per gas.
30    fn set_basefee(&mut self, basefee: u64);
31
32    /// Sets the block difficulty.
33    fn set_difficulty(&mut self, difficulty: U256);
34
35    /// Sets the prevrandao value.
36    fn set_prevrandao(&mut self, prevrandao: Option<B256>);
37
38    /// Sets the excess blob gas and blob gasprice.
39    fn set_blob_excess_gas_and_price(
40        &mut self,
41        _excess_blob_gas: u64,
42        _base_fee_update_fraction: u64,
43    );
44}
45
46impl FoundryBlock for BlockEnv {
47    fn set_number(&mut self, number: U256) {
48        self.number = number;
49    }
50
51    fn set_beneficiary(&mut self, beneficiary: Address) {
52        self.beneficiary = beneficiary;
53    }
54
55    fn set_timestamp(&mut self, timestamp: U256) {
56        self.timestamp = timestamp;
57    }
58
59    fn set_gas_limit(&mut self, gas_limit: u64) {
60        self.gas_limit = gas_limit;
61    }
62
63    fn set_basefee(&mut self, basefee: u64) {
64        self.basefee = basefee;
65    }
66
67    fn set_difficulty(&mut self, difficulty: U256) {
68        self.difficulty = difficulty;
69    }
70
71    fn set_prevrandao(&mut self, prevrandao: Option<B256>) {
72        self.prevrandao = prevrandao;
73    }
74
75    fn set_blob_excess_gas_and_price(
76        &mut self,
77        excess_blob_gas: u64,
78        base_fee_update_fraction: u64,
79    ) {
80        self.set_blob_excess_gas_and_price(excess_blob_gas, base_fee_update_fraction);
81    }
82}
83
84/// Extension of [`Transaction`] with mutable setters, allowing EVM-agnostic mutation of transaction
85/// fields.
86pub trait FoundryTransaction: Transaction {
87    /// Sets the transaction type.
88    fn set_tx_type(&mut self, tx_type: u8);
89
90    /// Sets the caller (sender) address.
91    fn set_caller(&mut self, caller: Address);
92
93    /// Sets the gas limit.
94    fn set_gas_limit(&mut self, gas_limit: u64);
95
96    /// Sets the gas price (or max fee per gas for EIP-1559).
97    fn set_gas_price(&mut self, gas_price: u128);
98
99    /// Sets the transaction kind (call or create).
100    fn set_kind(&mut self, kind: TxKind);
101
102    /// Sets the value sent with the transaction.
103    fn set_value(&mut self, value: U256);
104
105    /// Sets the transaction input data.
106    fn set_data(&mut self, data: Bytes);
107
108    /// Sets the nonce.
109    fn set_nonce(&mut self, nonce: u64);
110
111    /// Sets the chain ID.
112    fn set_chain_id(&mut self, chain_id: Option<u64>);
113
114    /// Sets the access list.
115    fn set_access_list(&mut self, access_list: AccessList);
116
117    /// Sets the max priority fee per gas.
118    fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>);
119
120    /// Sets the blob versioned hashes.
121    fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>);
122
123    /// Sets the max fee per blob gas.
124    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128);
125}
126
127impl FoundryTransaction for TxEnv {
128    fn set_tx_type(&mut self, tx_type: u8) {
129        self.tx_type = tx_type;
130    }
131
132    fn set_caller(&mut self, caller: Address) {
133        self.caller = caller;
134    }
135
136    fn set_gas_limit(&mut self, gas_limit: u64) {
137        self.gas_limit = gas_limit;
138    }
139
140    fn set_gas_price(&mut self, gas_price: u128) {
141        self.gas_price = gas_price;
142    }
143
144    fn set_kind(&mut self, kind: TxKind) {
145        self.kind = kind;
146    }
147
148    fn set_value(&mut self, value: U256) {
149        self.value = value;
150    }
151
152    fn set_data(&mut self, data: Bytes) {
153        self.data = data;
154    }
155
156    fn set_nonce(&mut self, nonce: u64) {
157        self.nonce = nonce;
158    }
159
160    fn set_chain_id(&mut self, chain_id: Option<u64>) {
161        self.chain_id = chain_id;
162    }
163
164    fn set_access_list(&mut self, access_list: AccessList) {
165        self.access_list = access_list;
166    }
167
168    fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {
169        self.gas_priority_fee = gas_priority_fee;
170    }
171
172    fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>) {
173        self.blob_hashes = blob_hashes;
174    }
175
176    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {
177        self.max_fee_per_blob_gas = max_fee_per_blob_gas;
178    }
179}
180
181/// Marker trait for Foundry's [`CfgEnv`] type, abstracting `Spec` type.
182pub trait FoundryCfg: Cfg + Clone + Debug {
183    type Spec: Into<SpecId> + Clone + Debug;
184}
185
186impl<SPEC: Into<SpecId> + Clone + Debug> FoundryCfg for CfgEnv<SPEC> {
187    type Spec = SPEC;
188}
189
190/// Extension trait providing mutable field access to block, tx, and cfg environments.
191///
192/// [`ContextTr`] only exposes immutable references for block, tx, and cfg.
193/// Cheatcodes like `vm.warp()`, `vm.roll()`, `vm.chainId()` need to mutate these fields.
194pub trait FoundryContextExt:
195    ContextTr<
196        Block: FoundryBlock + Clone,
197        Tx: FoundryTransaction + Clone,
198        Cfg: FoundryCfg,
199        Journal: JournalExt,
200    >
201{
202    /// Mutable reference to the block environment.
203    fn block_mut(&mut self) -> &mut Self::Block;
204    /// Mutable reference to the transaction environment.
205    fn tx_mut(&mut self) -> &mut Self::Tx;
206    /// Mutable reference to the configuration environment.
207    fn cfg_mut(&mut self) -> &mut Self::Cfg;
208    /// Mutable reference to the db and the journal inner.
209    fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState);
210    /// Sets block environment.
211    fn set_block(&mut self, block: Self::Block) {
212        *self.block_mut() = block;
213    }
214    /// Sets transaction environment.
215    fn set_tx(&mut self, tx: Self::Tx) {
216        *self.tx_mut() = tx;
217    }
218    /// Sets configuration environment.
219    fn set_cfg(&mut self, cfg: Self::Cfg) {
220        *self.cfg_mut() = cfg;
221    }
222    /// Sets journal inner.
223    fn set_journal_inner(&mut self, journal_inner: JournaledState) {
224        *self.db_journal_inner_mut().1 = journal_inner;
225    }
226    /// Sets EVM environment.
227    fn set_evm(&mut self, evm_env: EvmEnv<<Self::Cfg as FoundryCfg>::Spec, Self::Block>)
228    where
229        Self::Cfg: From<CfgEnv<<Self::Cfg as FoundryCfg>::Spec>>,
230    {
231        *self.cfg_mut() = evm_env.cfg_env.into();
232        *self.block_mut() = evm_env.block_env;
233    }
234    /// Cloned transaction environment.
235    fn tx_clone(&self) -> Self::Tx {
236        self.tx().clone()
237    }
238    /// Cloned EVM environment (Cfg + Block).
239    fn evm_clone(&self) -> EvmEnv<<Self::Cfg as FoundryCfg>::Spec, Self::Block>
240    where
241        Self::Cfg: Into<CfgEnv<<Self::Cfg as FoundryCfg>::Spec>>,
242    {
243        EvmEnv::new(self.cfg().clone().into(), self.block().clone())
244    }
245}
246
247impl<BLOCK: FoundryBlock + Clone, TX: FoundryTransaction + Clone, CFG: FoundryCfg, DB: Database>
248    FoundryContextExt for Context<BLOCK, TX, CFG, DB>
249{
250    fn block_mut(&mut self) -> &mut Self::Block {
251        &mut self.block
252    }
253    fn tx_mut(&mut self) -> &mut Self::Tx {
254        &mut self.tx
255    }
256    fn cfg_mut(&mut self) -> &mut Self::Cfg {
257        &mut self.cfg
258    }
259    fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState) {
260        (&mut self.journaled_state.database, &mut self.journaled_state.inner)
261    }
262}
263
264/// Temporary bound alias used during the transition to a fully generic foundry-evm and
265/// foundry-cheatcodes.
266///
267/// Pins the EVM context to Ethereum-specific environment types (`BlockEnv`, `TxEnv`, `CfgEnv`)
268/// so that cheatcode implementations don't need to repeat the full where-clause everywhere.
269/// Once cheatcodes are fully generic over network/environment types this alias will be removed.
270pub trait EthCheatCtx:
271    FoundryContextExt<
272        Block = BlockEnv,
273        Tx = TxEnv,
274        Cfg = CfgEnv,
275        Db: DatabaseExt<Self::Block, Self::Tx, <Self::Cfg as FoundryCfg>::Spec>,
276    >
277{
278}
279impl<CTX> EthCheatCtx for CTX where
280    CTX: FoundryContextExt<
281            Block = BlockEnv,
282            Tx = TxEnv,
283            Cfg = CfgEnv,
284            Db: DatabaseExt<Self::Block, Self::Tx, <Self::Cfg as FoundryCfg>::Spec>,
285        >
286{
287}