Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement trace_block EP and conversion logic #3515

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9,797 changes: 9,797 additions & 0 deletions packages/evm/jsonrpc/debug_trace_block_sample.json

Large diffs are not rendered by default.

55 changes: 52 additions & 3 deletions packages/evm/jsonrpc/evmchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ func (e *EVMChain) traceTransaction(
return tracer.GetResult()
}

func (e *EVMChain) traceBlock(config *tracers.TraceConfig, block *types.Block) (any, error) {
func (e *EVMChain) debugTraceBlock(config *tracers.TraceConfig, block *types.Block) (any, error) {
iscBlock, iscRequestsInBlock, err := e.iscRequestsInBlock(block.NumberU64())
if err != nil {
return nil, err
Expand Down Expand Up @@ -791,7 +791,7 @@ func (e *EVMChain) TraceBlockByHash(blockHash common.Hash, config *tracers.Trace
return nil, fmt.Errorf("block not found: %s", blockHash.String())
}

return e.traceBlock(config, block)
return e.debugTraceBlock(config, block)
}

func (e *EVMChain) TraceBlockByNumber(blockNumber uint64, config *tracers.TraceConfig) (any, error) {
Expand All @@ -802,7 +802,7 @@ func (e *EVMChain) TraceBlockByNumber(blockNumber uint64, config *tracers.TraceC
return nil, fmt.Errorf("block not found: %d", blockNumber)
}

return e.traceBlock(config, block)
return e.debugTraceBlock(config, block)
}

func (e *EVMChain) getBlockByNumberOrHash(blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
Expand Down Expand Up @@ -851,6 +851,55 @@ func (e *EVMChain) GetBlockReceipts(blockNrOrHash rpc.BlockNumberOrHash) ([]*typ
return db.GetReceiptsByBlockNumber(block.NumberU64()), db.GetTransactionsByBlockNumber(block.NumberU64()), nil
}

func (e *EVMChain) TraceBlock(bn rpc.BlockNumber) (any, error) {
e.log.Debugf("TraceBlock(blockNumber=%v)", bn)

block, err := e.getBlockByNumberOrHash(rpc.BlockNumberOrHashWithNumber(bn))
if err != nil {
return nil, err
}
iscBlock, iscRequestsInBlock, err := e.iscRequestsInBlock(block.NumberU64())
if err != nil {
return nil, err
}

blockTxs, err := e.txsByBlockNumber(new(big.Int).SetUint64(block.NumberU64()))
if err != nil {
return nil, err
}

results := TraceBlock{
Jsonrpc: "2.0",
Result: make([]*Trace, 0),
ID: 1,
}

for i, tx := range blockTxs {
debugResultJSON, err := e.traceTransaction(
&tracers.TraceConfig{},
iscBlock,
iscRequestsInBlock,
tx,
uint64(i),
block.Hash(),
)

if err == nil {
var debugResult CallFrame
err = json.Unmarshal(debugResultJSON, &debugResult)
if err != nil {
return nil, err
}

blockHash := block.Hash()
txHash := tx.Hash()
results.Result = append(results.Result, convertToTrace(debugResult, &blockHash, block.NumberU64(), &txHash, uint64(i))...)
}
}

return results, nil
}

var maxUint32 = big.NewInt(math.MaxUint32)

// the first EVM block (number 0) is "minted" at ISC block index 0 (init chain)
Expand Down
69 changes: 69 additions & 0 deletions packages/evm/jsonrpc/jsonrpctest/jsonrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package jsonrpctest

import (
"context"
"encoding/hex"
"encoding/json"
"math/big"
"slices"
Expand Down Expand Up @@ -791,6 +792,74 @@ func TestRPCTraceBlock(t *testing.T) {
require.NotEmpty(t, p)
}
})
t.Run("trace_block", func(t *testing.T) {
var res json.RawMessage
err = env.RawClient.CallContext(
context.Background(),
&res,
"trace_block",
rpc.BlockNumber(env.BlockNumber()),
)
require.NoError(t, err)

var result jsonrpc.TraceBlock
err = json.Unmarshal(res, &result)
require.NoError(t, err)
require.Len(t, result.Result, 4)

traceTx1Index := slices.IndexFunc(result.Result, func(v *jsonrpc.Trace) bool {
return *v.TransactionHash == tx1.Hash()
})
traceTx2Index := slices.IndexFunc(result.Result, func(v *jsonrpc.Trace) bool {
return *v.TransactionHash == tx2.Hash()
})

call11 := result.Result[traceTx1Index]
call12 := result.Result[traceTx1Index+1]
call21 := result.Result[traceTx2Index]
call22 := result.Result[traceTx2Index+1]

call11Action := call11.Action.(map[string]interface{})
call12Action := call12.Action.(map[string]interface{})
call21Action := call21.Action.(map[string]interface{})
call22Action := call22.Action.(map[string]interface{})

require.Equal(t, strings.ToLower(creatorAddress.String()), strings.ToLower(call11Action["from"].(string)))
require.Equal(t, strings.ToLower(contractAddress.String()), strings.ToLower(call11Action["to"].(string)))
require.Equal(t, "0x7b", call11Action["value"].(string))
expectedInput, err := contractABI.Pack("sendTo", common.Address{0x1}, big.NewInt(2))
require.NoError(t, err)
require.Equal(t, hex.EncodeToString(expectedInput), call11Action["input"].(string)[2:])
require.Empty(t, call11.Error)
require.Equal(t, 1, call11.Subtraces)
require.Equal(t, []int{}, call11.TraceAddress)

require.Equal(t, strings.ToLower(contractAddress.String()), strings.ToLower(call12Action["from"].(string)))
require.Equal(t, common.Address{0x1}.String(), strings.ToLower(call12Action["to"].(string)))
require.Equal(t, "0x2", call12Action["value"].(string))
require.Equal(t, "0x", call12Action["input"])
require.Empty(t, call12.Error)
require.Equal(t, 0, call12.Subtraces)
require.Equal(t, []int{0}, call12.TraceAddress)

require.Equal(t, strings.ToLower(creatorAddress2.String()), strings.ToLower(call21Action["from"].(string)))
require.Equal(t, strings.ToLower(contractAddress.String()), strings.ToLower(call21Action["to"].(string)))
require.Equal(t, "0x141", call21Action["value"].(string))
expectedInput, err = contractABI.Pack("sendTo", common.Address{0x2}, big.NewInt(3))
require.NoError(t, err)
require.Equal(t, hex.EncodeToString(expectedInput), call21Action["input"].(string)[2:])
require.Empty(t, call21.Error)
require.Equal(t, 1, call21.Subtraces)
require.Equal(t, []int{}, call21.TraceAddress)

require.Equal(t, strings.ToLower(contractAddress.String()), strings.ToLower(call22Action["from"].(string)))
require.Equal(t, common.Address{0x2}.String(), strings.ToLower(call22Action["to"].(string)))
require.Equal(t, "0x3", call22Action["value"].(string))
require.Equal(t, "0x", call22Action["input"])
require.Empty(t, call22.Error)
require.Equal(t, 0, call22.Subtraces)
require.Equal(t, []int{0}, call22.TraceAddress)
})
}

func TestRPCTraceBlockSingleCall(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions packages/evm/jsonrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func NewServer(
{"debug", NewDebugService(evmChain, metrics)},
{"txpool", NewTxPoolService()},
{"evm", NewEVMService(evmChain)},
{"trace", NewTraceService(evmChain, metrics)},
} {
err := rpcsrv.RegisterName(srv.namespace, srv.service)
if err != nil {
Expand Down
19 changes: 19 additions & 0 deletions packages/evm/jsonrpc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,25 @@ func (d *DebugService) GetRawBlock(blockNrOrHash rpc.BlockNumberOrHash) (interfa
})
}

type TraceService struct {
evmChain *EVMChain
metrics *metrics.ChainWebAPIMetrics
}

func NewTraceService(evmChain *EVMChain, metrics *metrics.ChainWebAPIMetrics) *TraceService {
return &TraceService{
evmChain: evmChain,
metrics: metrics,
}
}

// Block implements the `trace_block` RPC.
func (d *TraceService) Block(bn rpc.BlockNumber) (interface{}, error) {
return withMetrics(d.metrics, "trace_block", func() (interface{}, error) {
return d.evmChain.TraceBlock(bn)
})
}

type EVMService struct {
evmChain *EVMChain
}
Expand Down
Loading
Loading