Skip to content

Commit 5041002

Browse files
authored
fix(zetacore): allow object for tracerConfig (#3622)
* fix(zetacore): allow object for tracerConfig * add empty test case * use explicit error return * changelog
1 parent 06e66fb commit 5041002

File tree

7 files changed

+144
-12
lines changed

7 files changed

+144
-12
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
* [3509](https://github.com/zeta-chain/node/pull/3509) - schedule Bitcoin TSS keysign on interval to avoid TSS keysign spam
4343
* [3517](https://github.com/zeta-chain/node/pull/3517) - remove duplicate gateway event appending to fix false positive on multiple events in same tx
4444
* [3602](https://github.com/zeta-chain/node/pull/3602) - hardcode gas limits to avoid estimate gas calls
45+
* [3622](https://github.com/zeta-chain/node/pull/3622) - allow object for tracerConfig in `debug_traceTransaction` RPC
4546

4647
### Tests
4748

rpc/backend/backend.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ type EVMBackend interface {
165165
BloomStatus() (uint64, uint64)
166166

167167
// Tracing
168-
TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) (interface{}, error)
168+
TraceTransaction(hash common.Hash, config *rpctypes.TraceConfig) (interface{}, error)
169169
TraceBlock(
170170
height rpctypes.BlockNumber,
171-
config *evmtypes.TraceConfig,
171+
config *rpctypes.TraceConfig,
172172
block *tmrpctypes.ResultBlock,
173173
) ([]*evmtypes.TxTraceResult, error)
174174
}

rpc/backend/tracing.go

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030

3131
// TraceTransaction returns the structured logs created during the execution of EVM
3232
// and returns them as a JSON object.
33-
func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) (interface{}, error) {
33+
func (b *Backend) TraceTransaction(hash common.Hash, config *rpctypes.TraceConfig) (interface{}, error) {
3434
// Get transaction by hash
3535
transaction, _, err := b.GetTxByEthHash(hash)
3636
if err != nil {
@@ -80,7 +80,10 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi
8080
}
8181

8282
if config != nil {
83-
traceTxRequest.TraceConfig = config
83+
traceTxRequest.TraceConfig, err = convertConfig(config)
84+
if err != nil {
85+
return nil, err
86+
}
8487
}
8588

8689
// minus one to get the context of block beginning
@@ -109,7 +112,7 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi
109112
// executes all the transactions contained within. The return value will be one item
110113
// per transaction, dependent on the requested tracer.
111114
func (b *Backend) TraceBlock(height rpctypes.BlockNumber,
112-
config *evmtypes.TraceConfig,
115+
config *rpctypes.TraceConfig,
113116
block *tmrpctypes.ResultBlock,
114117
) ([]*evmtypes.TxTraceResult, error) {
115118
txs := block.Block.Txs
@@ -135,9 +138,14 @@ func (b *Backend) TraceBlock(height rpctypes.BlockNumber,
135138
}
136139
ctxWithHeight := rpctypes.ContextWithHeight(int64(contextHeight))
137140

141+
traceConfig, err := convertConfig(config)
142+
if err != nil {
143+
return nil, err
144+
}
145+
138146
traceBlockRequest := &evmtypes.QueryTraceBlockRequest{
139147
Txs: msgs,
140-
TraceConfig: config,
148+
TraceConfig: traceConfig,
141149
BlockNumber: block.Block.Height,
142150
BlockTime: block.Block.Time,
143151
BlockHash: common.Bytes2Hex(block.BlockID.Hash),
@@ -157,3 +165,31 @@ func (b *Backend) TraceBlock(height rpctypes.BlockNumber,
157165

158166
return decodedResults, nil
159167
}
168+
169+
func convertConfig(config *rpctypes.TraceConfig) (*evmtypes.TraceConfig, error) {
170+
if config == nil {
171+
return &evmtypes.TraceConfig{}, nil
172+
}
173+
174+
cfg := config.TraceConfig
175+
176+
if config.TracerConfig != nil {
177+
switch v := config.TracerConfig.(type) {
178+
case string:
179+
// It's already a string, use it directly
180+
cfg.TracerJsonConfig = v
181+
case map[string]interface{}:
182+
// this is the compliant style
183+
// we need to encode it to a string before passing it to the ethermint side
184+
jsonBytes, err := json.Marshal(v)
185+
if err != nil {
186+
return nil, fmt.Errorf("unable to encode traceConfig to JSON: %w", err)
187+
}
188+
cfg.TracerJsonConfig = string(jsonBytes)
189+
default:
190+
return nil, errors.New("unexpected traceConfig type")
191+
}
192+
}
193+
194+
return &cfg, nil
195+
}

rpc/backend/tracing_convert_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package backend
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
rpctypes "github.com/zeta-chain/node/rpc/types"
9+
)
10+
11+
const expectedConvertedValue = `{"onlyTopCall":false}`
12+
13+
const brokenStyleRaw = `
14+
{
15+
"tracer": "callTracer",
16+
"tracerConfig": "{\"onlyTopCall\":false}"
17+
}
18+
`
19+
20+
const compliantStyleRaw = `
21+
{
22+
"tracer": "callTracer",
23+
"tracerConfig": {"onlyTopCall":false}
24+
}
25+
`
26+
27+
const emptyStyleRaw = `
28+
{
29+
"tracer": "callTracer"
30+
}
31+
`
32+
33+
const invalidStyleRaw = `
34+
{
35+
"tracer": "callTracer",
36+
"tracerConfig": []
37+
}
38+
`
39+
40+
func TestConvertConfig(t *testing.T) {
41+
tests := []struct {
42+
name string
43+
input string
44+
expectError bool
45+
expected string
46+
}{
47+
{
48+
name: "broken style",
49+
input: brokenStyleRaw,
50+
expectError: false,
51+
expected: expectedConvertedValue,
52+
},
53+
{
54+
name: "compliant style",
55+
input: compliantStyleRaw,
56+
expectError: false,
57+
expected: expectedConvertedValue,
58+
},
59+
{
60+
name: "empty style",
61+
input: emptyStyleRaw,
62+
expectError: false,
63+
expected: "",
64+
},
65+
{
66+
name: "invalid style",
67+
input: invalidStyleRaw,
68+
expectError: true,
69+
expected: "",
70+
},
71+
}
72+
73+
for _, tt := range tests {
74+
t.Run(tt.name, func(t *testing.T) {
75+
rpcConfig := &rpctypes.TraceConfig{}
76+
err := json.Unmarshal([]byte(tt.input), rpcConfig)
77+
require.NoError(t, err)
78+
79+
ethermintConfig, err := convertConfig(rpcConfig)
80+
if tt.expectError {
81+
require.Error(t, err)
82+
return
83+
}
84+
require.NoError(t, err)
85+
require.Equal(t, tt.expected, ethermintConfig.TracerJsonConfig)
86+
})
87+
}
88+
}

rpc/backend/tracing_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/zeta-chain/ethermint/crypto/ethsecp256k1"
1515
"github.com/zeta-chain/ethermint/indexer"
1616
evmtypes "github.com/zeta-chain/ethermint/x/evm/types"
17+
rpctypes "github.com/zeta-chain/node/rpc/types"
1718

1819
"github.com/zeta-chain/node/rpc/backend/mocks"
1920
)
@@ -272,15 +273,15 @@ func (suite *BackendTestSuite) TestTraceBlock() {
272273
registerMock func()
273274
expTraceResults []*evmtypes.TxTraceResult
274275
resBlock *tmrpctypes.ResultBlock
275-
config *evmtypes.TraceConfig
276+
config *rpctypes.TraceConfig
276277
expPass bool
277278
}{
278279
{
279280
"pass - no transaction returning empty array",
280281
func() {},
281282
[]*evmtypes.TxTraceResult{},
282283
&resBlockEmpty,
283-
&evmtypes.TraceConfig{},
284+
&rpctypes.TraceConfig{},
284285
true,
285286
},
286287
{
@@ -293,7 +294,7 @@ func (suite *BackendTestSuite) TestTraceBlock() {
293294
},
294295
[]*evmtypes.TxTraceResult{},
295296
&resBlockFilled,
296-
&evmtypes.TraceConfig{},
297+
&rpctypes.TraceConfig{},
297298
false,
298299
},
299300
}

rpc/namespaces/ethereum/debug/api.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func NewAPI(
7272

7373
// TraceTransaction returns the structured logs created during the execution of EVM
7474
// and returns them as a JSON object.
75-
func (a *API) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) (interface{}, error) {
75+
func (a *API) TraceTransaction(hash common.Hash, config *rpctypes.TraceConfig) (interface{}, error) {
7676
a.logger.Debug("debug_traceTransaction", "hash", hash)
7777
return a.backend.TraceTransaction(hash, config)
7878
}
@@ -81,7 +81,7 @@ func (a *API) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfig) (
8181
// EVM and returns them as a JSON object.
8282
func (a *API) TraceBlockByNumber(
8383
height rpctypes.BlockNumber,
84-
config *evmtypes.TraceConfig,
84+
config *rpctypes.TraceConfig,
8585
) ([]*evmtypes.TxTraceResult, error) {
8686
a.logger.Debug("debug_traceBlockByNumber", "height", height)
8787
if height == 0 {
@@ -99,7 +99,7 @@ func (a *API) TraceBlockByNumber(
9999

100100
// TraceBlockByHash returns the structured logs created during the execution of
101101
// EVM and returns them as a JSON object.
102-
func (a *API) TraceBlockByHash(hash common.Hash, config *evmtypes.TraceConfig) ([]*evmtypes.TxTraceResult, error) {
102+
func (a *API) TraceBlockByHash(hash common.Hash, config *rpctypes.TraceConfig) ([]*evmtypes.TxTraceResult, error) {
103103
a.logger.Debug("debug_traceBlockByHash", "hash", hash)
104104
// Get Tendermint Block
105105
resBlock, err := a.backend.TendermintBlockByHash(hash)

rpc/types/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/ethereum/go-ethereum/common"
2222
"github.com/ethereum/go-ethereum/common/hexutil"
2323
ethtypes "github.com/ethereum/go-ethereum/core/types"
24+
evmtypes "github.com/zeta-chain/ethermint/x/evm/types"
2425
)
2526

2627
// Copied the Account and StorageResult types since they are registered under an
@@ -115,3 +116,8 @@ type OneFeeHistory struct {
115116
Reward []*big.Int // each element of the array will have the tip provided to miners for the percentile given
116117
GasUsedRatio float64 // the ratio of gas used to the gas limit for each block
117118
}
119+
120+
type TraceConfig struct {
121+
evmtypes.TraceConfig
122+
TracerConfig interface{} `json:"tracerConfig"`
123+
}

0 commit comments

Comments
 (0)