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