GitHub Logo HIP-801: Add support for debug_traceTransaction RPC API

Author Ivan Kavaldzhiev, Stoyan Panayotov
Working Group Steven Sheehy, Nana Essilfie-Conduah, Danno Ferrin, David Bakin, Georgi Lazarov
Discussions-To https://github.com/hashgraph/hedera-improvement-proposal/discussions/802
Status Accepted
Needs Council Approval No
Review period ends Wed, 10 Jan 2024 07:00:00 +0000
Type Standards Track
Category Service
Created 2023-08-31
Updated 2024-01-24

Abstract

This HIP describes the mechanism of adding initial support for handling DEBUG requests for historical EVM transaction to the JSON-RPC Relay and the Hedera Mirror Node.

Motivation

Ethereum nodes can be configured to enable support for debugging historical transactions and thus producing a detailed output log with information related to the transaction execution. Hedera’s current architecture does not support this functionality.

Ongoing efforts to achieve Ethereum equivalence require Hedera to enable debugging of historical EVM transactions. This enhancement would improve Hedera’s interoperability with different Ethereum tools and providers, including Remix, Hardhat, Ganache, Geth, Alchemy, etc.

Rationale

Hedera’s architecture consists of three types of nodes:

  • JSON-RPC Relay nodes expose a JSON-RPC API similar to the one that Ethereum nodes use. The Relay handles user requests by either forwarding them to a Consensus or Mirror node.
  • Consensus nodes execute transactions, produce transaction records, and maintain the world state.
  • Mirror nodes ingest the record files produced by the consensus nodes, maintain a “mirror” of the world state, and provide an API for queries and simulations which can work with the current, or a historical state.

Enhancing the JSON-RPC Relay and the Mirror Archive Node with debug APIs will allow users to replay historical transactions and inspect and analyse them by having detailed information for the execution based on a tracer type that is specified in the request.

Add support of debug_traceTransaction in the JSON-RPC Relay which returns detailed information for a historical transaction that was executed in the past.

The JSON-RPC Relay will in turn make a request to the Mirror Node REST API which will be enhanced with a new endpoint that returns opcode logs. The Mirror node already has an endpoint that returns call traces.

User stories

  1. As a user, I want to perform debug_traceTransaction calls to explore the op code traces for a historical transaction.
  2. As a user, I want to perform debug_traceTransaction calls to explore the sub calls that were executed for a historical transaction.

Specification

In order to enable trace calls, we should meet some requirements on the Mirror Archive Node side:

  • Support EVM versioning, so that we use the appropriate EVM version for a specific historical block.
  • Use full mirror node, keeping state from the genesis block and configured with enabled ingest of CONTRACT_BYTECODE , CONTRACT_STATE_CHANGE and CONTRACT_ACTION sidecar types.
  • Re-execute historical transactions using the information for state values read from the downloaded CONTRACT_STATE_CHANGE sidecar record files.

JSON-RPC Relay Trace API

The JSON-RPC Relay will be enhanced with a debug_traceTransaction endpoint. The endpoint has one required parameter - transactionHash - and also accepts a list of properties - a tracer, and a list of configuration flags.

Example payload for callTracer type:

{
	"jsonrpc": "2.0",
	"method": "debug_traceTransaction",
	"params": [
        // The transaction hash.
	  "0x123...", 
	  { 
	   tracer: "callTracer" 
	  }
	],
	"id": 0
}

Output: detailed information for the transaction execution with list of actions

Example output:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "type": "CALL",
    "from": "0x5067c042e35881843f2b31dfc2db1f4f272ef48c",
    "to": "0x3ee18b2214aff97000d974cf647e7c347e8fa585",
    "value": "0x0",
    "gas": "0x17459",
    "gasUsed": "0x166cb",
    "input": "0x0f5287b0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000001debea42000000000000000000000000000000000000000000000000000000000000000167c46aa713cfe47608dd1c16f8a0325208df084c3cbebf9f366ad0eafc2653e400000000000000000000000000000000000000000000000000000000001e8542000000000000000000000000000000000000000000000000000000006eca0000",
    "output": "0x000000000000000000000000000000000000000000000000000000000001371e",
    "calls": [
      {
        "type": "DELEGATECALL",
        "from": "0x3ee18b2214aff97000d974cf647e7c347e8fa585",
        "to": "0x76364611e457b1f97cd58ffc332ddc7561a193f6",
        "gas": "0x15bc0",
        "gasUsed": "0x1538e",
        "input": "0x0f5287b0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000001debea42000000000000000000000000000000000000000000000000000000000000000167c46aa713cfe47608dd1c16f8a0325208df084c3cbebf9f366ad0eafc2653e400000000000000000000000000000000000000000000000000000000001e8542000000000000000000000000000000000000000000000000000000006eca0000",
        "output": "0x000000000000000000000000000000000000000000000000000000000001371e",
        "calls": [
          {
            "type": "STATICCALL",
            "from": "0x3ee18b2214aff97000d974cf647e7c347e8fa585",
            "to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
            "gas": "0x123bb",
            "gasUsed": "0x25c0",
            "input": "0x313ce567",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000006",
            "calls": [
              {
                "type": "DELEGATECALL",
                "from": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                "to": "0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf",
                "gas": "0x10357",
                "gasUsed": "0x94d",
                "input": "0x313ce567",
                "output": "0x0000000000000000000000000000000000000000000000000000000000000006"
              }
            ]
          },
          {
            "type": "STATICCALL",
            "from": "0x3ee18b2214aff97000d974cf647e7c347e8fa585",
            "to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
            "gas": "0xf9d6",
            "gasUsed": "0xcf3",
            "input": "0x70a082310000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585",
            "output": "0x00000000000000000000000000000000000000000000000000001691e551e115",
            "calls": [
              {
                "type": "DELEGATECALL",
                "from": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                "to": "0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf",
                "gas": "0xf315",
                "gasUsed": "0x9e1",
                "input": "0x70a082310000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585",
                "output": "0x00000000000000000000000000000000000000000000000000001691e551e115"
              }
            ]
          },
          {
            "type": "CALL",
            "from": "0x3ee18b2214aff97000d974cf647e7c347e8fa585",
            "to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
            "value": "0x0",
            "gas": "0xe796",
            "gasUsed": "0x5f48",
            "input": "0x23b872dd0000000000000000000000005067c042e35881843f2b31dfc2db1f4f272ef48c0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000000000000000000000000000000000000000000000000001debea42",
            "output": "0x0000000000000000000000000000000000000000000000000000000000000001",
            "calls": [
              {
                "type": "DELEGATECALL",
                "from": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                "to": "0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf",
                "gas": "0xe115",
                "gasUsed": "0x5c2d",
                "input": "0x23b872dd0000000000000000000000005067c042e35881843f2b31dfc2db1f4f272ef48c0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585000000000000000000000000000000000000000000000000000000001debea42",
                "output": "0x0000000000000000000000000000000000000000000000000000000000000001"
              }
            ]
          },
          {
            "type": "STATICCALL",
            "from": "0x3ee18b2214aff97000d974cf647e7c347e8fa585",
            "to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
            "gas": "0x857c",
            "gasUsed": "0x523",
            "input": "0x70a082310000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585",
            "output": "0x00000000000000000000000000000000000000000000000000001692033dcb57",
            "calls": [
              {
                "type": "DELEGATECALL",
                "from": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
                "to": "0xa2327a938febf5fec13bacfb16ae10ecbc4cbdcf",
                "gas": "0x808c",
                "gasUsed": "0x211",
                "input": "0x70a082310000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585",
                "output": "0x00000000000000000000000000000000000000000000000000001692033dcb57"
              }
            ]
          },
          {
            "type": "CALL",
            "from": "0x3ee18b2214aff97000d974cf647e7c347e8fa585",
            "to": "0x98f3c9e6e3face36baad05fe09d375ef1464288b",
            "value": "0x0",
            "gas": "0x4f9f",
            "gasUsed": "0x46c6",
            "input": "0xb19a437e000000000000000000000000000000000000000000000000000000006eca00000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000008501000000000000000000000000000000000000000000000000000000001debea42000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000267c46aa713cfe47608dd1c16f8a0325208df084c3cbebf9f366ad0eafc2653e4000100000000000000000000000000000000000000000000000000000000001e8542000000000000000000000000000000000000000000000000000000",
            "output": "0x000000000000000000000000000000000000000000000000000000000001371e",
            "calls": [
              {
                "type": "DELEGATECALL",
                "from": "0x98f3c9e6e3face36baad05fe09d375ef1464288b",
                "to": "0x8c0041566e0bc27efe285a9e98d0b4217a46809c",
                "gas": "0x3b88",
                "gasUsed": "0x3377",
                "input": "0xb19a437e000000000000000000000000000000000000000000000000000000006eca00000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000008501000000000000000000000000000000000000000000000000000000001debea42000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000267c46aa713cfe47608dd1c16f8a0325208df084c3cbebf9f366ad0eafc2653e4000100000000000000000000000000000000000000000000000000000000001e8542000000000000000000000000000000000000000000000000000000",
                "output": "0x000000000000000000000000000000000000000000000000000000000001371e"
              }
            ]
          }
        ]
      }
    ]
  }
}

Example payload for a transaction execution with opcodeLogger and disableMemory, disableStack and disableStorage flags not set (default values of false):

{
	"jsonrpc": "2.0",
	"method": "debug_traceTransaction",
	"params": [
        // The transaction hash.
	  "0x123...", 
	  { 
	   tracer: "opcodeLogger" 
	  }
	],
	"id": 0
}

Output for the detailed transaction execution with memory, stack and storage information

Example output:

{
    "jsonrpc": "2.0",
    "id": 0,
    "result": {
        "gas": 52139,
        "failed": false,
        "returnValue": "0000000000000000000000000000000000000000000000000000000000000001",
        "structLogs": [
            {
                "pc": 542,
                "op": "SWAP2",
                "gas": 4419,
                "gasCost": 3,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 543,
                "op": "POP",
                "gas": 4416,
                "gasCost": 2,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000000"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 544,
                "op": "PUSH1",
                "gas": 4414,
                "gasCost": 3,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 546,
                "op": "SLOAD",
                "gas": 4411,
                "gasCost": 2100,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000001"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 547,
                "op": "SWAP2",
                "gas": 2311,
                "gasCost": 3,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000000"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 548,
                "op": "POP",
                "gas": 2308,
                "gasCost": 2,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            }
	    ]
    }
}

Example payload for a transaction execution with opcodeLogger and disableMemory set to true:

{
	"jsonrpc": "2.0",
	"method": "debug_traceTransaction",
	"params": [
        // The transaction hash.
	  "0x123...", 
	  { 
	   tracer: "opcodeLogger",
	   disableMemory: true
	  }
	],
	"id": 0
}

Output: detailed information for the transaction execution without memory information

Example output:

{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "gas": 24116,
        "failed": false,
        "returnValue": "",
        "structLogs": [
             {
                "pc": 538,
                "op": "SSTORE",
                "gas": 4622,
                "gasCost": 100,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000000"
                ],
                "memory": null,
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 539,
                "op": "PUSH1",
                "gas": 4522,
                "gasCost": 3,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000014"
                ],
                "memory": null,
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 541,
                "op": "SLOAD",
                "gas": 4519,
                "gasCost": 100,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000000"
                ],
                "memory": null,
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            }
        ]
    }
}           

Example payload for a transaction execution with opcodeLogger and disableStack flag set to true

{
	"jsonrpc": "2.0",
	"method": "debug_traceTransaction",
	"params": [
        // The transaction hash.
	  "0x123...", 
	  { 
	   tracer: "opcodeLogger",
	   disableStack: true
	  }
	],
	"id": 0
}

Output: detailed information for the transaction execution without stack information

Example output:

{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "gas": 24116,
        "failed": false,
        "returnValue": "",
        "structLogs": [
            {
                "pc": 541,
                "op": "SLOAD",
                "gas": 4519,
                "gasCost": 100,
                "depth": 1,
                "stack": null,
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 542,
                "op": "SWAP2",
                "gas": 4419,
                "gasCost": 3,
                "depth": 1,
                "stack": null,
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 543,
                "op": "POP",
                "gas": 4416,
                "gasCost": 2,
                "depth": 1,
                "stack": null,
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 544,
                "op": "PUSH1",
                "gas": 4414,
                "gasCost": 3,
                "depth": 1,
                "stack": null,
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 546,
                "op": "SLOAD",
                "gas": 4411,
                "gasCost": 2100,
                "depth": 1,
                "stack": null,
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            }
        ] 
    }
}           

Example payload for a transaction execution with opcodeLogger and disableStorage flag set to true

{
	"jsonrpc": "2.0",
	"method": "debug_traceTransaction",
	"params": [
        // The transaction hash.
	  "0x123...", 
	  { 
	   tracer: "opcodeLogger",
	   disableStorage: true
	  }
	],
	"id": 0
}

Output: detailed information for the transaction execution without storage information

Example output:

{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "gas": 24116,
        "failed": false,
        "returnValue": "",
        "structLogs": [
            {
                "pc": 546,
                "op": "SLOAD",
                "gas": 4411,
                "gasCost": 2100,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000001"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": null,
                "reason": null
            },
            {
                "pc": 547,
                "op": "SWAP2",
                "gas": 2311,
                "gasCost": 3,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000000"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": null,
                "reason": null
            },
            {
                "pc": 548,
                "op": "POP",
                "gas": 2308,
                "gasCost": 2,
                "depth": 1,
                "stack": [
                    "00000000000000000000000000000000000000000000000000000000094f6253",
                    "00000000000000000000000000000000000000000000000000000000000000a5",
                    "0000000000000000000000008fa74f0a79112c8c46c8e6739eb8cc929083298c",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000014",
                    "0000000000000000000000000000000000000000000000000000000000000014"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": null,
                "reason": null
            }
        ]
    }
}           

Mirror node Trace REST API

The JSON-RPC Relay will in turn call the Mirror Node REST API. Depending on the tracer that was provided as an input parameter to the debug_traceTransaction RPC endpoint, one of two Mirror node endpoints will be called:

  1. For debug_traceTransaction called with callTracer, the Mirror Node /api/v1/contracts/results/{transactionIdOrHash}/actions endpoint will be called.
  2. For debug_traceTransaction called with opcodeLogger, the Mirror Node /api/v1/contracts/results/{transactionIdOrHash}/opcodes endpoint will be called.

The /actions endpoint is already implemented.

This section will specify the /opcodes endpoint.

/api/v1/contracts/results/{transactionIdOrHash}/opcodes

Input parameters: The endpoint will accept three optional parameters:

// Boolean flag controlling whether to return stack information. Defaults to `true`.

stack: <bool> 

// Boolean flag controlling whether to return memory information. Defaults to `false`.

memory: <bool> 

// Boolean flag controlling whether to return storage information. Defaults to `false`.

storage: <bool>

Disabling stack, memory and storage traces will significantly reduce the size of the opcode related data. This would be helpful for reducing the network bandwidth.

Output: detailed information for the transaction execution with stack, memory and storage set to true Example output:

{
    "address": "0x8fa74f0a79112c8c46c8e6739eb8cc929083298c",
    "contract_id": "0.0.1054",
    "gas": 52139,
    "failed": false,
    "return_value": "0x0000000000000000000000000000000000000000000000000000000000000001",
    "opcodes": [
        {
                "pc": 1273,
                "op": "PUSH1",
                "gas": 2731,
                "gas_cost": 3,
                "depth": 2,
                "stack": [
                    "000000000000000000000000000000000000000000000000000000004700d305",
                    "00000000000000000000000000000000000000000000000000000000000000a7",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "000000000000000000000000000000000000000000000000000000000000016c",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000004",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000521",
                    "0000000000000000000000000000000000000000000000000000000000000024"
                ],
                "memory": [
                    "4e487b7100000000000000000000000000000000000000000000000000000000",
                    "0000001200000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {},
                "reason": null
            },
            {
                "pc": 1275,
                "op": "REVERT",
                "gas": 2728,
                "gas_cost": 0,
                "depth": 2,
                "stack": [
                    "000000000000000000000000000000000000000000000000000000004700d305",
                    "00000000000000000000000000000000000000000000000000000000000000a7",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "000000000000000000000000000000000000000000000000000000000000016c",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000004",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000521",
                    "0000000000000000000000000000000000000000000000000000000000000024",
                    "0000000000000000000000000000000000000000000000000000000000000000"
                ],
                "memory": [
                    "4e487b7100000000000000000000000000000000000000000000000000000000",
                    "0000001200000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {},
                "reason": "0x4e487b710000000000000000000000000000000000000000000000000000000000000012"
            },
            {
                "pc": 682,
                "op": "SWAP3",
                "gas": 2776,
                "gas_cost": 3,
                "depth": 1,
                "stack": [
                    "000000000000000000000000000000000000000000000000000000000135b7d0",
                    "00000000000000000000000000000000000000000000000000000000000000a0",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "00000000000000000000000096769c2405eab9fdc59b25b178041e517ddc0f32",
                    "000000000000000000000000000000000000000000000000000000004700d305",
                    "0000000000000000000000000000000000000000000000000000000000000084",
                    "0000000000000000000000000000000000000000000000000000000000000000"
                ],
                "memory": [
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "0000000000000000000000000000000000000000000000000000000000000080",
                    "0000000000000000000000000000000000000000000000000000000000000000",
                    "4e487b7100000000000000000000000000000000000000000000000000000000"
                ],
                "storage": {},
                "reason": null
            }
    ]
}    

Output: detailed information for the transaction execution with stack set to false Example output:

{
        "address": "0x8fa74f0a79112c8c46c8e6739eb8cc929083298c",
        "contract_id": "0.0.1059",
        "gas": 24116,
        "failed": false,
        "return_value": "",
        "opcodes": [
            {
                "pc": 541,
                "op": "SLOAD",
                "gas": 4519,
                "gas_cost": 100,
                "depth": 1,
                "stack": [],
                "memory": [
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 542,
                "op": "SWAP2",
                "gas": 4419,
                "gas_cost": 3,
                "depth": 1,
                "stack": [],
                "memory": [
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 543,
                "op": "POP",
                "gas": 4416,
                "gas_cost": 2,
                "depth": 1,
                "stack": [],
                "memory": [
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 544,
                "op": "PUSH1",
                "gas": 4414,
                "gas_cost": 3,
                "depth": 1,
                "stack": [],
                "memory": [
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            },
            {
                "pc": 546,
                "op": "SLOAD",
                "gas": 4411,
                "gas_cost": 2100,
                "depth": 1,
                "stack": [],
                "memory": [
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000000000000000000000000000000000000000000080"
                ],
                "storage": {
                    "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000014"
                },
                "reason": null
            }
        ]
}

For providing output formatted by opcodeLogger, the Mirror node will re-execute the transaction using the state from the contract_state_changes sidecars produced by the consensus nodes. In this way, we can have a track on all of the storage/memory information and the entire trace of opcodes that were executed during the replay.

⚠️ The output generated from the opcodeLogger is very verbose. The /opcodes endpoint will be disabled by default and can be enabled by users of the Hedera Local node or users running their own Mirror Nodes.

Performance considerations

Since the output generated by this tracer might be quite large, we could add a flag for enabling different type of tracers, based on the usage and setup of the Mirror Archive Node. This would give us control and flexibility. A user would be able to enable opcodeLogger in a local environment and get the full response data. The default tracer enabled by default on production, could be the callTracer.

Since this API would use a lot of resources like memory, CPU usage or requests to the DB, we can have a very strict rate limit that can be configurable based on the context of usage. We can use 1 call per second as initial rate limit. If a given provider want to run the Archive Node with more resources, the rate limit could be increased.

Backward Compatibility

Mirror Nodes that will support the new REST APIs should have enabled importing of CONTRACT_BYTECODE , CONTRACT_STATE_CHANGE and CONTRACT_ACTION sidecar types. Otherwise, executing the endpoints would result in missing runtime bytecode, contract storage data or contract actions information. In addition, the mirror node should have full historical support (keeping state from the first block), so that it could replay transactions from the entire lifetime of the system.

Security Implications

There would be some security implementations for Mirror Nodes. Since the debug_trace RPC calls would be free of charge and the Mirror Nodes don’t have gas based throttle mechanism, some attack vectors would be possible. The Nodes could be overloaded with huge amount of calls or invoke smart contract methods with huge gas usage, both of which might take more system usage and slow down the network for other users. A rate limit per IP address and rate limit per Kubernetes pod will be implemented, so that the load put on Mirror Nodes to be balanced.

How to Teach This

Respective documentation will be added.

References

https://hips.hedera.com/hip/hip-584

https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug

https://ganache.dev/#debug_traceTransaction

https://book.getfoundry.sh/reference/anvil/?highlight=debug_tra#description

https://docs.alchemy.com/reference/debug-tracetransaction

https://hardhat.org/hardhat-network/docs/reference#debug_tracetransaction

https://hardhat.org/hardhat-network/docs/overview#the-debug-tracetransaction-method

Open Issues

None.

Copyright/license

This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)

Citation

Please cite this document as: