github.com/ethereum/go-ethereum@v1.16.1/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  	"github.com/ethereum/go-ethereum/params"
    28  )
    29  
    30  func init() {
    31  	tracers.DefaultDirectory.Register("muxTracer", newMuxTracer, false)
    32  }
    33  
    34  // muxTracer is a go implementation of the Tracer interface which
    35  // runs multiple tracers in one go.
    36  type muxTracer struct {
    37  	names   []string
    38  	tracers []*tracers.Tracer
    39  }
    40  
    41  // newMuxTracer returns a new mux tracer.
    42  func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
    43  	var config map[string]json.RawMessage
    44  	if err := json.Unmarshal(cfg, &config); err != nil {
    45  		return nil, err
    46  	}
    47  	objects := make([]*tracers.Tracer, 0, len(config))
    48  	names := make([]string, 0, len(config))
    49  	for k, v := range config {
    50  		t, err := tracers.DefaultDirectory.New(k, ctx, v, chainConfig)
    51  		if err != nil {
    52  			return nil, err
    53  		}
    54  		objects = append(objects, t)
    55  		names = append(names, k)
    56  	}
    57  
    58  	t := &muxTracer{names: names, tracers: objects}
    59  	return &tracers.Tracer{
    60  		Hooks: &tracing.Hooks{
    61  			OnTxStart:       t.OnTxStart,
    62  			OnTxEnd:         t.OnTxEnd,
    63  			OnEnter:         t.OnEnter,
    64  			OnExit:          t.OnExit,
    65  			OnOpcode:        t.OnOpcode,
    66  			OnFault:         t.OnFault,
    67  			OnGasChange:     t.OnGasChange,
    68  			OnBalanceChange: t.OnBalanceChange,
    69  			OnNonceChange:   t.OnNonceChange,
    70  			OnCodeChange:    t.OnCodeChange,
    71  			OnStorageChange: t.OnStorageChange,
    72  			OnLog:           t.OnLog,
    73  		},
    74  		GetResult: t.GetResult,
    75  		Stop:      t.Stop,
    76  	}, nil
    77  }
    78  
    79  func (t *muxTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
    80  	for _, t := range t.tracers {
    81  		if t.OnOpcode != nil {
    82  			t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err)
    83  		}
    84  	}
    85  }
    86  
    87  func (t *muxTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
    88  	for _, t := range t.tracers {
    89  		if t.OnFault != nil {
    90  			t.OnFault(pc, op, gas, cost, scope, depth, err)
    91  		}
    92  	}
    93  }
    94  
    95  func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {
    96  	for _, t := range t.tracers {
    97  		if t.OnGasChange != nil {
    98  			t.OnGasChange(old, new, reason)
    99  		}
   100  	}
   101  }
   102  
   103  func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
   104  	for _, t := range t.tracers {
   105  		if t.OnEnter != nil {
   106  			t.OnEnter(depth, typ, from, to, input, gas, value)
   107  		}
   108  	}
   109  }
   110  
   111  func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
   112  	for _, t := range t.tracers {
   113  		if t.OnExit != nil {
   114  			t.OnExit(depth, output, gasUsed, err, reverted)
   115  		}
   116  	}
   117  }
   118  
   119  func (t *muxTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
   120  	for _, t := range t.tracers {
   121  		if t.OnTxStart != nil {
   122  			t.OnTxStart(env, tx, from)
   123  		}
   124  	}
   125  }
   126  
   127  func (t *muxTracer) OnTxEnd(receipt *types.Receipt, err error) {
   128  	for _, t := range t.tracers {
   129  		if t.OnTxEnd != nil {
   130  			t.OnTxEnd(receipt, err)
   131  		}
   132  	}
   133  }
   134  
   135  func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
   136  	for _, t := range t.tracers {
   137  		if t.OnBalanceChange != nil {
   138  			t.OnBalanceChange(a, prev, new, reason)
   139  		}
   140  	}
   141  }
   142  
   143  func (t *muxTracer) OnNonceChange(a common.Address, prev, new uint64) {
   144  	for _, t := range t.tracers {
   145  		if t.OnNonceChange != nil {
   146  			t.OnNonceChange(a, prev, new)
   147  		}
   148  	}
   149  }
   150  
   151  func (t *muxTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
   152  	for _, t := range t.tracers {
   153  		if t.OnCodeChange != nil {
   154  			t.OnCodeChange(a, prevCodeHash, prev, codeHash, code)
   155  		}
   156  	}
   157  }
   158  
   159  func (t *muxTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {
   160  	for _, t := range t.tracers {
   161  		if t.OnStorageChange != nil {
   162  			t.OnStorageChange(a, k, prev, new)
   163  		}
   164  	}
   165  }
   166  
   167  func (t *muxTracer) OnLog(log *types.Log) {
   168  	for _, t := range t.tracers {
   169  		if t.OnLog != nil {
   170  			t.OnLog(log)
   171  		}
   172  	}
   173  }
   174  
   175  // GetResult returns an empty json object.
   176  func (t *muxTracer) GetResult() (json.RawMessage, error) {
   177  	resObject := make(map[string]json.RawMessage)
   178  	for i, tt := range t.tracers {
   179  		r, err := tt.GetResult()
   180  		if err != nil {
   181  			return nil, err
   182  		}
   183  		resObject[t.names[i]] = r
   184  	}
   185  	res, err := json.Marshal(resObject)
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  	return res, nil
   190  }
   191  
   192  // Stop terminates execution of the tracer at the first opportune moment.
   193  func (t *muxTracer) Stop(err error) {
   194  	for _, t := range t.tracers {
   195  		t.Stop(err)
   196  	}
   197  }