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  }