Skip to content

Commit 9710e98

Browse files
authored
turbo/jsonrpc: add optional includePrecompiles flag to trace_* apis (#10979)
relates to #9784 - Adds support for an optional `"includePrecompiles"` tracer config option for our OeTracer (OpenEthereum) that users can use to match output of debug_* apis with callTracer (by default it includes precompiles). Note default spec for OpenEthereum traces are to not include precompiles - this is preserved by this PR - Note geth has support for `"includePrecompiles"` so we are getting more aligned as well - https://github.com/ethereum/go-ethereum/blob/master/eth/tracers/native/call_flat.go#L124 - Adds tests for OeTracer
1 parent 7055c2c commit 9710e98

8 files changed

Lines changed: 1965 additions & 48 deletions

turbo/jsonrpc/call_traces_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ package jsonrpc
22

33
import (
44
"context"
5-
"github.com/ledgerwatch/erigon-lib/common/hexutil"
65
"sync"
76
"testing"
87

98
"github.com/holiman/uint256"
109
jsoniter "github.com/json-iterator/go"
11-
"github.com/ledgerwatch/erigon-lib/common"
1210
"github.com/stretchr/testify/assert"
1311
"github.com/stretchr/testify/require"
1412
"github.com/valyala/fastjson"
1513

14+
"github.com/ledgerwatch/erigon-lib/common"
15+
"github.com/ledgerwatch/erigon-lib/common/hexutil"
1616
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg"
1717
"github.com/ledgerwatch/erigon/core"
1818
"github.com/ledgerwatch/erigon/core/types"
@@ -67,7 +67,7 @@ func TestCallTraceOneByOne(t *testing.T) {
6767
ToBlock: (*hexutil.Uint64)(&toBlock),
6868
ToAddress: []*common.Address{&toAddress1},
6969
}
70-
if err = api.Filter(context.Background(), traceReq1, new(bool), stream); err != nil {
70+
if err = api.Filter(context.Background(), traceReq1, new(bool), nil, stream); err != nil {
7171
t.Fatalf("trace_filter failed: %v", err)
7272
}
7373
assert.Equal(t, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, blockNumbersFromTraces(t, stream.Buffer()))
@@ -110,7 +110,7 @@ func TestCallTraceUnwind(t *testing.T) {
110110
ToBlock: (*hexutil.Uint64)(&toBlock),
111111
ToAddress: []*common.Address{&toAddress1},
112112
}
113-
if err = api.Filter(context.Background(), traceReq1, new(bool), stream); err != nil {
113+
if err = api.Filter(context.Background(), traceReq1, new(bool), nil, stream); err != nil {
114114
t.Fatalf("trace_filter failed: %v", err)
115115
}
116116
assert.Equal(t, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, blockNumbersFromTraces(t, stream.Buffer()))
@@ -125,7 +125,7 @@ func TestCallTraceUnwind(t *testing.T) {
125125
ToBlock: (*hexutil.Uint64)(&toBlock),
126126
ToAddress: []*common.Address{&toAddress1},
127127
}
128-
if err = api.Filter(context.Background(), traceReq2, new(bool), stream); err != nil {
128+
if err = api.Filter(context.Background(), traceReq2, new(bool), nil, stream); err != nil {
129129
t.Fatalf("trace_filter failed: %v", err)
130130
}
131131
assert.Equal(t, []int{1, 2, 3, 4, 5, 11, 12}, blockNumbersFromTraces(t, stream.Buffer()))
@@ -141,7 +141,7 @@ func TestCallTraceUnwind(t *testing.T) {
141141
ToBlock: (*hexutil.Uint64)(&toBlock),
142142
ToAddress: []*common.Address{&toAddress1},
143143
}
144-
if err = api.Filter(context.Background(), traceReq3, new(bool), stream); err != nil {
144+
if err = api.Filter(context.Background(), traceReq3, new(bool), nil, stream); err != nil {
145145
t.Fatalf("trace_filter failed: %v", err)
146146
}
147147
assert.Equal(t, []int{12, 13, 14, 15, 16, 17, 18, 19, 20}, blockNumbersFromTraces(t, stream.Buffer()))
@@ -171,7 +171,7 @@ func TestFilterNoAddresses(t *testing.T) {
171171
FromBlock: (*hexutil.Uint64)(&fromBlock),
172172
ToBlock: (*hexutil.Uint64)(&toBlock),
173173
}
174-
if err = api.Filter(context.Background(), traceReq1, new(bool), stream); err != nil {
174+
if err = api.Filter(context.Background(), traceReq1, new(bool), nil, stream); err != nil {
175175
t.Fatalf("trace_filter failed: %v", err)
176176
}
177177
assert.Equal(t, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, blockNumbersFromTraces(t, stream.Buffer()))
@@ -220,7 +220,7 @@ func TestFilterAddressIntersection(t *testing.T) {
220220
ToAddress: []*common.Address{&m.Address, &toAddress2},
221221
Mode: TraceFilterModeIntersection,
222222
}
223-
if err = api.Filter(context.Background(), traceReq1, new(bool), stream); err != nil {
223+
if err = api.Filter(context.Background(), traceReq1, new(bool), nil, stream); err != nil {
224224
t.Fatalf("trace_filter failed: %v", err)
225225
}
226226
assert.Equal(t, []int{6, 7, 8, 9, 10}, blockNumbersFromTraces(t, stream.Buffer()))
@@ -236,7 +236,7 @@ func TestFilterAddressIntersection(t *testing.T) {
236236
ToAddress: []*common.Address{&toAddress1, &m.Address},
237237
Mode: TraceFilterModeIntersection,
238238
}
239-
if err = api.Filter(context.Background(), traceReq1, new(bool), stream); err != nil {
239+
if err = api.Filter(context.Background(), traceReq1, new(bool), nil, stream); err != nil {
240240
t.Fatalf("trace_filter failed: %v", err)
241241
}
242242
assert.Equal(t, []int{1, 2, 3, 4, 5}, blockNumbersFromTraces(t, stream.Buffer()))
@@ -252,7 +252,7 @@ func TestFilterAddressIntersection(t *testing.T) {
252252
FromAddress: []*common.Address{&toAddress2, &toAddress1, &other},
253253
Mode: TraceFilterModeIntersection,
254254
}
255-
if err = api.Filter(context.Background(), traceReq1, new(bool), stream); err != nil {
255+
if err = api.Filter(context.Background(), traceReq1, new(bool), nil, stream); err != nil {
256256
t.Fatalf("trace_filter failed: %v", err)
257257
}
258258
require.Empty(t, blockNumbersFromTraces(t, stream.Buffer()))

turbo/jsonrpc/gen_traces_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func TestGeneratedTraceApi(t *testing.T) {
120120
stateCache := kvcache.New(kvcache.DefaultCoherentConfig)
121121
baseApi := NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs)
122122
api := NewTraceAPI(baseApi, m.DB, &httpcfg.HttpCfg{})
123-
traces, err := api.Block(context.Background(), rpc.BlockNumber(1), new(bool))
123+
traces, err := api.Block(context.Background(), rpc.BlockNumber(1), new(bool), nil)
124124
if err != nil {
125125
t.Errorf("trace_block %d: %v", 0, err)
126126
}
@@ -275,7 +275,7 @@ func TestGeneratedTraceApi(t *testing.T) {
275275
func TestGeneratedTraceApiCollision(t *testing.T) {
276276
m := rpcdaemontest.CreateTestSentryForTracesCollision(t)
277277
api := NewTraceAPI(newBaseApiForTest(m), m.DB, &httpcfg.HttpCfg{})
278-
traces, err := api.Transaction(context.Background(), common.HexToHash("0xb2b9fa4c999c1c8370ce1fbd1c4315a9ce7f8421fe2ebed8a9051ff2e4e7e3da"), new(bool))
278+
traces, err := api.Transaction(context.Background(), common.HexToHash("0xb2b9fa4c999c1c8370ce1fbd1c4315a9ce7f8421fe2ebed8a9051ff2e4e7e3da"), new(bool), nil)
279279
if err != nil {
280280
t.Errorf("trace_block %d: %v", 0, err)
281281
}

turbo/jsonrpc/testdata/oetracer/tracer_config_default_0x536434786ace02697118c44abf2835f188bf79902807c61a523ca3a6200bc350.json

Lines changed: 854 additions & 0 deletions
Large diffs are not rendered by default.

turbo/jsonrpc/testdata/oetracer/tracer_config_include_precompiles_0x536434786ace02697118c44abf2835f188bf79902807c61a523ca3a6200bc350.json

Lines changed: 905 additions & 0 deletions
Large diffs are not rendered by default.

turbo/jsonrpc/trace_adhoc.go

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/ledgerwatch/erigon/core/types"
2323
"github.com/ledgerwatch/erigon/core/types/accounts"
2424
"github.com/ledgerwatch/erigon/core/vm"
25+
"github.com/ledgerwatch/erigon/eth/tracers"
2526
"github.com/ledgerwatch/erigon/polygon/tracer"
2627
"github.com/ledgerwatch/erigon/rpc"
2728
"github.com/ledgerwatch/erigon/turbo/rpchelper"
@@ -224,7 +225,24 @@ func (args *TraceCallParam) ToMessage(globalGasCap uint64, baseFee *uint256.Int)
224225
return msg, nil
225226
}
226227

227-
// OpenEthereum-style tracer
228+
func parseOeTracerConfig(traceConfig *tracers.TraceConfig) (OeTracerConfig, error) {
229+
if traceConfig == nil || traceConfig.TracerConfig == nil || *traceConfig.TracerConfig == nil {
230+
return OeTracerConfig{}, nil
231+
}
232+
233+
var config OeTracerConfig
234+
if err := json.Unmarshal(*traceConfig.TracerConfig, &config); err != nil {
235+
return OeTracerConfig{}, err
236+
}
237+
238+
return config, nil
239+
}
240+
241+
type OeTracerConfig struct {
242+
IncludePrecompiles bool `json:"includePrecompiles"` // by default Parity/OpenEthereum format does not include precompiles
243+
}
244+
245+
// OeTracer is an OpenEthereum-style tracer
228246
type OeTracer struct {
229247
r *TraceCallResult
230248
traceAddr []int
@@ -240,6 +258,7 @@ type OeTracer struct {
240258
lastOffStack *VmTraceOp
241259
vmOpStack []*VmTraceOp // Stack of vmTrace operations as call depth increases
242260
idx []string // Prefix for the "idx" inside operations, for easier navigation
261+
config OeTracerConfig
243262
}
244263

245264
func (ot *OeTracer) CaptureTxStart(gasLimit uint64) {}
@@ -279,7 +298,9 @@ func (ot *OeTracer) captureStartOrEnter(deep bool, typ vm.OpCode, from libcommon
279298
}
280299
if precompile && deep && (value == nil || value.IsZero()) {
281300
ot.precompile = true
282-
return
301+
if !ot.config.IncludePrecompiles {
302+
return
303+
}
283304
}
284305
if gas > 500000000 {
285306
gas = 500000001 - (0x8000000000000000 - gas)
@@ -378,7 +399,9 @@ func (ot *OeTracer) captureEndOrExit(deep bool, output []byte, usedGas uint64, e
378399
}
379400
if ot.precompile {
380401
ot.precompile = false
381-
return
402+
if !ot.config.IncludePrecompiles {
403+
return
404+
}
382405
}
383406
if !deep {
384407
ot.r.Output = libcommon.CopyBytes(output)
@@ -711,7 +734,7 @@ func (sd *StateDiff) CompareStates(initialIbs, ibs *state.IntraBlockState) {
711734
}
712735
}
713736

714-
func (api *TraceAPIImpl) ReplayTransaction(ctx context.Context, txHash libcommon.Hash, traceTypes []string, gasBailOut *bool) (*TraceCallResult, error) {
737+
func (api *TraceAPIImpl) ReplayTransaction(ctx context.Context, txHash libcommon.Hash, traceTypes []string, gasBailOut *bool, traceConfig *tracers.TraceConfig) (*TraceCallResult, error) {
715738
if gasBailOut == nil {
716739
gasBailOut = new(bool) // false by default
717740
}
@@ -770,7 +793,7 @@ func (api *TraceAPIImpl) ReplayTransaction(ctx context.Context, txHash libcommon
770793

771794
signer := types.MakeSigner(chainConfig, blockNum, block.Time())
772795
// Returns an array of trace arrays, one trace array for each transaction
773-
traces, _, err := api.callManyTransactions(ctx, tx, block, traceTypes, txnIndex, *gasBailOut, signer, chainConfig)
796+
traces, _, err := api.callManyTransactions(ctx, tx, block, traceTypes, txnIndex, *gasBailOut, signer, chainConfig, traceConfig)
774797
if err != nil {
775798
return nil, err
776799
}
@@ -811,7 +834,7 @@ func (api *TraceAPIImpl) ReplayTransaction(ctx context.Context, txHash libcommon
811834
return result, nil
812835
}
813836

814-
func (api *TraceAPIImpl) ReplayBlockTransactions(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, traceTypes []string, gasBailOut *bool) ([]*TraceCallResult, error) {
837+
func (api *TraceAPIImpl) ReplayBlockTransactions(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, traceTypes []string, gasBailOut *bool, traceConfig *tracers.TraceConfig) ([]*TraceCallResult, error) {
815838
if gasBailOut == nil {
816839
gasBailOut = new(bool) // false by default
817840
}
@@ -854,7 +877,7 @@ func (api *TraceAPIImpl) ReplayBlockTransactions(ctx context.Context, blockNrOrH
854877

855878
signer := types.MakeSigner(chainConfig, blockNumber, block.Time())
856879
// Returns an array of trace arrays, one trace array for each transaction
857-
traces, _, err := api.callManyTransactions(ctx, tx, block, traceTypes, -1 /* all tx indices */, *gasBailOut, signer, chainConfig)
880+
traces, _, err := api.callManyTransactions(ctx, tx, block, traceTypes, -1 /* all tx indices */, *gasBailOut, signer, chainConfig, traceConfig)
858881
if err != nil {
859882
return nil, err
860883
}
@@ -882,7 +905,7 @@ func (api *TraceAPIImpl) ReplayBlockTransactions(ctx context.Context, blockNrOrH
882905
}
883906

884907
// Call implements trace_call.
885-
func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTypes []string, blockNrOrHash *rpc.BlockNumberOrHash) (*TraceCallResult, error) {
908+
func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTypes []string, blockNrOrHash *rpc.BlockNumberOrHash, traceConfig *tracers.TraceConfig) (*TraceCallResult, error) {
886909
tx, err := api.kv.BeginRo(ctx)
887910
if err != nil {
888911
return nil, err
@@ -952,6 +975,10 @@ func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTyp
952975
traceResult.VmTrace = &VmTrace{Ops: []*VmTraceOp{}}
953976
}
954977
var ot OeTracer
978+
ot.config, err = parseOeTracerConfig(traceConfig)
979+
if err != nil {
980+
return nil, err
981+
}
955982
ot.compat = api.compatibility
956983
if traceTypeTrace || traceTypeVmTrace {
957984
ot.r = traceResult
@@ -1016,7 +1043,7 @@ func (api *TraceAPIImpl) Call(ctx context.Context, args TraceCallParam, traceTyp
10161043
}
10171044

10181045
// CallMany implements trace_callMany.
1019-
func (api *TraceAPIImpl) CallMany(ctx context.Context, calls json.RawMessage, parentNrOrHash *rpc.BlockNumberOrHash) ([]*TraceCallResult, error) {
1046+
func (api *TraceAPIImpl) CallMany(ctx context.Context, calls json.RawMessage, parentNrOrHash *rpc.BlockNumberOrHash, traceConfig *tracers.TraceConfig) ([]*TraceCallResult, error) {
10201047
dbtx, err := api.kv.BeginRo(ctx)
10211048
if err != nil {
10221049
return nil, err
@@ -1096,12 +1123,13 @@ func (api *TraceAPIImpl) CallMany(ctx context.Context, calls json.RawMessage, pa
10961123
return nil, fmt.Errorf("convert callParam to msg: %w", err)
10971124
}
10981125
}
1099-
results, _, err := api.doCallMany(ctx, dbtx, msgs, callParams, parentNrOrHash, nil, true /* gasBailout */, -1 /* all tx indices */)
1126+
results, _, err := api.doCallMany(ctx, dbtx, msgs, callParams, parentNrOrHash, nil, true /* gasBailout */, -1 /* all tx indices */, traceConfig)
11001127
return results, err
11011128
}
11021129

11031130
func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []types.Message, callParams []TraceCallParam,
11041131
parentNrOrHash *rpc.BlockNumberOrHash, header *types.Header, gasBailout bool, txIndexNeeded int,
1132+
traceConfig *tracers.TraceConfig,
11051133
) ([]*TraceCallResult, *state.IntraBlockState, error) {
11061134
chainConfig, err := api.chainConfig(ctx, dbtx)
11071135
if err != nil {
@@ -1184,6 +1212,10 @@ func (api *TraceAPIImpl) doCallMany(ctx context.Context, dbtx kv.Tx, msgs []type
11841212
vmConfig := vm.Config{}
11851213
if (traceTypeTrace && (txIndexNeeded == -1 || txIndex == txIndexNeeded)) || traceTypeVmTrace {
11861214
var ot OeTracer
1215+
ot.config, err = parseOeTracerConfig(traceConfig)
1216+
if err != nil {
1217+
return nil, nil, err
1218+
}
11871219
ot.compat = api.compatibility
11881220
ot.r = traceResult
11891221
ot.idx = []string{fmt.Sprintf("%d-", txIndex)}

0 commit comments

Comments
 (0)