Transaction tracing enables a deeper look into smart contract inner calls and account creation calls. It is inspired by the OpenEthereum (Parity) node trace module, which is used in a lot of projects.
For now, the following JSON-RPC methods are implemented:
Currently, it is deployed on these endpoints for the Opera mainnet and testnet:
Because of stored traces, a tracing node requires slightly bigger storage (around a quarter more). For more information, please follow the README.md file in the txtracing branch.
You can check out and build the tx tracing release version from the .
It's recommended to launch a new node from scratch with the CLI option --tracenode
as this flag has to be set to use stored transaction traces.
Enable JSON-RPC API with the option trace
:
A complete example command:
For the first start of the node, you have to specify the genesis file, which defines the blockchain and contains its history.
Transaction traces are created on the node while processing transactions and then stored in a node database. You can export these traces and import them on other nodes.
This addition allows for responses to certain changes that may alter the trace content without requiring a complete resynchronization of the blockchain.
Another method is to delete traces, which will be recreated upon the next request to them from the RPC API. However, this approach is not recommended because recreating traces this way is slower when the first request targets a non-existent transaction trace.
All these operations must be performed while the node is stopped, as they involve modifying data in the core database. For both export and delete operations, you can specify a block range to limit the number of processed transaction traces.
The command for exporting is export txtraces <filename.gz> <from block> <to block>
:
For importing, it's:
No file needs to be specified when using the delete option. delete txtraces <from block> <to block>
This section provides information on migrating a transaction tracing API node to a newer version of go-opera. It will indicate whether a full node resynchronization is required due to stored transaction traces or if only a code update is necessary to upgrade from the previous version.
release/txtracing/1.1.2-rc.2 — don't use this version
When using version 1.1.2, you need to add the db.preset argument for the starting Opera command. You can view the available options for this parameter with the opera help command. For standard conditions, please use the following option:
db.preset=ldb-1
Returns traces created at the given block.
Quantity
or Tag
— Integer of a block number, or the string 'earliest'
, 'latest'
, or 'pending'
.
Array
— Block traces.
Request:
Response:
Returns all traces of the given transaction.
Hash
— Transaction hash
Array
— Traces of given transaction
Request:
Returns traces matching the given filter.
Object
— The filter object
fromBlock
: Quantity
or Tag
— (optional) From this block.
toBlock
: Quantity
or Tag
— (optional) To this block.
fromAddress
: Array
— (optional) Sent from these addresses.
toAddress
: Address
— (optional) Sent to these addresses.
after
: Quantity
— (optional) The offset trace number
count
: Quantity
— (optional) Integer number of traces to display in a batch.
Array
— Traces matching the given filter.
Request:
Returns trace at given position.
Hash
— Transaction hash.
Array
— Index positions of the traces.
Object
— Trace object
Request:
The method returns a full stack trace of all invoked opcodes of all transaction that were included in a block identified by a block number. The parent of this block must be present or it will fail.
Number
- Block number to be traced.
Object
- (optional) Options for the trace.
tracer
: String
- (optional) Setting this will enable JavaScript-based transaction tracing, described below.
Array
- A trace object per transaction inside the block.
This method returns a full stack trace of all invoked opcodes of all transactions that were included in a block identified by a hash. The parent of this block must be present or it will fail.
Hash
— Hash of the block to be traced.
Object
— (optional) Options for the trace.
tracer
: String
— (optional) Setting this will enable JavaScript-based transaction tracing, described below.
Array
— A trace object per transaction inside the block.
This method will try to run the transaction in the same way it was executed on the network. It will replay any transactions that occurred before it in the block and then attempt to execute the transaction corresponding to the given hash.
Hash
— Hash of the transaction to be traced.
Object
— (optional) Options for the trace.
tracer
: String
— (optional) Setting this will enable JavaScript-based transaction tracing, described below.
Object
— A trace object of the traced transaction.
Specifying the tracer
option in the second argument of the debug tracing calls enables JavaScript-based tracing. In this mode, tracer
is interpreted as a JavaScript expression that is expected to evaluate an object which must expose the result
and fault
methods. There exists 4 additional methods, namely: setup
, step
, enter
, and exit
. enter
and exit
must be present or omitted together.
Method setup
is invoked once, in the beginning when the tracer is being constructed for each transaction being traced. It takes in one argument, config
, which allows users to pass in options to the tracer. config
is to be JSON-decoded for usage and its default value is "{}"
.
Method step
is a function that takes two arguments, log
and db
, and is called for each step of the EVM, or when an error occurs, as a transaction is traced.
log
has the following fields:
op
: Object, an OpCode object representing the current opcode
stack
: Object, a structure representing the EVM execution stack
memory
: Object, a structure representing the contract’s memory space
contract
: Object, an object representing the account executing the current operation
And the following methods:
getPC()
— returns a number with the current program counter
getGas()
— returns a number with the amount of gas remaining
getCost()
— returns the cost of the opcode as a number
getDepth()
— returns the execution depth as a number
getRefund()
— returns the amount to be refunded as a number
getError()
— returns information about the error if one occurred, otherwise returns undefined
If an error is non-empty, all other fields should be ignored.
For efficiency, the same log
object is reused on each execution step, updated with current values; make sure to copy values you want to preserve beyond the current call.
log.op
has the following methods:
isPush()
— returns true if the opcode is a PUSHn
toString()
— returns the string representation of the opcode
toNumber()
— returns the opcode’s number
log.memory
has the following methods:
slice(start, stop)
— returns the specified segment of memory as a byte slice
getUint(offset)
— returns the 32 bytes at the given offset
length()
— returns the memory size
log.stack
has the following methods:
peek(idx)
— returns the idx-th element from the top of the stack (0 is the topmost element) as a big.Int
length()
— returns the number of elements in the stack
log.contract
has the following methods:
getCaller()
— returns the address of the caller
getAddress()
— returns the address of the current contract
getValue()
— returns the amount of value sent from caller to contract as a big.Int
getInput()
— returns the input data passed to the contract
db
has the following methods:
getBalance(address)
— returns a big.Int
with the specified account’s balance
getNonce(address)
— returns a Number with the specified account’s nonce
getCode(address)
— returns a byte slice with the code for the specified account
getState(address, hash)
— returns the state value for the specified account and the specified hash
exists(address)
— returns true if the specified address exists
If the step function throws an exception or executes an illegal operation at any point, it will not be called on any further VM steps, and the error will be returned to the caller.
Method result
is a function that takes two arguments, ctx
and db
, and is expected to return a JSON-serializable value to return to the RPC caller.
ctx
is the context in which the transaction is executed and has the following fields:
type
— String, one of the two values, CALL
and CREATE
from
— Address, sender of the transaction
to
— Address, target of the transaction
input
— Buffer, input transaction data
gas
— Number, gas budget of the transaction
gasUsed
- Number, amount of gas used in executing the transaction (excludes txdata costs)
gasPrice
— Number, gas price configured in the transaction being executed
intrinsicGas
— Number, intrinsic gas for the transaction being executed
value
— big.Int, amount to be transferred in wei
block
— Number, block number
output
— Buffer, value returned from EVM
time
— String, execution runtime
Method fault
is a function that takes two arguments, log
and db
, just like step
, and is invoked when an error happens during the execution of an opcode which wasn’t reported in step
. The method log.getError()
has information about the error.
Methods enter
and exit
are respectively invoked on stepping in and out of an internal call. More specifically, they are invoked on the CALL
variants, CREATE
variants, and also for the transfer implied by a SELFDESTRUCT
.
enter
takes a callFrame
object as argument which has the following methods:
getType()
— returns a string which has the type of the call frame
getFrom()
— returns the address of the call frame sender
getTo()
— returns the address of the call frame target
getInput()
— returns the input as a buffer
getGas()
— returns a number that has the amount of gas provided for the frame
getValue()
— returns a big.Int
with the amount to be transferred only if available, otherwise undefined
exit
takes in a frameResult
object which has the following methods:
getGasUsed()
— returns amount of gas used throughout the frame as a Number
getOutput()
— returns the output as a buffer
getError()
— returns an error if one occurred during execution and undefined otherwise
Please select a with a full history ("full-mpt" in the filename) if you need transaction traces for historical states. It's recommended to use the following genesis file, , for a full-history tracing node.
— no resync from 1.1.1-rc.2, just update
— resync from all previous versions and see notes below
timeout
: String
- (optional) Overrides the default timeout of 5 seconds for JavaScript-based tracing calls. Check documentation for for valid values.
timeout
: String
— (optional) Overrides the default timeout of 5 seconds for JavaScript-based tracing calls. Check documentation for for valid values.
timeout
: String
— (optional) Overrides the default timeout of 5 seconds for JavaScript-based tracing calls. Check documentation for for valid values.