gitee.com/liu-zhao234568/cntest@v1.0.0/cmd/evm/runner.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "io/ioutil" 24 "math/big" 25 "os" 26 goruntime "runtime" 27 "runtime/pprof" 28 "testing" 29 "time" 30 31 "gitee.com/liu-zhao234568/cntest/cmd/evm/internal/compiler" 32 "gitee.com/liu-zhao234568/cntest/cmd/utils" 33 "gitee.com/liu-zhao234568/cntest/common" 34 "gitee.com/liu-zhao234568/cntest/core" 35 "gitee.com/liu-zhao234568/cntest/core/rawdb" 36 "gitee.com/liu-zhao234568/cntest/core/state" 37 "gitee.com/liu-zhao234568/cntest/core/vm" 38 "gitee.com/liu-zhao234568/cntest/core/vm/runtime" 39 "gitee.com/liu-zhao234568/cntest/log" 40 "gitee.com/liu-zhao234568/cntest/params" 41 "gopkg.in/urfave/cli.v1" 42 ) 43 44 var runCommand = cli.Command{ 45 Action: runCmd, 46 Name: "run", 47 Usage: "run arbitrary evm binary", 48 ArgsUsage: "<code>", 49 Description: `The run command runs arbitrary EVM code.`, 50 } 51 52 // readGenesis will read the given JSON format genesis file and return 53 // the initialized Genesis structure 54 func readGenesis(genesisPath string) *core.Genesis { 55 // Make sure we have a valid genesis JSON 56 //genesisPath := ctx.Args().First() 57 if len(genesisPath) == 0 { 58 utils.Fatalf("Must supply path to genesis JSON file") 59 } 60 file, err := os.Open(genesisPath) 61 if err != nil { 62 utils.Fatalf("Failed to read genesis file: %v", err) 63 } 64 defer file.Close() 65 66 genesis := new(core.Genesis) 67 if err := json.NewDecoder(file).Decode(genesis); err != nil { 68 utils.Fatalf("invalid genesis file: %v", err) 69 } 70 return genesis 71 } 72 73 type execStats struct { 74 time time.Duration // The execution time. 75 allocs int64 // The number of heap allocations during execution. 76 bytesAllocated int64 // The cumulative number of bytes allocated during execution. 77 } 78 79 func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []byte, gasLeft uint64, stats execStats, err error) { 80 if bench { 81 result := testing.Benchmark(func(b *testing.B) { 82 for i := 0; i < b.N; i++ { 83 output, gasLeft, err = execFunc() 84 } 85 }) 86 87 // Get the average execution time from the benchmarking result. 88 // There are other useful stats here that could be reported. 89 stats.time = time.Duration(result.NsPerOp()) 90 stats.allocs = result.AllocsPerOp() 91 stats.bytesAllocated = result.AllocedBytesPerOp() 92 } else { 93 var memStatsBefore, memStatsAfter goruntime.MemStats 94 goruntime.ReadMemStats(&memStatsBefore) 95 startTime := time.Now() 96 output, gasLeft, err = execFunc() 97 stats.time = time.Since(startTime) 98 goruntime.ReadMemStats(&memStatsAfter) 99 stats.allocs = int64(memStatsAfter.Mallocs - memStatsBefore.Mallocs) 100 stats.bytesAllocated = int64(memStatsAfter.TotalAlloc - memStatsBefore.TotalAlloc) 101 } 102 103 return output, gasLeft, stats, err 104 } 105 106 func runCmd(ctx *cli.Context) error { 107 glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 108 glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) 109 log.Root().SetHandler(glogger) 110 logconfig := &vm.LogConfig{ 111 DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name), 112 DisableStack: ctx.GlobalBool(DisableStackFlag.Name), 113 DisableStorage: ctx.GlobalBool(DisableStorageFlag.Name), 114 DisableReturnData: ctx.GlobalBool(DisableReturnDataFlag.Name), 115 Debug: ctx.GlobalBool(DebugFlag.Name), 116 } 117 118 var ( 119 tracer vm.Tracer 120 debugLogger *vm.StructLogger 121 statedb *state.StateDB 122 chainConfig *params.ChainConfig 123 sender = common.BytesToAddress([]byte("sender")) 124 receiver = common.BytesToAddress([]byte("receiver")) 125 genesisConfig *core.Genesis 126 ) 127 if ctx.GlobalBool(MachineFlag.Name) { 128 tracer = vm.NewJSONLogger(logconfig, os.Stdout) 129 } else if ctx.GlobalBool(DebugFlag.Name) { 130 debugLogger = vm.NewStructLogger(logconfig) 131 tracer = debugLogger 132 } else { 133 debugLogger = vm.NewStructLogger(logconfig) 134 } 135 if ctx.GlobalString(GenesisFlag.Name) != "" { 136 gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) 137 genesisConfig = gen 138 db := rawdb.NewMemoryDatabase() 139 genesis := gen.ToBlock(db) 140 statedb, _ = state.New(genesis.Root(), state.NewDatabase(db), nil) 141 chainConfig = gen.Config 142 } else { 143 statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 144 genesisConfig = new(core.Genesis) 145 } 146 if ctx.GlobalString(SenderFlag.Name) != "" { 147 sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) 148 } 149 statedb.CreateAccount(sender) 150 151 if ctx.GlobalString(ReceiverFlag.Name) != "" { 152 receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) 153 } 154 155 var code []byte 156 codeFileFlag := ctx.GlobalString(CodeFileFlag.Name) 157 codeFlag := ctx.GlobalString(CodeFlag.Name) 158 159 // The '--code' or '--codefile' flag overrides code in state 160 if codeFileFlag != "" || codeFlag != "" { 161 var hexcode []byte 162 if codeFileFlag != "" { 163 var err error 164 // If - is specified, it means that code comes from stdin 165 if codeFileFlag == "-" { 166 //Try reading from stdin 167 if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil { 168 fmt.Printf("Could not load code from stdin: %v\n", err) 169 os.Exit(1) 170 } 171 } else { 172 // Codefile with hex assembly 173 if hexcode, err = ioutil.ReadFile(codeFileFlag); err != nil { 174 fmt.Printf("Could not load code from file: %v\n", err) 175 os.Exit(1) 176 } 177 } 178 } else { 179 hexcode = []byte(codeFlag) 180 } 181 hexcode = bytes.TrimSpace(hexcode) 182 if len(hexcode)%2 != 0 { 183 fmt.Printf("Invalid input length for hex data (%d)\n", len(hexcode)) 184 os.Exit(1) 185 } 186 code = common.FromHex(string(hexcode)) 187 } else if fn := ctx.Args().First(); len(fn) > 0 { 188 // EASM-file to compile 189 src, err := ioutil.ReadFile(fn) 190 if err != nil { 191 return err 192 } 193 bin, err := compiler.Compile(fn, src, false) 194 if err != nil { 195 return err 196 } 197 code = common.Hex2Bytes(bin) 198 } 199 initialGas := ctx.GlobalUint64(GasFlag.Name) 200 if genesisConfig.GasLimit != 0 { 201 initialGas = genesisConfig.GasLimit 202 } 203 runtimeConfig := runtime.Config{ 204 Origin: sender, 205 State: statedb, 206 GasLimit: initialGas, 207 GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), 208 Value: utils.GlobalBig(ctx, ValueFlag.Name), 209 Difficulty: genesisConfig.Difficulty, 210 Time: new(big.Int).SetUint64(genesisConfig.Timestamp), 211 Coinbase: genesisConfig.Coinbase, 212 BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), 213 EVMConfig: vm.Config{ 214 Tracer: tracer, 215 Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), 216 }, 217 } 218 219 if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { 220 f, err := os.Create(cpuProfilePath) 221 if err != nil { 222 fmt.Println("could not create CPU profile: ", err) 223 os.Exit(1) 224 } 225 if err := pprof.StartCPUProfile(f); err != nil { 226 fmt.Println("could not start CPU profile: ", err) 227 os.Exit(1) 228 } 229 defer pprof.StopCPUProfile() 230 } 231 232 if chainConfig != nil { 233 runtimeConfig.ChainConfig = chainConfig 234 } else { 235 runtimeConfig.ChainConfig = params.AllEthashProtocolChanges 236 } 237 238 var hexInput []byte 239 if inputFileFlag := ctx.GlobalString(InputFileFlag.Name); inputFileFlag != "" { 240 var err error 241 if hexInput, err = ioutil.ReadFile(inputFileFlag); err != nil { 242 fmt.Printf("could not load input from file: %v\n", err) 243 os.Exit(1) 244 } 245 } else { 246 hexInput = []byte(ctx.GlobalString(InputFlag.Name)) 247 } 248 input := common.FromHex(string(bytes.TrimSpace(hexInput))) 249 250 var execFunc func() ([]byte, uint64, error) 251 if ctx.GlobalBool(CreateFlag.Name) { 252 input = append(code, input...) 253 execFunc = func() ([]byte, uint64, error) { 254 output, _, gasLeft, err := runtime.Create(input, &runtimeConfig) 255 return output, gasLeft, err 256 } 257 } else { 258 if len(code) > 0 { 259 statedb.SetCode(receiver, code) 260 } 261 execFunc = func() ([]byte, uint64, error) { 262 return runtime.Call(receiver, input, &runtimeConfig) 263 } 264 } 265 266 bench := ctx.GlobalBool(BenchFlag.Name) 267 output, leftOverGas, stats, err := timedExec(bench, execFunc) 268 269 if ctx.GlobalBool(DumpFlag.Name) { 270 statedb.Commit(true) 271 statedb.IntermediateRoot(true) 272 fmt.Println(string(statedb.Dump(nil))) 273 } 274 275 if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { 276 f, err := os.Create(memProfilePath) 277 if err != nil { 278 fmt.Println("could not create memory profile: ", err) 279 os.Exit(1) 280 } 281 if err := pprof.WriteHeapProfile(f); err != nil { 282 fmt.Println("could not write memory profile: ", err) 283 os.Exit(1) 284 } 285 f.Close() 286 } 287 288 if ctx.GlobalBool(DebugFlag.Name) { 289 if debugLogger != nil { 290 fmt.Fprintln(os.Stderr, "#### TRACE ####") 291 vm.WriteTrace(os.Stderr, debugLogger.StructLogs()) 292 } 293 fmt.Fprintln(os.Stderr, "#### LOGS ####") 294 vm.WriteLogs(os.Stderr, statedb.Logs()) 295 } 296 297 if bench || ctx.GlobalBool(StatDumpFlag.Name) { 298 fmt.Fprintf(os.Stderr, `EVM gas used: %d 299 execution time: %v 300 allocations: %d 301 allocated bytes: %d 302 `, initialGas-leftOverGas, stats.time, stats.allocs, stats.bytesAllocated) 303 } 304 if tracer == nil { 305 fmt.Printf("0x%x\n", output) 306 if err != nil { 307 fmt.Printf(" error: %v\n", err) 308 } 309 } 310 311 return nil 312 }