Skip to content

Commit

Permalink
Add more debugging doc (#300)
Browse files Browse the repository at this point in the history
* Add debugging doc

* fix
  • Loading branch information
pgherveou authored Jan 19, 2024
1 parent b94a67c commit bc789fa
Showing 1 changed file with 94 additions and 1 deletion.
95 changes: 94 additions & 1 deletion docs/basics/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ hide_title: true
# Contract Debugging

There are three ways to debug your ink! contract currently:

* You can write tests using one of the mechanisms described on the
[Contract Testing](/basics/contract-testing) page.
* You can interact with your contract via a UI or command-line. This is
Expand All @@ -19,6 +20,7 @@ There are three ways to debug your ink! contract currently:
### How do I print to the terminal console from ink!?

You can use those two macros:

* [`ink::env::debug_println!`](https://docs.rs/ink_env/4.0.0/ink_env/macro.debug_println.html)
* [`ink::env::debug_print!`](https://docs.rs/ink_env/4.0.0/ink_env/macro.debug_print.html)

Expand All @@ -30,13 +32,15 @@ There are things you could do to enable debug messages on the client console:

1. __Set the log level of your node to `runtime::contracts=debug`.__<br/>
For example, to have only errors and debug output show up for the `substrate-contracts-node`:

```
substrate-contracts-node -lerror,runtime::contracts=debug
```

1. __Set the log level of your node to `runtime::contracts::strace` to trace host function calls.__<br/>
These function calls logs will also be displayed in the `Debug message` panel of [Contracts UI](https://github.com/paritytech/contracts-ui).
For example, to view these traces in addition to the logs described above:

```
substrate-contracts-node -lerror,runtime::contracts=debug,runtime::contracts::strace=trace
```
Expand All @@ -61,9 +65,98 @@ fn print(&self) {
}
```


:::note
Debug output is not printed for transactions!

It is only printed for RPC calls or off-chain tests.
:::

# Decode Data Payload

You can use a block explorer or an app like PolkadotJs to retrieve the data payload of a contract transaction, and then use [cargo-contract](https://github.com/paritytech/cargo-contract) to decode it.

```bash
# From your contract directory
cargo contract decode message -d fe5bd8ea01000000
```

This command will output the method name and parameters encoded in the data payload:

```
Decoded data: inc_by { n: 1 }
```

If the contract was called through a cross-contract interaction, the payload will not be available in the transaction. In such cases, you can use the approach described in the next section to access it.

# Replay and Debug a Block

To replay a transaction, you can use [Chopstick](https://github.com/AcalaNetwork/chopsticks) to create a local fork of the chain and replay the block with trace-level logging.

Assuming you have a node that you can connect to at `$ENDPOINT` and the transaction you want to replay is in block `$BLOCK_HASH`, you can use the following command:

```bash
npx @acala-network/chopsticks@latest run-block \
--endpoint $ENDPOINT \
--block $BLOCK_HASH \
--runtime-log-level 5 \
| grep runtime::contracts
```

This command replays the block with trace-level logging enabled. By filtering the output with `runtime::contracts`, you can view all the contract calls in the block:

```
runtime::contracts TRACE: call ExportedFunction::Call account: , input_data: [246, 118, 44, 201]
runtime::contracts TRACE: call ExportedFunction::Call account: , input_data: [254, 91, 216, 234, 1, 0, 0, 0]
runtime::contracts TRACE: call result ExecReturnValue { flags: (empty), data: [0] }
runtime::contracts TRACE: call result ExecReturnValue { flags: (empty), data: [0] }
```

From here, you can identify the call you are interested in and decode the data payload:

```bash
echo 254, 91, 216, 234, 1, 0, 0, 0 \
| tr ',' ' ' \
| xargs printf '%02x' \
| xargs cargo contract decode message -d
```

This command will output the following:

```
Decoded data: inc_by { n: 1 }
```

# Fork Node and Replay Transactions

You can also use [Chopstick](https://github.com/AcalaNetwork/chopsticks) to start a local fork of your chain.

This command starts a fork beginning at block `$BLOCK_HASH`. You can connect to this fork using `ws://localhost:8000` to submit extrinsics via PolkadotJs or `cargo contract`:

```bash
npx @acala-network/chopsticks@latest \
--endpoint $ENDPOINT \
--block $BLOCK_HASH \
--runtime-log-level 5
```

Here, for example, you can re-run the transaction that we decoded in the previous section:

```bash
cargo contract call \
--contract $CONTRACT_ADDR \
--message inc_by --args 1 \
--suri //Alice \
--url ws://localhost:8000
```

Since trace-level logging is used, you will receive detailed information about all the host functions called during the execution of the contract:

```
runtime::contracts TRACE: call ExportedFunction::Call account: , input_data: [254, 91, 216, 234, 2, 0, 0, 0]
runtime::contracts TRACE: call result ExecReturnValue { flags: (empty), data: [0] }
runtime::contracts DEBUG: Execution finished with debug buffer: seal0::value_transferred(out_ptr: 65488, out_len_ptr: 65516) = Ok(())
seal0::input(out_ptr: 65536, out_len_ptr: 65524) = Ok(())
seal1::get_storage(key_ptr: 65536, key_len: 4, out_ptr: 65540, out_len_ptr: 65524) = Ok(Success)
seal2::set_storage(key_ptr: 65536, key_len: 4, value_ptr: 65540, value_len: 4) = Ok(4)
seal0::seal_return(flags: 0, data_ptr: 65536, data_len: 1) = Err(TrapReason::Return(ReturnData { flags: 0, data: [0] }))
```

0 comments on commit bc789fa

Please sign in to comment.