diff --git a/eth/tracers/tracer.go b/eth/tracers/tracer.go index bf4bd634a8..2c52761f5e 100644 --- a/eth/tracers/tracer.go +++ b/eth/tracers/tracer.go @@ -310,6 +310,8 @@ type Tracer struct { interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption + + activePrecompiles []common.Address // Updated on CaptureStart based on given rules } // Context contains some contextual infos for a transaction execution that is not @@ -414,8 +416,14 @@ func New(code string, ctx *Context) (*Tracer, error) { return 1 }) tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int { - _, ok := vm.PrecompiledContractsIstanbul[common.BytesToAddress(popSlice(ctx))] - ctx.PushBoolean(ok) + addr := common.BytesToAddress(popSlice(ctx)) + for _, p := range tracer.activePrecompiles { + if p == addr { + ctx.PushBoolean(true) + return 1 + } + } + ctx.PushBoolean(false) return 1 }) tracer.vm.PushGlobalGoFunction("slice", func(ctx *duktape.Context) int { @@ -570,6 +578,9 @@ func (jst *Tracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr // Initialize the context jst.ctx["block"] = env.Context.BlockNumber.Uint64() jst.dbWrapper.db = env.StateDB + // Update list of precompiles based on current block + rules := env.ChainConfig().Rules(env.Context.BlockNumber) + jst.activePrecompiles = vm.ActivePrecompiles(rules) // Compute intrinsic gas isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) diff --git a/eth/tracers/tracer_test.go b/eth/tracers/tracer_test.go index cd1a8cddc5..d4b3534897 100644 --- a/eth/tracers/tracer_test.go +++ b/eth/tracers/tracer_test.go @@ -58,8 +58,8 @@ func testCtx() *vmContext { return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} } -func runTrace(tracer *Tracer, vmctx *vmContext) (json.RawMessage, error) { - env := vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) +func runTrace(tracer *Tracer, vmctx *vmContext, chaincfg *params.ChainConfig) (json.RawMessage, error) { + env := vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Debug: true, Tracer: tracer}) var ( startGas uint64 = 10000 value = big.NewInt(0) @@ -86,7 +86,7 @@ func TestTracer(t *testing.T) { ret, err := runTrace(tracer, &vmContext{ blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}, - }) + }, params.TestChainConfig) if err != nil { return nil, err.Error() // Stringify to allow comparison without nil checks } @@ -141,7 +141,7 @@ func TestHalt(t *testing.T) { time.Sleep(1 * time.Second) tracer.Stop(timeout) }() - if _, err = runTrace(tracer, testCtx()); err.Error() != "stahp in server-side tracer function 'step'" { + if _, err = runTrace(tracer, testCtx(), params.TestChainConfig); err.Error() != "stahp in server-side tracer function 'step'" { t.Errorf("Expected timeout error, got %v", err) } } @@ -205,3 +205,34 @@ func TestNoStepExec(t *testing.T) { } } } + +func TestIsPrecompile(t *testing.T) { + chaincfg := ¶ms.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), EWASMBlock: nil, CatalystBlock: nil, Ethash: new(params.EthashConfig), Clique: nil} + chaincfg.ByzantiumBlock = big.NewInt(100) + chaincfg.IstanbulBlock = big.NewInt(200) + chaincfg.BerlinBlock = big.NewInt(300) + txCtx := vm.TxContext{GasPrice: big.NewInt(100000)} + tracer, err := New("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", new(Context)) + if err != nil { + t.Fatal(err) + } + + blockCtx := vm.BlockContext{BlockNumber: big.NewInt(150)} + res, err := runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg) + if err != nil { + t.Error(err) + } + if string(res) != "false" { + t.Errorf("Tracer should not consider blake2f as precompile in byzantium") + } + + tracer, _ = New("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", new(Context)) + blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)} + res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg) + if err != nil { + t.Error(err) + } + if string(res) != "true" { + t.Errorf("Tracer should consider blake2f as precompile in istanbul") + } +}