Skip to content

Commit

Permalink
More docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
azteca1998 committed Dec 12, 2024
1 parent 897cdcb commit c5272da
Show file tree
Hide file tree
Showing 2 changed files with 235 additions and 136 deletions.
75 changes: 42 additions & 33 deletions docs/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@ export NATIVE_DEBUG_DUMP=1
### Debugging with LLDB

To debug with LLDB (or another debugger), we must compile the binary with the `with-debug-utils` feature.

```bash
cargo build --bin cairo-native-run --features with-debug-utils
```

Then, we can add the a debugger breakpoint trap. To add it at a given sierra statement, we can set the following env var:

```bash
export NATIVE_DEBUG_TRAP_AT_STMT=10
```

The trap instruction may not end up exactly where the statement is.

If we want to manually set the breakpoint (for example, when executing a particular libfunc), then we can use the `DebugUtils` metadata in the code.

```rust,ignore
#[cfg(feature = "with-debug-utils")]
{
Expand All @@ -47,13 +50,15 @@ lldb -- target/debug/cairo-native-run -s programs/recursion.cairo --available-ga
```

Some usefull lldb commands:

- `process launch`: starts the program
- `frame select`: shows the current line information
- `thread step-in`: makes a source level single step
- `thread continue`: continues execution of the current process
- `disassemble --frame --mixed`: shows assembly instructions mixed with source level code

## Logging

Enable logging to see the compilation process:

```bash
Expand All @@ -77,6 +82,7 @@ export RUST_LOG="cairo_native=trace"
## Debugging Contracts

Contracts are difficult to debug for various reasons, including:

- They are external to the project.
- We don’t have their source code.
- They run autogenerated code (the wrapper).
Expand All @@ -86,6 +92,7 @@ Contracts are difficult to debug for various reasons, including:
Some of them have workarounds:

### Obtaining the contract

There are various options for obtaining the contract, which include:

- Manually invoking the a Starknet API using `curl` with the contract class.
Expand Down Expand Up @@ -114,6 +121,7 @@ Both should provide us with the contract, but if we’re manually invoking the A
- Convert the ABI from a string of JSON into a JSON object.

### Interpreting the contract

The contract JSON contains the Sierra program in a useless form (in the sense
that we cannot understand anything), as well as some information about the
entry points and some ABI types. We’ll need the Sierra program (in Sierra
Expand Down Expand Up @@ -278,6 +286,7 @@ why it’s important to check for those cases and keep following the control
flow backwards as required.

### Fixing the bug

Before fixing the bug it’s really important to know:

- **Where** it happens (in our compiler, not so much in the contract at this point)
Expand Down Expand Up @@ -307,17 +316,17 @@ To aid in the debugging process, we developed [sierra-emu](https://github.com/la

In addition to this, we developed the `with-trace-dump` feature for Cairo Native, which generates an execution trace that records every statement executed. It has the same shape as the one generated by the Sierra emulator. Supporting transaction execution with Cairo Native trace dump required quite a few hacks, which is why we haven’t merged it to main. This is why we need to use a specific cairo native branch.

By combining both tools, we can hopefully pinpoint exactly which *libfunc* implementation is buggy.
By combining both tools, we can hopefully pinpoint exactly which _libfunc_ implementation is buggy.

Before starting, make sure to clone [starknet-replay](https://github.com/lambdaclass/starknet-replay).

#### Obtaining Sierra Emulator Trace in Starknet Replay

1. Checkout starknet-replay `trace-dump` branch.
2. Execute a single transaction with the `use-sierra-emu` feature
```bash
cargo run --features use-sierra-emu tx <HASH> <CHAIN> <BLOCK>
```
```bash
cargo run --features use-sierra-emu tx <HASH> <CHAIN> <BLOCK>
```
3. Once finished, it will have written the traces of each inner contract inside of `traces/emu`, relative to the current working directory.

As a single transaction can invoke multiple contracts (by contract and library calls), this generates a trace file for each contract executed, numbered in ascending order: `trace_0.json`, `trace_1.json`, etc.
Expand All @@ -326,9 +335,9 @@ As a single transaction can invoke multiple contracts (by contract and library c

1. Checkout starknet-replay `trace-dump` branch.
2. Execute a single transaction with the `with-trace-dump` feature
```bash
cargo run --features with-trace-dump tx <HASH> <CHAIN> <BLOCK>
```
```bash
cargo run --features with-trace-dump tx <HASH> <CHAIN> <BLOCK>
```
3. Once finished, it will have written the traces of each inner contract inside of `traces/native`, relative to the current working directory.

#### Patching Dependencies
Expand All @@ -347,41 +356,41 @@ sierra-emu = { path = "../sierra-emu" }
Once you have generated the traces for both the Sierra emulator and Cairo Native, you can begin debugging.

1. Compare the traces of the same contract with the favorite tool:
```bash
diff "traces/{emu,native}/trace_0.json" # or
delta "traces/{emu,native}/trace_0.json" --side-by-side
```
```bash
diff "traces/{emu,native}/trace_0.json" # or
delta "traces/{emu,native}/trace_0.json" --side-by-side
```
2. Look for the first significant difference between the traces. Not all the differences are significant, for example:
1. Sometimes the emulator and Cairo Native differ in the Gas builtin. It usually doesn’t affect the outcome of the contract.
2. The ec_state_init libfunc randomizes an elliptic curve point, which is why they always differ.
1. Sometimes the emulator and Cairo Native differ in the Gas builtin. It usually doesn’t affect the outcome of the contract.
2. The ec_state_init libfunc randomizes an elliptic curve point, which is why they always differ.
3. Find the index of the statement executed immediately previous to the first difference.
4. Open `traces/prog_0.sierra` and look for that statement.
1. If it’s a return, then you are dealing with a control flow bug. These are difficult to debug.
2. If it’s a libfunc invocation, then that libfunc is probably the one that is buggy.
3. If it’s a library or contract call, then the bug is probably in another contract, and you should move onto the next trace.
1. If it’s a return, then you are dealing with a control flow bug. These are difficult to debug.
2. If it’s a libfunc invocation, then that libfunc is probably the one that is buggy.
3. If it’s a library or contract call, then the bug is probably in another contract, and you should move onto the next trace.

#### Useful Scripts

In the `scripts` folder of starknet-replay, you can find useful scripts for debugging. Make sure to execute them in the root directory. Some scripts require `delta` to be installed.

- `compare-traces`: Compares every trace and outputs which are different. This can help finding the buggy contract when there are a lot of traces.
```bash
> ./scripts/compare-traces.sh
difference: ./traces/emu/trace_0.json ./traces/native/trace_0.json
difference: ./traces/emu/trace_1.json ./traces/native/trace_1.json
difference: ./traces/emu/trace_3.json ./traces/native/trace_3.json
missing file: ./traces/native/trace_4.json
```
```bash
> ./scripts/compare-traces.sh
difference: ./traces/emu/trace_0.json ./traces/native/trace_0.json
difference: ./traces/emu/trace_1.json ./traces/native/trace_1.json
difference: ./traces/emu/trace_3.json ./traces/native/trace_3.json
missing file: ./traces/native/trace_4.json
```
- `diff-trace`: Receives a trace number, and executes `delta` to compare that trace.
```bash
./scripts/diff-trace.sh 1
```
```bash
./scripts/diff-trace.sh 1
```
- `diff-trace-flow`: Like `diff-trace`, but only diffs (with `delta`) the statement indexes. It can be used to visualize the control flow difference.
```bash
./scripts/diff-trace-flow.sh 1
```
```bash
./scripts/diff-trace-flow.sh 1
```
- `string-to-felt`: Converts the given string to a felt. Can be used to search in the code where a specific error message was generated.
```bash
> ./scripts/string-to-felt.sh "u256_mul Overflow"
753235365f6d756c204f766572666c6f77
```
```bash
> ./scripts/string-to-felt.sh "u256_mul Overflow"
753235365f6d756c204f766572666c6f77
```
Loading

0 comments on commit c5272da

Please sign in to comment.