@@ -946,6 +946,17 @@ impl VirtualMachine {
946946 self . segments . memory . insert_value ( key, val)
947947 }
948948
949+ /// Unset (delete) the first cell of the given contract segment, to prevent contract segment
950+ /// execution. Returns an error if the first cell of the contract segment is already accessed.
951+ pub fn prevent_contract_segment_execution (
952+ & mut self ,
953+ contract_segment_start : Relocatable ,
954+ ) -> Result < ( ) , MemoryError > {
955+ self . segments
956+ . memory
957+ . prevent_contract_segment_execution ( contract_segment_start)
958+ }
959+
949960 ///Writes data into the memory from address ptr and returns the first address after the data.
950961 pub fn load_data (
951962 & mut self ,
@@ -4727,6 +4738,80 @@ mod tests {
47274738 assert_eq ! ( vm. segments. compute_effective_sizes( ) , & vec![ 4 ] ) ;
47284739 }
47294740
4741+ #[ test]
4742+ #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
4743+ fn test_prevent_contract_segment_execution ( ) {
4744+ let mut vm = vm ! ( ) ;
4745+
4746+ let segment0 = vm. segments . add ( ) ;
4747+ let segment1 = vm. segments . add ( ) ;
4748+ let segment2 = vm. segments . add ( ) ;
4749+ let segment3 = vm. segments . add ( ) ;
4750+ let tmp_segment = vm. add_temporary_segment ( ) ;
4751+ assert_eq ! ( segment0. segment_index, 0 ) ;
4752+ assert_eq ! ( segment1. segment_index, 1 ) ;
4753+ assert_eq ! ( segment2. segment_index, 2 ) ;
4754+ assert_eq ! ( segment3. segment_index, 3 ) ;
4755+ assert_eq ! ( tmp_segment. segment_index, -1 ) ;
4756+ vm. segments . memory = memory ! [
4757+ ( ( 0 , 1 ) , 1 ) ,
4758+ ( ( 1 , 0 ) , 3 ) ,
4759+ ( ( 1 , 1 ) , 4 ) ,
4760+ ( ( 2 , 0 ) , 7 ) ,
4761+ ( ( 3 , 0 ) , 7 ) ,
4762+ ( ( -1 , 0 ) , 5 ) ,
4763+ ( ( -1 , 1 ) , 5 ) ,
4764+ ( ( -1 , 2 ) , 5 )
4765+ ] ;
4766+ vm. run_finished = true ;
4767+
4768+ vm. mark_address_range_as_accessed ( ( 2 , 0 ) . into ( ) , 1 ) . unwrap ( ) ;
4769+
4770+ let cell0 = Relocatable :: from ( ( 0 , 0 ) ) ;
4771+ let cell1 = Relocatable :: from ( ( 1 , 1 ) ) ;
4772+ let cell2 = Relocatable :: from ( ( 2 , 0 ) ) ;
4773+ let cell3 = Relocatable :: from ( ( 3 , 7 ) ) ;
4774+ let cell7 = Relocatable :: from ( ( 7 , 17 ) ) ;
4775+ let cell_tmp = Relocatable :: from ( ( -1 , 1 ) ) ;
4776+ vm. prevent_contract_segment_execution ( cell0) . unwrap ( ) ;
4777+ vm. prevent_contract_segment_execution ( cell1) . unwrap ( ) ;
4778+ vm. prevent_contract_segment_execution ( cell_tmp) . unwrap ( ) ;
4779+ vm. prevent_contract_segment_execution ( cell3) . unwrap ( ) ;
4780+
4781+ // Check that the cells were set to NONE.
4782+ assert ! ( vm
4783+ . segments
4784+ . memory
4785+ . get_cell_for_testing( cell0)
4786+ . unwrap( )
4787+ . is_none( ) ) ;
4788+ assert ! ( vm
4789+ . segments
4790+ . memory
4791+ . get_cell_for_testing( cell1)
4792+ . unwrap( )
4793+ . is_none( ) ) ;
4794+ assert ! ( vm
4795+ . segments
4796+ . memory
4797+ . get_cell_for_testing( cell_tmp)
4798+ . unwrap( )
4799+ . is_none( ) ) ;
4800+ // Segment 3 cell was out of offset range, so it should not be modified or allocated.
4801+ assert ! ( vm. segments. memory. get_cell_for_testing( cell3) . is_none( ) ) ;
4802+ // Segment 2 cell was accessed, so attempting to unset the memory should result in error.
4803+ assert_matches ! (
4804+ vm. prevent_contract_segment_execution( cell2) . unwrap_err( ) ,
4805+ MemoryError :: CellAlreadyAccessed ( relocatable) if relocatable == cell2
4806+ ) ;
4807+ // Segment 7 was not allocated, so attempting to unset the memory should result in error.
4808+ assert_matches ! (
4809+ vm. prevent_contract_segment_execution( cell7) . unwrap_err( ) ,
4810+ MemoryError :: UnallocatedSegment ( boxed)
4811+ if * boxed == ( cell7. segment_index. try_into( ) . unwrap( ) , cell7. offset)
4812+ ) ;
4813+ }
4814+
47304815 #[ test]
47314816 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
47324817 fn mark_as_accessed ( ) {
0 commit comments