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