|
1 | 1 | use crate::{
|
2 | 2 | db::{StateAcc, TryStateAcc},
|
3 | 3 | driver::DriveBlockResult,
|
4 |
| - helpers::{Ctx, Evm}, |
| 4 | + helpers::{Ctx, Evm, Instruction}, |
5 | 5 | Block, BlockDriver, BundleDriver, Cfg, ChainDriver, DriveBundleResult, DriveChainResult,
|
6 | 6 | ErroredState, EvmErrored, EvmExtUnchecked, EvmNeedsBlock, EvmNeedsCfg, EvmNeedsTx, EvmReady,
|
7 | 7 | EvmTransacted, HasBlock, HasCfg, HasTx, NeedsCfg, NeedsTx, TransactedState, Tx,
|
@@ -188,33 +188,57 @@ where
|
188 | 188 | }
|
189 | 189 | }
|
190 | 190 |
|
| 191 | + /// Overide an opcode with a custom handler. Returns the previous |
| 192 | + /// instruction handler for the opcode. |
| 193 | + pub fn override_opcode(&mut self, opcode: u8, handler: Instruction<Db>) -> Instruction<Db> { |
| 194 | + std::mem::replace(&mut self.inner.instruction.instruction_table[opcode as usize], handler) |
| 195 | + } |
| 196 | + |
| 197 | + /// Disable an opcode by replacing it with unknown opcode behavior. This is |
| 198 | + /// a shortcut for [`Self::override_opcode`] with [`control::unknown`]. |
| 199 | + pub fn disable_opcode(&mut self, opcode: u8) -> Instruction<Db> { |
| 200 | + self.override_opcode(opcode, control::unknown) |
| 201 | + } |
| 202 | + |
| 203 | + /// Run some closure with an opcode override, then restore the previous |
| 204 | + /// setting. |
| 205 | + pub fn with_opcode_override<F, NewState>( |
| 206 | + mut self, |
| 207 | + opcode: u8, |
| 208 | + handler: Instruction<Db>, |
| 209 | + f: F, |
| 210 | + ) -> Trevm<Db, Insp, NewState> |
| 211 | + where |
| 212 | + F: FnOnce(Self) -> Trevm<Db, Insp, NewState>, |
| 213 | + { |
| 214 | + let old = self.override_opcode(opcode, handler); |
| 215 | + self.inner.instruction.insert_instruction(opcode, handler); |
| 216 | + let mut this = f(self); |
| 217 | + this.override_opcode(opcode, old); |
| 218 | + this |
| 219 | + } |
| 220 | + |
191 | 221 | /// Disable the prevrandao opcode, by replacing it with unknown opcode
|
192 | 222 | /// behavior. This is useful for block simulation, where the prevrandao
|
193 | 223 | /// opcode may produce incorrect results.
|
194 |
| - pub fn disable_prevrandao(&mut self) { |
195 |
| - self.inner.instruction.insert_instruction(DIFFICULTY, control::unknown); |
| 224 | + pub fn disable_prevrandao(&mut self) -> Instruction<Db> { |
| 225 | + self.disable_opcode(DIFFICULTY) |
196 | 226 | }
|
197 | 227 |
|
198 | 228 | /// Enable the prevrandao opcode. If the prevrandao opcode was not
|
199 | 229 | /// previously disabled or replaced, this will have no effect on behavior.
|
200 |
| - pub fn enable_prevrandao(&mut self) { |
201 |
| - self.inner.instruction.insert_instruction(DIFFICULTY, block_info::difficulty); |
| 230 | + pub fn enable_prevrandao(&mut self) -> Instruction<Db> { |
| 231 | + self.override_opcode(DIFFICULTY, block_info::difficulty) |
202 | 232 | }
|
203 | 233 |
|
204 | 234 | /// Run some code with the prevrandao opcode disabled, then restore the
|
205 | 235 | /// previous setting. This is useful for block simulation, where the
|
206 | 236 | /// prevrandao opcode may produce incorrect results.
|
207 |
| - pub fn without_prevrandao<F, NewState>(mut self, f: F) -> Trevm<Db, Insp, NewState> |
| 237 | + pub fn without_prevrandao<F, NewState>(self, f: F) -> Trevm<Db, Insp, NewState> |
208 | 238 | where
|
209 | 239 | F: FnOnce(Self) -> Trevm<Db, Insp, NewState>,
|
210 | 240 | {
|
211 |
| - let handler = std::mem::replace( |
212 |
| - &mut self.inner.instruction.instruction_table[DIFFICULTY as usize], |
213 |
| - control::unknown, |
214 |
| - ); |
215 |
| - let mut new = f(self); |
216 |
| - new.inner.instruction.insert_instruction(DIFFICULTY, handler); |
217 |
| - new |
| 241 | + self.with_opcode_override(DIFFICULTY, control::unknown, f) |
218 | 242 | }
|
219 | 243 | }
|
220 | 244 |
|
|
0 commit comments