@@ -947,6 +947,17 @@ impl VirtualMachine {
947947 self . segments . memory . insert_value ( key, val)
948948 }
949949
950+ /// Removes (unsets) a value from a memory cell that was not accessed by the VM.
951+ ///
952+ /// This function can be used to implement lazy opening of merkelized contracts. The full
953+ /// program is initially loaded into memory via a hint. After execution, any entry points to
954+ /// contract segments that were not accessed are replaced with an invalid opcode.
955+ ///
956+ /// [Use case](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/core/os/contract_class/compiled_class.cairo#L244-L253)
957+ pub fn delete_unaccessed ( & mut self , addr : Relocatable ) -> Result < ( ) , MemoryError > {
958+ self . segments . memory . delete_unaccessed ( addr)
959+ }
960+
950961 ///Writes data into the memory from address ptr and returns the first address after the data.
951962 pub fn load_data (
952963 & mut self ,
@@ -4733,6 +4744,84 @@ mod tests {
47334744 assert_eq ! ( vm. segments. compute_effective_sizes( ) , & vec![ 4 ] ) ;
47344745 }
47354746
4747+ #[ test]
4748+ #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
4749+ fn test_delete_unaccessed ( ) {
4750+ let mut vm = vm ! ( ) ;
4751+
4752+ let segment0 = vm. segments . add ( ) ;
4753+ let segment1 = vm. segments . add ( ) ;
4754+ let segment2 = vm. segments . add ( ) ;
4755+ let segment3 = vm. segments . add ( ) ;
4756+ let tmp_segment = vm. add_temporary_segment ( ) ;
4757+ assert_eq ! ( segment0. segment_index, 0 ) ;
4758+ assert_eq ! ( segment1. segment_index, 1 ) ;
4759+ assert_eq ! ( segment2. segment_index, 2 ) ;
4760+ assert_eq ! ( segment3. segment_index, 3 ) ;
4761+ assert_eq ! ( tmp_segment. segment_index, -1 ) ;
4762+ vm. segments . memory = memory ! [
4763+ ( ( 0 , 1 ) , 1 ) ,
4764+ ( ( 1 , 0 ) , 3 ) ,
4765+ ( ( 1 , 1 ) , 4 ) ,
4766+ ( ( 2 , 0 ) , 7 ) ,
4767+ ( ( 3 , 0 ) , 7 ) ,
4768+ ( ( -1 , 0 ) , 5 ) ,
4769+ ( ( -1 , 1 ) , 5 ) ,
4770+ ( ( -1 , 2 ) , 5 )
4771+ ] ;
4772+ vm. run_finished = true ;
4773+
4774+ vm. mark_address_range_as_accessed ( ( 2 , 0 ) . into ( ) , 1 ) . unwrap ( ) ;
4775+
4776+ let cell0 = Relocatable :: from ( ( 0 , 0 ) ) ;
4777+ let cell1 = Relocatable :: from ( ( 1 , 1 ) ) ;
4778+ let cell2 = Relocatable :: from ( ( 2 , 0 ) ) ;
4779+ let cell3 = Relocatable :: from ( ( 3 , 7 ) ) ;
4780+ let cell7 = Relocatable :: from ( ( 7 , 17 ) ) ;
4781+ let cell_tmp = Relocatable :: from ( ( -1 , 1 ) ) ;
4782+ vm. delete_unaccessed ( cell0) . unwrap ( ) ;
4783+ vm. delete_unaccessed ( cell1) . unwrap ( ) ;
4784+ vm. delete_unaccessed ( cell_tmp) . unwrap ( ) ;
4785+
4786+ // Check that the cells were set to NONE.
4787+ assert ! ( vm
4788+ . segments
4789+ . memory
4790+ . get_cell_for_testing( cell0)
4791+ . unwrap( )
4792+ . is_none( ) ) ;
4793+ assert ! ( vm
4794+ . segments
4795+ . memory
4796+ . get_cell_for_testing( cell1)
4797+ . unwrap( )
4798+ . is_none( ) ) ;
4799+ assert ! ( vm
4800+ . segments
4801+ . memory
4802+ . get_cell_for_testing( cell_tmp)
4803+ . unwrap( )
4804+ . is_none( ) ) ;
4805+ // Segment 3 cell was out of offset range, so it should not be modified or allocated.
4806+ assert ! ( vm. segments. memory. get_cell_for_testing( cell3) . is_none( ) ) ;
4807+ // Segment 2 cell was accessed, so attempting to unset the memory should result in error.
4808+ assert_matches ! (
4809+ vm. delete_unaccessed( cell2) . unwrap_err( ) ,
4810+ MemoryError :: UnsetAccessedCell ( relocatable) if relocatable == cell2
4811+ ) ;
4812+ // Segment 3 is unallocated, so attempting to unset the memory should result in error.
4813+ assert_matches ! (
4814+ vm. delete_unaccessed( cell3) . unwrap_err( ) ,
4815+ MemoryError :: UnsetUnallocatedCell ( relocatable) if relocatable == cell3
4816+ ) ;
4817+ // Segment 7 was not allocated, so attempting to unset the memory should result in error.
4818+ assert_matches ! (
4819+ vm. delete_unaccessed( cell7) . unwrap_err( ) ,
4820+ MemoryError :: UnallocatedSegment ( boxed)
4821+ if * boxed == ( cell7. segment_index. try_into( ) . unwrap( ) , vm. segments. memory. data. len( ) )
4822+ ) ;
4823+ }
4824+
47364825 #[ test]
47374826 #[ cfg_attr( target_arch = "wasm32" , wasm_bindgen_test) ]
47384827 fn mark_as_accessed ( ) {
0 commit comments