Skip to content

Commit

Permalink
chore: regression test #7195 (#7233)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeljklein authored Feb 21, 2025
1 parent a995bf2 commit 47aec5d
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 11 deletions.
6 changes: 6 additions & 0 deletions test_programs/execution_success/regression_7195/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "regression_7195"
type = "bin"
authors = [""]

[dependencies]
2 changes: 2 additions & 0 deletions test_programs/execution_success/regression_7195/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x = "1"
y = "2"
21 changes: 21 additions & 0 deletions test_programs/execution_success/regression_7195/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
fn bar(y: Field) {
assert(y != 0);
}

fn foo(x: Field) {
// Safety: test
let y = unsafe { baz(x) };
bar(y);
}

unconstrained fn baz(x: Field) -> Field {
x
}

fn main(x: Field, y: pub Field) {
// Safety: test
let x = unsafe { baz(x) };
foo(x);
foo(y);
assert(x != y);
}
3 changes: 2 additions & 1 deletion tooling/debugger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ pub fn run_repl_session<B: BlackBoxFunctionSolver<FieldElement>>(
solver: &B,
program: CompiledProgram,
initial_witness: WitnessMap<FieldElement>,
raw_source_printing: bool,
) -> Result<Option<WitnessStack<FieldElement>>, NargoError<FieldElement>> {
repl::run(solver, program, initial_witness)
repl::run(solver, program, initial_witness, raw_source_printing)
}

pub fn run_dap_loop<R: Read, W: Write, B: BlackBoxFunctionSolver<FieldElement>>(
Expand Down
16 changes: 14 additions & 2 deletions tooling/debugger/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ pub struct ReplDebugger<'a, B: BlackBoxFunctionSolver<FieldElement>> {

// Brillig functions referenced from the ACIR circuits above
unconstrained_functions: &'a [BrilligBytecode<FieldElement>],

// whether to print the source without highlighting, pretty-printing,
// or line numbers
raw_source_printing: bool,
}

impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
Expand All @@ -41,6 +45,7 @@ impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
debug_artifact: &'a DebugArtifact,
initial_witness: WitnessMap<FieldElement>,
unconstrained_functions: &'a [BrilligBytecode<FieldElement>],
raw_source_printing: bool,
) -> Self {
let foreign_call_executor = Box::new(DefaultDebugForeignCallExecutor::from_artifact(
PrintOutput::Stdout,
Expand Down Expand Up @@ -68,6 +73,7 @@ impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
initial_witness,
last_result,
unconstrained_functions,
raw_source_printing,
}
}

Expand Down Expand Up @@ -97,7 +103,11 @@ impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
}
}
let locations = self.context.get_source_location_for_debug_location(&location);
print_source_code_location(self.debug_artifact, &locations);
print_source_code_location(
self.debug_artifact,
&locations,
self.raw_source_printing,
);
}
}
}
Expand Down Expand Up @@ -125,7 +135,7 @@ impl<'a, B: BlackBoxFunctionSolver<FieldElement>> ReplDebugger<'a, B> {
}
}
let locations = self.context.get_source_location_for_debug_location(debug_location);
print_source_code_location(self.debug_artifact, &locations);
print_source_code_location(self.debug_artifact, &locations, self.raw_source_printing);
}

pub fn show_current_call_stack(&self) {
Expand Down Expand Up @@ -427,6 +437,7 @@ pub fn run<B: BlackBoxFunctionSolver<FieldElement>>(
blackbox_solver: &B,
program: CompiledProgram,
initial_witness: WitnessMap<FieldElement>,
raw_source_printing: bool,
) -> Result<Option<WitnessStack<FieldElement>>, NargoError<FieldElement>> {
let circuits = &program.program.functions;
let debug_artifact =
Expand All @@ -438,6 +449,7 @@ pub fn run<B: BlackBoxFunctionSolver<FieldElement>>(
debug_artifact,
initial_witness,
unconstrained_functions,
raw_source_printing,
));
let ref_context = &context;

Expand Down
34 changes: 29 additions & 5 deletions tooling/debugger/src/source_code_printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ struct LocationPrintContext {
// Given a DebugArtifact and an OpcodeLocation, prints all the source code
// locations the OpcodeLocation maps to, with some surrounding context and
// visual aids to highlight the location itself.
pub(super) fn print_source_code_location(debug_artifact: &DebugArtifact, locations: &[Location]) {
pub(super) fn print_source_code_location(
debug_artifact: &DebugArtifact,
locations: &[Location],
raw_source_printing: bool,
) {
let locations = locations.iter();

for loc in locations {
Expand All @@ -41,9 +45,11 @@ pub(super) fn print_source_code_location(debug_artifact: &DebugArtifact, locatio
for line in lines {
match line {
PrintedLine::Skip => {}
PrintedLine::Ellipsis { line_number } => print_ellipsis(line_number),
PrintedLine::Ellipsis { line_number } => {
print_ellipsis(line_number, raw_source_printing)
}
PrintedLine::Content { line_number, cursor, content, highlight } => {
print_content(line_number, cursor, content, highlight)
print_content(line_number, cursor, content, highlight, raw_source_printing)
}
}
}
Expand All @@ -57,11 +63,29 @@ fn print_location_path(debug_artifact: &DebugArtifact, loc: Location) {
println!("At {}:{line_number}:{column_number}", debug_artifact.name(loc.file).unwrap());
}

fn print_ellipsis(line_number: usize) {
fn print_ellipsis(line_number: usize, raw_source_printing: bool) {
if raw_source_printing {
println!("...");
return;
}

println!("{:>3} {:2} {}", line_number.dimmed(), "", "...".dimmed());
}

fn print_content(line_number: usize, cursor: &str, content: &str, highlight: Option<Range<usize>>) {
fn print_content(
line_number: usize,
cursor: &str,
content: &str,
highlight: Option<Range<usize>>,
raw_source_printing: bool,
) {
if raw_source_printing {
if cursor == "->" && highlight.is_some() {
println!("{}", content);
}
return;
}

match highlight {
Some(highlight) => {
println!(
Expand Down
111 changes: 111 additions & 0 deletions tooling/debugger/tests/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,115 @@ mod tests {
// Exit the bash session.
dbg_session.send_line("exit").expect("Failed to quit bash session");
}

#[test]
fn debugger_expected_call_stack() {
let nargo_bin =
cargo_bin("nargo").into_os_string().into_string().expect("Cannot parse nargo path");

let timeout_seconds = 30;
let mut dbg_session =
spawn_bash(Some(timeout_seconds * 1000)).expect("Could not start bash session");

let test_program_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../test_programs/execution_success/regression_7195");
let test_program_dir = test_program_path.display();

// Start debugger and test that it loads for the given program.
dbg_session
.execute(
&format!(
"{nargo_bin} debug --raw-source-printing true --program-dir {test_program_dir} --force-brillig --expression-width 3"
),
".*\\Starting debugger.*",
)
.expect("Could not start debugger");

let num_steps = 16;
for _ in 1..=num_steps {
// While running the debugger, issue a "next" cmd,
// which should run to the program to the next source line given
// we haven't set any breakpoints.
// ">" is the debugger's prompt, so finding one
// after running "next" indicates that the
// debugger has not panicked for this step.
dbg_session
.send_line("next")
.expect("Debugger panicked while attempting to step through program.");
dbg_session
.exp_string(">")
.expect("Failed while waiting for debugger to step through program.");
}

let mut lines = vec![];
while let Ok(line) = dbg_session.read_line() {
if !(line.starts_with(">next") || line.starts_with("At ") || line.starts_with("...")) {
lines.push(line);
}
}

let lines_expected_to_contain: Vec<&str> = vec![
"> next",
" let x = unsafe { baz(x) };",
"unconstrained fn baz(x: Field) -> Field {",
"> next",
" let x = unsafe { baz(x) };",
"unconstrained fn baz(x: Field) -> Field {",
"> next",
" let x = unsafe { baz(x) };",
"}",
"> next",
" let x = unsafe { baz(x) };",
"> next",
" foo(x);",
"fn foo(x: Field) {",
"> next",
" foo(x);",
"fn foo(x: Field) {",
"> next",
" foo(x);",
" let y = unsafe { baz(x) };",
"unconstrained fn baz(x: Field) -> Field {",
"> next",
" foo(x);",
" let y = unsafe { baz(x) };",
"unconstrained fn baz(x: Field) -> Field {",
"> next",
" foo(x);",
" let y = unsafe { baz(x) };",
"}",
"> next",
" foo(x);",
" let y = unsafe { baz(x) };",
"> next",
" foo(x);",
" bar(y);",
"fn bar(y: Field) {",
"> next",
" foo(x);",
" bar(y);",
"fn bar(y: Field) {",
"> next",
" foo(x);",
" bar(y);",
" assert(y != 0);",
];

for (line, line_expected_to_contain) in lines.into_iter().zip(lines_expected_to_contain) {
let ascii_line: String = line.chars().filter(char::is_ascii).collect();
let line_expected_to_contain = line_expected_to_contain.trim_start();
assert!(
ascii_line.contains(line_expected_to_contain),
"{:?}\ndid not contain\n{:?}",
ascii_line,
line_expected_to_contain,
);
}

// Run the "quit" command
dbg_session.send_line("quit").expect("Failed to quit debugger");

// Exit the bash session.
dbg_session.send_line("exit").expect("Failed to quit bash session");
}
}
20 changes: 17 additions & 3 deletions tooling/nargo_cli/src/cli/debug_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ pub(crate) struct DebugCommand {
/// Disable vars debug instrumentation (enabled by default)
#[clap(long)]
skip_instrumentation: Option<bool>,

/// Raw string printing of source for testing
#[clap(long, hide = true)]
raw_source_printing: Option<bool>,
}

impl WorkspaceCommand for DebugCommand {
Expand Down Expand Up @@ -97,6 +101,7 @@ pub(crate) fn run(args: DebugCommand, workspace: Workspace) -> Result<(), CliErr
&args.witness_name,
target_dir,
args.compile_options.pedantic_solving,
args.raw_source_printing.unwrap_or(false),
)
}

Expand Down Expand Up @@ -185,14 +190,20 @@ fn run_async(
witness_name: &Option<String>,
target_dir: &PathBuf,
pedantic_solving: bool,
raw_source_printing: bool,
) -> Result<(), CliError> {
use tokio::runtime::Builder;
let runtime = Builder::new_current_thread().enable_all().build().unwrap();

runtime.block_on(async {
println!("[{}] Starting debugger", package.name);
let (return_value, witness_stack) =
debug_program_and_decode(program, package, prover_name, pedantic_solving)?;
let (return_value, witness_stack) = debug_program_and_decode(
program,
package,
prover_name,
pedantic_solving,
raw_source_printing,
)?;

if let Some(solved_witness_stack) = witness_stack {
println!("[{}] Circuit witness successfully solved", package.name);
Expand Down Expand Up @@ -220,12 +231,13 @@ fn debug_program_and_decode(
package: &Package,
prover_name: &str,
pedantic_solving: bool,
raw_source_printing: bool,
) -> Result<(Option<InputValue>, Option<WitnessStack<FieldElement>>), CliError> {
// Parse the initial witness values from Prover.toml
let (inputs_map, _) =
read_inputs_from_file(&package.root_dir, prover_name, Format::Toml, &program.abi)?;
let program_abi = program.abi.clone();
let witness_stack = debug_program(program, &inputs_map, pedantic_solving)?;
let witness_stack = debug_program(program, &inputs_map, pedantic_solving, raw_source_printing)?;

match witness_stack {
Some(witness_stack) => {
Expand All @@ -244,13 +256,15 @@ pub(crate) fn debug_program(
compiled_program: CompiledProgram,
inputs_map: &InputMap,
pedantic_solving: bool,
raw_source_printing: bool,
) -> Result<Option<WitnessStack<FieldElement>>, CliError> {
let initial_witness = compiled_program.abi.encode(inputs_map, None)?;

noir_debugger::run_repl_session(
&Bn254BlackBoxSolver(pedantic_solving),
compiled_program,
initial_witness,
raw_source_printing,
)
.map_err(CliError::from)
}

1 comment on commit 47aec5d

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Test Suite Duration'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: 47aec5d Previous: a995bf2 Ratio
AztecProtocol_aztec-packages_noir-projects_noir-protocol-circuits_crates_blob 65 s 52 s 1.25

This comment was automatically generated by workflow using github-action-benchmark.

CC: @TomAFrench

Please sign in to comment.