Skip to content

Commit

Permalink
new tracers (0xPolygonHermez#2663)
Browse files Browse the repository at this point in the history
  • Loading branch information
tclemos authored Nov 23, 2023
1 parent a4212eb commit d7630ce
Show file tree
Hide file tree
Showing 15 changed files with 1,271 additions and 1,562 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ services:
zkevm-prover:
container_name: zkevm-prover
restart: unless-stopped
image: hermeznetwork/zkevm-prover:v3.0.0-RC2
image: hermeznetwork/zkevm-prover:83c6275
depends_on:
zkevm-state-db:
condition: service_healthy
Expand Down
159 changes: 1 addition & 158 deletions jsonrpc/endpoints_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,17 @@ package jsonrpc

import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"net/http"
"sort"
"strings"
"sync"
"time"

"github.com/0xPolygonHermez/zkevm-node/jsonrpc/types"
"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/0xPolygonHermez/zkevm-node/state"
"github.com/0xPolygonHermez/zkevm-node/state/runtime/fakevm"
"github.com/0xPolygonHermez/zkevm-node/state/runtime/instrumentation"
"github.com/ethereum/go-ethereum/common"
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/jackc/pgx/v4"
Expand Down Expand Up @@ -56,27 +52,6 @@ type traceConfig struct {
TracerConfig json.RawMessage `json:"tracerConfig"`
}

// StructLogRes represents the debug trace information for each opcode
type StructLogRes struct {
Pc uint64 `json:"pc"`
Op string `json:"op"`
Gas uint64 `json:"gas"`
GasCost uint64 `json:"gasCost"`
Depth int `json:"depth"`
Error string `json:"error,omitempty"`
Stack *[]types.ArgBig `json:"stack,omitempty"`
Memory *[]string `json:"memory,omitempty"`
Storage *map[string]string `json:"storage,omitempty"`
RefundCounter uint64 `json:"refund,omitempty"`
}

type traceTransactionResponse struct {
Gas uint64 `json:"gas"`
Failed bool `json:"failed"`
ReturnValue interface{} `json:"returnValue"`
StructLogs []StructLogRes `json:"structLogs"`
}

type traceBlockTransactionResponse struct {
Result interface{} `json:"result"`
}
Expand Down Expand Up @@ -301,11 +276,6 @@ func (d *DebugEndpoints) buildTraceTransaction(ctx context.Context, hash common.
traceCfg = defaultTraceConfig
}

// check tracer
if traceCfg.Tracer != nil && *traceCfg.Tracer != "" && !isBuiltInTracer(*traceCfg.Tracer) && !isJSCustomTracer(*traceCfg.Tracer) {
return RPCErrorResponse(types.DefaultErrorCode, "invalid tracer", nil, false)
}

stateTraceConfig := state.TraceConfig{
DisableStack: traceCfg.DisableStack,
DisableStorage: traceCfg.DisableStorage,
Expand All @@ -322,134 +292,7 @@ func (d *DebugEndpoints) buildTraceTransaction(ctx context.Context, hash common.
return nil, types.NewRPCError(types.DefaultErrorCode, errorMessage)
}

// if a tracer was specified, then return the trace result
if stateTraceConfig.Tracer != nil && *stateTraceConfig.Tracer != "" && len(result.ExecutorTraceResult) > 0 {
return result.ExecutorTraceResult, nil
}

receipt, err := d.state.GetTransactionReceipt(ctx, hash, dbTx)
if err != nil {
const errorMessage = "failed to tx receipt"
log.Errorf("%v: %v", errorMessage, err)
return nil, types.NewRPCError(types.DefaultErrorCode, errorMessage)
}

failed := receipt.Status == ethTypes.ReceiptStatusFailed
var returnValue interface{}
if stateTraceConfig.EnableReturnData {
returnValue = common.Bytes2Hex(result.ReturnValue)
}

structLogs := d.buildStructLogs(result.StructLogs, *traceCfg)

resp := traceTransactionResponse{
Gas: result.GasUsed,
Failed: failed,
ReturnValue: returnValue,
StructLogs: structLogs,
}

return resp, nil
}

func (d *DebugEndpoints) buildStructLogs(stateStructLogs []instrumentation.StructLog, cfg traceConfig) []StructLogRes {
structLogs := make([]StructLogRes, 0, len(stateStructLogs))
memory := fakevm.NewMemory()
for _, structLog := range stateStructLogs {
errRes := ""
if structLog.Err != nil {
errRes = structLog.Err.Error()
}

op := structLog.Op
if op == "SHA3" {
op = "KECCAK256"
} else if op == "STOP" && structLog.Pc == 0 {
// this stop is generated for calls with single
// step(no depth increase) and must be ignored
continue
}

structLogRes := StructLogRes{
Pc: structLog.Pc,
Op: op,
Gas: structLog.Gas,
GasCost: structLog.GasCost,
Depth: structLog.Depth,
Error: errRes,
RefundCounter: structLog.RefundCounter,
}

if !cfg.DisableStack {
stack := make([]types.ArgBig, 0, len(structLog.Stack))
for _, stackItem := range structLog.Stack {
if stackItem != nil {
stack = append(stack, types.ArgBig(*stackItem))
}
}
structLogRes.Stack = &stack
}

if cfg.EnableMemory {
memory.Resize(uint64(structLog.MemorySize))
if len(structLog.Memory) > 0 {
memory.Set(uint64(structLog.MemoryOffset), uint64(len(structLog.Memory)), structLog.Memory)
}

if structLog.MemorySize > 0 {
// Populate the structLog memory
structLog.Memory = memory.Data()

// Convert memory to string array
const memoryChunkSize = 32
memoryArray := make([]string, 0, len(structLog.Memory))

for i := 0; i < len(structLog.Memory); i = i + memoryChunkSize {
slice32Bytes := make([]byte, memoryChunkSize)
copy(slice32Bytes, structLog.Memory[i:i+memoryChunkSize])
memoryStringItem := hex.EncodeToString(slice32Bytes)
memoryArray = append(memoryArray, memoryStringItem)
}

structLogRes.Memory = &memoryArray
} else {
memory = fakevm.NewMemory()
structLogRes.Memory = &[]string{}
}
}

if !cfg.DisableStorage && len(structLog.Storage) > 0 {
storage := make(map[string]string, len(structLog.Storage))
for storageKey, storageValue := range structLog.Storage {
k := hex.EncodeToString(storageKey.Bytes())
v := hex.EncodeToString(storageValue.Bytes())
storage[k] = v
}
structLogRes.Storage = &storage
}

structLogs = append(structLogs, structLogRes)
}
return structLogs
}

// isBuiltInTracer checks if the tracer is one of the
// built-in tracers
func isBuiltInTracer(tracer string) bool {
// built-in tracers
switch tracer {
case "callTracer", "4byteTracer", "prestateTracer", "noopTracer":
return true
default:
return false
}
}

// isJSCustomTracer checks if the tracer contains the
// functions result and fault which are required for a custom tracer
// https://geth.ethereum.org/docs/developers/evm-tracing/custom-tracer
func isJSCustomTracer(tracer string) bool {
return strings.Contains(tracer, "result") && strings.Contains(tracer, "fault")
return result.TraceResult, nil
}

// waitTimeout waits for the waitGroup for the specified max timeout.
Expand Down
42 changes: 6 additions & 36 deletions proto/src/proto/executor/v1/executor.proto
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,8 @@ message TraceConfig {
uint32 enable_memory = 3;
// Enables return data (default=false)
uint32 enable_return_data = 4;
// Hash of tx in batch to retrieve the execution trace
bytes tx_hash_to_generate_execute_trace = 5;
// Hash of tx in batch to retrieve the call trace
bytes tx_hash_to_generate_call_trace = 6;
// Hash of tx in batch to retrieve the trace
bytes tx_hash_to_generate_full_trace = 5;
}
message InfoReadWrite {
// If nonce="" then it has not been set; if set, string is in decimal (base 10)
Expand All @@ -102,7 +100,7 @@ message InfoReadWrite {
string balance = 2;
}

message CallTrace {
message FullTrace {
TransactionContext context = 1;
repeated TransactionStep steps = 2;
}
Expand Down Expand Up @@ -163,6 +161,8 @@ message TransactionStep {
Contract contract = 13;
// Error
RomError error = 14;
// Content of the storage
map<string, string> storage = 15;
}

message Contract {
Expand Down Expand Up @@ -201,8 +201,7 @@ message ProcessTransactionResponse {
// Logs emited by LOG opcode
repeated Log logs = 11;
// Trace
repeated ExecutionTraceStep execution_trace = 13;
CallTrace call_trace = 14;
FullTrace full_trace = 14;
// Efective Gas Price
string effective_gas_price = 15;
uint32 effective_percentage = 16;
Expand Down Expand Up @@ -231,35 +230,6 @@ message Log {
uint32 index = 8;
}

message ExecutionTraceStep {
// Program Counter
uint64 pc = 1;
// OpCode
string op = 2;
// Remaining gas
uint64 remaining_gas = 3;
// Gas cost of the operation
uint64 gas_cost = 4;
// Content of memory, starting at memory_offset, showing only changes vs. previous step
bytes memory = 5;
// Total size of memory
uint32 memory_size = 6;
// Offset of memory changes
uint32 memory_offset = 7;
// Content of the stack
repeated string stack = 8;
// Returned data
bytes return_data = 9;
// Content of the storage
map<string, string> storage = 10;
// Call depth
uint32 depth = 11;
// Gas refund
uint64 gas_refund = 12;
// Error
RomError error = 13;
}

enum RomError {
ROM_ERROR_UNSPECIFIED = 0;
// ROM_ERROR_NO_ERROR indicates the execution ended successfully
Expand Down
Loading

0 comments on commit d7630ce

Please sign in to comment.