Skip to content
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
50 changes: 46 additions & 4 deletions acvm-repo/acvm/src/pwg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
let Opcode::BrilligCall { id, inputs, outputs, predicate } =
&self.opcodes[self.instruction_pointer]
else {
unreachable!("Not executing a Brillig opcode");
unreachable!("Not executing a BrilligCall opcode");
};

let witness = &mut self.witness_map;
Expand Down Expand Up @@ -468,9 +468,17 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
}
}

pub fn step_into_brillig(&mut self) -> StepResult<'a, B> {
match &self.opcodes[self.instruction_pointer] {
Opcode::Brillig(_) => self.step_into_brillig_opcode(),
Opcode::BrilligCall { .. } => self.step_into_brillig_call_opcode(),
_ => StepResult::Status(self.solve_opcode()),
}
}

pub fn step_into_brillig_opcode(&mut self) -> StepResult<'a, B> {
let Opcode::Brillig(brillig) = &self.opcodes[self.instruction_pointer] else {
return StepResult::Status(self.solve_opcode());
unreachable!("Not executing a Brillig opcode");
};

let witness = &mut self.witness_map;
Expand Down Expand Up @@ -498,9 +506,43 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> {
}
}

fn step_into_brillig_call_opcode(&mut self) -> StepResult<'a, B> {
let Opcode::BrilligCall { id, inputs, outputs, predicate } =
&self.opcodes[self.instruction_pointer]
else {
unreachable!("Not executing a BrilligCall opcode");
};

let witness = &mut self.witness_map;
let should_skip = match is_predicate_false(witness, predicate) {
Ok(result) => result,
Err(err) => return StepResult::Status(self.handle_opcode_resolution(Err(err))),
};
if should_skip {
let resolution = BrilligSolver::<B>::zero_out_brillig_outputs(witness, outputs);
return StepResult::Status(self.handle_opcode_resolution(resolution));
}

let solver = BrilligSolver::new_call(
witness,
&self.block_solvers,
inputs,
&self.unconstrained_functions[*id as usize].bytecode,
self.backend,
self.instruction_pointer,
);
match solver {
Ok(solver) => StepResult::IntoBrillig(solver),
Err(..) => StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))),
}
}

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");
if !matches!(
self.opcodes[self.instruction_pointer],
Opcode::Brillig(..) | Opcode::BrilligCall { .. }
) {
unreachable!("Not executing a Brillig/BrilligCall opcode");
}
self.brillig_solver = Some(solver);
self.solve_opcode()
Expand Down
113 changes: 63 additions & 50 deletions tooling/debugger/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub(super) struct DebugContext<'a, B: BlackBoxFunctionSolver> {
debug_artifact: &'a DebugArtifact,
breakpoints: HashSet<OpcodeLocation>,
source_to_opcodes: BTreeMap<FileId, Vec<(usize, OpcodeLocation)>>,
unconstrained_functions: &'a [BrilligBytecode],
}

impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
Expand All @@ -59,6 +60,7 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
debug_artifact,
breakpoints: HashSet::new(),
source_to_opcodes,
unconstrained_functions,
}
}

Expand Down Expand Up @@ -216,6 +218,9 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
.iter()
.map(|opcode| match opcode {
Opcode::Brillig(brillig_block) => brillig_block.bytecode.len(),
Opcode::BrilligCall { id, .. } => {
self.unconstrained_functions[*id as usize].bytecode.len()
}
_ => 1,
})
.collect()
Expand Down Expand Up @@ -296,19 +301,30 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
None => String::from("invalid"),
Some(OpcodeLocation::Acir(acir_index)) => {
let opcode = &opcodes[*acir_index];
if let Opcode::Brillig(ref brillig) = opcode {
let first_opcode = &brillig.bytecode[0];
format!("BRILLIG {first_opcode:?}")
} else {
format!("{opcode:?}")
match opcode {
Opcode::Brillig(brillig) => {
let first_opcode = &brillig.bytecode[0];
format!("BRILLIG {first_opcode:?}")
}
Opcode::BrilligCall { id, .. } => {
let first_opcode = &self.unconstrained_functions[*id as usize].bytecode[0];
format!("BRILLIG CALL {first_opcode:?}")
}
_ => format!("{opcode:?}"),
}
}
Some(OpcodeLocation::Brillig { acir_index, brillig_index }) => {
if let Opcode::Brillig(ref brillig) = opcodes[*acir_index] {
let opcode = &brillig.bytecode[*brillig_index];
format!(" | {opcode:?}")
} else {
String::from(" | invalid")
match &opcodes[*acir_index] {
Opcode::Brillig(brillig) => {
let opcode = &brillig.bytecode[*brillig_index];
format!(" | {opcode:?}")
}
Opcode::BrilligCall { id, .. } => {
let bytecode = &self.unconstrained_functions[*id as usize].bytecode;
let opcode = &bytecode[*brillig_index];
format!(" | {opcode:?}")
}
_ => String::from(" | invalid"),
}
}
}
Expand Down Expand Up @@ -400,7 +416,7 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
return self.step_brillig_opcode();
}

match self.acvm.step_into_brillig_opcode() {
match self.acvm.step_into_brillig() {
StepResult::IntoBrillig(solver) => {
self.brillig_solver = Some(solver);
self.step_brillig_opcode()
Expand All @@ -409,20 +425,6 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
}
}

fn currently_executing_brillig(&self) -> bool {
if self.brillig_solver.is_some() {
return true;
}

match self.get_current_opcode_location() {
Some(OpcodeLocation::Brillig { .. }) => true,
Some(OpcodeLocation::Acir(acir_index)) => {
matches!(self.get_opcodes()[acir_index], Opcode::Brillig(_))
}
_ => false,
}
}

fn get_current_acir_index(&self) -> Option<usize> {
self.get_current_opcode_location().map(|opcode_location| match opcode_location {
OpcodeLocation::Acir(acir_index) => acir_index,
Expand All @@ -446,8 +448,25 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
}
}

pub(super) fn is_executing_brillig(&self) -> bool {
if self.brillig_solver.is_some() {
return true;
}

match self.get_current_opcode_location() {
Some(OpcodeLocation::Brillig { .. }) => true,
Some(OpcodeLocation::Acir(acir_index)) => {
matches!(
self.get_opcodes()[acir_index],
Opcode::Brillig(_) | Opcode::BrilligCall { .. }
)
}
_ => false,
}
}

pub(super) fn step_acir_opcode(&mut self) -> DebugCommandResult {
if self.currently_executing_brillig() {
if self.is_executing_brillig() {
self.step_out_of_brillig_opcode()
} else {
let status = self.acvm.solve_opcode();
Expand Down Expand Up @@ -511,12 +530,6 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
}
}

pub(super) fn is_executing_brillig(&self) -> bool {
let opcodes = self.get_opcodes();
let acir_index = self.acvm.instruction_pointer();
acir_index < opcodes.len() && matches!(opcodes[acir_index], Opcode::Brillig(..))
}

pub(super) fn get_brillig_memory(&self) -> Option<&[MemoryValue]> {
self.brillig_solver.as_ref().map(|solver| solver.get_memory())
}
Expand Down Expand Up @@ -552,15 +565,18 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> {
match *location {
OpcodeLocation::Acir(acir_index) => acir_index < opcodes.len(),
OpcodeLocation::Brillig { acir_index, brillig_index } => {
acir_index < opcodes.len()
&& matches!(opcodes[acir_index], Opcode::Brillig(..))
&& {
if let Opcode::Brillig(ref brillig) = opcodes[acir_index] {
brillig_index < brillig.bytecode.len()
} else {
false
if acir_index < opcodes.len() {
match &opcodes[acir_index] {
Opcode::Brillig(brillig) => brillig_index < brillig.bytecode.len(),
Opcode::BrilligCall { id, .. } => {
let bytecode = &self.unconstrained_functions[*id as usize].bytecode;
brillig_index < bytecode.len()
}
_ => false,
}
} else {
false
}
}
}
}
Expand Down Expand Up @@ -849,16 +865,7 @@ mod tests {
#[test]
fn test_offset_opcode_location() {
let opcodes = vec![
Opcode::Brillig(Brillig {
inputs: vec![],
outputs: vec![],
bytecode: vec![
BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 },
BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 },
BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 },
],
predicate: None,
}),
Opcode::BrilligCall { id: 0, inputs: vec![], outputs: vec![], predicate: None },
Opcode::MemoryInit { block_id: BlockId(0), init: vec![] },
Opcode::Brillig(Brillig {
inputs: vec![],
Expand All @@ -875,7 +882,13 @@ mod tests {
let circuit = Circuit { opcodes, ..Circuit::default() };
let debug_artifact =
DebugArtifact { debug_symbols: vec![], file_map: BTreeMap::new(), warnings: vec![] };
let brillig_funcs = &vec![];
let brillig_funcs = &vec![BrilligBytecode {
bytecode: vec![
BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 },
BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 },
BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 },
],
}];
let context = DebugContext::new(
&StubbedBlackBoxSolver,
&circuit,
Expand Down
56 changes: 39 additions & 17 deletions tooling/debugger/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::context::{DebugCommandResult, DebugContext};
use acvm::acir::circuit::brillig::BrilligBytecode;
use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation};
use acvm::acir::native_types::{Witness, WitnessMap};
use acvm::brillig_vm::brillig::Opcode as BrilligOpcode;
use acvm::{BlackBoxFunctionSolver, FieldElement};

use crate::foreign_calls::DefaultDebugForeignCallExecutor;
Expand Down Expand Up @@ -79,12 +80,16 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> {
println!("At opcode {}: {}", ip, opcode_summary);
}
OpcodeLocation::Brillig { acir_index, brillig_index } => {
let Opcode::Brillig(ref brillig) = opcodes[acir_index] else {
unreachable!("Brillig location does not contain a Brillig block");
let brillig_bytecode = match opcodes[acir_index] {
Opcode::Brillig(ref brillig) => &brillig.bytecode,
Opcode::BrilligCall { id, .. } => {
&self.unconstrained_functions[id as usize].bytecode
}
_ => unreachable!("Brillig location does not contain a Brillig block"),
};
println!(
"At opcode {}.{}: {:?}",
acir_index, brillig_index, brillig.bytecode[brillig_index]
acir_index, brillig_index, brillig_bytecode[brillig_index]
);
}
}
Expand All @@ -104,12 +109,16 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> {
)
}
OpcodeLocation::Brillig { acir_index, brillig_index } => {
let Opcode::Brillig(ref brillig) = opcodes[*acir_index] else {
unreachable!("Brillig location does not contain a Brillig block");
let brillig_bytecode = match opcodes[*acir_index] {
Opcode::Brillig(ref brillig) => &brillig.bytecode,
Opcode::BrilligCall { id, .. } => {
&self.unconstrained_functions[id as usize].bytecode
}
_ => unreachable!("Brillig location does not contain a Brillig block"),
};
println!(
"Frame #{index}, opcode {}.{}: {:?}",
acir_index, brillig_index, brillig.bytecode[*brillig_index]
acir_index, brillig_index, brillig_bytecode[*brillig_index]
);
}
}
Expand Down Expand Up @@ -162,22 +171,35 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> {
""
}
};
let print_brillig_bytecode = |acir_index, bytecode: &[BrilligOpcode]| {
for (brillig_index, brillig_opcode) in bytecode.iter().enumerate() {
println!(
"{:>3}.{:<2} |{:2} {:?}",
acir_index,
brillig_index,
brillig_marker(acir_index, brillig_index),
brillig_opcode
);
}
};
for (acir_index, opcode) in opcodes.iter().enumerate() {
let marker = outer_marker(acir_index);
if let Opcode::Brillig(brillig) = opcode {
println!("{:>3} {:2} BRILLIG inputs={:?}", acir_index, marker, brillig.inputs);
println!(" | outputs={:?}", brillig.outputs);
for (brillig_index, brillig_opcode) in brillig.bytecode.iter().enumerate() {
match &opcode {
Opcode::Brillig(brillig) => {
println!("{:>3} {:2} BRILLIG inputs={:?}", acir_index, marker, brillig.inputs);
println!(" | outputs={:?}", brillig.outputs);
print_brillig_bytecode(acir_index, &brillig.bytecode);
}
Opcode::BrilligCall { id, inputs, outputs, .. } => {
println!(
"{:>3}.{:<2} |{:2} {:?}",
acir_index,
brillig_index,
brillig_marker(acir_index, brillig_index),
brillig_opcode
"{:>3} {:2} BRILLIG CALL id={} inputs={:?}",
acir_index, marker, id, inputs
);
println!(" | outputs={:?}", outputs);
let bytecode = &self.unconstrained_functions[*id as usize].bytecode;
print_brillig_bytecode(acir_index, bytecode);
}
} else {
println!("{:>3} {:2} {:?}", acir_index, marker, opcode);
_ => println!("{:>3} {:2} {:?}", acir_index, marker, opcode),
}
}
}
Expand Down