github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/eth/tracers/native/mux.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package native
    18  
    19  import (
    20  	"encoding/json"
    21  	"math/big"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/core/tracing"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/eth/tracers"
    27  )
    28  
    29  func init() {
    30  	tracers.DefaultDirectory.Register("muxTracer", newMuxTracer, false)
    31  }
    32  
    33  // muxTracer is a go implementation of the Tracer interface which
    34  // runs multiple tracers in one go.
    35  type muxTracer struct {
    36  	names   []string
    37  	tracers []*tracers.Tracer
    38  }
    39  
    40  // newMuxTracer returns a new mux tracer.
    41  func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
    42  	var config map[string]json.RawMessage
    43  	if cfg != nil {
    44  		if err := json.Unmarshal(cfg, &config); err != nil {
    45  			return nil, err
    46  		}
    47  	}
    48  	objects := make([]*tracers.Tracer, 0, len(config))
    49  	names := make([]string, 0, len(config))
    50  	for k, v := range config {
    51  		t, err := tracers.DefaultDirectory.New(k, ctx, v)
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  		objects = append(objects, t)
    56  		names = append(names, k)
    57  	}
    58  
    59  	t := &muxTracer{names: names, tracers: objects}
    60  	return &tracers.Tracer{
    61  		Hooks: &tracing.Hooks{
    62  			OnTxStart:       t.OnTxStart,
    63  			OnTxEnd:         t.OnTxEnd,
    64  			OnEnter:         t.OnEnter,
    65  			OnExit:          t.OnExit,
    66  			OnOpcode:        t.OnOpcode,
    67  			OnFault:         t.OnFault,
    68  			OnGasChange:     t.OnGasChange,
    69  			OnBalanceChange: t.OnBalanceChange,
    70  			OnNonceChange:   t.OnNonceChange,
    71  			OnCodeChange:    t.OnCodeChange,
    72  			OnStorageChange: t.OnStorageChange,
    73  			OnLog:           t.OnLog,
    74  		},
    75  		GetResult: t.GetResult,
    76  		Stop:      t.Stop,
    77  	}, nil
    78  }
    79  
    80  func (t *muxTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
    81  	for _, t := range t.tracers {
    82  		if t.OnOpcode != nil {
    83  			t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err)
    84  		}
    85  	}
    86  }
    87  
    88  func (t *muxTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
    89  	for _, t := range t.tracers {
    90  		if t.OnFault != nil {
    91  			t.OnFault(pc, op, gas, cost, scope, depth, err)
    92  		}
    93  	}
    94  }
    95  
    96  func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {
    97  	for _, t := range t.tracers {
    98  		if t.OnGasChange != nil {
    99  			t.OnGasChange(old, new, reason)
   100  		}
   101  	}
   102  }
   103  
   104  func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
   105  	for _, t := range t.tracers {
   106  		if t.OnEnter != nil {
   107  			t.OnEnter(depth, typ, from, to, input, gas, value)
   108  		}
   109  	}
   110  }
   111  
   112  func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
   113  	for _, t := range t.tracers {
   114  		if t.OnExit != nil {
   115  			t.OnExit(depth, output, gasUsed, err, reverted)
   116  		}
   117  	}
   118  }
   119  
   120  func (t *muxTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
   121  	for _, t := range t.tracers {
   122  		if t.OnTxStart != nil {
   123  			t.OnTxStart(env, tx, from)
   124  		}
   125  	}
   126  }
   127  
   128  func (t *muxTracer) OnTxEnd(receipt *types.Receipt, err error) {
   129  	for _, t := range t.tracers {
   130  		if t.OnTxEnd != nil {
   131  			t.OnTxEnd(receipt, err)
   132  		}
   133  	}
   134  }
   135  
   136  func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
   137  	for _, t := range t.tracers {
   138  		if t.OnBalanceChange != nil {
   139  			t.OnBalanceChange(a, prev, new, reason)
   140  		}
   141  	}
   142  }
   143  
   144  func (t *muxTracer) OnNonceChange(a common.Address, prev, new uint64) {
   145  	for _, t := range t.tracers {
   146  		if t.OnNonceChange != nil {
   147  			t.OnNonceChange(a, prev, new)
   148  		}
   149  	}
   150  }
   151  
   152  func (t *muxTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
   153  	for _, t := range t.tracers {
   154  		if t.OnCodeChange != nil {
   155  			t.OnCodeChange(a, prevCodeHash, prev, codeHash, code)
   156  		}
   157  	}
   158  }
   159  
   160  func (t *muxTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {
   161  	for _, t := range t.tracers {
   162  		if t.OnStorageChange != nil {
   163  			t.OnStorageChange(a, k, prev, new)
   164  		}
   165  	}
   166  }
   167  
   168  func (t *muxTracer) OnLog(log *types.Log) {
   169  	for _, t := range t.tracers {
   170  		if t.OnLog != nil {
   171  			t.OnLog(log)
   172  		}
   173  	}
   174  }
   175  
   176  // GetResult returns an empty json object.
   177  func (t *muxTracer) GetResult() (json.RawMessage, error) {
   178  	resObject := make(map[string]json.RawMessage)
   179  	for i, tt := range t.tracers {
   180  		r, err := tt.GetResult()
   181  		if err != nil {
   182  			return nil, err
   183  		}
   184  		resObject[t.names[i]] = r
   185  	}
   186  	res, err := json.Marshal(resObject)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	return res, nil
   191  }
   192  
   193  // Stop terminates execution of the tracer at the first opportune moment.
   194  func (t *muxTracer) Stop(err error) {
   195  	for _, t := range t.tracers {
   196  		t.Stop(err)
   197  	}
   198  }