-
Notifications
You must be signed in to change notification settings - Fork 0
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(debugger): Add support for debugging tests (#5208) #7
base: feat/5208-debug-tests-repl-dap
Are you sure you want to change the base?
Changes from all commits
37283ac
21f0739
1589176
1580110
e3f10d6
d9aaa1d
6d16905
aebba26
8b96a17
7b3961a
536a89f
54fd555
6b1cc78
16a76a1
873d516
92e551d
8da3eef
5a1625e
9eacfe6
c36f131
c8f8b40
ac3aa22
7914726
19bf1e9
2dc687c
b70cd79
8d76cac
2dbda88
4364c48
5ef8e84
38b58e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -14,7 +14,7 @@ sidebar_position: 1 | |||||
|
||||||
#### Pre-requisites | ||||||
|
||||||
In order to use the REPL debugger, first you need to install recent enough versions of Nargo and vscode-noir. | ||||||
In order to use the REPL debugger, first you need to install recent enough versions of Nargo and vscode-noir. | ||||||
|
||||||
## Debugging a simple circuit | ||||||
|
||||||
|
@@ -162,3 +162,44 @@ Finished execution | |||||
Upon quitting the debugger after a solved circuit, the resulting circuit witness gets saved, equivalent to what would happen if we had run the same circuit with `nargo execute`. | ||||||
|
||||||
We just went through the basics of debugging using Noir REPL debugger. For a comprehensive reference, check out [the reference page](../../reference/debugger/debugger_repl.md). | ||||||
|
||||||
## Debugging a test function | ||||||
|
||||||
Let's debug a simple circuit: | ||||||
|
||||||
```rust | ||||||
#[noir] | ||||||
fn test_simple_equal() { | ||||||
let x = 2; | ||||||
let y = 1 + 1; | ||||||
assert(x == y, "should be equal"); | ||||||
} | ||||||
``` | ||||||
|
||||||
To start the REPL debugger for a test function, using a terminal, go to a Noir circuit's home directory. Then invoke the `debug` command setting the `--test-name` argument. | ||||||
|
||||||
```bash | ||||||
nargo debug --test-name test_simple_equal | ||||||
``` | ||||||
|
||||||
After that, the debugger has started and works the same as debugging a main function, you can use any of the above explained commands to control the execution of the test function. | ||||||
|
||||||
### Test result | ||||||
|
||||||
The debugger does not end the session automatically. Once you finish debugging the execution of the test function you will notice that the debugger remain in the `Execution finished` state. If you are done debugging the test function you should exit the debugger by using the `quit` command. Once you finish the debugging session you should see the test result. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
```text | ||||||
$ nargo debug --test-name test_simple_equal | ||||||
|
||||||
[simple_noir_project] Starting debugger | ||||||
At opcode 0:0 :: BRILLIG CALL func 0: inputs: [], outputs: [] | ||||||
|
||||||
> continue | ||||||
(Continuing execution...) | ||||||
Finished execution | ||||||
|
||||||
> quit | ||||||
[simple_noir_project] Circuit witness successfully solved | ||||||
[simple_noir_project] Testing test_simple_equal... ok | ||||||
[simple_noir_project] 1 test passed | ||||||
``` |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -23,9 +23,15 @@ This guide will show you how to use VS Code with the vscode-noir extension to de | |||||
|
||||||
## Running the debugger | ||||||
|
||||||
The easiest way to start debugging is to open the file you want to debug, and press `F5`. This will cause the debugger to launch, using your `Prover.toml` file as input. | ||||||
The easiest way to start debugging is to open the file you want to debug, and click on `Debug` codelens over main functions or `Debug test` over `#[test]` functions | ||||||
|
||||||
You should see something like this: | ||||||
If you don't see the codelens options `Compile|Info|..|Debug` over the `main` function or `Run test| Debug test` over a test function then you probably have the codelens feature disabled. For enabling it head to the extension configuration and turn on the `Enable Code Lens` setting. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
![Debugger codelens](@site/static/img/debugger/debugger-codelens.png) | ||||||
|
||||||
Another way of starting the debugger is to press `F5` on the file you want to debug. This will cause the debugger to launch, using your `Prover.toml` file as input. | ||||||
|
||||||
Once the debugger has started you should see something like this: | ||||||
|
||||||
![Debugger launched](@site/static/img/debugger/1-started.png) | ||||||
|
||||||
|
@@ -65,4 +71,4 @@ We just need to click the to the right of the line number 18. Once the breakpoin | |||||
|
||||||
Now we are debugging the `keccak256` function, notice the _Call Stack pane_ at the lower right. This lets us inspect the current call stack of our process. | ||||||
|
||||||
That covers most of the current debugger functionalities. Check out [the reference](../../reference/debugger/debugger_vscode.md) for more details on how to configure the debugger. | ||||||
That covers most of the current debugger functionalities. Check out [the reference](../../reference/debugger/debugger_vscode.md) for more details on how to configure the debugger. |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -20,17 +20,23 @@ Runs the Noir REPL debugger. If a `WITNESS_NAME` is provided the debugger writes | |||||
|
||||||
### Options | ||||||
|
||||||
| Option | Description | | ||||||
| --------------------- | ------------------------------------------------------------ | | ||||||
| Option | Description | | ||||||
| --------------------------------- | ----------------------------------------------------------------------------------- | | ||||||
| `-p, --prover-name <PROVER_NAME>` | The name of the toml file which contains the inputs for the prover [default: Prover]| | ||||||
| `--package <PACKAGE>` | The name of the package to debug | | ||||||
| `--print-acir` | Display the ACIR for compiled circuit | | ||||||
| `--deny-warnings` | Treat all warnings as errors | | ||||||
| `--silence-warnings` | Suppress warnings | | ||||||
| `-h, --help` | Print help | | ||||||
| `--package <PACKAGE>` | The name of the package to debug | | ||||||
| `--print-acir` | Display the ACIR for compiled circuit | | ||||||
| `--deny-warnings` | Treat all warnings as errors | | ||||||
| `--silence-warnings` | Suppress warnings | | ||||||
| `--test-name` <TEST_NAME> | The name of the test function to debug - which name contains this string | | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| `-h, --help` | Print help | | ||||||
|
||||||
None of these options are required. | ||||||
|
||||||
:::note | ||||||
If the `--test-name` option is provided the debugger will debug the matching function instead of the package `main` function. | ||||||
This argument must only match one function. If the given name matches with more than one test function the debugger will not start. | ||||||
::: | ||||||
|
||||||
:::note | ||||||
Since the debugger starts by compiling the target package, all Noir compiler options are also available. Check out the [compiler reference](../nargo_commands.md#nargo-compile) to learn more about the compiler options. | ||||||
::: | ||||||
|
@@ -357,4 +363,4 @@ Update a memory cell with the given value. For example: | |||||
|
||||||
:::note | ||||||
This command is only functional while the debugger is executing unconstrained code. | ||||||
::: | ||||||
::: |
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; | ||
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::{ | ||
|
@@ -12,7 +12,7 @@ | |
|
||
use codespan_reporting::files::{Files, SimpleFile}; | ||
use fm::FileId; | ||
use nargo::errors::{ExecutionError, Location}; | ||
use nargo::errors::{map_execution_error, ExecutionError, Location}; | ||
use nargo::NargoError; | ||
use noirc_artifacts::debug::{DebugArtifact, StackFrame}; | ||
use noirc_driver::DebugFile; | ||
|
@@ -183,9 +183,14 @@ | |
|
||
#[derive(Debug)] | ||
pub(super) enum DebugCommandResult { | ||
// TODO: validate comments | ||
// The debugging session is over successfully | ||
Done, | ||
// The session is active and we should continue with the execution | ||
Ok, | ||
// Execution should be paused since we reached a Breakpoint | ||
BreakpointReached(DebugLocation), | ||
// Session is over with an error | ||
Comment on lines
+186
to
+193
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In all of these, it's probably desirable to use |
||
Error(NargoError<FieldElement>), | ||
} | ||
|
||
|
@@ -316,6 +321,20 @@ | |
frames | ||
} | ||
|
||
fn get_resolved_call_stack(&self) -> Vec<ResolvedOpcodeLocation> { | ||
self.get_call_stack() | ||
.iter() | ||
.map(|debug_loc| { | ||
// usize should be at least u32 for supported platforms | ||
let acir_function_index = usize::try_from(debug_loc.circuit_id).unwrap(); | ||
acvm::acir::circuit::ResolvedOpcodeLocation { | ||
acir_function_index, | ||
opcode_location: debug_loc.opcode_location, | ||
} | ||
}) | ||
Comment on lines
+327
to
+334
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be better to implement the self.get_call_stack().iter().map(|debug_loc| debug_loc.into()).collect() |
||
.collect() | ||
} | ||
|
||
pub(super) fn is_source_location_in_debug_module(&self, location: &Location) -> bool { | ||
self.debug_artifact | ||
.file_map | ||
|
@@ -472,9 +491,13 @@ | |
self.brillig_solver = Some(solver); | ||
self.handle_foreign_call(foreign_call) | ||
} | ||
Err(err) => DebugCommandResult::Error(NargoError::ExecutionError( | ||
ExecutionError::SolvingError(err, None), | ||
)), | ||
Err(err) => { | ||
self.brillig_solver = Some(solver); | ||
DebugCommandResult::Error(NargoError::ExecutionError(map_execution_error( | ||
err, | ||
&self.get_resolved_call_stack(), | ||
))) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -574,7 +597,7 @@ | |
} | ||
} | ||
ACVMStatus::Failure(error) => DebugCommandResult::Error(NargoError::ExecutionError( | ||
ExecutionError::SolvingError(error, None), | ||
map_execution_error(error, &self.get_resolved_call_stack()), | ||
)), | ||
ACVMStatus::RequiresForeignCall(foreign_call) => self.handle_foreign_call(foreign_call), | ||
ACVMStatus::RequiresAcirCall(call_info) => self.handle_acir_call(call_info), | ||
|
@@ -904,7 +927,7 @@ | |
outputs: vec![], | ||
predicate: None, | ||
}]; | ||
let brillig_funcs = &vec![brillig_bytecode]; | ||
let current_witness_index = 2; | ||
let circuit = Circuit { current_witness_index, opcodes, ..Circuit::default() }; | ||
let circuits = &vec![circuit]; | ||
|
@@ -923,7 +946,7 @@ | |
debug_artifact, | ||
initial_witness, | ||
foreign_call_executor, | ||
brillig_funcs, | ||
); | ||
|
||
assert_eq!( | ||
|
@@ -1042,14 +1065,14 @@ | |
|
||
let foreign_call_executor = | ||
Box::new(DefaultDebugForeignCallExecutor::from_artifact(true, debug_artifact)); | ||
let brillig_funcs = &vec![brillig_bytecode]; | ||
let mut context = DebugContext::new( | ||
&StubbedBlackBoxSolver, | ||
circuits, | ||
debug_artifact, | ||
initial_witness, | ||
foreign_call_executor, | ||
brillig_funcs, | ||
); | ||
|
||
// set breakpoint | ||
|
@@ -1116,7 +1139,7 @@ | |
}; | ||
let circuits = vec![circuit_one, circuit_two]; | ||
let debug_artifact = DebugArtifact { debug_symbols: vec![], file_map: BTreeMap::new() }; | ||
let brillig_funcs = &vec![brillig_one, brillig_two]; | ||
|
||
let context = DebugContext::new( | ||
&StubbedBlackBoxSolver, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.