# Cargo Stylus Replay
Cargo stylus ships with an extra crate called `cargo-stylus-replay` which contains two useful pieces of functionality: the ability to perform trace calls against Stylus transactions using Ethereum nodes' `debug_traceTransaction` RPC, and the ability to use `gdb` to replay and debug the execution of a Stylus transaction against its program's codebase.
## Replaying
**NOTES: Only tested on Linux, x86 systems at the moment with gdb installed**
Requirements:
- Rust installed, v1.77 at least
- `cargo-stylus`, `cargo-stylus-replay`, `cargo-stylus-check`
crates
- GNU debugger (gdb)
- [Cast](https://book.getfoundry.sh/cast/)
- A local, Arbitrum sepolia node with tracing endpoints enabled, or a local Stylus testnet v2 node
`cargo stylus replay` allows users to debug the execution of a Stylus transaction using the popular GNU project debugger, [gdb](https://sourceware.org/gdb/), against the source code of the program in Rust.
To use `cargo stylus replay`, make sure to install the `cargo-stylus` and `cargo-stylus-replay` crates and [gdb](https://sourceware.org/gdb/).
The way it works is that a user can get the transaction hash of a mutating call that interacted with their program, run `cargo stylus replay --tx=0xabc...`, and set breakpoints at different lines of code or methods in their source code to inspect what is happening at each step.
For example, let's try to debug the execution of the `increment()` method in the [stylus-hello-world](https://github.com/OffchainLabs/stylus-hello-world) smart contract. In Rust, it looks something like this, within `src/lib.rs`.
```rust
#[external]
impl Counter {
...
/// Increments `number` and updates its value in storage.
pub fn increment(&mut self) {
let number = self.number.get();
self.set_number(number + U256::from(1));
}
...
}
```
Let's first deploy the program to Arbitrum Sepolia. Set your RPC endpoint to a node that has **tracing enabled** (you may need to run your own), and set your private key.
```
export RPC_URL=...
export PRIV_KEY=...
```
Then, run
```
cargo stylus deploy --private-key=$PRIV_KEY --endpoint=$RPC_UR
```
You should see something like this:
```
contract size: 4.0 KB
wasm size: 12.1 KB
contract size: 4.0 KB
deployed code at address: 0x2c8d8a1229252b07e73b35774ad91c0b973ecf71
wasm already activated!
```
We can then call the increment() method of the program using the popular Ethereum CLI tool, [cast](https://book.getfoundry.sh/cast/)
Set the address of the deployed program as an env var
```
export ADDR=0x2c8d8a1229252b07e73b35774ad91c0b973ecf71
```
Then, send the increment transaction.
```
cast send --rpc-url=$RPC_URL --private-key=$PRIV_KEY $ADDR "increment()"
```
You should then take the transaction hash and set it as an env var.
```
export TX_HASH=0x18b241841fa0a59e02d3c6d693750ff0080ad792204aac7e5d4ce9e20c466835
```
Now, we can replay it with cargo stylus and GDB to inspect each step of the tx against our source code. Make sure gdb is installed and that you are on a Linux, x86 system.
```
cargo stylus replay --tx=$TX_HASH --endpoint=$RPC_URL
```
You should see gdb load up and set a breakpoint automatically at the `user_entrypoint` internal Stylus function.
```
[Detaching after vfork from child process 370003]
Thread 1 "cargo-stylus-re" hit Breakpoint 1, stylus_hello_world::user_entrypoint (len=4) at src/lib.rs:38
38 #[entrypoint]
(gdb)
```
Next, we can set a breakpoint at our `increment` method.
```
(gdb) b stylus_hello_world::Counter::increment
Breakpoint 2 at 0x7ffff7e4ee33: file src/lib.rs, line 69.
```
Then, type `c` to continue the execution and you will reach that line where increment is called.
```
Thread 1 "cargo-stylus-re" hit Breakpoint 2, stylus_hello_world::Counter::increment (self=0x7fffffff9ae8) at src/lib.rs:69
69 let number = self.number.get();
(gdb) p number
```
Then, you can print out local variables and leverage all the tools that gdb has available.
Full set of flags:
```
Replay a transaction in gdb
Usage: cargo stylus replay [OPTIONS] --tx <TX>
Options:
-e, --endpoint <ENDPOINT> RPC endpoint [default: http://localhost:8547]
-t, --tx <TX> Tx to replay
-p, --project <PROJECT> Project path [default: .]
-s, --stable-rust Whether to use stable Rust. Note that nightly is needed to expand macros
-h, --help Print help
-V, --version Print version
➜ cargo-stylus git:(main) cargo stylus trace --help
Trace a transaction
```
## Tracing
For more traditional tracing, cargo stylus supports interpreting calls to `debug_traceTransaction`.
```
Trace a transaction
Usage: cargo stylus trace [OPTIONS] --tx <TX>
Options:
-e, --endpoint <ENDPOINT> RPC endpoint [default: http://localhost:8547]
-t, --tx <TX> Tx to replay
-p, --project <PROJECT> Project path [default: .]
-h, --help Print help
-V, --version Print version
```
You can run the following
`cargo stylus trace --tx=$TX_HASH --endpoint=$RPC_URL`
and obtain a corresponding trace output of the functions called and ink left along each method:
```json!
[{"args":[0,0,0,4],"endInk":846200000,"name":"user_entrypoint","outs":[],"startInk":846200000},{"args":[],"endInk":846167558,"name":"msg_reentrant","outs":[0,0,0,0],"startInk":846175958},{"args":[],"endInk":846047922,"name":"read_args","outs":[208,157,224,138],"startInk":846061362},{"args":[],"endInk":845914924,"name":"msg_value","outs":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"startInk":845928364},{"args":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"endInk":227196069,"name":"storage_load_bytes32","outs":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"startInk":844944549},{"args":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],"endInk":226716083,"name":"storage_cache_bytes32","outs":[],"startInk":226734563},{"args":[0],"endInk":226418732,"name":"storage_flush_cache","outs":[],"startInk":226486805},{"args":[],"endInk":226362319,"name":"write_result","outs":[],"startInk":226403481},{"args":[],"endInk":846200000,"name":"user_returned","outs":[0,0,0,0],"startInk":846200000}]
```