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/debug tests functions #8

Draft
wants to merge 27 commits into
base: feat/5208-debug-tests-2025
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4533576
initial version: debug tests with `nargo debug --test-name`
anaPerezGhiglia Feb 13, 2025
fed0f14
Configure oracle-resolver in DebugForeignCallExecutor
anaPerezGhiglia Feb 7, 2025
63182cb
Spawn debugger in different thread than REPL
anaPerezGhiglia Feb 12, 2025
371147b
fix: set root_path and package_name on ForeignCallResolver from debugger
anaPerezGhiglia Feb 13, 2025
b5663e5
debug println!
anaPerezGhiglia Feb 13, 2025
0742fa6
run cargo fmt
anaPerezGhiglia Feb 14, 2025
277c70f
Map opcode resulution erros in debugger as well
anaPerezGhiglia Feb 14, 2025
4ede00e
Use PrettyFormatter for printing test result in debug_cmd
anaPerezGhiglia Feb 14, 2025
1214932
remove unused import
anaPerezGhiglia Feb 14, 2025
fd68608
Instrument contract functions + set package_build_path in context
anaPerezGhiglia Feb 18, 2025
bc7394f
set pedantic_solving when creating the BlackBoxSolver
anaPerezGhiglia Feb 18, 2025
e5eaba0
avoid printing __debug foreign calls
anaPerezGhiglia Feb 18, 2025
5fd7863
workaround: retry rpc request restarting http_client on transport error
anaPerezGhiglia Feb 19, 2025
bad44c2
fix context.restart function
anaPerezGhiglia Feb 24, 2025
084a9ee
run cargo fmt
anaPerezGhiglia Feb 24, 2025
ef63315
A bit of code cleanup and enhancements
anaPerezGhiglia Feb 24, 2025
b00a641
Adapt breakpoint by sourcecode line to debugger in separate thread impl
anaPerezGhiglia Jun 7, 2024
f713eab
refactor: encapsulate debug-test logic into smaller functions
anaPerezGhiglia Feb 25, 2025
6b79a7a
extract runtime debugger and structs to separate file
anaPerezGhiglia Feb 25, 2025
0ea2d51
fix debugger panic
anaPerezGhiglia Feb 25, 2025
41b1207
get rid of nested Results
anaPerezGhiglia Feb 25, 2025
919202a
abstract extracting value from enum with extract! macro
anaPerezGhiglia Feb 25, 2025
5cf1716
some more code cleanup
anaPerezGhiglia Feb 26, 2025
ed33a14
cargo fmt & clippy
anaPerezGhiglia Feb 26, 2025
a233ab3
refactor to avoid exceeding # of function args
anaPerezGhiglia Feb 26, 2025
9947290
adapt dap iterface to debug test functions
anaPerezGhiglia Feb 27, 2025
aca1018
Analyze test result when running DAP debugger interface
anaPerezGhiglia Feb 28, 2025
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 19 additions & 1 deletion compiler/noirc_frontend/src/debug/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::ast::PathSegment;
use crate::parse_program;
use crate::parser::ParsedModule;
use crate::parser::{ParsedModule, ParsedSubModule};
use crate::signed_field::SignedField;
use crate::{
ast,
Expand Down Expand Up @@ -63,7 +63,25 @@
if let Item { kind: ItemKind::Function(f), .. } = item {
self.walk_fn(&mut f.def);
}
if let Item {
kind:
ItemKind::Submodules(ParsedSubModule {
is_contract: true,
contents: contract_module @ ParsedModule { .. },
..
}),
..
} = item
{
contract_module.items.iter_mut().for_each(|item| {
if let Item { kind: ItemKind::Function(f), .. } = item {
self.walk_fn(&mut f.def);
}
});
self.insert_state_set_oracle(contract_module, 8, file);
}
});

// this part absolutely must happen after ast traversal above
// so that oracle functions don't get wrapped, resulting in infinite recursion:
self.insert_state_set_oracle(module, 8, file);
Expand Down Expand Up @@ -315,7 +333,7 @@
}
ast::LValue::Dereference(_lv, location) => {
// TODO: this is a dummy statement for now, but we should
// somehow track the derefence and update the pointed to

Check warning on line 336 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (derefence)
// variable
ast::Statement {
kind: ast::StatementKind::Expression(uint_expr(0, *location)),
Expand Down Expand Up @@ -719,9 +737,9 @@
ast::Pattern::Tuple(patterns, _) => {
stack.extend(patterns.iter().map(|pattern| (pattern, false)));
}
ast::Pattern::Struct(_, pids, _) => {

Check warning on line 740 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
stack.extend(pids.iter().map(|(_, pattern)| (pattern, is_mut)));

Check warning on line 741 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
vars.extend(pids.iter().map(|(id, _)| (id.clone(), false)));

Check warning on line 742 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (pids)
}
ast::Pattern::Interned(_, _) => (),
}
Expand All @@ -732,7 +750,7 @@
fn pattern_to_string(pattern: &ast::Pattern) -> String {
match pattern {
ast::Pattern::Identifier(id) => id.0.contents.clone(),
ast::Pattern::Mutable(mpat, _, _) => format!("mut {}", pattern_to_string(mpat.as_ref())),

Check warning on line 753 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (mpat)

Check warning on line 753 in compiler/noirc_frontend/src/debug/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (mpat)
ast::Pattern::Tuple(elements, _) => format!(
"({})",
elements.iter().map(pattern_to_string).collect::<Vec<String>>().join(", ")
Expand Down
2 changes: 2 additions & 0 deletions tooling/debugger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ dap.workspace = true
easy-repl = "0.2.1"
owo-colors = "3"
serde_json.workspace = true
bn254_blackbox_solver.workspace = true


[dev-dependencies]
assert_cmd = "2.0.12"
Expand Down
135 changes: 112 additions & 23 deletions tooling/debugger/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::foreign_calls::DebugForeignCallExecutor;
use acvm::acir::brillig::BitSize;
use acvm::acir::circuit::brillig::{BrilligBytecode, BrilligFunctionId};
use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation};
use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation, ResolvedOpcodeLocation};
use acvm::acir::native_types::{Witness, WitnessMap, WitnessStack};
use acvm::brillig_vm::MemoryValue;
use acvm::pwg::{
Expand All @@ -12,15 +12,16 @@

use codespan_reporting::files::{Files, SimpleFile};
use fm::FileId;
use nargo::errors::{ExecutionError, Location};
use nargo::errors::{execution_error_from, ExecutionError, Location};
use nargo::NargoError;
use noirc_artifacts::debug::{DebugArtifact, StackFrame};
use noirc_driver::DebugFile;

use noirc_printable_type::{PrintableType, PrintableValue};
use thiserror::Error;

use std::collections::BTreeMap;
use std::collections::{hash_set::Iter, HashSet};
use std::collections::HashSet;

/// A Noir program is composed by
/// `n` ACIR circuits
Expand Down Expand Up @@ -189,6 +190,15 @@
}
}

impl From<DebugLocation> for ResolvedOpcodeLocation {
fn from(debug_loc: DebugLocation) -> Self {
ResolvedOpcodeLocation {
acir_function_index: usize::try_from(debug_loc.circuit_id).unwrap(),
opcode_location: debug_loc.opcode_location,
}
}
}

#[derive(Error, Debug)]
pub enum DebugLocationFromStrError {
#[error("Invalid debug location string: {0}")]
Expand Down Expand Up @@ -227,6 +237,29 @@
Error(NargoError<FieldElement>),
}

#[derive(Debug)]
pub struct DebugStackFrame<F> {
pub function_name: String,
pub function_params: Vec<String>,
pub variables: Vec<(String, PrintableValue<F>, PrintableType)>,
}

impl<F: Clone> From<&StackFrame<'_, F>> for DebugStackFrame<F> {
fn from(value: &StackFrame<F>) -> Self {
DebugStackFrame {
function_name: value.function_name.to_string(),
function_params: value.function_params.iter().map(|param| param.to_string()).collect(),
variables: value
.variables
.iter()
.map(|(name, value, var_type)| {
(name.to_string(), (**value).clone(), (*var_type).clone())
})
.collect(),
}
}
}

pub struct ExecutionFrame<'a, B: BlackBoxFunctionSolver<FieldElement>> {
circuit_id: u32,
acvm: ACVM<'a, FieldElement, B>,
Expand All @@ -251,6 +284,25 @@
unconstrained_functions: &'a [BrilligBytecode<FieldElement>],

acir_opcode_addresses: AddressMap,
initial_witness: WitnessMap<FieldElement>,
}

fn initialize_acvm<'a, B: BlackBoxFunctionSolver<FieldElement>>(
backend: &'a B,
circuits: &'a [Circuit<FieldElement>],
initial_witness: WitnessMap<FieldElement>,
unconstrained_functions: &'a [BrilligBytecode<FieldElement>],
) -> ACVM<'a, FieldElement, B> {
let current_circuit_id: u32 = 0;
let initial_circuit = &circuits[current_circuit_id as usize];

ACVM::new(
backend,
&initial_circuit.opcodes,
initial_witness,
unconstrained_functions,
&initial_circuit.assert_messages,
)
}

impl<'a, B: BlackBoxFunctionSolver<FieldElement>> DebugContext<'a, B> {
Expand All @@ -264,16 +316,8 @@
) -> Self {
let source_to_opcodes = build_source_to_opcode_debug_mappings(debug_artifact);
let current_circuit_id: u32 = 0;
let initial_circuit = &circuits[current_circuit_id as usize];
let acir_opcode_addresses = AddressMap::new(circuits, unconstrained_functions);
Self {
acvm: ACVM::new(
blackbox_solver,
&initial_circuit.opcodes,
initial_witness,
unconstrained_functions,
&initial_circuit.assert_messages,
),
current_circuit_id,
brillig_solver: None,
witness_stack: WitnessStack::default(),
Expand All @@ -286,6 +330,13 @@
circuits,
unconstrained_functions,
acir_opcode_addresses,
initial_witness: initial_witness.clone(), // keeping it to be able to restart the context by itself
acvm: initialize_acvm(
blackbox_solver,
circuits,
initial_witness,
unconstrained_functions,
),
}
}

Expand Down Expand Up @@ -415,6 +466,12 @@
Some(found_location)
}

pub(super) fn find_opcode_at_current_file_line(&self, line: i64) -> Option<DebugLocation> {
let file = self.get_current_file()?;

self.find_opcode_for_source_location(&file, line)
}

/// 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
Expand All @@ -430,7 +487,7 @@
}

/// Returns the `FileId` of the file associated with the innermost function on the call stack.
pub(super) fn get_current_file(&mut self) -> Option<FileId> {
fn get_current_file(&self) -> Option<FileId> {
self.get_current_source_location()
.and_then(|locations| locations.last().map(|location| location.file))
}
Expand Down Expand Up @@ -539,9 +596,17 @@
self.brillig_solver = Some(solver);
self.handle_foreign_call(foreign_call)
}
Err(err) => DebugCommandResult::Error(NargoError::ExecutionError(
ExecutionError::SolvingError(err, None),
)),
Err(err) => {
let error = execution_error_from(
err,
&self
.get_call_stack()
.into_iter()
.map(|op| op.into())
.collect::<Vec<ResolvedOpcodeLocation>>(),
);
DebugCommandResult::Error(NargoError::ExecutionError(error))
}
}
}

Expand All @@ -550,6 +615,7 @@
foreign_call: ForeignCallWaitInfo<FieldElement>,
) -> DebugCommandResult {
let foreign_call_result = self.foreign_call_executor.execute(&foreign_call);

match foreign_call_result {
Ok(foreign_call_result) => {
if let Some(mut solver) = self.brillig_solver.take() {
Expand Down Expand Up @@ -844,10 +910,6 @@
self.breakpoints.remove(location)
}

pub(super) fn iterate_breakpoints(&self) -> Iter<'_, DebugLocation> {
self.breakpoints.iter()
}

pub(super) fn clear_breakpoints(&mut self) {
self.breakpoints.clear();
}
Expand All @@ -861,6 +923,22 @@
self.witness_stack.push(0, last_witness_map);
self.witness_stack
}

pub(super) fn restart(&mut self) {
// restart everything that's progress related
// by assigning the initial values
self.current_circuit_id = 0;
self.brillig_solver = None;
self.witness_stack = WitnessStack::default();
self.acvm_stack = vec![];
self.foreign_call_executor.restart(self.debug_artifact);
self.acvm = initialize_acvm(
self.backend,
self.circuits,
self.initial_witness.clone(),
self.unconstrained_functions,
);
}
}

fn is_debug_file_in_debug_crate(debug_file: &DebugFile) -> bool {
Expand Down Expand Up @@ -1022,7 +1100,7 @@
outputs: vec![],
predicate: None,
}];
let brillig_funcs = &[brillig_bytecode];

Check warning on line 1103 in tooling/debugger/src/context.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (funcs)
let current_witness_index = 2;
let circuit = Circuit { current_witness_index, opcodes, ..Circuit::default() };
let circuits = &[circuit];
Expand All @@ -1035,15 +1113,18 @@

let foreign_call_executor = Box::new(DefaultDebugForeignCallExecutor::from_artifact(
PrintOutput::Stdout,
None,
debug_artifact,
None,
String::new(),
));
let mut context = DebugContext::new(
let mut context = DebugContext::<StubbedBlackBoxSolver>::new(
&solver,
circuits,
debug_artifact,
initial_witness,
foreign_call_executor,
brillig_funcs,

Check warning on line 1127 in tooling/debugger/src/context.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (funcs)
);

assert_eq!(
Expand Down Expand Up @@ -1079,7 +1160,7 @@
})
);

// Calldatacopy

Check warning on line 1163 in tooling/debugger/src/context.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Calldatacopy)
let result = context.step_into_opcode();
assert!(matches!(result, DebugCommandResult::Ok));
assert_eq!(
Expand Down Expand Up @@ -1203,10 +1284,13 @@

let foreign_call_executor = Box::new(DefaultDebugForeignCallExecutor::from_artifact(
PrintOutput::Stdout,
None,
debug_artifact,
None,
String::new(),
));
let brillig_funcs = &[brillig_bytecode];

Check warning on line 1292 in tooling/debugger/src/context.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (funcs)
let mut context = DebugContext::new(
let mut context = DebugContext::<StubbedBlackBoxSolver>::new(
&solver,
circuits,
debug_artifact,
Expand Down Expand Up @@ -1294,12 +1378,17 @@
let debug_artifact = DebugArtifact { debug_symbols: vec![], file_map: BTreeMap::new() };
let brillig_funcs = &[brillig_one, brillig_two];

let context = DebugContext::new(
let context = DebugContext::<StubbedBlackBoxSolver>::new(
&solver,
&circuits,
&debug_artifact,
WitnessMap::new(),
Box::new(DefaultDebugForeignCallExecutor::new(PrintOutput::Stdout)),
Box::new(DefaultDebugForeignCallExecutor::new(
PrintOutput::Stdout,
None,
None,
String::new(),
)),
brillig_funcs,
);

Expand Down
Loading
Loading