github.com/MetalBlockchain/subnet-evm@v0.4.9/eth/tracers/native/4byte.go (about) 1 // (c) 2020-2021, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2021 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package native 28 29 import ( 30 "encoding/json" 31 "math/big" 32 "strconv" 33 "sync/atomic" 34 "time" 35 36 "github.com/MetalBlockchain/subnet-evm/core/vm" 37 "github.com/MetalBlockchain/subnet-evm/eth/tracers" 38 "github.com/ethereum/go-ethereum/common" 39 ) 40 41 func init() { 42 register("4byteTracer", newFourByteTracer) 43 } 44 45 // fourByteTracer searches for 4byte-identifiers, and collects them for post-processing. 46 // It collects the methods identifiers along with the size of the supplied data, so 47 // a reversed signature can be matched against the size of the data. 48 // 49 // Example: 50 // > debug.traceTransaction( "0x214e597e35da083692f5386141e69f47e973b2c56e7a8073b1ea08fd7571e9de", {tracer: "4byteTracer"}) 51 // { 52 // 0x27dc297e-128: 1, 53 // 0x38cc4831-0: 2, 54 // 0x524f3889-96: 1, 55 // 0xadf59f99-288: 1, 56 // 0xc281d19e-0: 1 57 // } 58 type fourByteTracer struct { 59 env *vm.EVM 60 ids map[string]int // ids aggregates the 4byte ids found 61 interrupt uint32 // Atomic flag to signal execution interruption 62 reason error // Textual reason for the interruption 63 activePrecompiles []common.Address // Updated on CaptureStart based on given rules 64 } 65 66 // newFourByteTracer returns a native go tracer which collects 67 // 4 byte-identifiers of a tx, and implements vm.EVMLogger. 68 func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { 69 t := &fourByteTracer{ 70 ids: make(map[string]int), 71 } 72 return t, nil 73 } 74 75 // isPrecompiled returns whether the addr is a precompile. Logic borrowed from newJsTracer in eth/tracers/js/tracer.go 76 func (t *fourByteTracer) isPrecompiled(addr common.Address) bool { 77 for _, p := range t.activePrecompiles { 78 if p == addr { 79 return true 80 } 81 } 82 return false 83 } 84 85 // store saves the given identifier and datasize. 86 func (t *fourByteTracer) store(id []byte, size int) { 87 key := bytesToHex(id) + "-" + strconv.Itoa(size) 88 t.ids[key] += 1 89 } 90 91 // CaptureStart implements the EVMLogger interface to initialize the tracing operation. 92 func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { 93 t.env = env 94 95 // Update list of precompiles based on current block 96 rules := env.ChainConfig().AvalancheRules(env.Context.BlockNumber, env.Context.Time) 97 t.activePrecompiles = vm.ActivePrecompiles(rules) 98 99 // Save the outer calldata also 100 if len(input) >= 4 { 101 t.store(input[0:4], len(input)-4) 102 } 103 } 104 105 // CaptureState implements the EVMLogger interface to trace a single step of VM execution. 106 func (t *fourByteTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { 107 } 108 109 // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). 110 func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { 111 // Skip if tracing was interrupted 112 if atomic.LoadUint32(&t.interrupt) > 0 { 113 t.env.Cancel() 114 return 115 } 116 if len(input) < 4 { 117 return 118 } 119 // primarily we want to avoid CREATE/CREATE2/SELFDESTRUCT 120 if op != vm.DELEGATECALL && op != vm.STATICCALL && 121 op != vm.CALL && op != vm.CALLCODE { 122 return 123 } 124 // Skip any pre-compile invocations, those are just fancy opcodes 125 if t.isPrecompiled(to) { 126 return 127 } 128 t.store(input[0:4], len(input)-4) 129 } 130 131 // CaptureExit is called when EVM exits a scope, even if the scope didn't 132 // execute any code. 133 func (t *fourByteTracer) CaptureExit(output []byte, gasUsed uint64, err error) { 134 } 135 136 // CaptureFault implements the EVMLogger interface to trace an execution fault. 137 func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { 138 } 139 140 // CaptureEnd is called after the call finishes to finalize the tracing. 141 func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { 142 } 143 144 func (*fourByteTracer) CaptureTxStart(gasLimit uint64) {} 145 146 func (*fourByteTracer) CaptureTxEnd(restGas uint64) {} 147 148 // GetResult returns the json-encoded nested list of call traces, and any 149 // error arising from the encoding or forceful termination (via `Stop`). 150 func (t *fourByteTracer) GetResult() (json.RawMessage, error) { 151 res, err := json.Marshal(t.ids) 152 if err != nil { 153 return nil, err 154 } 155 return res, t.reason 156 } 157 158 // Stop terminates execution of the tracer at the first opportune moment. 159 func (t *fourByteTracer) Stop(err error) { 160 t.reason = err 161 atomic.StoreUint32(&t.interrupt, 1) 162 }