github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/vm/logger.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:36</date>
    10  //</624450082858602496>
    11  
    12  
    13  package vm
    14  
    15  import (
    16  	"encoding/hex"
    17  	"fmt"
    18  	"io"
    19  	"math/big"
    20  	"time"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/common/hexutil"
    24  	"github.com/ethereum/go-ethereum/common/math"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  )
    27  
    28  //存储表示合同的存储。
    29  type Storage map[common.Hash]common.Hash
    30  
    31  //复制复制复制当前存储。
    32  func (s Storage) Copy() Storage {
    33  	cpy := make(Storage)
    34  	for key, value := range s {
    35  		cpy[key] = value
    36  	}
    37  
    38  	return cpy
    39  }
    40  
    41  //logconfig是结构化记录器evm的配置选项
    42  type LogConfig struct {
    43  DisableMemory  bool //禁用内存捕获
    44  DisableStack   bool //禁用堆栈捕获
    45  DisableStorage bool //禁用存储捕获
    46  Debug          bool //捕获结束时打印输出
    47  Limit          int  //最大输出长度,但零表示无限制
    48  }
    49  
    50  //go:生成gencodec-type structlog-field override structlogmarshaling-out gen structlog.go
    51  
    52  //structlog在每个周期发送给evm,并列出有关当前内部状态的信息
    53  //在语句执行之前。
    54  type StructLog struct {
    55  	Pc            uint64                      `json:"pc"`
    56  	Op            OpCode                      `json:"op"`
    57  	Gas           uint64                      `json:"gas"`
    58  	GasCost       uint64                      `json:"gasCost"`
    59  	Memory        []byte                      `json:"memory"`
    60  	MemorySize    int                         `json:"memSize"`
    61  	Stack         []*big.Int                  `json:"stack"`
    62  	Storage       map[common.Hash]common.Hash `json:"-"`
    63  	Depth         int                         `json:"depth"`
    64  	RefundCounter uint64                      `json:"refund"`
    65  	Err           error                       `json:"-"`
    66  }
    67  
    68  //gencodec的覆盖
    69  type structLogMarshaling struct {
    70  	Stack       []*math.HexOrDecimal256
    71  	Gas         math.HexOrDecimal64
    72  	GasCost     math.HexOrDecimal64
    73  	Memory      hexutil.Bytes
    74  OpName      string `json:"opName"` //在marshaljson中添加对opname()的调用
    75  ErrorString string `json:"error"`  //在marshaljson中添加对ErrorString()的调用
    76  }
    77  
    78  //opname将操作数名称格式化为可读格式。
    79  func (s *StructLog) OpName() string {
    80  	return s.Op.String()
    81  }
    82  
    83  //ErrorString将日志的错误格式化为字符串。
    84  func (s *StructLog) ErrorString() string {
    85  	if s.Err != nil {
    86  		return s.Err.Error()
    87  	}
    88  	return ""
    89  }
    90  
    91  //跟踪程序用于从EVM事务收集执行跟踪
    92  //执行。对带有
    93  //当前VM状态。
    94  //请注意,引用类型是实际的VM数据结构;复制
    95  //如果您需要在当前呼叫之外保留它们。
    96  type Tracer interface {
    97  	CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value *big.Int) error
    98  	CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
    99  	CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
   100  	CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
   101  }
   102  
   103  //structlogger是一个EVM状态记录器并实现跟踪程序。
   104  //
   105  //结构记录器可以根据给定的日志配置捕获状态,并且还可以保留
   106  //修改后的存储的跟踪记录,用于报告
   107  //把他们的仓库收起来。
   108  type StructLogger struct {
   109  	cfg LogConfig
   110  
   111  	logs          []StructLog
   112  	changedValues map[common.Address]Storage
   113  	output        []byte
   114  	err           error
   115  }
   116  
   117  //newstructlogger返回新的记录器
   118  func NewStructLogger(cfg *LogConfig) *StructLogger {
   119  	logger := &StructLogger{
   120  		changedValues: make(map[common.Address]Storage),
   121  	}
   122  	if cfg != nil {
   123  		logger.cfg = *cfg
   124  	}
   125  	return logger
   126  }
   127  
   128  //CaptureStart实现跟踪程序接口以初始化跟踪操作。
   129  func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
   130  	return nil
   131  }
   132  
   133  //CaptureState记录新的结构化日志消息并将其推送到环境中
   134  //
   135  //CaptureState还跟踪sstore操作以跟踪脏值。
   136  func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
   137  //检查是否已累计指定数量的日志
   138  	if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
   139  		return ErrTraceLimitReached
   140  	}
   141  
   142  //为此合同初始化新的更改值存储容器
   143  //如果不存在。
   144  	if l.changedValues[contract.Address()] == nil {
   145  		l.changedValues[contract.Address()] = make(Storage)
   146  	}
   147  
   148  //捕获sstore操作码并确定更改的值并存储
   149  //它在本地存储容器中。
   150  	if op == SSTORE && stack.len() >= 2 {
   151  		var (
   152  			value   = common.BigToHash(stack.data[stack.len()-2])
   153  			address = common.BigToHash(stack.data[stack.len()-1])
   154  		)
   155  		l.changedValues[contract.Address()][address] = value
   156  	}
   157  //将当前内存状态的快照复制到新缓冲区
   158  	var mem []byte
   159  	if !l.cfg.DisableMemory {
   160  		mem = make([]byte, len(memory.Data()))
   161  		copy(mem, memory.Data())
   162  	}
   163  //将当前堆栈状态的快照复制到新缓冲区
   164  	var stck []*big.Int
   165  	if !l.cfg.DisableStack {
   166  		stck = make([]*big.Int, len(stack.Data()))
   167  		for i, item := range stack.Data() {
   168  			stck[i] = new(big.Int).Set(item)
   169  		}
   170  	}
   171  //将当前存储的快照复制到新容器
   172  	var storage Storage
   173  	if !l.cfg.DisableStorage {
   174  		storage = l.changedValues[contract.Address()].Copy()
   175  	}
   176  //创建EVM的新快照。
   177  	log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, env.StateDB.GetRefund(), err}
   178  
   179  	l.logs = append(l.logs, log)
   180  	return nil
   181  }
   182  
   183  //CaptureFault实现跟踪程序接口来跟踪执行错误
   184  //运行操作码时。
   185  func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
   186  	return nil
   187  }
   188  
   189  //在调用完成后调用CaptureEnd以完成跟踪。
   190  func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
   191  	l.output = output
   192  	l.err = err
   193  	if l.cfg.Debug {
   194  		fmt.Printf("0x%x\n", output)
   195  		if err != nil {
   196  			fmt.Printf(" error: %v\n", err)
   197  		}
   198  	}
   199  	return nil
   200  }
   201  
   202  //structlogs返回捕获的日志条目。
   203  func (l *StructLogger) StructLogs() []StructLog { return l.logs }
   204  
   205  //错误返回跟踪捕获的VM错误。
   206  func (l *StructLogger) Error() error { return l.err }
   207  
   208  //输出返回跟踪捕获的VM返回值。
   209  func (l *StructLogger) Output() []byte { return l.output }
   210  
   211  //WriteTrace将格式化的跟踪写入给定的写入程序
   212  func WriteTrace(writer io.Writer, logs []StructLog) {
   213  	for _, log := range logs {
   214  		fmt.Fprintf(writer, "%-16spc=%08d gas=%v cost=%v", log.Op, log.Pc, log.Gas, log.GasCost)
   215  		if log.Err != nil {
   216  			fmt.Fprintf(writer, " ERROR: %v", log.Err)
   217  		}
   218  		fmt.Fprintln(writer)
   219  
   220  		if len(log.Stack) > 0 {
   221  			fmt.Fprintln(writer, "Stack:")
   222  			for i := len(log.Stack) - 1; i >= 0; i-- {
   223  				fmt.Fprintf(writer, "%08d  %x\n", len(log.Stack)-i-1, math.PaddedBigBytes(log.Stack[i], 32))
   224  			}
   225  		}
   226  		if len(log.Memory) > 0 {
   227  			fmt.Fprintln(writer, "Memory:")
   228  			fmt.Fprint(writer, hex.Dump(log.Memory))
   229  		}
   230  		if len(log.Storage) > 0 {
   231  			fmt.Fprintln(writer, "Storage:")
   232  			for h, item := range log.Storage {
   233  				fmt.Fprintf(writer, "%x: %x\n", h, item)
   234  			}
   235  		}
   236  		fmt.Fprintln(writer)
   237  	}
   238  }
   239  
   240  //WriteLogs以可读的格式将VM日志写入给定的写入程序
   241  func WriteLogs(writer io.Writer, logs []*types.Log) {
   242  	for _, log := range logs {
   243  		fmt.Fprintf(writer, "LOG%d: %x bn=%d txi=%x\n", len(log.Topics), log.Address, log.BlockNumber, log.TxIndex)
   244  
   245  		for i, topic := range log.Topics {
   246  			fmt.Fprintf(writer, "%08d  %x\n", i, topic)
   247  		}
   248  
   249  		fmt.Fprint(writer, hex.Dump(log.Data))
   250  		fmt.Fprintln(writer)
   251  	}
   252  }
   253