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 }