1. Background
OKC is fully compatible with the deployment and execution of smart contracts. In some situations, developers need to debug contracts and trace the state of data.
2. Problem
In current, there is no function of tracing contract on OKC explorer whether in mainnet or testnet.
3. Solution
3.1 Description
To trace an transaction on OKC node and get accurate results as before, node needs the historic state of the transaction, block meta data and the state data of pointed block.
However, due to the pruning config in different node, there might be different result:
- the node with full archived data (pruning=nothing) could support any trace operation of any transaction
- the node with full pruned data (pruning=everyhing) could support any trace operation of those transaction which are mined before pruned.
- More pruning config could be referenced in https://forum.okt.club/d/193-pruning
3.2. Config & Usage
3.2.1 Enable trace
when node starts, add the following flag on command to enable debug api
--debug-api=true
3.2.2 Check trace information
3.3.2.1 Parameters
disableStack default is false, if set as true, there will be no context of Stack in log
disableStorage default is false, if set as true, there will be no context of Storage in log
disableMemory default is false, if set as true, there will be no context of Memory in log
disableReturnData default is false, if set as true, there will be no context of ReturnData in log
tracers default is empty, so there will be fully recorded with StructLogger
- Also, built-in scripts are supported, details are showed in the following link. https://github.com/ethereum/go-ethereum/tree/master/eth/tracers/js/internal/tracers
- Also, JavaScript is supported, grammar shows in the following link. https://geth.ethereum.org/docs/rpc/ns-debug#debug_tracetransaction
- If there is something in tracer field, ignore all disable configuration
3.3.2.2 Example
3.2.2.2.1. Config of disabled trace
Input:
$ curl -H "Content-Type: application/json" -d '{"id": 1, "method": "debug_traceTransaction", "params": ["0xfc9359e49278b7ba99f59edac0e3de49956e46e530a53c15aa71226b7aa92c6f", {"disableStack": true, "disableMemory": true, "disableStorage": true}]}' localhost:8545
Output:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"failed": false,
"gas": 21449,
"returnValue": "",
"structLogs": [
{
"depth": 1,
"gas": 42749,
"gasCost": 3,
"op": "PUSH1",
"pc": 0
},
{
"depth": 1,
"gas": 42746,
"gasCost": 3,
"op": "PUSH1",
"pc": 2
},
...
...
...
{
"depth": 1,
"gas": 21301,
"gasCost": 1,
"op": "JUMPDEST",
"pc": 154
},
{
"depth": 1,
"gas": 21300,
"gasCost": 0,
"op": "STOP",
"pc": 155
}
]
}
}
3.2.2.2.2 Built-in JS tracer files
Input :
curl -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0x585218efd4f452912f00878703984c58d2361e89618c9dd57586415756b6476f", {"tracer" : "unigramTracer"}],"id":1}' localhost:8545
Output:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"ADD": 3,
"CALLDATALOAD": 2,
"CALLDATASIZE": 2,
"CALLVALUE": 1,
"DUP1": 7,
"DUP2": 9,
"DUP3": 9,
"DUP4": 1,
"DUP5": 2,
"DUP6": 1,
"EQ": 4,
"GT": 1,
"ISZERO": 3,
"JUMP": 16,
"JUMPDEST": 21,
"JUMPI": 8,
"LT": 1,
"MSTORE": 1,
"POP": 24,
"PUSH1": 15,
"PUSH2": 24,
"PUSH32": 1,
"PUSH4": 3,
"SHR": 1,
"SLOAD": 1,
"SLT": 1,
"SSTORE": 1,
"STOP": 1,
"SUB": 3,
"SWAP1": 12,
"SWAP2": 10,
"SWAP3": 5
}
}
3.2.2.2.3 JavaScript-based tracing
input:
curl -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0x7E031D46C425A78F802E55058733699A341FF44E6778EEEFADD7BBD98F2A0DD6", {"tracer" : "{data: [], fault: function(log) {}, step: function(log) { if(log.op.toString() == \"SSTORE\") this.data.push(log.stack); }, result: function() { return this.data; }}"}],"id":1}' localhost:8545
output:
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"0",
"128",
"0",
"0",
"43576122634770472758325941782982599838796957244005075818703754470792663924736",
"154",
"4",
"0",
"0",
"4",
"1",
"1",
"0",
"0",
"1"
]
}
3.2.2.3 Error messages
1. tx (585218EFD4F452912F00878703984C58D2361E89618C9DD57586415756B6476E) not found
Comments: There is no transaction in the storage database
- check if the transaction has been executed already
- check if the running node is archived node (pruning=nothing)
- check if the running node using non-S3 snapshot when node started, and if the height of the transaction is included in snapshot.
2. tracer err : ReferenceError: identifier 'unig1ramTracer' undefined
Comments: The built-in script of unig1ramTracer doesn't exist.
- Only those scripts are supported: https://github.com/ethereum/go-ethereum/tree/master/eth/tracers/js/internal/tracers
3. tracer err : SyntaxError: parse error (line 1)
Comments: The grammar of script goes wrong
3.2.2.4 Attention
To call debug_traceTransaction api, there is non empty tracer field in vm.Config struct, so the node will use JavaScript-based Tracer as priority.