Learn what the trace_transaction method is, how to use it on EVM blockchains, and test an example use case.
Prerequisites
Before reading this article you should have a clear understanding of EVM Traces.
What is trace_transaction
?
trace_transaction
?trace_transaction
is an RPC method exposed by the Openethereum and Erigon Ethereum clients. You can get the EVM traces of a previously executed transaction using this method. This can be useful for debugging purposes, or for understanding how a transaction works.
Parameters
This method only takes one parameter which is the transaction hash of the transaction whose traces you wish to get:
Hash
- Transaction hash
params: ["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3"]
Response
This method returns the traces of the given transaction as a response:
array
- Traces of the given transaction
How to use trace_transaction
To use the trace_transaction method sign up for Alchemy on the Growth tier, or upgrade your account.
You can call the trace_transaction method by providing the transaction hash of the transaction you wish to trace. You can find this by looking up the transaction on a block explorer. Once you have the transaction hash, you can call the "trace_transaction" method with it as follows:
Request
curl https://eth-mainnet.g.alchemy.com/v2/your-api-key \
-X POST \
-H "Content-Type: application/json" \
-d '{"method":"trace_transaction","params":["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3"],"id":1,"jsonrpc":"2.0"}'
URL: https://eth-mainnet.g.alchemy.com/v2/your-api-key
RequestType: POST
Body:
{
"jsonrpc":"2.0",
"method":"trace_transaction",
"params":["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3"],
"id":1
}
const ethers = require("ethers");
(async () => {
const provider = new ethers.providers.JsonRpcProvider("https://eth-mainnet.g.alchemy.com/v2/your-api-key");
const transaction = await provider.send("trace_transaction", [
"0x3277c743c14e482243862c03a70e83ccb52e25cb9e54378b20a8303f15cb985d",
]);
console.log(transaction);
})();
from web3 import HTTPProvider
client = HTTPProvider('https://eth-mainnet.g.alchemy.com/v2/your-api-key/')
result = client.make_request("trace_transaction", ["0x3277c743c14e482243862c03a70e83ccb52e25cb9e54378b20a8303f15cb985d"])
print(result)
Response
{
"jsonrpc": "2.0",
"result": [
{
"action": {
"callType": "call",
"from": "0x83806d539d4ea1c140489a06660319c9a303f874",
"gas": "0x1a1f8",
"input": "0x",
"to": "0x1c39ba39e4735cb65978d4db400ddd70a72dc750",
"value": "0x7a16c911b4d00000"
},
"blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add",
"blockNumber": 3068185,
"result": {
"gasUsed": "0x2982",
"output": "0x"
},
"subtraces": 2,
"traceAddress": [],
"transactionHash": "0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3",
"transactionPosition": 2,
"type": "call"
},
{
"action": {
"callType": "call",
"from": "0x1c39ba39e4735cb65978d4db400ddd70a72dc750",
"gas": "0x13e99",
"input": "0x16c72721",
"to": "0x2bd2326c993dfaef84f696526064ff22eba5b362",
"value": "0x0"
},
"blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add",
"blockNumber": 3068185,
"result": {
"gasUsed": "0x183",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
"subtraces": 0,
"traceAddress": [
0
],
"transactionHash": "0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3",
"transactionPosition": 2,
"type": "call"
},
{
"action": {
"callType": "call",
"from": "0x1c39ba39e4735cb65978d4db400ddd70a72dc750",
"gas": "0x8fc",
"input": "0x",
"to": "0x70faa28a6b8d6829a4b1e649d26ec9a2a39ba413",
"value": "0x7a16c911b4d00000"
},
"blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add",
"blockNumber": 3068185,
"result": {
"gasUsed": "0x0",
"output": "0x"
},
"subtraces": 0,
"traceAddress": [
1
],
"transactionHash": "0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3",
"transactionPosition": 2,
"type": "call"
}
],
"id": 0
}
Here is the link to the transaction on Etherscan whose EVM trace is given above in the Response.
Use Cases
Understanding/Debugging a transaction
You can get the whole trace tree for a transaction and analyze what exactly happened during the transaction execution. The trace tree also returns the gas used for each action, the output values, and the revert reason (if the transaction failed). For example, in the trace image below you can see that the transaction failed due to an "Out of gas" exception, which means that there was not enough gas to complete the transaction.
Here is the link to the above-defined transaction on Etherscan.
Transaction Tracers
As you can get the traces for a previously executed transaction using trace_call
, you can build transaction tracers like txs.fyi using it. Transaction tracers help us better understand the flow of a transaction. They extract the EVM traces for a transaction and display them in a way that’s readable by us. For example here is the result for a USDT transfer transaction on txs.fyi.
As you can see it’s clear from the execution trace that the caller called the transfer function of the TetherToken contract and the contract transferred 285 USDT from the caller to the target address.
Contract Performance Analysis
Transaction traces can be used to analyze the performance of smart contracts by looking at the number of actions it takes for each transaction to be processed. This information can be used to identify bottlenecks and optimize the contract for better performance.
Conclusion
In conclusion, the trace_transaction
method is a valuable tool for debugging transactions. It provides a step-by-step record of the execution of a transaction and can be used to identify errors and optimize code.