foundry_evm_core/env/
context.rs1use super::{EvmEnv, FoundryBlock, FoundryCfg, FoundryChain, FoundryJournal, FoundryTransaction};
4use crate::backend::JournaledState;
5use revm::{
6 Context, Database,
7 context::{Cfg, CfgEnv},
8 context_interface::ContextTr,
9 primitives::hardfork::SpecId,
10};
11use std::fmt::Debug;
12
13pub trait FoundryContextExt:
18 ContextTr<
19 Block: FoundryBlock + Clone,
20 Tx: FoundryTransaction + Clone,
21 Cfg: FoundryCfg<Spec = Self::Spec>,
22 Journal: FoundryJournal,
23 Chain: FoundryChain<Self::Tx>,
24 >
25{
26 type Spec: Into<SpecId> + Copy + Debug;
30
31 fn block_mut(&mut self) -> &mut Self::Block;
33
34 fn tx_mut(&mut self) -> &mut Self::Tx;
36
37 fn cfg_mut(&mut self) -> &mut Self::Cfg;
39
40 fn cfg_env(&self) -> &CfgEnv<Self::Spec> {
42 self.cfg().cfg_env()
43 }
44
45 fn cfg_env_mut(&mut self) -> &mut CfgEnv<Self::Spec> {
47 self.cfg_mut().cfg_env_mut()
48 }
49
50 fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState) {
52 self.journal_mut().db_journal_inner_mut()
53 }
54
55 fn journal_inner(&self) -> &JournaledState {
57 self.journal().journal_inner()
58 }
59
60 fn set_spec_and_gas_params(&mut self, spec: Self::Spec) {
62 self.cfg_mut().set_spec_and_gas_params(spec);
63 }
64
65 fn set_block(&mut self, block: Self::Block) {
67 *self.block_mut() = block;
68 }
69
70 fn set_tx(&mut self, tx: Self::Tx) {
72 *self.tx_mut() = tx;
73 }
74
75 fn set_cfg(&mut self, cfg: Self::Cfg) {
77 *self.cfg_mut() = cfg;
78 }
79
80 fn set_journal_inner(&mut self, journal_inner: JournaledState) {
82 *self.db_journal_inner_mut().1 = journal_inner;
83 }
84
85 fn set_evm(&mut self, evm_env: EvmEnv<Self::Spec, Self::Block>) {
87 *self.cfg_mut() = evm_env.cfg_env.into();
88 *self.block_mut() = evm_env.block_env;
89 }
90
91 fn tx_clone(&self) -> Self::Tx {
93 self.tx().clone()
94 }
95
96 fn evm_clone(&self) -> EvmEnv<Self::Spec, Self::Block> {
98 EvmEnv::new(self.cfg().clone().into(), self.block().clone())
99 }
100}
101
102impl<
103 BLOCK: FoundryBlock + Clone,
104 TX: FoundryTransaction + Clone,
105 CFG: FoundryCfg,
106 DB: Database,
107 J: FoundryJournal<Database = DB>,
108 C: FoundryChain<TX>,
109> FoundryContextExt for Context<BLOCK, TX, CFG, DB, J, C>
110{
111 type Spec = <Self::Cfg as Cfg>::Spec;
112
113 fn block_mut(&mut self) -> &mut Self::Block {
114 &mut self.block
115 }
116
117 fn tx_mut(&mut self) -> &mut Self::Tx {
118 &mut self.tx
119 }
120
121 fn cfg_mut(&mut self) -> &mut Self::Cfg {
122 &mut self.cfg
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use alloy_evm::{EthEvmFactory, EvmFactory};
130 use alloy_primitives::U256;
131 use foundry_evm_hardforks::TempoHardfork;
132 use revm::{
133 context::{Block, Transaction},
134 database::EmptyDB,
135 };
136 use tempo_evm::TempoEvmFactory;
137
138 #[cfg(feature = "base")]
139 use base_common_evm::{BaseEvmFactory, BaseSpecId, BaseUpgrade};
140
141 #[test]
142 fn eth_evm_foundry_context_ext_implementation() {
143 let mut evm = EthEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
144 assert_context_mutation(evm.ctx_mut(), SpecId::AMSTERDAM);
145 }
146
147 #[cfg(feature = "base")]
148 #[test]
149 fn base_evm_foundry_context_ext_implementation() {
150 let mut evm = BaseEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
151 assert_context_mutation(evm.ctx_mut(), BaseSpecId::new(BaseUpgrade::Beryl));
152 }
153
154 #[cfg(feature = "monad")]
155 #[test]
156 fn monad_evm_foundry_context_ext_implementation() {
157 let mut evm = alloy_monad_evm::MonadEvmFactory::default().create_evm(
158 EmptyDB::default(),
159 EvmEnv::new(
160 CfgEnv::new_with_spec(monad_revm::MonadHardfork::MonadNine),
161 Default::default(),
162 ),
163 );
164 assert_context_mutation(evm.ctx_mut(), monad_revm::MonadHardfork::MonadEight);
165 evm.ctx_mut().journal_mut().set_preserve_reserve_balance(true);
166 let mut inner = evm.ctx().journal_inner().clone();
167 inner.depth = 2;
168 evm.ctx_mut().set_journal_inner(inner);
169 assert_eq!(evm.ctx().journal_inner().depth, 2);
170 assert!(evm.ctx().journal().preserves_reserve_balance());
171 }
172
173 #[test]
174 fn tempo_evm_foundry_context_ext_implementation() {
175 let mut evm = TempoEvmFactory::default().create_evm(EmptyDB::default(), EvmEnv::default());
176 assert_context_mutation(evm.ctx_mut(), TempoHardfork::Genesis);
177 }
178
179 #[cfg(feature = "optimism")]
180 mod optimism {
181 use super::*;
182 use alloy_op_evm::{OpEvmFactory, OpTx};
183 use op_revm::OpSpecId;
184
185 #[test]
186 fn op_evm_foundry_context_ext_implementation() {
187 let mut evm =
188 OpEvmFactory::<OpTx>::default().create_evm(EmptyDB::default(), EvmEnv::default());
189 assert_context_mutation(evm.ctx_mut(), OpSpecId::JOVIAN);
190 }
191 }
192
193 fn assert_context_mutation<CTX: FoundryContextExt>(ctx: &mut CTX, spec: CTX::Spec)
194 where
195 CTX::Spec: PartialEq,
196 {
197 ctx.block_mut().set_number(U256::from(123));
198 assert_eq!(ctx.block().number(), U256::from(123));
199 ctx.tx_mut().set_nonce(99);
200 assert_eq!(ctx.tx().nonce(), 99);
201 ctx.cfg_env_mut().spec = spec;
202 assert_eq!(ctx.cfg().spec(), spec);
203
204 let tx = ctx.tx_clone();
205 ctx.tx_mut().set_nonce(0);
206 ctx.set_tx(tx);
207 assert_eq!(ctx.tx().nonce(), 99);
208 ctx.cfg_env_mut().chain_id = 42;
209 let env = ctx.evm_clone();
210 ctx.block_mut().set_number(U256::ZERO);
211 ctx.cfg_env_mut().chain_id = 43;
212 ctx.set_evm(env);
213 assert_eq!(ctx.block().number(), U256::from(123));
214 assert_eq!(ctx.cfg().spec(), spec);
215 assert_eq!(ctx.cfg().chain_id(), 42);
216 }
217}