Skip to content
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
13 changes: 3 additions & 10 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ var (
VMTraceConfigFlag = &cli.StringFlag{
Name: "vmtrace.config",
Usage: "Tracer configuration (JSON)",
Value: "{}",
Category: flags.VMCategory,
}
RPCGlobalGasCapFlag = &cli.Uint64Flag{
Expand Down Expand Up @@ -2147,13 +2148,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// VM tracing config.
if ctx.IsSet(VMTraceFlag.Name) {
if name := ctx.String(VMTraceFlag.Name); name != "" {
var config string
if ctx.IsSet(VMTraceConfigFlag.Name) {
config = ctx.String(VMTraceConfigFlag.Name)
}

cfg.VMTrace = name
cfg.VMTraceConfig = config
cfg.VMTraceConfig = ctx.String(VMTraceConfigFlag.Name)
}
}
if ctx.IsSet(DisableTxBroadcastFromFlag.Name) {
Expand Down Expand Up @@ -2428,10 +2424,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)}
if ctx.IsSet(VMTraceFlag.Name) {
if name := ctx.String(VMTraceFlag.Name); name != "" {
var config json.RawMessage
if ctx.IsSet(VMTraceConfigFlag.Name) {
config = json.RawMessage(ctx.String(VMTraceConfigFlag.Name))
}
config := json.RawMessage(ctx.String(VMTraceConfigFlag.Name))
t, err := tracers.LiveDirectory.New(name, config)
if err != nil {
Fatalf("Failed to create tracer %q: %v", name, err)
Expand Down
5 changes: 2 additions & 3 deletions core/tracing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ type VMContext struct {
BlockNumber *big.Int
Time uint64
// Effective tx gas price
GasPrice *big.Int
ChainConfig *params.ChainConfig
StateDB StateDB
GasPrice *big.Int
StateDB StateDB
}

// BlockEvent is emitted upon tracing an incoming block.
Expand Down
1 change: 0 additions & 1 deletion core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,6 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
BlockNumber: evm.Context.BlockNumber,
Time: evm.Context.Time,
GasPrice: evm.TxContext.GasPrice,
ChainConfig: evm.ChainConfig(),
StateDB: evm.StateDB,
}
}
6 changes: 3 additions & 3 deletions core/vm/runtime/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
cfg.GasLimit = gas
if len(tracerCode) > 0 {
tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil)
tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil, cfg.ChainConfig)
if err != nil {
b.Fatal(err)
}
Expand Down Expand Up @@ -826,7 +826,7 @@ func TestRuntimeJSTracer(t *testing.T) {
statedb.SetCode(common.HexToAddress("0xee"), calleeCode)
statedb.SetCode(common.HexToAddress("0xff"), depressedCode)

tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil, params.MainnetChainConfig)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -861,7 +861,7 @@ func TestJSTracerCreateTx(t *testing.T) {
code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)}

statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil, params.MainnetChainConfig)
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,7 @@ func (api *API) traceTx(
Stop: logger.Stop,
}
} else {
tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig, api.backend.ChainConfig())
if err != nil {
return nil, err
}
Expand Down
14 changes: 9 additions & 5 deletions eth/tracers/dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/params"
)

// Context contains some contextual infos for a transaction execution that is not
Expand All @@ -44,8 +45,8 @@ type Tracer struct {
Stop func(err error)
}

type ctorFn func(*Context, json.RawMessage) (*Tracer, error)
type jsCtorFn func(string, *Context, json.RawMessage) (*Tracer, error)
type ctorFn func(*Context, json.RawMessage, *params.ChainConfig) (*Tracer, error)
type jsCtorFn func(string, *Context, json.RawMessage, *params.ChainConfig) (*Tracer, error)

type elem struct {
ctor ctorFn
Expand Down Expand Up @@ -78,12 +79,15 @@ func (d *directory) RegisterJSEval(f jsCtorFn) {
// New returns a new instance of a tracer, by iterating through the
// registered lookups. Name is either name of an existing tracer
// or an arbitrary JS code.
func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (*Tracer, error) {
func (d *directory) New(name string, ctx *Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*Tracer, error) {
if len(cfg) == 0 {
cfg = json.RawMessage("{}")
}
if elem, ok := d.elems[name]; ok {
return elem.ctor(ctx, cfg)
return elem.ctor(ctx, cfg, chainConfig)
}
// Assume JS code
return d.jsEval(name, ctx, cfg)
return d.jsEval(name, ctx, cfg, chainConfig)
}

// IsJS will return true if the given tracer will evaluate
Expand Down
9 changes: 5 additions & 4 deletions eth/tracers/internal/tracetest/calltrace2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func testCallTracer2(tracerName string, dirPath string, scheme string, t *testin
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, scheme)
)
defer triedb.Close()
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
Expand Down Expand Up @@ -276,7 +276,7 @@ func benchTracer2(tracerName string, test *callTracer2Test, b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
b.Fatalf("failed to create call tracer: %v", err)
}
Expand Down Expand Up @@ -343,16 +343,17 @@ func TestZeroValueToNotExitCall2(t *testing.T) {
}
triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme)
defer triedb.Close()
chainConfig := params.MainnetChainConfig
// Create the tracer, the EVM environment and run it
tracer, err := tracers.DefaultDirectory.New("callTracer2", new(tracers.Context), nil)
tracer, err := tracers.DefaultDirectory.New("callTracer2", new(tracers.Context), nil, chainConfig)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer.Hooks})
evm := vm.NewEVM(context, txContext, statedb, chainConfig, vm.Config{Debug: true, Tracer: tracer.Hooks})
statedb.SetLogger(tracer.Hooks)
tracer.OnTxStart(evm.GetVMContext(), tx, msg.Payer)
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
Expand Down
6 changes: 3 additions & 3 deletions eth/tracers/internal/tracetest/calltrace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func testCallTracer(tracerName string, dirPath string, scheme string, t *testing
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, scheme)
)
triedb.Close()
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
Expand Down Expand Up @@ -253,7 +253,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config)
if err != nil {
b.Fatalf("failed to create call tracer: %v", err)
}
Expand Down Expand Up @@ -290,7 +290,7 @@ func TestInternals(t *testing.T) {
}
)
mkTracer := func(name string, cfg json.RawMessage) *tracers.Tracer {
tr, err := tracers.DefaultDirectory.New(name, nil, cfg)
tr, err := tracers.DefaultDirectory.New(name, nil, cfg, config)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion eth/tracers/internal/tracetest/flat_calltrace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
defer triedb.Close()

// Create the tracer, the EVM environment and run it
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
return fmt.Errorf("failed to create call tracer: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion eth/tracers/internal/tracetest/prestate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, scheme string, t
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, scheme)
)
defer triedb.Close()
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
Expand Down
17 changes: 10 additions & 7 deletions eth/tracers/js/goja.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/eth/tracers/internal"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"

"github.com/ethereum/go-ethereum/common"
Expand All @@ -45,10 +46,10 @@ func init() {
if err != nil {
panic(err)
}
type ctorFn = func(*tracers.Context, json.RawMessage) (*tracers.Tracer, error)
type ctorFn = func(*tracers.Context, json.RawMessage, *params.ChainConfig) (*tracers.Tracer, error)
lookup := func(code string) ctorFn {
return func(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
return newJsTracer(code, ctx, cfg)
return func(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
return newJsTracer(code, ctx, cfg, chainConfig)
}
}
for name, code := range assetTracers {
Expand Down Expand Up @@ -101,6 +102,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b
type jsTracer struct {
vm *goja.Runtime
env *tracing.VMContext
chainConfig *params.ChainConfig
toBig toBigFn // Converts a hex string into a JS bigint
toBuf toBufFn // Converts a []byte into a JS buffer
fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte
Expand Down Expand Up @@ -137,13 +139,14 @@ type jsTracer struct {
// The methods `result` and `fault` are required to be present.
// The methods `step`, `enter`, and `exit` are optional, but note that
// `enter` and `exit` always go together.
func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
vm := goja.New()
// By default field names are exported to JS as is, i.e. capitalized.
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
t := &jsTracer{
vm: vm,
ctx: make(map[string]goja.Value),
vm: vm,
ctx: make(map[string]goja.Value),
chainConfig: chainConfig,
}

t.setTypeConverters()
Expand Down Expand Up @@ -243,7 +246,7 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from
db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf}
t.dbValue = db.setupObject()
// Update list of precompiles based on current block
rules := env.ChainConfig.Rules(env.BlockNumber)
rules := t.chainConfig.Rules(env.BlockNumber)
t.activePrecompiles = vm.ActivePrecompiles(rules)
t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
t.ctx["gas"] = t.vm.ToValue(tx.Gas())
Expand Down
34 changes: 20 additions & 14 deletions eth/tracers/js/tracer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo
func TestTracer(t *testing.T) {
execTracer := func(code string, contract []byte) ([]byte, string) {
t.Helper()
tracer, err := newJsTracer(code, nil, nil)
chainConfig := params.TestChainConfig
tracer, err := newJsTracer(code, nil, nil, chainConfig)
if err != nil {
t.Fatal(err)
}
ret, err := runTrace(tracer, testCtx(), params.TestChainConfig, contract)
ret, err := runTrace(tracer, testCtx(), chainConfig, contract)
if err != nil {
return nil, err.Error() // Stringify to allow comparison without nil checks
}
Expand Down Expand Up @@ -164,7 +165,8 @@ func TestTracer(t *testing.T) {

func TestHalt(t *testing.T) {
timeout := errors.New("stahp")
tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil, nil)
chainConfig := params.TestChainConfig
tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil, nil, chainConfig)
if err != nil {
t.Fatal(err)
}
Expand All @@ -178,7 +180,8 @@ func TestHalt(t *testing.T) {
}

func TestHaltBetweenSteps(t *testing.T) {
tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil, nil)
chainConfig := params.TestChainConfig
tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil, nil, chainConfig)
if err != nil {
t.Fatal(err)
}
Expand All @@ -203,11 +206,12 @@ func TestHaltBetweenSteps(t *testing.T) {
func TestNoStepExec(t *testing.T) {
execTracer := func(code string) []byte {
t.Helper()
tracer, err := newJsTracer(code, nil, nil)
chainConfig := params.TestChainConfig
tracer, err := newJsTracer(code, nil, nil, chainConfig)
if err != nil {
t.Fatal(err)
}
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks})
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks})
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0), 0)
tracer.OnExit(0, nil, 0, nil, false)
Expand Down Expand Up @@ -238,7 +242,7 @@ func TestIsPrecompile(t *testing.T) {
chaincfg.IstanbulBlock = big.NewInt(200)
chaincfg.BerlinBlock = big.NewInt(300)
txCtx := vm.TxContext{GasPrice: big.NewInt(100000)}
tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil)
tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil, chaincfg)
if err != nil {
t.Fatal(err)
}
Expand All @@ -252,7 +256,7 @@ func TestIsPrecompile(t *testing.T) {
t.Errorf("tracer should not consider blake2f as precompile in byzantium")
}

tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil)
tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil, chaincfg)
blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)}
res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg, nil)
if err != nil {
Expand All @@ -264,15 +268,16 @@ func TestIsPrecompile(t *testing.T) {
}

func TestEnterExit(t *testing.T) {
chainConfig := params.TestChainConfig
// test that either both or none of enter() and exit() are defined
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil); err == nil {
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil, chainConfig); err == nil {
t.Fatal("tracer creation should've failed without exit() definition")
}
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil); err != nil {
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil, chainConfig); err != nil {
t.Fatal(err)
}
// test that the enter and exit method are correctly invoked and the values passed
tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil)
tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil, chainConfig)
if err != nil {
t.Fatal(err)
}
Expand All @@ -293,8 +298,9 @@ func TestEnterExit(t *testing.T) {
}

func TestSetup(t *testing.T) {
chainConfig := params.TestChainConfig
// Test empty config
_, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil)
_, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil, chainConfig)
if err != nil {
t.Error(err)
}
Expand All @@ -304,12 +310,12 @@ func TestSetup(t *testing.T) {
t.Fatal(err)
}
// Test no setup func
_, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg)
_, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg, chainConfig)
if err != nil {
t.Fatal(err)
}
// Test config value
tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg)
tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg, chainConfig)
if err != nil {
t.Fatal(err)
}
Expand Down
3 changes: 3 additions & 0 deletions eth/tracers/live.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ func (d *liveDirectory) Register(name string, f ctorFunc) {

// New instantiates a tracer by name.
func (d *liveDirectory) New(name string, config json.RawMessage) (*tracing.Hooks, error) {
if len(config) == 0 {
config = json.RawMessage("{}")
}
if f, ok := d.elems[name]; ok {
return f(config)
}
Expand Down
Loading