github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/core/vm/logger.go (about)

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