github.com/ethereum/go-ethereum@v1.16.1/internal/ethapi/logtracer.go (about)

     1  // Copyright 2023 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 ethapi
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/core/tracing"
    24  	"github.com/ethereum/go-ethereum/core/types"
    25  	"github.com/ethereum/go-ethereum/core/vm"
    26  )
    27  
    28  var (
    29  	// keccak256("Transfer(address,address,uint256)")
    30  	transferTopic = common.HexToHash("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
    31  	// ERC-7528
    32  	transferAddress = common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE")
    33  )
    34  
    35  // tracer is a simple tracer that records all logs and
    36  // ether transfers. Transfers are recorded as if they
    37  // were logs. Transfer events include:
    38  // - tx value
    39  // - call value
    40  // - self destructs
    41  //
    42  // The log format for a transfer is:
    43  // - address: 0x0000000000000000000000000000000000000000
    44  // - data: Value
    45  // - topics:
    46  //   - Transfer(address,address,uint256)
    47  //   - Sender address
    48  //   - Recipient address
    49  type tracer struct {
    50  	// logs keeps logs for all open call frames.
    51  	// This lets us clear logs for failed calls.
    52  	logs           [][]*types.Log
    53  	count          int
    54  	traceTransfers bool
    55  	blockNumber    uint64
    56  	blockHash      common.Hash
    57  	txHash         common.Hash
    58  	txIdx          uint
    59  }
    60  
    61  func newTracer(traceTransfers bool, blockNumber uint64, blockHash, txHash common.Hash, txIndex uint) *tracer {
    62  	return &tracer{
    63  		traceTransfers: traceTransfers,
    64  		blockNumber:    blockNumber,
    65  		blockHash:      blockHash,
    66  		txHash:         txHash,
    67  		txIdx:          txIndex,
    68  	}
    69  }
    70  
    71  func (t *tracer) Hooks() *tracing.Hooks {
    72  	return &tracing.Hooks{
    73  		OnEnter: t.onEnter,
    74  		OnExit:  t.onExit,
    75  		OnLog:   t.onLog,
    76  	}
    77  }
    78  
    79  func (t *tracer) onEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
    80  	t.logs = append(t.logs, make([]*types.Log, 0))
    81  	if vm.OpCode(typ) != vm.DELEGATECALL && value != nil && value.Cmp(common.Big0) > 0 {
    82  		t.captureTransfer(from, to, value)
    83  	}
    84  }
    85  
    86  func (t *tracer) onExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
    87  	if depth == 0 {
    88  		t.onEnd(reverted)
    89  		return
    90  	}
    91  	size := len(t.logs)
    92  	if size <= 1 {
    93  		return
    94  	}
    95  	// pop call
    96  	call := t.logs[size-1]
    97  	t.logs = t.logs[:size-1]
    98  	size--
    99  
   100  	// Clear logs if call failed.
   101  	if !reverted {
   102  		t.logs[size-1] = append(t.logs[size-1], call...)
   103  	}
   104  }
   105  
   106  func (t *tracer) onEnd(reverted bool) {
   107  	if reverted {
   108  		t.logs[0] = nil
   109  	}
   110  }
   111  
   112  func (t *tracer) onLog(log *types.Log) {
   113  	t.captureLog(log.Address, log.Topics, log.Data)
   114  }
   115  
   116  func (t *tracer) captureLog(address common.Address, topics []common.Hash, data []byte) {
   117  	t.logs[len(t.logs)-1] = append(t.logs[len(t.logs)-1], &types.Log{
   118  		Address:     address,
   119  		Topics:      topics,
   120  		Data:        data,
   121  		BlockNumber: t.blockNumber,
   122  		BlockHash:   t.blockHash,
   123  		TxHash:      t.txHash,
   124  		TxIndex:     t.txIdx,
   125  		Index:       uint(t.count),
   126  	})
   127  	t.count++
   128  }
   129  
   130  func (t *tracer) captureTransfer(from, to common.Address, value *big.Int) {
   131  	if !t.traceTransfers {
   132  		return
   133  	}
   134  	topics := []common.Hash{
   135  		transferTopic,
   136  		common.BytesToHash(from.Bytes()),
   137  		common.BytesToHash(to.Bytes()),
   138  	}
   139  	t.captureLog(transferAddress, topics, common.BigToHash(value).Bytes())
   140  }
   141  
   142  // reset prepares the tracer for the next transaction.
   143  func (t *tracer) reset(txHash common.Hash, txIdx uint) {
   144  	t.logs = nil
   145  	t.txHash = txHash
   146  	t.txIdx = txIdx
   147  }
   148  
   149  func (t *tracer) Logs() []*types.Log {
   150  	return t.logs[0]
   151  }