diff --git a/src/decommit.rs b/src/decommit.rs index 3a37d020..d1a36191 100644 --- a/src/decommit.rs +++ b/src/decommit.rs @@ -77,11 +77,12 @@ impl WorldDiff { Some((UnpaidDecommit { cost, code_key }, is_evm)) } - pub(crate) fn decommit_opcode(&mut self, world: &mut dyn World, code_hash: U256) -> Vec { - let mut code_info_bytes = [0; 32]; - code_hash.to_big_endian(&mut code_info_bytes); - self.decommitted_hashes.insert(code_hash, ()); - world.decommit_code(code_hash) + /// Returns the decommitted contract code and a flag set to `true` if this is a fresh decommit (i.e., + /// the code wasn't decommitted previously in the same VM run). + #[doc(hidden)] // should be used for testing purposes only; can break VM operation otherwise + pub fn decommit_opcode(&mut self, world: &mut dyn World, code_hash: U256) -> (Vec, bool) { + let was_decommitted = self.decommitted_hashes.insert(code_hash, ()).is_some(); + (world.decommit_code(code_hash), !was_decommitted) } pub(crate) fn pay_for_decommit( diff --git a/src/instruction_handlers/decommit.rs b/src/instruction_handlers/decommit.rs index 88a26973..49b677fa 100644 --- a/src/instruction_handlers/decommit.rs +++ b/src/instruction_handlers/decommit.rs @@ -33,7 +33,10 @@ fn decommit( return; } - let program = vm.world_diff.decommit_opcode(world, code_hash); + let (program, is_fresh) = vm.world_diff.decommit_opcode(world, code_hash); + if !is_fresh { + vm.state.current_frame.gas += extra_cost; + } let heap = vm.state.heaps.allocate(); vm.state.current_frame.heaps_i_am_keeping_alive.push(heap); @@ -49,6 +52,7 @@ fn decommit( Register1::set_fat_ptr(args, &mut vm.state, value); }) } + impl Instruction { pub fn from_decommit( abi: Register1,