From 66059e990eddaf19096704b559ebb5f1285b0104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Mon, 23 Oct 2023 11:59:42 -0400 Subject: [PATCH 1/5] feat: allow stepping through Brillig code by popping out a BrilligSolver --- Cargo.lock | 2 ++ acvm-repo/acvm/Cargo.toml | 1 + acvm-repo/acvm/src/pwg/brillig.rs | 18 +++++++--- acvm-repo/acvm/src/pwg/mod.rs | 42 +++++++++++++++++++++- tooling/debugger/Cargo.toml | 3 +- tooling/debugger/src/lib.rs | 60 +++++++++++++++++++++++++++++-- 6 files changed, 117 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5601dbae53d..f7e1ecae19c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,6 +42,7 @@ dependencies = [ "acvm_blackbox_solver", "acvm_stdlib", "brillig_vm", + "either", "indexmap 1.9.3", "num-bigint", "num-traits", @@ -2543,6 +2544,7 @@ version = "0.16.0" dependencies = [ "acvm", "easy-repl", + "either", "nargo", "noirc_printable_type", "owo-colors", diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml index f51bb627fd9..0d0dadd77f8 100644 --- a/acvm-repo/acvm/Cargo.toml +++ b/acvm-repo/acvm/Cargo.toml @@ -16,6 +16,7 @@ repository.workspace = true num-bigint.workspace = true num-traits.workspace = true thiserror.workspace = true +either = "1.8.1" acir.workspace = true stdlib.workspace = true diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 6fc54d42eab..b0e5ec6dd48 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -14,13 +14,14 @@ use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; use super::{get_value, insert_value}; -pub(super) enum BrilligSolverStatus { +#[derive(Debug)] +pub enum BrilligSolverStatus { Finished, InProgress, ForeignCallWait(ForeignCallWaitInfo), } -pub(super) struct BrilligSolver<'b, B: BlackBoxFunctionSolver> { +pub struct BrilligSolver<'b, B: BlackBoxFunctionSolver> { vm: VM<'b, B>, acir_index: usize, } @@ -62,7 +63,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { /// Constructs a solver for a Brillig block given the bytecode and initial /// witness. pub(super) fn new( - initial_witness: &mut WitnessMap, + initial_witness: &WitnessMap, brillig: &'b Brillig, bb_solver: &'b B, acir_index: usize, @@ -116,6 +117,15 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { self.handle_vm_status(status) } + pub fn step(&mut self) -> Result { + let status = self.vm.process_opcode(); + self.handle_vm_status(status) + } + + pub fn program_counter(&self) -> usize { + self.vm.program_counter() + } + fn handle_vm_status( &self, vm_status: VMStatus, @@ -185,7 +195,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { Ok(()) } - pub(super) fn resolve_pending_foreign_call(&mut self, foreign_call_result: ForeignCallResult) { + pub fn resolve_pending_foreign_call(&mut self, foreign_call_result: ForeignCallResult) { match self.vm.get_status() { VMStatus::ForeignCallWait { .. } => self.vm.resolve_foreign_call(foreign_call_result), _ => unreachable!("Brillig VM is not waiting for a foreign call"), diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index 057597e6392..ee974574e72 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -12,13 +12,13 @@ use acvm_blackbox_solver::BlackBoxResolutionError; use self::{ arithmetic::ArithmeticSolver, - brillig::{BrilligSolver, BrilligSolverStatus}, directives::solve_directives, memory_op::MemoryOpSolver, }; use crate::{BlackBoxFunctionSolver, Language}; use thiserror::Error; +use either::Either; // arithmetic pub(crate) mod arithmetic; @@ -31,6 +31,7 @@ mod blackbox; mod memory_op; pub use brillig::ForeignCallWaitInfo; +pub use self::brillig::{BrilligSolver, BrilligSolverStatus}; #[derive(Debug, Clone, PartialEq)] pub enum ACVMStatus { @@ -263,6 +264,10 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { res => res.map(|_| ()), }, }; + self.handle_opcode_resolution(resolution) + } + + fn handle_opcode_resolution(&mut self, resolution: Result<(), OpcodeResolutionError>) -> ACVMStatus { match resolution { Ok(()) => { self.instruction_pointer += 1; @@ -331,6 +336,41 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { } } } + + pub fn step_into_brillig_opcode(&mut self) -> Either, ACVMStatus> { + if let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] { + let witness = &mut self.witness_map; + match BrilligSolver::::should_skip(witness, brillig) { + Ok(true) => { + let resolution = BrilligSolver::::zero_out_brillig_outputs(witness, brillig); + Either::Right(self.handle_opcode_resolution(resolution)) + } + Ok(false) => { + let solver = BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer); + match solver { + Ok(solver) => Either::Left(solver), + Err(..) => Either::Right(self.handle_opcode_resolution(solver.map(|_| ()))), + } + } + Err(err) => { + Either::Right(self.handle_opcode_resolution(Err(err))) + } + } + } else { + Either::Right(self.solve_opcode()) + } + } + + pub fn finish_brillig_with_solver( + &mut self, + solver: BrilligSolver<'a, B>, + ) -> ACVMStatus { + if !matches!(&self.opcodes[self.instruction_pointer], Opcode::Brillig(..)) { + unreachable!("Not executing a Brillig opcode"); + } + self.brillig_solver = Some(solver); + self.solve_opcode() + } } // Returns the concrete value for a particular witness diff --git a/tooling/debugger/Cargo.toml b/tooling/debugger/Cargo.toml index e01abd9ac61..5413ef25103 100644 --- a/tooling/debugger/Cargo.toml +++ b/tooling/debugger/Cargo.toml @@ -14,4 +14,5 @@ nargo.workspace = true noirc_printable_type.workspace = true thiserror.workspace = true easy-repl = "0.2.1" -owo-colors = "3" \ No newline at end of file +owo-colors = "3" +either = "1.8.1" diff --git a/tooling/debugger/src/lib.rs b/tooling/debugger/src/lib.rs index f8e9db19234..b98cef611ec 100644 --- a/tooling/debugger/src/lib.rs +++ b/tooling/debugger/src/lib.rs @@ -1,5 +1,5 @@ use acvm::acir::circuit::OpcodeLocation; -use acvm::pwg::{ACVMStatus, ErrorLocation, OpcodeResolutionError, ACVM}; +use acvm::pwg::{ACVMStatus, BrilligSolver, ErrorLocation, OpcodeResolutionError, ACVM, BrilligSolverStatus}; use acvm::BlackBoxFunctionSolver; use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; @@ -13,6 +13,7 @@ use easy_repl::{command, CommandStatus, Critical, Repl}; use std::cell::{Cell, RefCell}; use owo_colors::OwoColorize; +use either::Either; enum SolveResult { Done, @@ -21,6 +22,7 @@ enum SolveResult { struct DebugContext<'backend, B: BlackBoxFunctionSolver> { acvm: ACVM<'backend, B>, + brillig_solver: Option>, debug_artifact: DebugArtifact, foreign_call_executor: ForeignCallExecutor, circuit: &'backend Circuit, @@ -28,10 +30,61 @@ struct DebugContext<'backend, B: BlackBoxFunctionSolver> { } impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { + fn step_brillig_opcode(&mut self) -> Result { + let Some(mut solver) = self.brillig_solver.take() else { + unreachable!("Missing Brillig solver"); + }; + match solver.step() { + Ok(status) => { + println!("Brillig step result: {:?}", status); + println!("Brillig program counter: {:?}", solver.program_counter()); + match status { + BrilligSolverStatus::InProgress => { + self.brillig_solver = Some(solver); + Ok(SolveResult::Ok) + }, + BrilligSolverStatus::Finished => { + let status = self.acvm.finish_brillig_with_solver(solver); + self.handle_acvm_status(status) + } + BrilligSolverStatus::ForeignCallWait(foreign_call) => { + let foreign_call_result = + self.foreign_call_executor.execute(&foreign_call, self.show_output)?; + solver.resolve_pending_foreign_call(foreign_call_result); + self.brillig_solver = Some(solver); + Ok(SolveResult::Ok) + } + } + } + Err(err) => { + self.handle_acvm_status(ACVMStatus::Failure(err)) + } + } + } + fn step_opcode(&mut self) -> Result { - let solver_status = self.acvm.solve_opcode(); + if matches!(self.brillig_solver, Some(_)) { + self.step_brillig_opcode() + } else { + match self.acvm.step_into_brillig_opcode() { + Either::Left(solver) => { + self.brillig_solver = Some(solver); + self.step_brillig_opcode() + } + Either::Right(status) => { + self.handle_acvm_status(status) + } + } + } + } + + fn step_acir_opcode(&mut self) -> Result { + let status = self.acvm.solve_opcode(); + self.handle_acvm_status(status) + } - match solver_status { + fn handle_acvm_status(&mut self, status: ACVMStatus) -> Result { + match status { ACVMStatus::Solved => Ok(SolveResult::Done), ACVMStatus::InProgress => Ok(SolveResult::Ok), ACVMStatus::Failure(error) => { @@ -129,6 +182,7 @@ pub fn debug_circuit( let context = RefCell::new(DebugContext { acvm: ACVM::new(blackbox_solver, &circuit.opcodes, initial_witness), foreign_call_executor: ForeignCallExecutor::default(), + brillig_solver: None, circuit, debug_artifact, show_output, From 68da2a7803db9a97b8eab3cd893f5371ba947f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Mon, 23 Oct 2023 12:52:24 -0400 Subject: [PATCH 2/5] chore: use an enum instead of Either to model the result of opcode stepping --- Cargo.lock | 2 -- acvm-repo/acvm/Cargo.toml | 1 - acvm-repo/acvm/src/pwg/mod.rs | 18 +++++++++++------- tooling/debugger/Cargo.toml | 1 - tooling/debugger/src/lib.rs | 7 +++---- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7e1ecae19c..5601dbae53d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,7 +42,6 @@ dependencies = [ "acvm_blackbox_solver", "acvm_stdlib", "brillig_vm", - "either", "indexmap 1.9.3", "num-bigint", "num-traits", @@ -2544,7 +2543,6 @@ version = "0.16.0" dependencies = [ "acvm", "easy-repl", - "either", "nargo", "noirc_printable_type", "owo-colors", diff --git a/acvm-repo/acvm/Cargo.toml b/acvm-repo/acvm/Cargo.toml index 0d0dadd77f8..f51bb627fd9 100644 --- a/acvm-repo/acvm/Cargo.toml +++ b/acvm-repo/acvm/Cargo.toml @@ -16,7 +16,6 @@ repository.workspace = true num-bigint.workspace = true num-traits.workspace = true thiserror.workspace = true -either = "1.8.1" acir.workspace = true stdlib.workspace = true diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index ee974574e72..de78e46174f 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -18,7 +18,6 @@ use self::{ use crate::{BlackBoxFunctionSolver, Language}; use thiserror::Error; -use either::Either; // arithmetic pub(crate) mod arithmetic; @@ -64,6 +63,11 @@ impl std::fmt::Display for ACVMStatus { } } +pub enum StepResult<'a, B: BlackBoxFunctionSolver> { + Status(ACVMStatus), + IntoBrillig(BrilligSolver<'a, B>), +} + // This enum represents the different cases in which an // opcode can be unsolvable. // The most common being that one of its input has not been @@ -337,27 +341,27 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { } } - pub fn step_into_brillig_opcode(&mut self) -> Either, ACVMStatus> { + pub fn step_into_brillig_opcode(&mut self) -> StepResult<'a, B> { if let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] { let witness = &mut self.witness_map; match BrilligSolver::::should_skip(witness, brillig) { Ok(true) => { let resolution = BrilligSolver::::zero_out_brillig_outputs(witness, brillig); - Either::Right(self.handle_opcode_resolution(resolution)) + StepResult::Status(self.handle_opcode_resolution(resolution)) } Ok(false) => { let solver = BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer); match solver { - Ok(solver) => Either::Left(solver), - Err(..) => Either::Right(self.handle_opcode_resolution(solver.map(|_| ()))), + Ok(solver) => StepResult::IntoBrillig(solver), + Err(..) => StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))), } } Err(err) => { - Either::Right(self.handle_opcode_resolution(Err(err))) + StepResult::Status(self.handle_opcode_resolution(Err(err))) } } } else { - Either::Right(self.solve_opcode()) + StepResult::Status(self.solve_opcode()) } } diff --git a/tooling/debugger/Cargo.toml b/tooling/debugger/Cargo.toml index 5413ef25103..7e06c549d2d 100644 --- a/tooling/debugger/Cargo.toml +++ b/tooling/debugger/Cargo.toml @@ -15,4 +15,3 @@ noirc_printable_type.workspace = true thiserror.workspace = true easy-repl = "0.2.1" owo-colors = "3" -either = "1.8.1" diff --git a/tooling/debugger/src/lib.rs b/tooling/debugger/src/lib.rs index b98cef611ec..b63b97cf2cc 100644 --- a/tooling/debugger/src/lib.rs +++ b/tooling/debugger/src/lib.rs @@ -1,5 +1,5 @@ use acvm::acir::circuit::OpcodeLocation; -use acvm::pwg::{ACVMStatus, BrilligSolver, ErrorLocation, OpcodeResolutionError, ACVM, BrilligSolverStatus}; +use acvm::pwg::{ACVMStatus, BrilligSolver, ErrorLocation, OpcodeResolutionError, ACVM, BrilligSolverStatus, StepResult}; use acvm::BlackBoxFunctionSolver; use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; @@ -13,7 +13,6 @@ use easy_repl::{command, CommandStatus, Critical, Repl}; use std::cell::{Cell, RefCell}; use owo_colors::OwoColorize; -use either::Either; enum SolveResult { Done, @@ -67,11 +66,11 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { self.step_brillig_opcode() } else { match self.acvm.step_into_brillig_opcode() { - Either::Left(solver) => { + StepResult::IntoBrillig(solver) => { self.brillig_solver = Some(solver); self.step_brillig_opcode() } - Either::Right(status) => { + StepResult::Status(status) => { self.handle_acvm_status(status) } } From c65ec7cf679069b8ebc5286255463cde60d9ef7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Mon, 23 Oct 2023 13:01:32 -0400 Subject: [PATCH 3/5] chore: cargo fmt --- acvm-repo/acvm/src/pwg/mod.rs | 33 +++++++++++++++++---------------- tooling/debugger/src/lib.rs | 15 +++++++-------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index de78e46174f..ff3bf969cf6 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -10,11 +10,7 @@ use acir::{ }; use acvm_blackbox_solver::BlackBoxResolutionError; -use self::{ - arithmetic::ArithmeticSolver, - directives::solve_directives, - memory_op::MemoryOpSolver, -}; +use self::{arithmetic::ArithmeticSolver, directives::solve_directives, memory_op::MemoryOpSolver}; use crate::{BlackBoxFunctionSolver, Language}; use thiserror::Error; @@ -29,8 +25,8 @@ mod directives; mod blackbox; mod memory_op; -pub use brillig::ForeignCallWaitInfo; pub use self::brillig::{BrilligSolver, BrilligSolverStatus}; +pub use brillig::ForeignCallWaitInfo; #[derive(Debug, Clone, PartialEq)] pub enum ACVMStatus { @@ -271,7 +267,10 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { self.handle_opcode_resolution(resolution) } - fn handle_opcode_resolution(&mut self, resolution: Result<(), OpcodeResolutionError>) -> ACVMStatus { + fn handle_opcode_resolution( + &mut self, + resolution: Result<(), OpcodeResolutionError>, + ) -> ACVMStatus { match resolution { Ok(()) => { self.instruction_pointer += 1; @@ -350,25 +349,27 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { StepResult::Status(self.handle_opcode_resolution(resolution)) } Ok(false) => { - let solver = BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer); + let solver = BrilligSolver::new( + witness, + brillig, + self.backend, + self.instruction_pointer, + ); match solver { Ok(solver) => StepResult::IntoBrillig(solver), - Err(..) => StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))), + Err(..) => { + StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))) + } } } - Err(err) => { - StepResult::Status(self.handle_opcode_resolution(Err(err))) - } + Err(err) => StepResult::Status(self.handle_opcode_resolution(Err(err))), } } else { StepResult::Status(self.solve_opcode()) } } - pub fn finish_brillig_with_solver( - &mut self, - solver: BrilligSolver<'a, B>, - ) -> ACVMStatus { + pub fn finish_brillig_with_solver(&mut self, solver: BrilligSolver<'a, B>) -> ACVMStatus { if !matches!(&self.opcodes[self.instruction_pointer], Opcode::Brillig(..)) { unreachable!("Not executing a Brillig opcode"); } diff --git a/tooling/debugger/src/lib.rs b/tooling/debugger/src/lib.rs index b63b97cf2cc..9f4ee3b7fa6 100644 --- a/tooling/debugger/src/lib.rs +++ b/tooling/debugger/src/lib.rs @@ -1,5 +1,8 @@ use acvm::acir::circuit::OpcodeLocation; -use acvm::pwg::{ACVMStatus, BrilligSolver, ErrorLocation, OpcodeResolutionError, ACVM, BrilligSolverStatus, StepResult}; +use acvm::pwg::{ + ACVMStatus, BrilligSolver, BrilligSolverStatus, ErrorLocation, OpcodeResolutionError, + StepResult, ACVM, +}; use acvm::BlackBoxFunctionSolver; use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; @@ -41,7 +44,7 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { BrilligSolverStatus::InProgress => { self.brillig_solver = Some(solver); Ok(SolveResult::Ok) - }, + } BrilligSolverStatus::Finished => { let status = self.acvm.finish_brillig_with_solver(solver); self.handle_acvm_status(status) @@ -55,9 +58,7 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { } } } - Err(err) => { - self.handle_acvm_status(ACVMStatus::Failure(err)) - } + Err(err) => self.handle_acvm_status(ACVMStatus::Failure(err)), } } @@ -70,9 +71,7 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { self.brillig_solver = Some(solver); self.step_brillig_opcode() } - StepResult::Status(status) => { - self.handle_acvm_status(status) - } + StepResult::Status(status) => self.handle_acvm_status(status), } } } From e0c66bb1fce975be99333a017b7c8fbb839ddbc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Mon, 23 Oct 2023 18:14:29 -0400 Subject: [PATCH 4/5] chore: remove unused function to apease clippy --- tooling/debugger/src/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tooling/debugger/src/lib.rs b/tooling/debugger/src/lib.rs index 9f4ee3b7fa6..68dbbb69f28 100644 --- a/tooling/debugger/src/lib.rs +++ b/tooling/debugger/src/lib.rs @@ -76,11 +76,6 @@ impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { } } - fn step_acir_opcode(&mut self) -> Result { - let status = self.acvm.solve_opcode(); - self.handle_acvm_status(status) - } - fn handle_acvm_status(&mut self, status: ACVMStatus) -> Result { match status { ACVMStatus::Solved => Ok(SolveResult::Done), From 410425ea08ed5e2895d31d390cd3275fb0c0c6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 24 Oct 2023 10:40:28 -0400 Subject: [PATCH 5/5] chore: use early returns to avoid nesting --- acvm-repo/acvm/src/pwg/mod.rs | 91 ++++++++++++++++------------------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index ff3bf969cf6..1022ad13800 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -310,62 +310,55 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] else { unreachable!("Not executing a Brillig opcode"); }; + let witness = &mut self.witness_map; if BrilligSolver::::should_skip(witness, brillig)? { - BrilligSolver::::zero_out_brillig_outputs(witness, brillig).map(|_| None) - } else { - // If we're resuming execution after resolving a foreign call then - // there will be a cached `BrilligSolver` to avoid recomputation. - let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { - Some(solver) => solver, - None => { - BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)? - } - }; - match solver.solve()? { - BrilligSolverStatus::ForeignCallWait(foreign_call) => { - // Cache the current state of the solver - self.brillig_solver = Some(solver); - Ok(Some(foreign_call)) - } - BrilligSolverStatus::InProgress => { - unreachable!("Brillig solver still in progress") - } - BrilligSolverStatus::Finished => { - // Write execution outputs - solver.finalize(witness, brillig)?; - Ok(None) - } + return BrilligSolver::::zero_out_brillig_outputs(witness, brillig).map(|_| None); + } + + // If we're resuming execution after resolving a foreign call then + // there will be a cached `BrilligSolver` to avoid recomputation. + let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { + Some(solver) => solver, + None => BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)?, + }; + match solver.solve()? { + BrilligSolverStatus::ForeignCallWait(foreign_call) => { + // Cache the current state of the solver + self.brillig_solver = Some(solver); + Ok(Some(foreign_call)) + } + BrilligSolverStatus::InProgress => { + unreachable!("Brillig solver still in progress") + } + BrilligSolverStatus::Finished => { + // Write execution outputs + solver.finalize(witness, brillig)?; + Ok(None) } } } pub fn step_into_brillig_opcode(&mut self) -> StepResult<'a, B> { - if let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] { - let witness = &mut self.witness_map; - match BrilligSolver::::should_skip(witness, brillig) { - Ok(true) => { - let resolution = BrilligSolver::::zero_out_brillig_outputs(witness, brillig); - StepResult::Status(self.handle_opcode_resolution(resolution)) - } - Ok(false) => { - let solver = BrilligSolver::new( - witness, - brillig, - self.backend, - self.instruction_pointer, - ); - match solver { - Ok(solver) => StepResult::IntoBrillig(solver), - Err(..) => { - StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))) - } - } - } - Err(err) => StepResult::Status(self.handle_opcode_resolution(Err(err))), - } - } else { - StepResult::Status(self.solve_opcode()) + let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] else { + return StepResult::Status(self.solve_opcode()); + }; + + let witness = &mut self.witness_map; + let should_skip = match BrilligSolver::::should_skip(witness, brillig) { + Ok(result) => result, + Err(err) => return StepResult::Status(self.handle_opcode_resolution(Err(err))), + }; + + if should_skip { + let resolution = BrilligSolver::::zero_out_brillig_outputs(witness, brillig); + return StepResult::Status(self.handle_opcode_resolution(resolution)); + } + + let solver = BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer); + match solver { + Ok(solver) => StepResult::IntoBrillig(solver), + Err(..) => StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))), } }