From cf41ea217e8ca094fdc45514534d098f31050472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Fri, 27 Oct 2023 17:22:40 -0400 Subject: [PATCH 1/7] feat: add commands to show witness map and overwrite their values --- acvm-repo/acvm/src/pwg/mod.rs | 8 +++++ tooling/debugger/src/context.rs | 18 ++++++++-- tooling/debugger/src/repl.rs | 60 +++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index 6016d0d1f3e..c1edf60161a 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -168,6 +168,14 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { &self.witness_map } + pub fn overwrite_witness( + &mut self, + witness: Witness, + value: FieldElement, + ) -> Option { + self.witness_map.insert(witness, value) + } + /// Returns a slice containing the opcodes of the circuit being executed. pub fn opcodes(&self) -> &[Opcode] { self.opcodes diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index a97bc9e8b86..5a01a788dd4 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -1,9 +1,9 @@ -use acvm::acir::circuit::{Opcode, OpcodeLocation}; +use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; +use acvm::acir::native_types::{Witness, WitnessMap}; use acvm::pwg::{ ACVMStatus, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, StepResult, ACVM, }; -use acvm::BlackBoxFunctionSolver; -use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; +use acvm::{BlackBoxFunctionSolver, FieldElement}; use nargo::artifacts::debug::DebugArtifact; use nargo::errors::{ExecutionError, Location}; @@ -50,6 +50,18 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { self.acvm.opcodes() } + pub(super) fn get_witness_map(&self) -> &WitnessMap { + self.acvm.witness_map() + } + + pub(super) fn overwrite_witness( + &mut self, + witness: Witness, + value: FieldElement, + ) -> Option { + self.acvm.overwrite_witness(witness, value) + } + pub(super) fn get_current_opcode_location(&self) -> Option { let ip = self.acvm.instruction_pointer(); if ip >= self.get_opcodes().len() { diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 320d8edf63a..1590b009c88 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -1,8 +1,8 @@ use crate::context::{DebugCommandResult, DebugContext}; -use acvm::acir::circuit::{Opcode, OpcodeLocation}; -use acvm::BlackBoxFunctionSolver; -use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; +use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; +use acvm::acir::native_types::{Witness, WitnessMap}; +use acvm::{BlackBoxFunctionSolver, FieldElement}; use nargo::artifacts::debug::DebugArtifact; use nargo::NargoError; @@ -283,6 +283,30 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { self.show_current_vm_status(); } + pub fn show_witness_map(&self) { + let witness_map = self.context.get_witness_map(); + // NOTE: we need to clone() here to get the iterator + for (witness, value) in witness_map.clone().into_iter() { + println!("_{} = {value}", witness.witness_index()); + } + } + + pub fn show_witness(&self, index: u32) { + if let Some(value) = self.context.get_witness_map().get_index(index) { + println!("_{} = {value}", index); + } + } + + pub fn update_witness(&mut self, index: u32, value: String) { + if let Some(field_value) = FieldElement::try_from_str(&value) { + let witness = Witness::from(index); + _ = self.context.overwrite_witness(witness, field_value); + println!("_{} = {value}", index); + } else { + println!("Invalid witness value: {value}"); + } + } + fn is_solved(&self) -> bool { self.context.is_solved() } @@ -393,6 +417,36 @@ pub fn run( } }, ) + .add( + "witness", + command! { + "show witness map", + () => || { + ref_context.borrow().show_witness_map(); + Ok(CommandStatus::Done) + } + }, + ) + .add( + "witness", + command! { + "display a single witness from the witness map", + (index: u32) => |index| { + ref_context.borrow().show_witness(index); + Ok(CommandStatus::Done) + } + }, + ) + .add( + "witness", + command! { + "update a witness with the given value", + (index: u32, value: String) => |index, value| { + ref_context.borrow_mut().update_witness(index, value); + Ok(CommandStatus::Done) + } + }, + ) .build() .expect("Failed to initialize debugger repl"); From 69c595dd48ce5b5a653d88d91b459027cb6b8a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Fri, 27 Oct 2023 18:14:23 -0400 Subject: [PATCH 2/7] feat: add command to show Brillig VM register contents --- acvm-repo/acvm/src/pwg/brillig.rs | 4 ++++ tooling/debugger/src/context.rs | 11 +++++++++++ tooling/debugger/src/repl.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index b0e5ec6dd48..c1b58980ffa 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -112,6 +112,10 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { Ok(Self { vm, acir_index }) } + pub fn get_registers(&self) -> &Registers { + self.vm.get_registers() + } + pub(super) fn solve(&mut self) -> Result { let status = self.vm.process_opcodes(); self.handle_vm_status(status) diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 5a01a788dd4..a5b48e5684d 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -1,5 +1,6 @@ use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; +use acvm::brillig_vm::Registers; use acvm::pwg::{ ACVMStatus, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, StepResult, ACVM, }; @@ -202,6 +203,16 @@ 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_registers(&self) -> Option<&Registers> { + self.brillig_solver.as_ref().map(|solver| solver.get_registers()) + } + fn breakpoint_reached(&self) -> bool { if let Some(location) = self.get_current_opcode_location() { self.breakpoints.contains(&location) diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 1590b009c88..1c0814177a7 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -307,6 +307,22 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } } + pub fn show_brillig_registers(&self) { + if !self.context.is_executing_brillig() { + println!("Not executing a Brillig block"); + return; + } + + let Some(registers) = self.context.get_brillig_registers() else { + println!("Brillig VM registers not available"); + return; + }; + + for (index, value) in registers.inner.iter().enumerate() { + println!("{index} = {:?}", value); + } + } + fn is_solved(&self) -> bool { self.context.is_solved() } @@ -447,6 +463,16 @@ pub fn run( } }, ) + .add( + "registers", + command! { + "show Brillig registers (valid when executing a Brillig block)", + () => || { + ref_context.borrow().show_brillig_registers(); + Ok(CommandStatus::Done) + } + }, + ) .build() .expect("Failed to initialize debugger repl"); From e565e3d8e07094b32738c14a777069a7a9018110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 31 Oct 2023 14:47:39 -0400 Subject: [PATCH 3/7] chore: format method documentation Remnant of previous PR. --- tooling/debugger/src/context.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index a5b48e5684d..03b1b66ee1e 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -77,11 +77,11 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } - // Returns the callstack in source code locations for the currently - // executing opcode. This can be None if the execution finished (and - // get_current_opcode_location() returns None) or if the opcode is not - // mapped to a specific source location in the debug artifact (which can - // happen for certain opcodes inserted synthetically by the compiler) + /// Returns the callstack in source code locations for the currently + /// executing opcode. This can be `None` if the execution finished (and + /// `get_current_opcode_location()` returns `None`) or if the opcode is not + /// mapped to a specific source location in the debug artifact (which can + /// happen for certain opcodes inserted synthetically by the compiler) pub(super) fn get_current_source_location(&self) -> Option> { self.get_current_opcode_location() .as_ref() From 25e88b48a743d0c5f8536d8315c135e4641575d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 31 Oct 2023 16:50:50 -0400 Subject: [PATCH 4/7] feat: add command to show Brillig VM memory during debugging --- acvm-repo/acvm/src/pwg/brillig.rs | 4 ++++ tooling/debugger/src/context.rs | 6 +++++- tooling/debugger/src/repl.rs | 34 ++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index c1b58980ffa..138bef0a880 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -116,6 +116,10 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { self.vm.get_registers() } + pub fn get_memory(&self) -> &Vec { + self.vm.get_memory() + } + pub(super) fn solve(&mut self) -> Result { let status = self.vm.process_opcodes(); self.handle_vm_status(status) diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 03b1b66ee1e..fcc8430ad87 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -1,6 +1,6 @@ use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap}; -use acvm::brillig_vm::Registers; +use acvm::brillig_vm::{brillig::Value, Registers}; use acvm::pwg::{ ACVMStatus, BrilligSolver, BrilligSolverStatus, ForeignCallWaitInfo, StepResult, ACVM, }; @@ -213,6 +213,10 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { self.brillig_solver.as_ref().map(|solver| solver.get_registers()) } + pub(super) fn get_brillig_memory(&self) -> Option<&Vec> { + self.brillig_solver.as_ref().map(|solver| solver.get_memory()) + } + fn breakpoint_reached(&self) -> bool { if let Some(location) = self.get_current_opcode_location() { self.breakpoints.contains(&location) diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 1c0814177a7..799ed70597d 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -314,12 +314,34 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } let Some(registers) = self.context.get_brillig_registers() else { + // this can happen when just entering the Brillig block since ACVM + // would have not initialized the Brillig VM yet; in fact, the + // Brillig code may be skipped altogether println!("Brillig VM registers not available"); return; }; for (index, value) in registers.inner.iter().enumerate() { - println!("{index} = {:?}", value); + println!("{index} = {}", value.to_field()); + } + } + + pub fn show_brillig_memory(&self) { + if !self.context.is_executing_brillig() { + println!("Not executing a Brillig block"); + return; + } + + let Some(memory) = self.context.get_brillig_memory() else { + // this can happen when just entering the Brillig block since ACVM + // would have not initialized the Brillig VM yet; in fact, the + // Brillig code may be skipped altogether + println!("Brillig VM memory not available"); + return; + }; + + for (index, value) in memory.iter().enumerate() { + println!("{index} = {}", value.to_field()); } } @@ -473,6 +495,16 @@ pub fn run( } }, ) + .add( + "memory", + command! { + "show Brillig memory (valid when executing a Brillig block)", + () => || { + ref_context.borrow().show_brillig_memory(); + Ok(CommandStatus::Done) + } + }, + ) .build() .expect("Failed to initialize debugger repl"); From 988563dd9ae203e80a1306e030703d84562e2dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 31 Oct 2023 18:30:55 -0400 Subject: [PATCH 5/7] feat: add debug commands to update registers and memory in Brillig VM --- acvm-repo/acvm/src/pwg/brillig.rs | 8 +++++ acvm-repo/brillig_vm/src/lib.rs | 8 +++++ tooling/debugger/src/context.rs | 12 +++++++ tooling/debugger/src/repl.rs | 57 +++++++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 138bef0a880..d5f8c68ac31 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -116,10 +116,18 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { self.vm.get_registers() } + pub fn set_register(&mut self, register_index: usize, value: Value) { + self.vm.set_register(RegisterIndex(register_index), value); + } + pub fn get_memory(&self) -> &Vec { self.vm.get_memory() } + pub fn write_memory_at(&mut self, ptr: usize, value: Value) { + self.vm.write_memory_at(ptr, value); + } + pub(super) fn solve(&mut self) -> Result { let status = self.vm.process_opcodes(); self.handle_vm_status(status) diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index e0d30f7b2e0..482b9b36d77 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -164,10 +164,18 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { &self.registers } + pub fn set_register(&mut self, register_index: RegisterIndex, value: Value) { + self.registers.set(register_index, value); + } + pub fn get_memory(&self) -> &Vec { self.memory.values() } + pub fn write_memory_at(&mut self, ptr: usize, value: Value) { + self.memory.write(ptr, value); + } + /// Process a single opcode and modify the program counter. pub fn process_opcode(&mut self) -> VMStatus { let opcode = &self.bytecode[self.program_counter]; diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index fcc8430ad87..30812dcf5c2 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -213,10 +213,22 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { self.brillig_solver.as_ref().map(|solver| solver.get_registers()) } + pub(super) fn set_brillig_register(&mut self, register_index: usize, value: FieldElement) { + if let Some(solver) = self.brillig_solver.as_mut() { + solver.set_register(register_index, value.into()); + } + } + pub(super) fn get_brillig_memory(&self) -> Option<&Vec> { self.brillig_solver.as_ref().map(|solver| solver.get_memory()) } + pub(super) fn write_brillig_memory(&mut self, ptr: usize, value: FieldElement) { + if let Some(solver) = self.brillig_solver.as_mut() { + solver.write_memory_at(ptr, value.into()); + } + } + fn breakpoint_reached(&self) -> bool { if let Some(location) = self.get_current_opcode_location() { self.breakpoints.contains(&location) diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 799ed70597d..23abe83c38d 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -298,13 +298,14 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } pub fn update_witness(&mut self, index: u32, value: String) { - if let Some(field_value) = FieldElement::try_from_str(&value) { - let witness = Witness::from(index); - _ = self.context.overwrite_witness(witness, field_value); - println!("_{} = {value}", index); - } else { + let Some(field_value) = FieldElement::try_from_str(&value) else { println!("Invalid witness value: {value}"); - } + return; + }; + + let witness = Witness::from(index); + _ = self.context.overwrite_witness(witness, field_value); + println!("_{} = {value}", index); } pub fn show_brillig_registers(&self) { @@ -326,6 +327,18 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } } + pub fn set_brillig_register(&mut self, index: usize, value: String) { + let Some(field_value) = FieldElement::try_from_str(&value) else { + println!("Invalid value: {value}"); + return; + }; + if !self.context.is_executing_brillig() { + println!("Not executing a Brillig block"); + return; + } + self.context.set_brillig_register(index, field_value); + } + pub fn show_brillig_memory(&self) { if !self.context.is_executing_brillig() { println!("Not executing a Brillig block"); @@ -345,6 +358,18 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { } } + pub fn write_brillig_memory(&mut self, index: usize, value: String) { + let Some(field_value) = FieldElement::try_from_str(&value) else { + println!("Invalid value: {value}"); + return; + }; + if !self.context.is_executing_brillig() { + println!("Not executing a Brillig block"); + return; + } + self.context.write_brillig_memory(index, field_value); + } + fn is_solved(&self) -> bool { self.context.is_solved() } @@ -495,6 +520,16 @@ pub fn run( } }, ) + .add( + "regset", + command! { + "update a Brillig register with the given value", + (index: usize, value: String) => |index, value| { + ref_context.borrow_mut().set_brillig_register(index, value); + Ok(CommandStatus::Done) + } + }, + ) .add( "memory", command! { @@ -505,6 +540,16 @@ pub fn run( } }, ) + .add( + "memset", + command! { + "update a Brillig memory cell with the given value", + (index: usize, value: String) => |index, value| { + ref_context.borrow_mut().write_brillig_memory(index, value); + Ok(CommandStatus::Done) + } + }, + ) .build() .expect("Failed to initialize debugger repl"); From 4289e77de56fb2cdcbad0a4b4b2089061915569f Mon Sep 17 00:00:00 2001 From: Martin Verzilli Date: Sun, 19 Nov 2023 12:47:08 +0100 Subject: [PATCH 6/7] Update acvm-repo/acvm/src/pwg/brillig.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- acvm-repo/acvm/src/pwg/brillig.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index d5f8c68ac31..0db38c776e2 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -120,7 +120,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { self.vm.set_register(RegisterIndex(register_index), value); } - pub fn get_memory(&self) -> &Vec { + pub fn get_memory(&self) -> &[Value] { self.vm.get_memory() } From 38a9806359f231021c96cf44d6dae8c5cacfb529 Mon Sep 17 00:00:00 2001 From: Martin Verzilli Date: Sun, 19 Nov 2023 12:47:14 +0100 Subject: [PATCH 7/7] Update tooling/debugger/src/context.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- tooling/debugger/src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 30812dcf5c2..37c3b9d89d9 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -219,7 +219,7 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { } } - pub(super) fn get_brillig_memory(&self) -> Option<&Vec> { + pub(super) fn get_brillig_memory(&self) -> Option<&[Value]> { self.brillig_solver.as_ref().map(|solver| solver.get_memory()) }