diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d6f09706d..4db8a16beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ #### Upcoming Changes +* Fix `BuiltinRunner::final_stack` and remove quick fix [#778](https://github.com/lambdaclass/cairo-rs/pull/778) + * Public Api changes: + * Various changes to public `BuiltinRunner` method's signatures: + * `final_stack(&self, vm: &VirtualMachine, pointer: Relocatable) -> Result<(Relocatable, usize), RunnerError>` to `final_stack(&mut self, segments: &MemorySegmentManager, memory: &Memory, pointer: Relocatable) -> Result`. + * `get_used_cells(&self, vm: &VirtualMachine) -> Result` to `get_used_cells(&self, segments: &MemorySegmentManager) -> Result`. + * `get_used_instances(&self, vm: &VirtualMachine) -> Result` to `get_used_instances(&self, segments: &MemorySegmentManager) -> Result`. + * Bugfixes: + * `BuiltinRunner::final_stack` now updates the builtin's stop_ptr instead of returning it. This replaces the bugfix on PR #768. + #### [0.1.3] - 2023-01-26 * Add secure_run flag + integrate verify_secure_runner into cairo-run [#771](https://github.com/lambdaclass/cairo-rs/pull/777) * Public Api changes: diff --git a/src/types/instance_definitions/builtins_instance_def.rs b/src/types/instance_definitions/builtins_instance_def.rs index 5dab19e543..e86ddc1dee 100644 --- a/src/types/instance_definitions/builtins_instance_def.rs +++ b/src/types/instance_definitions/builtins_instance_def.rs @@ -84,7 +84,7 @@ impl BuiltinsInstanceDef { _ecdsa: None, bitwise: Some(BitwiseInstanceDef::new(16)), ec_op: None, - keccak: Some(KeccakInstanceDef::new(2048)), + keccak: Some(KeccakInstanceDef::new(2048, vec![200; 8])), } } diff --git a/src/types/instance_definitions/keccak_instance_def.rs b/src/types/instance_definitions/keccak_instance_def.rs index 2141d48e3b..19a46d8fdc 100644 --- a/src/types/instance_definitions/keccak_instance_def.rs +++ b/src/types/instance_definitions/keccak_instance_def.rs @@ -17,9 +17,10 @@ impl Default for KeccakInstanceDef { } impl KeccakInstanceDef { - pub(crate) fn new(_ratio: u32) -> Self { + pub(crate) fn new(_ratio: u32, _state_rep: Vec) -> Self { Self { _ratio, + _state_rep, ..Default::default() } } @@ -56,7 +57,7 @@ mod tests { _state_rep: vec![200; 8], _instance_per_component: 16, }; - assert_eq!(KeccakInstanceDef::new(2048), builtin_instance); + assert_eq!(KeccakInstanceDef::new(2048, vec![200; 8]), builtin_instance); } #[test] diff --git a/src/vm/runners/builtin_runner/bitwise.rs b/src/vm/runners/builtin_runner/bitwise.rs index 287d53d1a4..ec14859000 100644 --- a/src/vm/runners/builtin_runner/bitwise.rs +++ b/src/vm/runners/builtin_runner/bitwise.rs @@ -22,12 +22,12 @@ pub struct BitwiseBuiltinRunner { pub(crate) n_input_cells: u32, bitwise_builtin: BitwiseInstanceDef, pub(crate) stop_ptr: Option, - pub(crate) _included: bool, + pub(crate) included: bool, instances_per_component: u32, } impl BitwiseBuiltinRunner { - pub(crate) fn new(instance_def: &BitwiseInstanceDef, include: bool) -> Self { + pub(crate) fn new(instance_def: &BitwiseInstanceDef, included: bool) -> Self { BitwiseBuiltinRunner { base: 0, ratio: instance_def.ratio, @@ -35,7 +35,7 @@ impl BitwiseBuiltinRunner { n_input_cells: INPUT_CELLS_PER_BITWISE, bitwise_builtin: instance_def.clone(), stop_ptr: None, - _included: include, + included, instances_per_component: 1, } } @@ -49,7 +49,7 @@ impl BitwiseBuiltinRunner { } pub fn initial_stack(&self) -> Vec { - if self._included { + if self.included { vec![MaybeRelocatable::from((self.base, 0))] } else { vec![] @@ -124,9 +124,9 @@ impl BitwiseBuiltinRunner { (self.base, self.stop_ptr) } - pub fn get_used_cells(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { let base = self.base(); - vm.segments + segments .get_segment_used_size( base.try_into() .map_err(|_| MemoryError::AddressInTemporarySegment(base))?, @@ -144,7 +144,7 @@ impl BitwiseBuiltinRunner { if vm.current_step < min_step { Err(MemoryError::InsufficientAllocatedCells) } else { - let used = self.get_used_cells(vm)?; + let used = self.get_used_cells(&vm.segments)?; let size = cells_per_instance as usize * safe_div_usize(vm.current_step, ratio) .map_err(|_| MemoryError::InsufficientAllocatedCells)?; @@ -174,40 +174,43 @@ impl BitwiseBuiltinRunner { } pub fn final_stack( - &self, - vm: &VirtualMachine, + &mut self, + segments: &MemorySegmentManager, + memory: &Memory, pointer: Relocatable, - ) -> Result<(Relocatable, usize), RunnerError> { - if self._included { - if let Ok(stop_pointer) = - vm.get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) + ) -> Result { + if self.included { + if let Ok(stop_pointer) = memory + .get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) { if self.base() != stop_pointer.segment_index { return Err(RunnerError::InvalidStopPointer("bitwise".to_string())); } let stop_ptr = stop_pointer.offset; let num_instances = self - .get_used_instances(vm) + .get_used_instances(segments) .map_err(|_| RunnerError::FinalStack)?; let used_cells = num_instances * self.cells_per_instance as usize; if stop_ptr != used_cells { return Err(RunnerError::InvalidStopPointer("bitwise".to_string())); } - Ok(( - pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?, - stop_ptr, - )) + self.stop_ptr = Some(stop_ptr); + Ok(pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?) } else { Err(RunnerError::FinalStack) } } else { let stop_ptr = self.base() as usize; - Ok((pointer, stop_ptr)) + self.stop_ptr = Some(stop_ptr); + Ok(pointer) } } - pub fn get_used_instances(&self, vm: &VirtualMachine) -> Result { - let used_cells = self.get_used_cells(vm)?; + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { + let used_cells = self.get_used_cells(segments)?; Ok(div_ceil(used_cells, self.cells_per_instance as usize)) } } @@ -238,12 +241,12 @@ mod tests { vm.segments.segment_used_sizes = Some(vec![1]); - assert_eq!(builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] fn final_stack() { - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(10), true); + let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(10), true); let mut vm = vm!(); @@ -259,14 +262,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 1)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 1)) ); } #[test] fn final_stack_error_stop_pointer() { - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(10), true); + let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(10), true); let mut vm = vm!(); @@ -282,14 +287,14 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::InvalidStopPointer("bitwise".to_string())) ); } #[test] - fn final_stack_error_when_not_included() { - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(10), false); + fn final_stack_error_when_notincluded() { + let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(10), false); let mut vm = vm!(); @@ -305,14 +310,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 2)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 2)) ); } #[test] fn final_stack_error_non_relocatable() { - let builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(10), true); + let mut builtin = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::new(10), true); let mut vm = vm!(); @@ -328,7 +335,7 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::FinalStack) ); } @@ -524,7 +531,7 @@ mod tests { let vm = vm!(); assert_eq!( - builtin.get_used_cells(&vm), + builtin.get_used_cells(&vm.segments), Err(MemoryError::MissingSegmentUsedSizes) ); } @@ -538,7 +545,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_used_cells(&vm), Ok(0)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0)); } #[test] @@ -550,7 +557,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!(builtin.get_used_cells(&vm), Ok(4)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4)); } #[test] diff --git a/src/vm/runners/builtin_runner/ec_op.rs b/src/vm/runners/builtin_runner/ec_op.rs index 50bf1b4c46..8f9332f547 100644 --- a/src/vm/runners/builtin_runner/ec_op.rs +++ b/src/vm/runners/builtin_runner/ec_op.rs @@ -22,7 +22,7 @@ pub struct EcOpBuiltinRunner { pub(crate) n_input_cells: u32, ec_op_builtin: EcOpInstanceDef, pub(crate) stop_ptr: Option, - _included: bool, + included: bool, instances_per_component: u32, } @@ -35,7 +35,7 @@ impl EcOpBuiltinRunner { cells_per_instance: CELLS_PER_EC_OP, ec_op_builtin: instance_def.clone(), stop_ptr: None, - _included: included, + included, instances_per_component: 1, } } @@ -115,7 +115,7 @@ impl EcOpBuiltinRunner { } pub fn initial_stack(&self) -> Vec { - if self._included { + if self.included { vec![MaybeRelocatable::from((self.base, 0))] } else { vec![] @@ -227,9 +227,9 @@ impl EcOpBuiltinRunner { (self.base, self.stop_ptr) } - pub fn get_used_cells(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { let base = self.base(); - vm.segments + segments .get_segment_used_size( base.try_into() .map_err(|_| MemoryError::AddressInTemporarySegment(base))?, @@ -247,7 +247,7 @@ impl EcOpBuiltinRunner { if vm.current_step < min_step { Err(MemoryError::InsufficientAllocatedCells) } else { - let used = self.get_used_cells(vm)?; + let used = self.get_used_cells(&vm.segments)?; let size = cells_per_instance as usize * safe_div_usize(vm.current_step, ratio) .map_err(|_| MemoryError::InsufficientAllocatedCells)?; @@ -258,42 +258,44 @@ impl EcOpBuiltinRunner { } } - pub fn get_used_instances(&self, vm: &VirtualMachine) -> Result { - let used_cells = self.get_used_cells(vm)?; + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { + let used_cells = self.get_used_cells(segments)?; Ok(div_ceil(used_cells, self.cells_per_instance as usize)) } pub fn final_stack( - &self, - vm: &VirtualMachine, + &mut self, + segments: &MemorySegmentManager, + memory: &Memory, pointer: Relocatable, - ) -> Result<(Relocatable, usize), RunnerError> { - if self._included { - if let Ok(stop_pointer) = - vm.get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) + ) -> Result { + if self.included { + if let Ok(stop_pointer) = memory + .get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) { if self.base() != stop_pointer.segment_index { return Err(RunnerError::InvalidStopPointer("ec_op".to_string())); } let stop_ptr = stop_pointer.offset; let num_instances = self - .get_used_instances(vm) + .get_used_instances(segments) .map_err(|_| RunnerError::FinalStack)?; let used_cells = num_instances * self.cells_per_instance as usize; if stop_ptr != used_cells { return Err(RunnerError::InvalidStopPointer("ec_op".to_string())); } - - Ok(( - pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?, - stop_ptr, - )) + self.stop_ptr = Some(stop_ptr); + Ok(pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?) } else { Err(RunnerError::FinalStack) } } else { let stop_ptr = self.base() as usize; - Ok((pointer, stop_ptr)) + self.stop_ptr = Some(stop_ptr); + Ok(pointer) } } @@ -333,22 +335,14 @@ mod tests { let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), true); let mut vm = vm!(); - - vm.memory = memory![ - ((0, 0), (0, 0)), - ((0, 1), (0, 1)), - ((2, 0), (0, 0)), - ((2, 1), (0, 0)) - ]; - vm.segments.segment_used_sizes = Some(vec![1]); - assert_eq!(builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] fn final_stack() { - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), true); + let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), true); let mut vm = vm!(); @@ -364,14 +358,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 1)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 1)) ); } #[test] fn final_stack_error_stop_pointer() { - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), true); + let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), true); let mut vm = vm!(); @@ -387,14 +383,14 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::InvalidStopPointer("ec_op".to_string())) ); } #[test] - fn final_stack_error_when_not_included() { - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), false); + fn final_stack_error_when_notincluded() { + let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), false); let mut vm = vm!(); @@ -410,14 +406,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 2)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 2)) ); } #[test] fn final_stack_error_non_relocatable() { - let builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), true); + let mut builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::new(10), true); let mut vm = vm!(); @@ -433,7 +431,7 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::FinalStack) ); } @@ -999,7 +997,7 @@ mod tests { let vm = vm!(); assert_eq!( - builtin.get_used_cells(&vm), + builtin.get_used_cells(&vm.segments), Err(MemoryError::MissingSegmentUsedSizes) ); } @@ -1011,7 +1009,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_used_cells(&vm), Ok(0)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0)); } #[test] @@ -1021,17 +1019,17 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!(builtin.get_used_cells(&vm), Ok(4)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4)); } #[test] - fn initial_stack_included_test() { + fn initial_stackincluded_test() { let ec_op_builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true); assert_eq!(ec_op_builtin.initial_stack(), vec![mayberelocatable!(0, 0)]) } #[test] - fn initial_stack_not_included_test() { + fn initial_stack_notincluded_test() { let ec_op_builtin = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), false); assert_eq!(ec_op_builtin.initial_stack(), Vec::new()) } diff --git a/src/vm/runners/builtin_runner/hash.rs b/src/vm/runners/builtin_runner/hash.rs index 9feec8ca48..9aa45c201b 100644 --- a/src/vm/runners/builtin_runner/hash.rs +++ b/src/vm/runners/builtin_runner/hash.rs @@ -21,7 +21,7 @@ pub struct HashBuiltinRunner { pub(crate) cells_per_instance: u32, pub(crate) n_input_cells: u32, pub(crate) stop_ptr: Option, - pub(crate) _included: bool, + pub(crate) included: bool, instances_per_component: u32, // This act as a cache to optimize calls to deduce_memory_cell // Therefore need interior mutability @@ -37,7 +37,7 @@ impl HashBuiltinRunner { n_input_cells: INPUT_CELLS_PER_HASH, stop_ptr: None, verified_addresses: RefCell::new(Vec::new()), - _included: included, + included, instances_per_component: 1, } } @@ -51,7 +51,7 @@ impl HashBuiltinRunner { } pub fn initial_stack(&self) -> Vec { - if self._included { + if self.included { vec![MaybeRelocatable::from((self.base, 0))] } else { vec![] @@ -128,9 +128,9 @@ impl HashBuiltinRunner { (self.base, self.stop_ptr) } - pub fn get_used_cells(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { let base = self.base(); - vm.segments + segments .get_segment_used_size( base.try_into() .map_err(|_| MemoryError::AddressInTemporarySegment(base))?, @@ -148,7 +148,7 @@ impl HashBuiltinRunner { if vm.current_step < min_step { Err(MemoryError::InsufficientAllocatedCells) } else { - let used = self.get_used_cells(vm)?; + let used = self.get_used_cells(&vm.segments)?; let size = cells_per_instance as usize * safe_div_usize(vm.current_step, ratio) .map_err(|_| MemoryError::InsufficientAllocatedCells)?; @@ -159,19 +159,23 @@ impl HashBuiltinRunner { } } - pub fn get_used_instances(&self, vm: &VirtualMachine) -> Result { - let used_cells = self.get_used_cells(vm)?; + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { + let used_cells = self.get_used_cells(segments)?; Ok(div_ceil(used_cells, self.cells_per_instance as usize)) } pub fn final_stack( - &self, - vm: &VirtualMachine, + &mut self, + segments: &MemorySegmentManager, + memory: &Memory, pointer: Relocatable, - ) -> Result<(Relocatable, usize), RunnerError> { - if self._included { - if let Ok(stop_pointer) = - vm.get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) + ) -> Result { + if self.included { + if let Ok(stop_pointer) = memory + .get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) { if self.base() != stop_pointer.segment_index { return Err(RunnerError::InvalidStopPointer("pedersen".to_string())); @@ -179,22 +183,21 @@ impl HashBuiltinRunner { let stop_ptr = stop_pointer.offset; let num_instances = self - .get_used_instances(vm) + .get_used_instances(segments) .map_err(|_| RunnerError::FinalStack)?; let used_cells = num_instances * self.cells_per_instance as usize; if stop_ptr != used_cells { return Err(RunnerError::InvalidStopPointer("pedersen".to_string())); } - Ok(( - pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?, - stop_ptr, - )) + self.stop_ptr = Some(stop_ptr); + Ok(pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?) } else { Err(RunnerError::FinalStack) } } else { let stop_ptr = self.base() as usize; - Ok((pointer, stop_ptr)) + self.stop_ptr = Some(stop_ptr); + Ok(pointer) } } } @@ -217,22 +220,14 @@ mod tests { let builtin = HashBuiltinRunner::new(10, true); let mut vm = vm!(); - - vm.memory = memory![ - ((0, 0), (0, 0)), - ((0, 1), (0, 1)), - ((2, 0), (0, 0)), - ((2, 1), (0, 0)) - ]; - vm.segments.segment_used_sizes = Some(vec![1]); - assert_eq!(builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] fn final_stack() { - let builtin = HashBuiltinRunner::new(10, true); + let mut builtin = HashBuiltinRunner::new(10, true); let mut vm = vm!(); @@ -248,14 +243,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 1)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 1)) ); } #[test] fn final_stack_error_stop_pointer() { - let builtin = HashBuiltinRunner::new(10, true); + let mut builtin = HashBuiltinRunner::new(10, true); let mut vm = vm!(); @@ -271,14 +268,14 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::InvalidStopPointer("pedersen".to_string())) ); } #[test] - fn final_stack_error_when_not_included() { - let builtin = HashBuiltinRunner::new(10, false); + fn final_stack_error_when_notincluded() { + let mut builtin = HashBuiltinRunner::new(10, false); let mut vm = vm!(); @@ -294,14 +291,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 2)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 2)) ); } #[test] fn final_stack_error_non_relocatable() { - let builtin = HashBuiltinRunner::new(10, true); + let mut builtin = HashBuiltinRunner::new(10, true); let mut vm = vm!(); @@ -317,7 +316,7 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::FinalStack) ); } @@ -503,7 +502,7 @@ mod tests { let vm = vm!(); assert_eq!( - builtin.get_used_cells(&vm), + builtin.get_used_cells(&vm.segments), Err(MemoryError::MissingSegmentUsedSizes) ); } @@ -514,7 +513,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_used_cells(&vm), Ok(0)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0)); } #[test] @@ -523,6 +522,6 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!(builtin.get_used_cells(&vm), Ok(4)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4)); } } diff --git a/src/vm/runners/builtin_runner/keccak.rs b/src/vm/runners/builtin_runner/keccak.rs index 9283474703..ac5980e994 100644 --- a/src/vm/runners/builtin_runner/keccak.rs +++ b/src/vm/runners/builtin_runner/keccak.rs @@ -24,7 +24,7 @@ pub struct KeccakBuiltinRunner { pub(crate) n_input_cells: u32, verified_addresses: Vec, pub(crate) stop_ptr: Option, - _included: bool, + included: bool, state_rep: Vec, instances_per_component: u32, } @@ -38,7 +38,7 @@ impl KeccakBuiltinRunner { cells_per_instance: instance_def._cells_per_builtin(), stop_ptr: None, verified_addresses: Vec::new(), - _included: included, + included, instances_per_component: instance_def._instance_per_component, state_rep: instance_def._state_rep.clone(), } @@ -53,7 +53,7 @@ impl KeccakBuiltinRunner { } pub fn initial_stack(&self) -> Vec { - if self._included { + if self.included { vec![MaybeRelocatable::from((self.base, 0))] } else { vec![] @@ -154,9 +154,9 @@ impl KeccakBuiltinRunner { (self.base, self.stop_ptr) } - pub fn get_used_cells(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { let base = self.base(); - vm.segments + segments .get_segment_used_size( base.try_into() .map_err(|_| MemoryError::AddressInTemporarySegment(base))?, @@ -175,7 +175,7 @@ impl KeccakBuiltinRunner { if vm.current_step < min_step { Err(MemoryError::InsufficientAllocatedCells) } else { - let used = self.get_used_cells(vm)?; + let used = self.get_used_cells(&vm.segments)?; let size = cells_per_instance as usize * safe_div_usize(vm.current_step, ratio) .map_err(|_| MemoryError::InsufficientAllocatedCells)?; @@ -183,42 +183,45 @@ impl KeccakBuiltinRunner { } } - pub fn get_used_instances(&self, vm: &VirtualMachine) -> Result { - let used_cells = self.get_used_cells(vm)?; + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { + let used_cells = self.get_used_cells(segments)?; Ok(div_ceil(used_cells, self.cells_per_instance as usize)) } pub fn final_stack( - &self, - vm: &VirtualMachine, + &mut self, + segments: &MemorySegmentManager, + memory: &Memory, pointer: Relocatable, - ) -> Result<(Relocatable, usize), RunnerError> { - if self._included { - if let Ok(stop_pointer) = - vm.get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) + ) -> Result { + if self.included { + if let Ok(stop_pointer) = memory + .get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) { if self.base() != stop_pointer.segment_index { return Err(RunnerError::InvalidStopPointer("keccak".to_string())); } let stop_ptr = stop_pointer.offset; let num_instances = self - .get_used_instances(vm) + .get_used_instances(segments) .map_err(|_| RunnerError::FinalStack)?; let used_cells = num_instances * self.cells_per_instance as usize; if stop_ptr != used_cells { return Err(RunnerError::InvalidStopPointer("keccak".to_string())); } - Ok(( - pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?, - stop_ptr, - )) + self.stop_ptr = Some(stop_ptr); + Ok(pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?) } else { Err(RunnerError::FinalStack) } } else { let stop_ptr = self.base() as usize; - Ok((pointer, stop_ptr)) + self.stop_ptr = Some(stop_ptr); + Ok(pointer) } } @@ -269,25 +272,17 @@ mod tests { #[test] fn get_used_instances() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10), true); + let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10, vec![200; 8]), true); let mut vm = vm!(); - - vm.memory = memory![ - ((0, 0), (0, 0)), - ((0, 1), (0, 1)), - ((2, 0), (0, 0)), - ((2, 1), (0, 0)) - ]; - vm.segments.segment_used_sizes = Some(vec![1]); - assert_eq!(builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] fn final_stack() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10), true); + let mut builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10, vec![200; 8]), true); let mut vm = vm!(); @@ -303,14 +298,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 1)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 1)) ); } #[test] fn final_stack_error_stop_pointer() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10), true); + let mut builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10, vec![200; 8]), true); let mut vm = vm!(); @@ -326,14 +323,15 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::InvalidStopPointer("keccak".to_string())) ); } #[test] - fn final_stack_error_when_not_included() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10), false); + fn final_stack_error_when_notincluded() { + let mut builtin = + KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10, vec![200; 8]), false); let mut vm = vm!(); @@ -349,14 +347,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 2)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 2)) ); } #[test] fn final_stack_error_non_relocatable() { - let builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10), true); + let mut builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10, vec![200; 8]), true); let mut vm = vm!(); @@ -372,7 +372,7 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::FinalStack) ); } @@ -380,7 +380,7 @@ mod tests { #[test] fn get_used_cells_and_allocated_size_test() { let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10), true).into(); + KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10, vec![200; 8]), true).into(); let mut vm = vm!(); @@ -407,7 +407,7 @@ mod tests { #[test] fn get_allocated_memory_units() { let builtin: BuiltinRunner = - KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10), true).into(); + KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10, vec![200; 8]), true).into(); let mut vm = vm!(); @@ -499,7 +499,7 @@ mod tests { let vm = vm!(); assert_eq!( - builtin.get_used_cells(&vm), + builtin.get_used_cells(&vm.segments), Err(MemoryError::MissingSegmentUsedSizes) ); } @@ -511,7 +511,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_used_cells(&vm), Ok(0)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0)); } #[test] @@ -521,11 +521,11 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!(builtin.get_used_cells(&vm), Ok(4)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4)); } #[test] - fn initial_stack_included_test() { + fn initial_stackincluded_test() { let keccak_builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), true); assert_eq!( keccak_builtin.initial_stack(), @@ -534,7 +534,7 @@ mod tests { } #[test] - fn initial_stack_not_included_test() { + fn initial_stack_notincluded_test() { let keccak_builtin = KeccakBuiltinRunner::new(&KeccakInstanceDef::default(), false); assert_eq!(keccak_builtin.initial_stack(), Vec::new()) } @@ -679,8 +679,7 @@ mod tests { ((0, 35), 0) ]; - let mut keccak_instance = KeccakInstanceDef::default(); - keccak_instance._state_rep = vec![1; 8]; + let keccak_instance = KeccakInstanceDef::new(2048, vec![1; 8]); let builtin = KeccakBuiltinRunner::new(&keccak_instance, true); let result = builtin.deduce_memory_cell(&Relocatable::from((0, 25)), &memory); diff --git a/src/vm/runners/builtin_runner/mod.rs b/src/vm/runners/builtin_runner/mod.rs index 5c5d460913..95ebe11ab3 100644 --- a/src/vm/runners/builtin_runner/mod.rs +++ b/src/vm/runners/builtin_runner/mod.rs @@ -79,23 +79,30 @@ impl BuiltinRunner { } } - // Important note: the second returned value corresponds to the builtin's stop_ptr, which must be updated after calling this method - // It is not updated inside this method due to mutability problems pub fn final_stack( - &self, - vm: &VirtualMachine, + &mut self, + segments: &MemorySegmentManager, + memory: &Memory, stack_pointer: Relocatable, - ) -> Result<(Relocatable, usize), RunnerError> { + ) -> Result { match *self { - BuiltinRunner::Bitwise(ref bitwise) => bitwise.final_stack(vm, stack_pointer), - BuiltinRunner::EcOp(ref ec) => ec.final_stack(vm, stack_pointer), - BuiltinRunner::Hash(ref hash) => hash.final_stack(vm, stack_pointer), - BuiltinRunner::Output(ref output) => output.final_stack(vm, stack_pointer), - BuiltinRunner::RangeCheck(ref range_check) => { - range_check.final_stack(vm, stack_pointer) + BuiltinRunner::Bitwise(ref mut bitwise) => { + bitwise.final_stack(segments, memory, stack_pointer) + } + BuiltinRunner::EcOp(ref mut ec) => ec.final_stack(segments, memory, stack_pointer), + BuiltinRunner::Hash(ref mut hash) => hash.final_stack(segments, memory, stack_pointer), + BuiltinRunner::Output(ref mut output) => { + output.final_stack(segments, memory, stack_pointer) + } + BuiltinRunner::RangeCheck(ref mut range_check) => { + range_check.final_stack(segments, memory, stack_pointer) + } + BuiltinRunner::Keccak(ref mut keccak) => { + keccak.final_stack(segments, memory, stack_pointer) + } + BuiltinRunner::Signature(ref mut signature) => { + signature.final_stack(segments, memory, stack_pointer) } - BuiltinRunner::Keccak(ref keccak) => keccak.final_stack(vm, stack_pointer), - BuiltinRunner::Signature(ref signature) => signature.final_stack(vm, stack_pointer), } } @@ -204,27 +211,30 @@ impl BuiltinRunner { } } - pub fn get_used_cells(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { match self { - BuiltinRunner::Bitwise(ref bitwise) => bitwise.get_used_cells(vm), - BuiltinRunner::EcOp(ref ec) => ec.get_used_cells(vm), - BuiltinRunner::Hash(ref hash) => hash.get_used_cells(vm), - BuiltinRunner::Output(ref output) => output.get_used_cells(vm), - BuiltinRunner::RangeCheck(ref range_check) => range_check.get_used_cells(vm), - BuiltinRunner::Keccak(ref keccak) => keccak.get_used_cells(vm), - BuiltinRunner::Signature(ref signature) => signature.get_used_cells(vm), + BuiltinRunner::Bitwise(ref bitwise) => bitwise.get_used_cells(segments), + BuiltinRunner::EcOp(ref ec) => ec.get_used_cells(segments), + BuiltinRunner::Hash(ref hash) => hash.get_used_cells(segments), + BuiltinRunner::Output(ref output) => output.get_used_cells(segments), + BuiltinRunner::RangeCheck(ref range_check) => range_check.get_used_cells(segments), + BuiltinRunner::Keccak(ref keccak) => keccak.get_used_cells(segments), + BuiltinRunner::Signature(ref signature) => signature.get_used_cells(segments), } } - pub fn get_used_instances(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { match self { - BuiltinRunner::Bitwise(ref bitwise) => bitwise.get_used_instances(vm), - BuiltinRunner::EcOp(ref ec) => ec.get_used_instances(vm), - BuiltinRunner::Hash(ref hash) => hash.get_used_instances(vm), - BuiltinRunner::Output(ref output) => output.get_used_instances(vm), - BuiltinRunner::RangeCheck(ref range_check) => range_check.get_used_instances(vm), - BuiltinRunner::Keccak(ref keccak) => keccak.get_used_instances(vm), - BuiltinRunner::Signature(ref signature) => signature.get_used_instances(vm), + BuiltinRunner::Bitwise(ref bitwise) => bitwise.get_used_instances(segments), + BuiltinRunner::EcOp(ref ec) => ec.get_used_instances(segments), + BuiltinRunner::Hash(ref hash) => hash.get_used_instances(segments), + BuiltinRunner::Output(ref output) => output.get_used_instances(segments), + BuiltinRunner::RangeCheck(ref range_check) => range_check.get_used_instances(segments), + BuiltinRunner::Keccak(ref keccak) => keccak.get_used_instances(segments), + BuiltinRunner::Signature(ref signature) => signature.get_used_instances(segments), } } @@ -792,8 +802,10 @@ mod tests { #[test] fn get_allocated_memory_units_keccak_with_items() { - let builtin = - BuiltinRunner::Keccak(KeccakBuiltinRunner::new(&KeccakInstanceDef::new(10), true)); + let builtin = BuiltinRunner::Keccak(KeccakBuiltinRunner::new( + &KeccakInstanceDef::new(10, vec![200; 8]), + true, + )); let mut vm = vm!(); @@ -1386,7 +1398,7 @@ mod tests { let bitwise_builtin: BuiltinRunner = BitwiseBuiltinRunner::new(&BitwiseInstanceDef::default(), true).into(); - assert_eq!(bitwise_builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(bitwise_builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] @@ -1396,7 +1408,7 @@ mod tests { let ec_op_builtin: BuiltinRunner = EcOpBuiltinRunner::new(&EcOpInstanceDef::default(), true).into(); - assert_eq!(ec_op_builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(ec_op_builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] @@ -1405,7 +1417,7 @@ mod tests { vm.segments.segment_used_sizes = Some(vec![4]); let hash_builtin: BuiltinRunner = HashBuiltinRunner::new(8, true).into(); - assert_eq!(hash_builtin.get_used_instances(&vm), Ok(2)); + assert_eq!(hash_builtin.get_used_instances(&vm.segments), Ok(2)); } #[test] @@ -1414,7 +1426,7 @@ mod tests { vm.segments.segment_used_sizes = Some(vec![4]); let output_builtin: BuiltinRunner = OutputBuiltinRunner::new(true).into(); - assert_eq!(output_builtin.get_used_instances(&vm), Ok(4)); + assert_eq!(output_builtin.get_used_instances(&vm.segments), Ok(4)); } #[test] fn range_check_get_used_instances_test() { @@ -1423,12 +1435,12 @@ mod tests { let range_check_builtin: BuiltinRunner = BuiltinRunner::RangeCheck(RangeCheckBuiltinRunner::new(8, 8, true)); - assert_eq!(range_check_builtin.get_used_instances(&vm), Ok(4)); + assert_eq!(range_check_builtin.get_used_instances(&vm.segments), Ok(4)); } #[test] fn runners_final_stack() { - let builtins = vec![ + let mut builtins = vec![ BuiltinRunner::Bitwise(BitwiseBuiltinRunner::new( &BitwiseInstanceDef::default(), false, @@ -1448,8 +1460,11 @@ mod tests { ]; let vm = vm!(); - for br in builtins { - assert_eq!(br.final_stack(&vm, vm.get_ap()), Ok((vm.get_ap(), 0))); + for br in builtins.iter_mut() { + assert_eq!( + br.final_stack(&vm.segments, &vm.memory, vm.get_ap()), + Ok(vm.get_ap()) + ); } } diff --git a/src/vm/runners/builtin_runner/output.rs b/src/vm/runners/builtin_runner/output.rs index 1a0c2bd434..3bc78f6060 100644 --- a/src/vm/runners/builtin_runner/output.rs +++ b/src/vm/runners/builtin_runner/output.rs @@ -9,7 +9,7 @@ use crate::vm::vm_memory::memory_segments::MemorySegmentManager; pub struct OutputBuiltinRunner { base: isize, pub(crate) stop_ptr: Option, - pub(crate) _included: bool, + pub(crate) included: bool, } impl OutputBuiltinRunner { @@ -17,7 +17,7 @@ impl OutputBuiltinRunner { OutputBuiltinRunner { base: 0, stop_ptr: None, - _included: included, + included, } } @@ -30,7 +30,7 @@ impl OutputBuiltinRunner { } pub fn initial_stack(&self) -> Vec { - if self._included { + if self.included { vec![MaybeRelocatable::from((self.base, 0))] } else { vec![] @@ -61,9 +61,9 @@ impl OutputBuiltinRunner { (self.base, self.stop_ptr) } - pub fn get_used_cells(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { let base = self.base(); - vm.segments + segments .get_segment_used_size( base.try_into() .map_err(|_| MemoryError::AddressInTemporarySegment(base))?, @@ -75,44 +75,47 @@ impl OutputBuiltinRunner { &self, vm: &VirtualMachine, ) -> Result<(usize, usize), MemoryError> { - let used = self.get_used_cells(vm)?; + let used = self.get_used_cells(&vm.segments)?; Ok((used, used)) } - pub fn get_used_instances(&self, vm: &VirtualMachine) -> Result { - self.get_used_cells(vm) + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { + self.get_used_cells(segments) } pub fn final_stack( - &self, - vm: &VirtualMachine, + &mut self, + segments: &MemorySegmentManager, + memory: &Memory, pointer: Relocatable, - ) -> Result<(Relocatable, usize), RunnerError> { - if self._included { - if let Ok(stop_pointer) = - vm.get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) + ) -> Result { + if self.included { + if let Ok(stop_pointer) = memory + .get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) { if self.base() != stop_pointer.segment_index { return Err(RunnerError::InvalidStopPointer("output".to_string())); } let stop_ptr = stop_pointer.offset; let used = self - .get_used_cells(vm) + .get_used_cells(segments) .map_err(|_| RunnerError::FinalStack)?; if stop_ptr != used { return Err(RunnerError::InvalidStopPointer("output".to_string())); } - Ok(( - pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?, - stop_ptr, - )) + self.stop_ptr = Some(stop_ptr); + Ok(pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?) } else { Err(RunnerError::FinalStack) } } else { let stop_ptr = self.base() as usize; - Ok((pointer, stop_ptr)) + self.stop_ptr = Some(stop_ptr); + Ok(pointer) } } } @@ -139,22 +142,14 @@ mod tests { let builtin = OutputBuiltinRunner::new(true); let mut vm = vm!(); - - vm.memory = memory![ - ((0, 0), (0, 0)), - ((0, 1), (0, 1)), - ((2, 0), (0, 0)), - ((2, 1), (0, 0)) - ]; - vm.segments.segment_used_sizes = Some(vec![1]); - assert_eq!(builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] fn final_stack() { - let builtin = OutputBuiltinRunner::new(true); + let mut builtin = OutputBuiltinRunner::new(true); let mut vm = vm!(); @@ -170,14 +165,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 1)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 1)) ); } #[test] fn final_stack_error_stop_pointer() { - let builtin = OutputBuiltinRunner::new(true); + let mut builtin = OutputBuiltinRunner::new(true); let mut vm = vm!(); @@ -193,14 +190,14 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::InvalidStopPointer("output".to_string())) ); } #[test] - fn final_stack_error_when_not_included() { - let builtin = OutputBuiltinRunner::new(false); + fn final_stack_error_when_notincluded() { + let mut builtin = OutputBuiltinRunner::new(false); let mut vm = vm!(); @@ -216,14 +213,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 2)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 2)) ); } #[test] fn final_stack_error_non_relocatable() { - let builtin = OutputBuiltinRunner::new(true); + let mut builtin = OutputBuiltinRunner::new(true); let mut vm = vm!(); @@ -239,7 +238,7 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::FinalStack) ); } @@ -338,7 +337,7 @@ mod tests { let vm = vm!(); assert_eq!( - builtin.get_used_cells(&vm), + builtin.get_used_cells(&vm.segments), Err(MemoryError::MissingSegmentUsedSizes) ); } @@ -349,7 +348,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_used_cells(&vm), Ok(0)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0)); } #[test] @@ -358,6 +357,6 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!(builtin.get_used_cells(&vm), Ok(4)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4)); } } diff --git a/src/vm/runners/builtin_runner/range_check.rs b/src/vm/runners/builtin_runner/range_check.rs index 5feb474e0b..6239c7af13 100644 --- a/src/vm/runners/builtin_runner/range_check.rs +++ b/src/vm/runners/builtin_runner/range_check.rs @@ -30,7 +30,7 @@ pub struct RangeCheckBuiltinRunner { pub(crate) n_input_cells: u32, inner_rc_bound: usize, pub _bound: Option, - pub(crate) _included: bool, + pub(crate) included: bool, n_parts: u32, instances_per_component: u32, } @@ -54,7 +54,7 @@ impl RangeCheckBuiltinRunner { n_input_cells: CELLS_PER_RANGE_CHECK, inner_rc_bound, _bound, - _included: included, + included, n_parts, instances_per_component: 1, } @@ -69,7 +69,7 @@ impl RangeCheckBuiltinRunner { } pub fn initial_stack(&self) -> Vec { - if self._included { + if self.included { vec![MaybeRelocatable::from((self.base, 0))] } else { vec![] @@ -131,9 +131,9 @@ impl RangeCheckBuiltinRunner { (self.base, self.stop_ptr) } - pub fn get_used_cells(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { let base = self.base(); - vm.segments + segments .get_segment_used_size( base.try_into() .map_err(|_| MemoryError::AddressInTemporarySegment(base))?, @@ -151,7 +151,7 @@ impl RangeCheckBuiltinRunner { if vm.current_step < min_step { Err(MemoryError::InsufficientAllocatedCells) } else { - let used = self.get_used_cells(vm)?; + let used = self.get_used_cells(&vm.segments)?; let size = cells_per_instance as usize * safe_div_usize(vm.current_step, ratio) .map_err(|_| MemoryError::InsufficientAllocatedCells)?; @@ -189,41 +189,44 @@ impl RangeCheckBuiltinRunner { rc_bounds } - pub fn get_used_instances(&self, vm: &VirtualMachine) -> Result { - self.get_used_cells(vm) + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { + self.get_used_cells(segments) } pub fn final_stack( - &self, - vm: &VirtualMachine, + &mut self, + segments: &MemorySegmentManager, + memory: &Memory, pointer: Relocatable, - ) -> Result<(Relocatable, usize), RunnerError> { - if self._included { - if let Ok(stop_pointer) = - vm.get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) + ) -> Result { + if self.included { + if let Ok(stop_pointer) = memory + .get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) { if self.base() != stop_pointer.segment_index { return Err(RunnerError::InvalidStopPointer("range_check".to_string())); } let stop_ptr = stop_pointer.offset; let num_instances = self - .get_used_instances(vm) + .get_used_instances(segments) .map_err(|_| RunnerError::FinalStack)?; let used_cells = num_instances * self.cells_per_instance as usize; if stop_ptr != used_cells { return Err(RunnerError::InvalidStopPointer("range_check".to_string())); } - Ok(( - pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?, - stop_ptr, - )) + self.stop_ptr = Some(stop_ptr); + Ok(pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?) } else { Err(RunnerError::FinalStack) } } else { let stop_ptr = self.base() as usize; - Ok((pointer, stop_ptr)) + self.stop_ptr = Some(stop_ptr); + Ok(pointer) } } @@ -255,22 +258,14 @@ mod tests { let builtin = RangeCheckBuiltinRunner::new(10, 12, true); let mut vm = vm!(); - - vm.memory = memory![ - ((0, 0), (0, 0)), - ((0, 1), (0, 1)), - ((2, 0), (0, 0)), - ((2, 1), (0, 0)) - ]; - vm.segments.segment_used_sizes = Some(vec![1]); - assert_eq!(builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] fn final_stack() { - let builtin = RangeCheckBuiltinRunner::new(10, 12, true); + let mut builtin = RangeCheckBuiltinRunner::new(10, 12, true); let mut vm = vm!(); @@ -286,14 +281,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 1)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 1)) ); } #[test] fn final_stack_error_stop_pointer() { - let builtin = RangeCheckBuiltinRunner::new(10, 12, true); + let mut builtin = RangeCheckBuiltinRunner::new(10, 12, true); let mut vm = vm!(); @@ -309,14 +306,14 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::InvalidStopPointer("range_check".to_string())) ); } #[test] - fn final_stack_error_when_not_included() { - let builtin = RangeCheckBuiltinRunner::new(10, 12, false); + fn final_stack_error_when_notincluded() { + let mut builtin = RangeCheckBuiltinRunner::new(10, 12, false); let mut vm = vm!(); @@ -332,14 +329,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 2)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 2)) ); } #[test] fn final_stack_error_non_relocatable() { - let builtin = RangeCheckBuiltinRunner::new(10, 12, true); + let mut builtin = RangeCheckBuiltinRunner::new(10, 12, true); let mut vm = vm!(); @@ -355,7 +354,7 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::FinalStack) ); } @@ -519,7 +518,7 @@ mod tests { let vm = vm!(); assert_eq!( - builtin.get_used_cells(&vm), + builtin.get_used_cells(&vm.segments), Err(MemoryError::MissingSegmentUsedSizes) ); } @@ -530,7 +529,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_used_cells(&vm), Ok(0)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0)); } #[test] @@ -539,7 +538,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!(builtin.get_used_cells(&vm), Ok(4)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4)); } #[test] diff --git a/src/vm/runners/builtin_runner/signature.rs b/src/vm/runners/builtin_runner/signature.rs index fe0e812c8d..395bc6abe2 100644 --- a/src/vm/runners/builtin_runner/signature.rs +++ b/src/vm/runners/builtin_runner/signature.rs @@ -193,9 +193,9 @@ impl SignatureBuiltinRunner { (self.base, self.stop_ptr) } - pub fn get_used_cells(&self, vm: &VirtualMachine) -> Result { + pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result { let base = self.base(); - vm.segments + segments .get_segment_used_size( base.try_into() .map_err(|_| MemoryError::AddressInTemporarySegment(base))?, @@ -213,7 +213,7 @@ impl SignatureBuiltinRunner { if vm.current_step < min_step { Err(MemoryError::InsufficientAllocatedCells) } else { - let used = self.get_used_cells(vm)?; + let used = self.get_used_cells(&vm.segments)?; let size = cells_per_instance as usize * safe_div_usize(vm.current_step, ratio) .map_err(|_| MemoryError::InsufficientAllocatedCells)?; @@ -224,42 +224,45 @@ impl SignatureBuiltinRunner { } } - pub fn get_used_instances(&self, vm: &VirtualMachine) -> Result { - let used_cells = self.get_used_cells(vm)?; + pub fn get_used_instances( + &self, + segments: &MemorySegmentManager, + ) -> Result { + let used_cells = self.get_used_cells(segments)?; Ok(div_ceil(used_cells, self.cells_per_instance as usize)) } pub fn final_stack( - &self, - vm: &VirtualMachine, + &mut self, + segments: &MemorySegmentManager, + memory: &Memory, pointer: Relocatable, - ) -> Result<(Relocatable, usize), RunnerError> { + ) -> Result { if self.included { - if let Ok(stop_pointer) = - vm.get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) + if let Ok(stop_pointer) = memory + .get_relocatable(&(pointer.sub_usize(1)).map_err(|_| RunnerError::FinalStack)?) { if self.base() != stop_pointer.segment_index { return Err(RunnerError::InvalidStopPointer("ecdsa".to_string())); } let stop_ptr = stop_pointer.offset; let num_instances = self - .get_used_instances(vm) + .get_used_instances(segments) .map_err(|_| RunnerError::FinalStack)?; let used_cells = num_instances * self.cells_per_instance as usize; if stop_ptr != used_cells { return Err(RunnerError::InvalidStopPointer("ecdsa".to_string())); } - Ok(( - pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?, - stop_ptr, - )) + self.stop_ptr = Some(stop_ptr); + Ok(pointer.sub_usize(1).map_err(|_| RunnerError::FinalStack)?) } else { Err(RunnerError::FinalStack) } } else { let stop_ptr = self.base() as usize; - Ok((pointer, stop_ptr)) + self.stop_ptr = Some(stop_ptr); + Ok(pointer) } } } @@ -292,22 +295,14 @@ mod tests { let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); let mut vm = vm!(); - - vm.memory = memory![ - ((0, 0), (0, 0)), - ((0, 1), (0, 1)), - ((2, 0), (0, 0)), - ((2, 1), (0, 0)) - ]; - vm.segments.segment_used_sizes = Some(vec![1]); - assert_eq!(builtin.get_used_instances(&vm), Ok(1)); + assert_eq!(builtin.get_used_instances(&vm.segments), Ok(1)); } #[test] fn final_stack() { - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); let mut vm = vm!(); @@ -323,14 +318,16 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer).unwrap(), - (Relocatable::from((2, 1)), 0) + builtin + .final_stack(&vm.segments, &vm.memory, pointer) + .unwrap(), + Relocatable::from((2, 1)) ); } #[test] fn final_stack_error_stop_pointer() { - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); let mut vm = vm!(); @@ -346,14 +343,14 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::InvalidStopPointer("ecdsa".to_string())) ); } #[test] fn final_stack_error_non_relocatable() { - let builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); + let mut builtin = SignatureBuiltinRunner::new(&EcdsaInstanceDef::default(), true); let mut vm = vm!(); @@ -369,7 +366,7 @@ mod tests { let pointer = Relocatable::from((2, 2)); assert_eq!( - builtin.final_stack(&vm, pointer), + builtin.final_stack(&vm.segments, &vm.memory, pointer), Err(RunnerError::FinalStack) ); } @@ -436,7 +433,7 @@ mod tests { let vm = vm!(); assert_eq!( - builtin.get_used_cells(&vm), + builtin.get_used_cells(&vm.segments), Err(MemoryError::MissingSegmentUsedSizes) ); } @@ -450,7 +447,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![0]); - assert_eq!(builtin.get_used_cells(&vm), Ok(0)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(0)); } #[test] @@ -462,7 +459,7 @@ mod tests { let mut vm = vm!(); vm.segments.segment_used_sizes = Some(vec![4]); - assert_eq!(builtin.get_used_cells(&vm), Ok(4)); + assert_eq!(builtin.get_used_cells(&vm.segments), Ok(4)); } #[test] diff --git a/src/vm/runners/cairo_runner.rs b/src/vm/runners/cairo_runner.rs index 58ea71085f..e9e81b8967 100644 --- a/src/vm/runners/cairo_runner.rs +++ b/src/vm/runners/cairo_runner.rs @@ -843,7 +843,7 @@ impl CairoRunner { for (builtin_name, builtin_runner) in &vm.builtin_runners { builtin_instance_counter.insert( builtin_name.to_string(), - builtin_runner.get_used_instances(vm)?, + builtin_runner.get_used_instances(&vm.segments)?, ); } @@ -1062,33 +1062,10 @@ impl CairoRunner { if !self.run_ended { return Err(RunnerError::ReadReturnValuesNoEndRun); } - let mut stop_pointers = vec![]; let mut pointer = vm.get_ap(); - for builtin_name in self.program.builtins.iter().rev() { - let builtin_runner = vm - .builtin_runners - .iter() - .find(|(name, _builtin)| builtin_name == name); - - match builtin_runner { - None => return Err(RunnerError::MissingBuiltin(builtin_name.to_string())), - Some((_, builtin)) => { - let (new_pointer, stop_ptr) = builtin.final_stack(vm, pointer)?; - stop_pointers.push(stop_ptr); - pointer = new_pointer; - } - } - } - //FIXME: Update stop_ptr in BuilrinRunner::final_stack, instead of doing it here - // Quick and ugly solution to bypass mutability restrictions - for (index, builtin_name) in self.program.builtins.iter().rev().enumerate() { - let builtin_runner = vm - .builtin_runners - .iter_mut() - .find(|(name, _builtin)| builtin_name == name); - // We checked this before so this unwrap is safe - // We can safely index into stop_pointers as it was built using the same iteration - builtin_runner.unwrap().1.set_stop_ptr(stop_pointers[index]); + for (_, builtin_runner) in vm.builtin_runners.iter_mut().rev() { + let new_pointer = builtin_runner.final_stack(&vm.segments, &vm.memory, pointer)?; + pointer = new_pointer; } if self.segments_finalized { return Err(RunnerError::FailedAddingReturnValues); @@ -1128,6 +1105,27 @@ impl CairoRunner { offset: 0, } } + + // Iterates over the program builtins in reverse, calling BuiltinRunner::final_stack on each of them and returns the final pointer + // This method is used by cairo_rs_py to replace starknet functionality + pub fn get_builtins_final_stack( + &self, + vm: &mut VirtualMachine, + stack_ptr: Relocatable, + ) -> Result { + let mut stack_ptr = Relocatable::from(&stack_ptr); + for (_, runner) in + vm.builtin_runners + .iter_mut() + .rev() + .filter(|(builtin_name, _builtin_runner)| { + self.get_program_builtins().contains(builtin_name) + }) + { + stack_ptr = runner.final_stack(&vm.segments, &vm.memory, stack_ptr)? + } + Ok(stack_ptr) + } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -4183,7 +4181,7 @@ mod tests { BuiltinRunner::Hash(builtin) => { assert_eq!(builtin.base(), 0); assert_eq!(builtin.ratio(), 32); - assert!(builtin._included); + assert!(builtin.included); } _ => unreachable!(), } @@ -4211,7 +4209,7 @@ mod tests { BuiltinRunner::Hash(builtin) => { assert_eq!(builtin.base(), 1); assert_eq!(builtin.ratio(), 32); - assert!(builtin._included); + assert!(builtin.included); } _ => unreachable!(), } @@ -4293,4 +4291,64 @@ mod tests { let value = vec![MaybeRelocatable::from((0, 0))]; assert_eq!(expected, value.into()) } + + #[test] + fn get_builtins_final_stack_range_check_builtin() { + let program = Program::from_file( + Path::new("cairo_programs/assert_le_felt_hint.json"), + Some("main"), + ) + .unwrap(); + let mut runner = cairo_runner!(program); + let mut vm = vm!(); + let end = runner.initialize(&mut vm).unwrap(); + runner + .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) + .unwrap(); + vm.segments.compute_effective_sizes(&vm.memory); + let initial_pointer = vm.get_ap(); + let expected_pointer = vm.get_ap().sub_usize(1).unwrap(); + assert_eq!( + runner.get_builtins_final_stack(&mut vm, initial_pointer), + Ok(expected_pointer) + ); + } + + #[test] + fn get_builtins_final_stack_4_builtins() { + let program = + Program::from_file(Path::new("cairo_programs/integration.json"), Some("main")).unwrap(); + let mut runner = cairo_runner!(program); + let mut vm = vm!(); + let end = runner.initialize(&mut vm).unwrap(); + runner + .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) + .unwrap(); + vm.segments.compute_effective_sizes(&vm.memory); + let initial_pointer = vm.get_ap(); + let expected_pointer = vm.get_ap().sub_usize(4).unwrap(); + assert_eq!( + runner.get_builtins_final_stack(&mut vm, initial_pointer), + Ok(expected_pointer) + ); + } + + #[test] + fn get_builtins_final_stack_no_builtins() { + let program = + Program::from_file(Path::new("cairo_programs/fibonacci.json"), Some("main")).unwrap(); + let mut runner = cairo_runner!(program); + let mut vm = vm!(); + let end = runner.initialize(&mut vm).unwrap(); + runner + .run_until_pc(end, &mut vm, &mut BuiltinHintProcessor::new_empty()) + .unwrap(); + vm.segments.compute_effective_sizes(&vm.memory); + let initial_pointer = vm.get_ap(); + let expected_pointer = vm.get_ap(); + assert_eq!( + runner.get_builtins_final_stack(&mut vm, initial_pointer), + Ok(expected_pointer) + ); + } }