mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-22 14:44:30 +00:00
Here we add a Go API for running tracing plugins within the main block import process. As an advanced user of geth, you can now create a Go file in eth/tracers/live/, and within that file register your custom tracer implementation. Then recompile geth and select your tracer on the command line. Hooks defined in the tracer will run whenever a block is processed. The hook system is defined in package core/tracing. It uses a struct with callbacks, instead of requiring an interface, for several reasons: - We plan to keep this API stable long-term. The core/tracing hook API does not depend on on deep geth internals. - There are a lot of hooks, and tracers will only need some of them. Using a struct allows you to implement only the hooks you want to actually use. All existing tracers in eth/tracers/native have been rewritten to use the new hook system. This change breaks compatibility with the vm.EVMLogger interface that we used to have. If you are a user of vm.EVMLogger, please migrate to core/tracing, and sorry for breaking your stuff. But we just couldn't have both the old and new tracing APIs coexist in the EVM. --------- Co-authored-by: Sina M <1591639+s1na@users.noreply.github.com> Co-authored-by: Matthieu Vachon <matthieu.o.vachon@gmail.com> Co-authored-by: Delweng <delweng@gmail.com> Co-authored-by: Martin HS <martin@swende.se>
120 lines
3.2 KiB
Go
120 lines
3.2 KiB
Go
package native
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/big"
|
|
"strings"
|
|
"sync/atomic"
|
|
|
|
"github.com/XinFinOrg/XDPoSChain/common"
|
|
"github.com/XinFinOrg/XDPoSChain/core/tracing"
|
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
|
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
|
"github.com/XinFinOrg/XDPoSChain/eth/tracers"
|
|
)
|
|
|
|
func init() {
|
|
tracers.DefaultDirectory.Register("contractTracer", NewContractTracer, false)
|
|
}
|
|
|
|
type contractTracer struct {
|
|
Addrs map[string]string
|
|
config contractTracerConfig
|
|
interrupt uint32 // Atomic flag to signal execution interruption
|
|
reason error // Textual reason for the interruption
|
|
}
|
|
|
|
type contractTracerConfig struct {
|
|
OpCode string `json:"opCode"` // Target opcode to trace
|
|
}
|
|
|
|
// NewContractTracer returns a native go tracer which tracks the contracr was created
|
|
func NewContractTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
|
var config contractTracerConfig
|
|
if cfg != nil {
|
|
if err := json.Unmarshal(cfg, &config); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
t := &contractTracer{
|
|
Addrs: make(map[string]string, 1),
|
|
config: config,
|
|
}
|
|
// handle invalid opcode case
|
|
op := vm.StringToOp(t.config.OpCode)
|
|
if op == 0 && t.config.OpCode != "STOP" && t.config.OpCode != "" {
|
|
t.reason = fmt.Errorf("opcode %s not defined", t.config.OpCode)
|
|
return nil, t.reason
|
|
}
|
|
return &tracers.Tracer{
|
|
Hooks: &tracing.Hooks{
|
|
OnTxStart: t.OnTxStart,
|
|
OnTxEnd: t.OnTxEnd,
|
|
OnEnter: t.OnEnter,
|
|
OnExit: t.OnExit,
|
|
OnOpcode: t.OnOpcode,
|
|
OnFault: t.OnFault,
|
|
},
|
|
GetResult: t.GetResult,
|
|
Stop: t.Stop,
|
|
}, nil
|
|
}
|
|
|
|
func (*contractTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
|
}
|
|
|
|
func (*contractTracer) OnTxEnd(receipt *types.Receipt, err error) {}
|
|
|
|
func (t *contractTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
|
// Skip if tracing was interrupted
|
|
if atomic.LoadUint32(&t.interrupt) > 0 {
|
|
return
|
|
}
|
|
// If the OpCode is empty , exit early.
|
|
if t.config.OpCode == "" {
|
|
return
|
|
}
|
|
targetOp := vm.StringToOp(t.config.OpCode)
|
|
op := vm.OpCode(opcode)
|
|
if op == targetOp {
|
|
addr := scope.Address()
|
|
t.Addrs[addrToHex(addr)] = ""
|
|
}
|
|
}
|
|
|
|
func (t *contractTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
|
|
}
|
|
|
|
func (t *contractTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
|
create := vm.OpCode(typ) == vm.CREATE
|
|
if create && t.config.OpCode == "" {
|
|
t.Addrs[addrToHex(to)] = ""
|
|
}
|
|
}
|
|
|
|
func (t *contractTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
|
}
|
|
|
|
func (t *contractTracer) GetResult() (json.RawMessage, error) {
|
|
// return Address array without duplicate address
|
|
AddrArray := make([]string, 0, len(t.Addrs))
|
|
for addr := range t.Addrs {
|
|
AddrArray = append(AddrArray, addr)
|
|
}
|
|
|
|
res, err := json.Marshal(AddrArray)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return json.RawMessage(res), t.reason
|
|
}
|
|
|
|
func (t *contractTracer) Stop(err error) {
|
|
t.reason = err
|
|
atomic.StoreUint32(&t.interrupt, 1)
|
|
}
|
|
|
|
func addrToHex(a common.Address) string {
|
|
return strings.ToLower(a.String0x())
|
|
}
|