Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Extract Brillig VM to allow step debugging #3259

Merged
merged 5 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions acvm-repo/acvm/src/pwg/brillig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -116,6 +117,15 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> {
self.handle_vm_status(status)
}

pub fn step(&mut self) -> Result<BrilligSolverStatus, OpcodeResolutionError> {
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,
Expand Down Expand Up @@ -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"),
Expand Down
57 changes: 51 additions & 6 deletions acvm-repo/acvm/src/pwg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ use acir::{
};
use acvm_blackbox_solver::BlackBoxResolutionError;

use self::{
arithmetic::ArithmeticSolver,
brillig::{BrilligSolver, BrilligSolverStatus},
directives::solve_directives,
memory_op::MemoryOpSolver,
};
use self::{arithmetic::ArithmeticSolver, directives::solve_directives, memory_op::MemoryOpSolver};
use crate::{BlackBoxFunctionSolver, Language};

use thiserror::Error;
Expand All @@ -30,6 +25,7 @@ mod directives;
mod blackbox;
mod memory_op;

pub use self::brillig::{BrilligSolver, BrilligSolverStatus};
pub use brillig::ForeignCallWaitInfo;

#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -63,6 +59,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
Expand Down Expand Up @@ -263,6 +264,13 @@ 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;
Expand Down Expand Up @@ -331,6 +339,43 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
}
}
}

pub fn step_into_brillig_opcode(&mut self) -> StepResult<'a, B> {
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
if let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] {
let witness = &mut self.witness_map;
match BrilligSolver::<B>::should_skip(witness, brillig) {
Ok(true) => {
let resolution = BrilligSolver::<B>::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())
}
}

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
Expand Down
2 changes: 1 addition & 1 deletion tooling/debugger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ nargo.workspace = true
noirc_printable_type.workspace = true
thiserror.workspace = true
easy-repl = "0.2.1"
owo-colors = "3"
owo-colors = "3"
53 changes: 50 additions & 3 deletions tooling/debugger/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use acvm::acir::circuit::OpcodeLocation;
use acvm::pwg::{ACVMStatus, ErrorLocation, OpcodeResolutionError, ACVM};
use acvm::pwg::{
ACVMStatus, BrilligSolver, BrilligSolverStatus, ErrorLocation, OpcodeResolutionError,
StepResult, ACVM,
};
use acvm::BlackBoxFunctionSolver;
use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap};

Expand All @@ -21,17 +24,60 @@ enum SolveResult {

struct DebugContext<'backend, B: BlackBoxFunctionSolver> {
acvm: ACVM<'backend, B>,
brillig_solver: Option<BrilligSolver<'backend, B>>,
debug_artifact: DebugArtifact,
foreign_call_executor: ForeignCallExecutor,
circuit: &'backend Circuit,
show_output: bool,
}

impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> {
fn step_brillig_opcode(&mut self) -> Result<SolveResult, NargoError> {
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<SolveResult, NargoError> {
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() {
StepResult::IntoBrillig(solver) => {
self.brillig_solver = Some(solver);
self.step_brillig_opcode()
}
StepResult::Status(status) => self.handle_acvm_status(status),
}
}
}

match solver_status {
fn handle_acvm_status(&mut self, status: ACVMStatus) -> Result<SolveResult, NargoError> {
match status {
ACVMStatus::Solved => Ok(SolveResult::Done),
ACVMStatus::InProgress => Ok(SolveResult::Ok),
ACVMStatus::Failure(error) => {
Expand Down Expand Up @@ -129,6 +175,7 @@ pub fn debug_circuit<B: BlackBoxFunctionSolver>(
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,
Expand Down
Loading