From 97cf240fe0bc7bec20b697d16b6733f65246a21b Mon Sep 17 00:00:00 2001 From: Austin Roberts Date: Fri, 25 Jun 2021 13:55:31 -0500 Subject: [PATCH] Add tracer hooks for debug_traceCall, etc. --- eth/tracers/api.go | 30 ++++++++++++++++++------------ plugins/plugin_loader.go | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 65bf84dc4..d02f35730 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -40,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/plugins" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" ) @@ -799,19 +800,24 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac return nil, err } } - // Constuct the JavaScript tracer to execute with - if tracer, err = New(*config.Tracer, txContext); err != nil { - return nil, err - } - // Handle timeouts and RPC cancellations - deadlineCtx, cancel := context.WithTimeout(ctx, timeout) - go func() { - <-deadlineCtx.Done() - if deadlineCtx.Err() == context.DeadlineExceeded { - tracer.(*Tracer).Stop(errors.New("execution timeout")) + // Get the tracer from the plugin loader + if tr, ok := plugins.GetTracer(*config.Tracer); ok { + tracer = tr(statedb) + } else { + // Constuct the JavaScript tracer to execute with + if tracer, err = New(*config.Tracer, txContext); err != nil { + return nil, err } - }() - defer cancel() + // Handle timeouts and RPC cancellations + deadlineCtx, cancel := context.WithTimeout(ctx, timeout) + go func() { + <-deadlineCtx.Done() + if deadlineCtx.Err() == context.DeadlineExceeded { + tracer.(*Tracer).Stop(errors.New("execution timeout")) + } + }() + defer cancel() + } case config == nil: tracer = vm.NewStructLogger(nil) diff --git a/plugins/plugin_loader.go b/plugins/plugin_loader.go index 35290575c..a843678b7 100644 --- a/plugins/plugin_loader.go +++ b/plugins/plugin_loader.go @@ -5,6 +5,8 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/core/state" "gopkg.in/urfave/cli.v1" "flag" "io/ioutil" @@ -19,7 +21,7 @@ type Subcommand func(*cli.Context, []string) error type PluginLoader struct{ - TracerPlugins map[string]interface{} // TODO: Set interface + Tracers map[string]func(*state.StateDB)vm.Tracer StateHooks []interface{} // TODO: Set interface ChainEventHooks []interface{} // TODO: Set interface RPCPlugins []APILoader @@ -76,7 +78,7 @@ func NewPluginLoader(target string) (*PluginLoader, error) { if err == nil { subcommands, ok := sb.(map[string]func(*cli.Context, []string) error) if !ok { - log.Warn("Could not cast plugin.Subocmmands to `map[string]func(*cli.Context, []string) error`", "file", fpath) + log.Warn("Could not cast plugin.Subcommands to `map[string]func(*cli.Context, []string) error`", "file", fpath) } else { for k, v := range subcommands { if _, ok := pl.Subcommands[k]; ok { @@ -86,6 +88,20 @@ func NewPluginLoader(target string) (*PluginLoader, error) { } } } + tr, err := plug.Lookup("Tracers") + if err == nil { + tracers, ok := tr.(map[string]func(*state.StateDB)vm.Tracer) + if !ok { + log.Warn("Could not cast plugin.Tracers to `map[string]vm.Tracer`", "file", fpath) + } else { + for k, v := range tracers { + if _, ok := pl.Tracers[k]; ok { + log.Warn("Tracer redeclared", "file", fpath, "tracer", k) + } + pl.Tracers[k] = v + } + } + } } return pl, nil } @@ -133,8 +149,21 @@ func (pl *PluginLoader) GetAPIs(stack *node.Node, backend Backend) []rpc.API { func GetAPIs(stack *node.Node, backend Backend) []rpc.API { if defaultPluginLoader == nil { - log.Warn("Attempting GetAPIs ,but default PluginLoader has not been initialized") + log.Warn("Attempting GetAPIs, but default PluginLoader has not been initialized") return []rpc.API{} } return defaultPluginLoader.GetAPIs(stack, backend) } + +func (pl *PluginLoader) GetTracer(s string) (func(*state.StateDB)vm.Tracer, bool) { + tr, ok := pl.Tracers[s] + return tr, ok +} + +func GetTracer(s string) (func(*state.StateDB)vm.Tracer, bool) { + if defaultPluginLoader == nil { + log.Warn("Attempting GetTracer, but default PluginLoader has not been initialized") + return nil, false + } + return defaultPluginLoader.GetTracer(s) +}