github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/cmd/evm/runner.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:32</date> 10 //</624450067897520128> 11 12 13 package main 14 15 import ( 16 "bytes" 17 "encoding/json" 18 "fmt" 19 "io/ioutil" 20 "math/big" 21 "os" 22 goruntime "runtime" 23 "runtime/pprof" 24 "time" 25 26 "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" 27 "github.com/ethereum/go-ethereum/cmd/utils" 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/core" 30 "github.com/ethereum/go-ethereum/core/state" 31 "github.com/ethereum/go-ethereum/core/vm" 32 "github.com/ethereum/go-ethereum/core/vm/runtime" 33 "github.com/ethereum/go-ethereum/ethdb" 34 "github.com/ethereum/go-ethereum/log" 35 "github.com/ethereum/go-ethereum/params" 36 cli "gopkg.in/urfave/cli.v1" 37 ) 38 39 var runCommand = cli.Command{ 40 Action: runCmd, 41 Name: "run", 42 Usage: "run arbitrary evm binary", 43 ArgsUsage: "<code>", 44 Description: `The run command runs arbitrary EVM code.`, 45 } 46 47 //read genesis将读取给定的JSON格式genesis文件并返回 48 //初始化的Genesis结构 49 func readGenesis(genesisPath string) *core.Genesis { 50 //确保我们有一个有效的Genesis JSON 51 //genesPath:=ctx.args().first()) 52 if len(genesisPath) == 0 { 53 utils.Fatalf("Must supply path to genesis JSON file") 54 } 55 file, err := os.Open(genesisPath) 56 if err != nil { 57 utils.Fatalf("Failed to read genesis file: %v", err) 58 } 59 defer file.Close() 60 61 genesis := new(core.Genesis) 62 if err := json.NewDecoder(file).Decode(genesis); err != nil { 63 utils.Fatalf("invalid genesis file: %v", err) 64 } 65 return genesis 66 } 67 68 func runCmd(ctx *cli.Context) error { 69 glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 70 glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) 71 log.Root().SetHandler(glogger) 72 logconfig := &vm.LogConfig{ 73 DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name), 74 DisableStack: ctx.GlobalBool(DisableStackFlag.Name), 75 Debug: ctx.GlobalBool(DebugFlag.Name), 76 } 77 78 var ( 79 tracer vm.Tracer 80 debugLogger *vm.StructLogger 81 statedb *state.StateDB 82 chainConfig *params.ChainConfig 83 sender = common.BytesToAddress([]byte("sender")) 84 receiver = common.BytesToAddress([]byte("receiver")) 85 genesisConfig *core.Genesis 86 ) 87 if ctx.GlobalBool(MachineFlag.Name) { 88 tracer = vm.NewJSONLogger(logconfig, os.Stdout) 89 } else if ctx.GlobalBool(DebugFlag.Name) { 90 debugLogger = vm.NewStructLogger(logconfig) 91 tracer = debugLogger 92 } else { 93 debugLogger = vm.NewStructLogger(logconfig) 94 } 95 if ctx.GlobalString(GenesisFlag.Name) != "" { 96 gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) 97 genesisConfig = gen 98 db := ethdb.NewMemDatabase() 99 genesis := gen.ToBlock(db) 100 statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) 101 chainConfig = gen.Config 102 } else { 103 statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase())) 104 genesisConfig = new(core.Genesis) 105 } 106 if ctx.GlobalString(SenderFlag.Name) != "" { 107 sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) 108 } 109 statedb.CreateAccount(sender) 110 111 if ctx.GlobalString(ReceiverFlag.Name) != "" { 112 receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) 113 } 114 115 var ( 116 code []byte 117 ret []byte 118 err error 119 ) 120 //“--code”或“--codefile”标志重写处于状态的代码 121 if ctx.GlobalString(CodeFileFlag.Name) != "" { 122 var hexcode []byte 123 var err error 124 //如果指定了-则表示代码来自stdin 125 if ctx.GlobalString(CodeFileFlag.Name) == "-" { 126 //尝试从stdin读取 127 if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil { 128 fmt.Printf("Could not load code from stdin: %v\n", err) 129 os.Exit(1) 130 } 131 } else { 132 //带十六进制程序集的代码文件 133 if hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)); err != nil { 134 fmt.Printf("Could not load code from file: %v\n", err) 135 os.Exit(1) 136 } 137 } 138 code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) 139 140 } else if ctx.GlobalString(CodeFlag.Name) != "" { 141 code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) 142 } else if fn := ctx.Args().First(); len(fn) > 0 { 143 //要编译的EASM文件 144 src, err := ioutil.ReadFile(fn) 145 if err != nil { 146 return err 147 } 148 bin, err := compiler.Compile(fn, src, false) 149 if err != nil { 150 return err 151 } 152 code = common.Hex2Bytes(bin) 153 } 154 155 initialGas := ctx.GlobalUint64(GasFlag.Name) 156 if genesisConfig.GasLimit != 0 { 157 initialGas = genesisConfig.GasLimit 158 } 159 runtimeConfig := runtime.Config{ 160 Origin: sender, 161 State: statedb, 162 GasLimit: initialGas, 163 GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), 164 Value: utils.GlobalBig(ctx, ValueFlag.Name), 165 Difficulty: genesisConfig.Difficulty, 166 Time: new(big.Int).SetUint64(genesisConfig.Timestamp), 167 Coinbase: genesisConfig.Coinbase, 168 BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), 169 EVMConfig: vm.Config{ 170 Tracer: tracer, 171 Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), 172 EVMInterpreter: ctx.GlobalString(EVMInterpreterFlag.Name), 173 }, 174 } 175 176 if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { 177 f, err := os.Create(cpuProfilePath) 178 if err != nil { 179 fmt.Println("could not create CPU profile: ", err) 180 os.Exit(1) 181 } 182 if err := pprof.StartCPUProfile(f); err != nil { 183 fmt.Println("could not start CPU profile: ", err) 184 os.Exit(1) 185 } 186 defer pprof.StopCPUProfile() 187 } 188 189 if chainConfig != nil { 190 runtimeConfig.ChainConfig = chainConfig 191 } 192 tstart := time.Now() 193 var leftOverGas uint64 194 if ctx.GlobalBool(CreateFlag.Name) { 195 input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) 196 ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig) 197 } else { 198 if len(code) > 0 { 199 statedb.SetCode(receiver, code) 200 } 201 ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig) 202 } 203 execTime := time.Since(tstart) 204 205 if ctx.GlobalBool(DumpFlag.Name) { 206 statedb.Commit(true) 207 statedb.IntermediateRoot(true) 208 fmt.Println(string(statedb.Dump())) 209 } 210 211 if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { 212 f, err := os.Create(memProfilePath) 213 if err != nil { 214 fmt.Println("could not create memory profile: ", err) 215 os.Exit(1) 216 } 217 if err := pprof.WriteHeapProfile(f); err != nil { 218 fmt.Println("could not write memory profile: ", err) 219 os.Exit(1) 220 } 221 f.Close() 222 } 223 224 if ctx.GlobalBool(DebugFlag.Name) { 225 if debugLogger != nil { 226 fmt.Fprintln(os.Stderr, "#### TRACE ####") 227 vm.WriteTrace(os.Stderr, debugLogger.StructLogs()) 228 } 229 fmt.Fprintln(os.Stderr, "#### LOGS ####") 230 vm.WriteLogs(os.Stderr, statedb.Logs()) 231 } 232 233 if ctx.GlobalBool(StatDumpFlag.Name) { 234 var mem goruntime.MemStats 235 goruntime.ReadMemStats(&mem) 236 fmt.Fprintf(os.Stderr, `evm execution time: %v 237 heap objects: %d 238 allocations: %d 239 total allocations: %d 240 GC calls: %d 241 Gas used: %d 242 243 `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas) 244 } 245 if tracer == nil { 246 fmt.Printf("0x%x\n", ret) 247 if err != nil { 248 fmt.Printf(" error: %v\n", err) 249 } 250 } 251 252 return nil 253 } 254