Skip to content

Commit 607d226

Browse files
authored
Merge pull request #3515 from vitaliy-io/feature/implement-trace-block
Implement trace_block EP and conversion logic
2 parents e5caf13 + b88eaa7 commit 607d226

8 files changed

+32161
-3
lines changed

packages/evm/jsonrpc/debug_trace_block_sample.json

+9,797
Large diffs are not rendered by default.

packages/evm/jsonrpc/evmchain.go

+52-3
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ func (e *EVMChain) traceTransaction(
723723
return tracer.GetResult()
724724
}
725725

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

794-
return e.traceBlock(config, block)
794+
return e.debugTraceBlock(config, block)
795795
}
796796

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

805-
return e.traceBlock(config, block)
805+
return e.debugTraceBlock(config, block)
806806
}
807807

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

854+
func (e *EVMChain) TraceBlock(bn rpc.BlockNumber) (any, error) {
855+
e.log.Debugf("TraceBlock(blockNumber=%v)", bn)
856+
857+
block, err := e.getBlockByNumberOrHash(rpc.BlockNumberOrHashWithNumber(bn))
858+
if err != nil {
859+
return nil, err
860+
}
861+
iscBlock, iscRequestsInBlock, err := e.iscRequestsInBlock(block.NumberU64())
862+
if err != nil {
863+
return nil, err
864+
}
865+
866+
blockTxs, err := e.txsByBlockNumber(new(big.Int).SetUint64(block.NumberU64()))
867+
if err != nil {
868+
return nil, err
869+
}
870+
871+
results := TraceBlock{
872+
Jsonrpc: "2.0",
873+
Result: make([]*Trace, 0),
874+
ID: 1,
875+
}
876+
877+
for i, tx := range blockTxs {
878+
debugResultJSON, err := e.traceTransaction(
879+
&tracers.TraceConfig{},
880+
iscBlock,
881+
iscRequestsInBlock,
882+
tx,
883+
uint64(i),
884+
block.Hash(),
885+
)
886+
887+
if err == nil {
888+
var debugResult CallFrame
889+
err = json.Unmarshal(debugResultJSON, &debugResult)
890+
if err != nil {
891+
return nil, err
892+
}
893+
894+
blockHash := block.Hash()
895+
txHash := tx.Hash()
896+
results.Result = append(results.Result, convertToTrace(debugResult, &blockHash, block.NumberU64(), &txHash, uint64(i))...)
897+
}
898+
}
899+
900+
return results, nil
901+
}
902+
854903
var maxUint32 = big.NewInt(math.MaxUint32)
855904

856905
// the first EVM block (number 0) is "minted" at ISC block index 0 (init chain)

packages/evm/jsonrpc/jsonrpctest/jsonrpc_test.go

+69
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package jsonrpctest
55

66
import (
77
"context"
8+
"encoding/hex"
89
"encoding/json"
910
"math/big"
1011
"slices"
@@ -791,6 +792,74 @@ func TestRPCTraceBlock(t *testing.T) {
791792
require.NotEmpty(t, p)
792793
}
793794
})
795+
t.Run("trace_block", func(t *testing.T) {
796+
var res json.RawMessage
797+
err = env.RawClient.CallContext(
798+
context.Background(),
799+
&res,
800+
"trace_block",
801+
rpc.BlockNumber(env.BlockNumber()),
802+
)
803+
require.NoError(t, err)
804+
805+
var result jsonrpc.TraceBlock
806+
err = json.Unmarshal(res, &result)
807+
require.NoError(t, err)
808+
require.Len(t, result.Result, 4)
809+
810+
traceTx1Index := slices.IndexFunc(result.Result, func(v *jsonrpc.Trace) bool {
811+
return *v.TransactionHash == tx1.Hash()
812+
})
813+
traceTx2Index := slices.IndexFunc(result.Result, func(v *jsonrpc.Trace) bool {
814+
return *v.TransactionHash == tx2.Hash()
815+
})
816+
817+
call11 := result.Result[traceTx1Index]
818+
call12 := result.Result[traceTx1Index+1]
819+
call21 := result.Result[traceTx2Index]
820+
call22 := result.Result[traceTx2Index+1]
821+
822+
call11Action := call11.Action.(map[string]interface{})
823+
call12Action := call12.Action.(map[string]interface{})
824+
call21Action := call21.Action.(map[string]interface{})
825+
call22Action := call22.Action.(map[string]interface{})
826+
827+
require.Equal(t, strings.ToLower(creatorAddress.String()), strings.ToLower(call11Action["from"].(string)))
828+
require.Equal(t, strings.ToLower(contractAddress.String()), strings.ToLower(call11Action["to"].(string)))
829+
require.Equal(t, "0x7b", call11Action["value"].(string))
830+
expectedInput, err := contractABI.Pack("sendTo", common.Address{0x1}, big.NewInt(2))
831+
require.NoError(t, err)
832+
require.Equal(t, hex.EncodeToString(expectedInput), call11Action["input"].(string)[2:])
833+
require.Empty(t, call11.Error)
834+
require.Equal(t, 1, call11.Subtraces)
835+
require.Equal(t, []int{}, call11.TraceAddress)
836+
837+
require.Equal(t, strings.ToLower(contractAddress.String()), strings.ToLower(call12Action["from"].(string)))
838+
require.Equal(t, common.Address{0x1}.String(), strings.ToLower(call12Action["to"].(string)))
839+
require.Equal(t, "0x2", call12Action["value"].(string))
840+
require.Equal(t, "0x", call12Action["input"])
841+
require.Empty(t, call12.Error)
842+
require.Equal(t, 0, call12.Subtraces)
843+
require.Equal(t, []int{0}, call12.TraceAddress)
844+
845+
require.Equal(t, strings.ToLower(creatorAddress2.String()), strings.ToLower(call21Action["from"].(string)))
846+
require.Equal(t, strings.ToLower(contractAddress.String()), strings.ToLower(call21Action["to"].(string)))
847+
require.Equal(t, "0x141", call21Action["value"].(string))
848+
expectedInput, err = contractABI.Pack("sendTo", common.Address{0x2}, big.NewInt(3))
849+
require.NoError(t, err)
850+
require.Equal(t, hex.EncodeToString(expectedInput), call21Action["input"].(string)[2:])
851+
require.Empty(t, call21.Error)
852+
require.Equal(t, 1, call21.Subtraces)
853+
require.Equal(t, []int{}, call21.TraceAddress)
854+
855+
require.Equal(t, strings.ToLower(contractAddress.String()), strings.ToLower(call22Action["from"].(string)))
856+
require.Equal(t, common.Address{0x2}.String(), strings.ToLower(call22Action["to"].(string)))
857+
require.Equal(t, "0x3", call22Action["value"].(string))
858+
require.Equal(t, "0x", call22Action["input"])
859+
require.Empty(t, call22.Error)
860+
require.Equal(t, 0, call22.Subtraces)
861+
require.Equal(t, []int{0}, call22.TraceAddress)
862+
})
794863
}
795864

796865
func TestRPCTraceBlockSingleCall(t *testing.T) {

packages/evm/jsonrpc/server.go

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func NewServer(
7171
{"debug", NewDebugService(evmChain, metrics)},
7272
{"txpool", NewTxPoolService()},
7373
{"evm", NewEVMService(evmChain)},
74+
{"trace", NewTraceService(evmChain, metrics)},
7475
} {
7576
err := rpcsrv.RegisterName(srv.namespace, srv.service)
7677
if err != nil {

packages/evm/jsonrpc/service.go

+19
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,25 @@ func (d *DebugService) GetRawBlock(blockNrOrHash rpc.BlockNumberOrHash) (interfa
593593
})
594594
}
595595

596+
type TraceService struct {
597+
evmChain *EVMChain
598+
metrics *metrics.ChainWebAPIMetrics
599+
}
600+
601+
func NewTraceService(evmChain *EVMChain, metrics *metrics.ChainWebAPIMetrics) *TraceService {
602+
return &TraceService{
603+
evmChain: evmChain,
604+
metrics: metrics,
605+
}
606+
}
607+
608+
// Block implements the `trace_block` RPC.
609+
func (d *TraceService) Block(bn rpc.BlockNumber) (interface{}, error) {
610+
return withMetrics(d.metrics, "trace_block", func() (interface{}, error) {
611+
return d.evmChain.TraceBlock(bn)
612+
})
613+
}
614+
596615
type EVMService struct {
597616
evmChain *EVMChain
598617
}

0 commit comments

Comments
 (0)