github.com/theQRL/go-zond@v0.2.1/cmd/zvm/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/utils" 32 "github.com/theQRL/go-zond/cmd/zvm/internal/compiler" 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 zvm binary", 53 ArgsUsage: "<code>", 54 Description: `The run command runs arbitrary ZVM 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 err error 125 tracer vm.ZVMLogger 126 debugLogger *logger.StructLogger 127 statedb *state.StateDB 128 chainConfig *params.ChainConfig 129 sender = common.BytesToAddress([]byte("sender")) 130 receiver = common.BytesToAddress([]byte("receiver")) 131 genesisConfig *core.Genesis 132 preimages = ctx.Bool(DumpFlag.Name) 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, err = common.NewAddressFromString(ctx.String(SenderFlag.Name)) 168 if err != nil { 169 return err 170 } 171 } 172 statedb.CreateAccount(sender) 173 174 if ctx.String(ReceiverFlag.Name) != "" { 175 receiver, err = common.NewAddressFromString(ctx.String(ReceiverFlag.Name)) 176 if err != nil { 177 return err 178 } 179 } 180 181 var code []byte 182 codeFileFlag := ctx.String(CodeFileFlag.Name) 183 codeFlag := ctx.String(CodeFlag.Name) 184 185 // The '--code' or '--codefile' flag overrides code in state 186 if codeFileFlag != "" || codeFlag != "" { 187 var hexcode []byte 188 if codeFileFlag != "" { 189 var err error 190 // If - is specified, it means that code comes from stdin 191 if codeFileFlag == "-" { 192 //Try reading from stdin 193 if hexcode, err = io.ReadAll(os.Stdin); err != nil { 194 fmt.Printf("Could not load code from stdin: %v\n", err) 195 os.Exit(1) 196 } 197 } else { 198 // Codefile with hex assembly 199 if hexcode, err = os.ReadFile(codeFileFlag); err != nil { 200 fmt.Printf("Could not load code from file: %v\n", err) 201 os.Exit(1) 202 } 203 } 204 } else { 205 hexcode = []byte(codeFlag) 206 } 207 hexcode = bytes.TrimSpace(hexcode) 208 if len(hexcode)%2 != 0 { 209 fmt.Printf("Invalid input length for hex data (%d)\n", len(hexcode)) 210 os.Exit(1) 211 } 212 code = common.FromHex(string(hexcode)) 213 } else if fn := ctx.Args().First(); len(fn) > 0 { 214 // EASM-file to compile 215 src, err := os.ReadFile(fn) 216 if err != nil { 217 return err 218 } 219 bin, err := compiler.Compile(fn, src, false) 220 if err != nil { 221 return err 222 } 223 code = common.Hex2Bytes(bin) 224 } 225 initialGas := ctx.Uint64(GasFlag.Name) 226 if genesisConfig.GasLimit != 0 { 227 initialGas = genesisConfig.GasLimit 228 } 229 runtimeConfig := runtime.Config{ 230 Origin: sender, 231 State: statedb, 232 GasLimit: initialGas, 233 GasPrice: flags.GlobalBig(ctx, PriceFlag.Name), 234 Value: flags.GlobalBig(ctx, ValueFlag.Name), 235 Time: genesisConfig.Timestamp, 236 Coinbase: genesisConfig.Coinbase, 237 BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), 238 ZVMConfig: vm.Config{ 239 Tracer: tracer, 240 }, 241 } 242 243 if cpuProfilePath := ctx.String(CPUProfileFlag.Name); cpuProfilePath != "" { 244 f, err := os.Create(cpuProfilePath) 245 if err != nil { 246 fmt.Println("could not create CPU profile: ", err) 247 os.Exit(1) 248 } 249 if err := pprof.StartCPUProfile(f); err != nil { 250 fmt.Println("could not start CPU profile: ", err) 251 os.Exit(1) 252 } 253 defer pprof.StopCPUProfile() 254 } 255 256 if chainConfig != nil { 257 runtimeConfig.ChainConfig = chainConfig 258 } else { 259 runtimeConfig.ChainConfig = params.AllBeaconProtocolChanges 260 } 261 262 var hexInput []byte 263 if inputFileFlag := ctx.String(InputFileFlag.Name); inputFileFlag != "" { 264 var err error 265 if hexInput, err = os.ReadFile(inputFileFlag); err != nil { 266 fmt.Printf("could not load input from file: %v\n", err) 267 os.Exit(1) 268 } 269 } else { 270 hexInput = []byte(ctx.String(InputFlag.Name)) 271 } 272 hexInput = bytes.TrimSpace(hexInput) 273 if len(hexInput)%2 != 0 { 274 fmt.Println("input length must be even") 275 os.Exit(1) 276 } 277 input := common.FromHex(string(hexInput)) 278 279 var execFunc func() ([]byte, uint64, error) 280 if ctx.Bool(CreateFlag.Name) { 281 input = append(code, input...) 282 execFunc = func() ([]byte, uint64, error) { 283 output, _, gasLeft, err := runtime.Create(input, &runtimeConfig) 284 return output, gasLeft, err 285 } 286 } else { 287 if len(code) > 0 { 288 statedb.SetCode(receiver, code) 289 } 290 execFunc = func() ([]byte, uint64, error) { 291 return runtime.Call(receiver, input, &runtimeConfig) 292 } 293 } 294 295 bench := ctx.Bool(BenchFlag.Name) 296 output, leftOverGas, stats, err := timedExec(bench, execFunc) 297 298 if ctx.Bool(DumpFlag.Name) { 299 statedb.Commit(genesisConfig.Number, true) 300 fmt.Println(string(statedb.Dump(nil))) 301 } 302 303 if memProfilePath := ctx.String(MemProfileFlag.Name); memProfilePath != "" { 304 f, err := os.Create(memProfilePath) 305 if err != nil { 306 fmt.Println("could not create memory profile: ", err) 307 os.Exit(1) 308 } 309 if err := pprof.WriteHeapProfile(f); err != nil { 310 fmt.Println("could not write memory profile: ", err) 311 os.Exit(1) 312 } 313 f.Close() 314 } 315 316 if ctx.Bool(DebugFlag.Name) { 317 if debugLogger != nil { 318 fmt.Fprintln(os.Stderr, "#### TRACE ####") 319 logger.WriteTrace(os.Stderr, debugLogger.StructLogs()) 320 } 321 fmt.Fprintln(os.Stderr, "#### LOGS ####") 322 logger.WriteLogs(os.Stderr, statedb.Logs()) 323 } 324 325 if bench || ctx.Bool(StatDumpFlag.Name) { 326 fmt.Fprintf(os.Stderr, `ZVM gas used: %d 327 execution time: %v 328 allocations: %d 329 allocated bytes: %d 330 `, initialGas-leftOverGas, stats.time, stats.allocs, stats.bytesAllocated) 331 } 332 if tracer == nil { 333 fmt.Printf("%#x\n", output) 334 if err != nil { 335 fmt.Printf(" error: %v\n", err) 336 } 337 } 338 339 return nil 340 }