github.com/amazechain/amc@v0.1.3/internal/tracers/native/mux.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package native
    18  
    19  import (
    20  	"encoding/json"
    21  	"github.com/holiman/uint256"
    22  
    23  	common "github.com/amazechain/amc/common/types"
    24  	"github.com/amazechain/amc/internal/tracers"
    25  	"github.com/amazechain/amc/internal/vm"
    26  )
    27  
    28  func init() {
    29  	tracers.DefaultDirectory.Register("muxTracer", newMuxTracer, false)
    30  }
    31  
    32  // muxTracer is a go implementation of the Tracer interface which
    33  // runs multiple tracers in one go.
    34  type muxTracer struct {
    35  	names   []string
    36  	tracers []tracers.Tracer
    37  }
    38  
    39  // newMuxTracer returns a new mux tracer.
    40  func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
    41  	var config map[string]json.RawMessage
    42  	if cfg != nil {
    43  		if err := json.Unmarshal(cfg, &config); err != nil {
    44  			return nil, err
    45  		}
    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)
    51  		if err != nil {
    52  			return nil, err
    53  		}
    54  		objects = append(objects, t)
    55  		names = append(names, k)
    56  	}
    57  
    58  	return &muxTracer{names: names, tracers: objects}, nil
    59  }
    60  
    61  // CaptureStart implements the EVMLogger interface to initialize the tracing operation.
    62  func (t *muxTracer) CaptureStart(env vm.VMInterface, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *uint256.Int) {
    63  	for _, t := range t.tracers {
    64  		t.CaptureStart(env, from, to, create, input, gas, value)
    65  	}
    66  }
    67  
    68  // CaptureEnd is called after the call finishes to finalize the tracing.
    69  func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
    70  	for _, t := range t.tracers {
    71  		t.CaptureEnd(output, gasUsed, err)
    72  	}
    73  }
    74  
    75  // CaptureState implements the EVMLogger interface to trace a single step of VM execution.
    76  func (t *muxTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
    77  	for _, t := range t.tracers {
    78  		t.CaptureState(pc, op, gas, cost, scope, rData, depth, err)
    79  	}
    80  }
    81  
    82  // CaptureFault implements the EVMLogger interface to trace an execution fault.
    83  func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
    84  	for _, t := range t.tracers {
    85  		t.CaptureFault(pc, op, gas, cost, scope, depth, err)
    86  	}
    87  }
    88  
    89  // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
    90  func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *uint256.Int) {
    91  	for _, t := range t.tracers {
    92  		t.CaptureEnter(typ, from, to, input, gas, value)
    93  	}
    94  }
    95  
    96  // CaptureExit is called when EVM exits a scope, even if the scope didn't
    97  // execute any code.
    98  func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
    99  	for _, t := range t.tracers {
   100  		t.CaptureExit(output, gasUsed, err)
   101  	}
   102  }
   103  
   104  func (t *muxTracer) CaptureTxStart(gasLimit uint64) {
   105  	for _, t := range t.tracers {
   106  		t.CaptureTxStart(gasLimit)
   107  	}
   108  }
   109  
   110  func (t *muxTracer) CaptureTxEnd(restGas uint64) {
   111  	for _, t := range t.tracers {
   112  		t.CaptureTxEnd(restGas)
   113  	}
   114  }
   115  
   116  // GetResult returns an empty json object.
   117  func (t *muxTracer) GetResult() (json.RawMessage, error) {
   118  	resObject := make(map[string]json.RawMessage)
   119  	for i, tt := range t.tracers {
   120  		r, err := tt.GetResult()
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  		resObject[t.names[i]] = r
   125  	}
   126  	res, err := json.Marshal(resObject)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	return res, nil
   131  }
   132  
   133  // Stop terminates execution of the tracer at the first opportune moment.
   134  func (t *muxTracer) Stop(err error) {
   135  	for _, t := range t.tracers {
   136  		t.Stop(err)
   137  	}
   138  }