docs: fixup some things in the new tracing docs
This commit is contained in:
@ -3,10 +3,10 @@ title: Filtered Tracing
|
||||
sort_key: B
|
||||
---
|
||||
|
||||
In the previous section you learned how to create a complete trace. However, those traces can include the complete status of the EVM at every point
|
||||
In the previous section you learned how to create a complete trace. However, those traces can include the complete status of the EVM at every point
|
||||
in the execution, which is huge. Usually you are only interested in a small subset of this information. To get it, you can specify a JavaScript filter.
|
||||
|
||||
**Note:** The JavaScript package used by Geth is [Goja](https://github.com/dop251/goja), which is only up to the
|
||||
**Note:** The JavaScript interpreter used by Geth is [duktape](https://duktape.org), which is only up to the
|
||||
[ECMAScript 5.1 standard](https://262.ecma-international.org/5.1/). This means we cannot use [arrow functions](https://www.w3schools.com/js/js_arrow_function.asp)
|
||||
and [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals).
|
||||
|
||||
@ -16,14 +16,14 @@ and [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/
|
||||
1. Create a file, `filterTrace_1.js`, with this content:
|
||||
|
||||
```javascript
|
||||
|
||||
|
||||
tracer = function(tx) {
|
||||
return debug.traceTransaction(tx, {tracer:
|
||||
return debug.traceTransaction(tx, {tracer:
|
||||
'{' +
|
||||
'retVal: [],' +
|
||||
'step: function(log,db) {this.retVal.push(log.getPC() + ":" + log.op.toString())},' +
|
||||
'fault: function(log,db) {this.retVal.push("FAULT: " + JSON.stringify(log))},' +
|
||||
'result: function(ctx,db) {return this.retVal}' +
|
||||
'result: function(ctx,db) {return this.retVal}' +
|
||||
'}'
|
||||
}) // return debug.traceTransaction ...
|
||||
} // tracer = function ...
|
||||
@ -32,8 +32,8 @@ and [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/
|
||||
|
||||
We could specify this function directly in the JavaScript console, but it would be unwieldy and difficult
|
||||
to edit.
|
||||
|
||||
2. Run the [JavaScript console](https://geth.ethereum.org/docs/interface/javascript-console).
|
||||
|
||||
2. Run the [JavaScript console](https://geth.ethereum.org/docs/interface/javascript-console).
|
||||
3. Get the hash of a recent transaction. For example, if you use the Goerli network, you can get such a value
|
||||
[here](https://goerli.etherscan.io/).
|
||||
4. Run this command to run the script:
|
||||
@ -47,24 +47,24 @@ and [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/
|
||||
```javascript
|
||||
tracer("<hash of transaction>")
|
||||
```
|
||||
|
||||
|
||||
The bottom of the output looks similar to:
|
||||
```json
|
||||
"3366:POP", "3367:JUMP", "1355:JUMPDEST", "1356:PUSH1", "1358:MLOAD", "1359:DUP1", "1360:DUP3", "1361:ISZERO", "1362:ISZERO",
|
||||
"1363:ISZERO", "1364:ISZERO", "1365:DUP2", "1366:MSTORE", "1367:PUSH1", "1369:ADD", "1370:SWAP2", "1371:POP", "1372:POP", "1373:PUSH1",
|
||||
"3366:POP", "3367:JUMP", "1355:JUMPDEST", "1356:PUSH1", "1358:MLOAD", "1359:DUP1", "1360:DUP3", "1361:ISZERO", "1362:ISZERO",
|
||||
"1363:ISZERO", "1364:ISZERO", "1365:DUP2", "1366:MSTORE", "1367:PUSH1", "1369:ADD", "1370:SWAP2", "1371:POP", "1372:POP", "1373:PUSH1",
|
||||
"1375:MLOAD", "1376:DUP1", "1377:SWAP2", "1378:SUB", "1379:SWAP1", "1380:RETURN"]
|
||||
```
|
||||
|
||||
|
||||
6. This output isn't very readable. Run this line to get a more readable output with each string in its own line.
|
||||
|
||||
```javascript
|
||||
console.log(JSON.stringify(tracer("<hash of transaction>"), null, 2))
|
||||
```
|
||||
|
||||
You can read about the `JSON.stringify` function
|
||||
|
||||
You can read about the `JSON.stringify` function
|
||||
[here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). If we just
|
||||
return the output we get `\n` for newlines, which is why we need to use `console.log`.
|
||||
|
||||
|
||||
### How Does It Work?
|
||||
|
||||
We call the same `debug.traceTransaction` function we use for [basic traces](https://geth.ethereum.org/docs/dapp/tracing), but
|
||||
@ -137,10 +137,10 @@ The output looks similar to this:
|
||||
|
||||
## Stack Information
|
||||
|
||||
The trace above tells us the program counter (PC) and whether the program read from storage or wrote to it. That
|
||||
The trace above tells us the program counter (PC) and whether the program read from storage or wrote to it. That
|
||||
isn't very useful. To know more, you can use the `log.stack.peek` function to peek into the stack. `log.stack.peek(0)`
|
||||
is the stack top, `log.stack.peek(1)` the entry below it, etc. The values returned by `log.stack.peek` are
|
||||
Go `big.Int` objects. By default they are converted to JavaScript floating point numbers, so you need
|
||||
Go `big.Int` objects. By default they are converted to JavaScript floating point numbers, so you need
|
||||
`toString(16)` to get them as hexadecimals, which is how we normally represent 256-bit values such as
|
||||
storage cells and their content.
|
||||
|
||||
@ -184,13 +184,13 @@ you a more complete picture of the program's interaction with storage. The outpu
|
||||
|
||||
## Operation Results
|
||||
|
||||
One piece of information missing from the function above is the result on an `SLOAD` operation. The
|
||||
One piece of information missing from the function above is the result on an `SLOAD` operation. The
|
||||
state we get inside `log` is the state prior to the execution of the opcode, so that value is not
|
||||
known yet. For more operations we can figure it out for ourselves, but we don't have access to the
|
||||
storage, so here we can't.
|
||||
|
||||
The solution is to have a flag, `afterSload`, which is only true in the opcode right after an
|
||||
`SLOAD`, when we can see the result at the top of the stack.
|
||||
The solution is to have a flag, `afterSload`, which is only true in the opcode right after an
|
||||
`SLOAD`, when we can see the result at the top of the stack.
|
||||
|
||||
```javascript
|
||||
tracer = function(tx) {
|
||||
@ -243,10 +243,10 @@ line itself, but that would have been a bit more work.
|
||||
|
||||
## Dealing With Calls Between Contracts
|
||||
|
||||
So far we have treated the storage as if there are only 2^256 cells. However, that is not true. Contracts
|
||||
can call other contracts, and then the storage involved is the storage of the other contract. We can see
|
||||
the address of the current contract in `log.contract.getAddress()`. This value is the execution context,
|
||||
the contract whose storage we are using, even when we use code from another contract (by using
|
||||
So far we have treated the storage as if there are only 2^256 cells. However, that is not true. Contracts
|
||||
can call other contracts, and then the storage involved is the storage of the other contract. We can see
|
||||
the address of the current contract in `log.contract.getAddress()`. This value is the execution context,
|
||||
the contract whose storage we are using, even when we use code from another contract (by using
|
||||
`CALLCODE` or `DELEGATECODE`).
|
||||
|
||||
However, `log.contract.getAddress()` returns an array of bytes. We use `this.byteHex()` and `array2Hex()`
|
||||
@ -276,7 +276,7 @@ tracer = function(tx) {
|
||||
'getAddr: function(log) {' +
|
||||
' return this.array2Hex(log.contract.getAddress());' +
|
||||
'}, ' +
|
||||
|
||||
|
||||
'step: function(log,db) {' +
|
||||
' var opcode = log.op.toNumber();' +
|
||||
|
||||
@ -294,7 +294,7 @@ tracer = function(tx) {
|
||||
' log.stack.peek(0).toString(16)); ' +
|
||||
' this.afterSload = false; ' +
|
||||
' } ' +
|
||||
|
||||
|
||||
// SSTORE
|
||||
' if (opcode == 0x55) ' +
|
||||
' this.retVal.push(log.getPC() + ": SSTORE " +' +
|
||||
@ -310,7 +310,7 @@ tracer = function(tx) {
|
||||
'result: function(ctx,db) {return this.retVal}' +
|
||||
'}'
|
||||
}) // return debug.traceTransaction ...
|
||||
} // tracer = function ...
|
||||
} // tracer = function ...
|
||||
```
|
||||
|
||||
The output is similar to:
|
||||
@ -331,7 +331,7 @@ The output is similar to:
|
||||
"13529: SLOAD f2d68898557ccb2cf4c10c3ef2b034b2a69dad00:b38558064d8dd9c883d2a8c80c604667ddb90a324bc70b1bac4e70d90b148ed4",
|
||||
" Result: b38558064d8dd9c883d2a8c80c604667ddb90a324bc70b1bac4e70d90b148ed4",
|
||||
"11041: SSTORE 22ff293e14f1ec3a09b137e9e06084afd63addf9:6 <- 0"
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
@ -341,5 +341,3 @@ or how to use the `db` parameter to know the state of the chain at the time of e
|
||||
covered [in the reference](https://geth.ethereum.org/docs/rpc/ns-debug#javascript-based-tracing).
|
||||
|
||||
Hopefully with this tool you will find it easier to trace the EVM's behavior and debug thorny contract issues.
|
||||
|
||||
Original version by [Ori Pomerantz](qbzzt1@gmail.com)
|
||||
|
Reference in New Issue
Block a user