github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/cmd/evm/runner.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package main 13 14 import ( 15 "bytes" 16 "encoding/json" 17 "fmt" 18 "io/ioutil" 19 "os" 20 "runtime/pprof" 21 "time" 22 23 goruntime "runtime" 24 25 "github.com/Sberex/go-sberex/cmd/evm/internal/compiler" 26 "github.com/Sberex/go-sberex/cmd/utils" 27 "github.com/Sberex/go-sberex/common" 28 "github.com/Sberex/go-sberex/core" 29 "github.com/Sberex/go-sberex/core/state" 30 "github.com/Sberex/go-sberex/core/vm" 31 "github.com/Sberex/go-sberex/core/vm/runtime" 32 "github.com/Sberex/go-sberex/ethdb" 33 "github.com/Sberex/go-sberex/log" 34 "github.com/Sberex/go-sberex/params" 35 cli "gopkg.in/urfave/cli.v1" 36 ) 37 38 var runCommand = cli.Command{ 39 Action: runCmd, 40 Name: "run", 41 Usage: "run arbitrary evm binary", 42 ArgsUsage: "<code>", 43 Description: `The run command runs arbitrary EVM code.`, 44 } 45 46 // readGenesis will read the given JSON format genesis file and return 47 // the initialized Genesis structure 48 func readGenesis(genesisPath string) *core.Genesis { 49 // Make sure we have a valid genesis JSON 50 //genesisPath := ctx.Args().First() 51 if len(genesisPath) == 0 { 52 utils.Fatalf("Must supply path to genesis JSON file") 53 } 54 file, err := os.Open(genesisPath) 55 if err != nil { 56 utils.Fatalf("Failed to read genesis file: %v", err) 57 } 58 defer file.Close() 59 60 genesis := new(core.Genesis) 61 if err := json.NewDecoder(file).Decode(genesis); err != nil { 62 utils.Fatalf("invalid genesis file: %v", err) 63 } 64 return genesis 65 } 66 67 func runCmd(ctx *cli.Context) error { 68 glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 69 glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) 70 log.Root().SetHandler(glogger) 71 logconfig := &vm.LogConfig{ 72 DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name), 73 DisableStack: ctx.GlobalBool(DisableStackFlag.Name), 74 } 75 76 var ( 77 tracer vm.Tracer 78 debugLogger *vm.StructLogger 79 statedb *state.StateDB 80 chainConfig *params.ChainConfig 81 sender = common.StringToAddress("sender") 82 receiver = common.StringToAddress("receiver") 83 ) 84 if ctx.GlobalBool(MachineFlag.Name) { 85 tracer = NewJSONLogger(logconfig, os.Stdout) 86 } else if ctx.GlobalBool(DebugFlag.Name) { 87 debugLogger = vm.NewStructLogger(logconfig) 88 tracer = debugLogger 89 } else { 90 debugLogger = vm.NewStructLogger(logconfig) 91 } 92 if ctx.GlobalString(GenesisFlag.Name) != "" { 93 gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) 94 db, _ := ethdb.NewMemDatabase() 95 genesis := gen.ToBlock(db) 96 statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) 97 chainConfig = gen.Config 98 } else { 99 db, _ := ethdb.NewMemDatabase() 100 statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) 101 } 102 if ctx.GlobalString(SenderFlag.Name) != "" { 103 sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) 104 } 105 statedb.CreateAccount(sender) 106 107 if ctx.GlobalString(ReceiverFlag.Name) != "" { 108 receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) 109 } 110 111 var ( 112 code []byte 113 ret []byte 114 err error 115 ) 116 // The '--code' or '--codefile' flag overrides code in state 117 if ctx.GlobalString(CodeFileFlag.Name) != "" { 118 var hexcode []byte 119 var err error 120 // If - is specified, it means that code comes from stdin 121 if ctx.GlobalString(CodeFileFlag.Name) == "-" { 122 //Try reading from stdin 123 if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil { 124 fmt.Printf("Could not load code from stdin: %v\n", err) 125 os.Exit(1) 126 } 127 } else { 128 // Codefile with hex assembly 129 if hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)); err != nil { 130 fmt.Printf("Could not load code from file: %v\n", err) 131 os.Exit(1) 132 } 133 } 134 code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) 135 136 } else if ctx.GlobalString(CodeFlag.Name) != "" { 137 code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) 138 } else if fn := ctx.Args().First(); len(fn) > 0 { 139 // EASM-file to compile 140 src, err := ioutil.ReadFile(fn) 141 if err != nil { 142 return err 143 } 144 bin, err := compiler.Compile(fn, src, false) 145 if err != nil { 146 return err 147 } 148 code = common.Hex2Bytes(bin) 149 } 150 151 initialGas := ctx.GlobalUint64(GasFlag.Name) 152 runtimeConfig := runtime.Config{ 153 Origin: sender, 154 State: statedb, 155 GasLimit: initialGas, 156 GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), 157 Value: utils.GlobalBig(ctx, ValueFlag.Name), 158 EVMConfig: vm.Config{ 159 Tracer: tracer, 160 Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), 161 DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), 162 }, 163 } 164 165 if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { 166 f, err := os.Create(cpuProfilePath) 167 if err != nil { 168 fmt.Println("could not create CPU profile: ", err) 169 os.Exit(1) 170 } 171 if err := pprof.StartCPUProfile(f); err != nil { 172 fmt.Println("could not start CPU profile: ", err) 173 os.Exit(1) 174 } 175 defer pprof.StopCPUProfile() 176 } 177 178 if chainConfig != nil { 179 runtimeConfig.ChainConfig = chainConfig 180 } 181 tstart := time.Now() 182 var leftOverGas uint64 183 if ctx.GlobalBool(CreateFlag.Name) { 184 input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) 185 ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig) 186 } else { 187 if len(code) > 0 { 188 statedb.SetCode(receiver, code) 189 } 190 ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig) 191 } 192 execTime := time.Since(tstart) 193 194 if ctx.GlobalBool(DumpFlag.Name) { 195 statedb.IntermediateRoot(true) 196 fmt.Println(string(statedb.Dump())) 197 } 198 199 if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { 200 f, err := os.Create(memProfilePath) 201 if err != nil { 202 fmt.Println("could not create memory profile: ", err) 203 os.Exit(1) 204 } 205 if err := pprof.WriteHeapProfile(f); err != nil { 206 fmt.Println("could not write memory profile: ", err) 207 os.Exit(1) 208 } 209 f.Close() 210 } 211 212 if ctx.GlobalBool(DebugFlag.Name) { 213 if debugLogger != nil { 214 fmt.Fprintln(os.Stderr, "#### TRACE ####") 215 vm.WriteTrace(os.Stderr, debugLogger.StructLogs()) 216 } 217 fmt.Fprintln(os.Stderr, "#### LOGS ####") 218 vm.WriteLogs(os.Stderr, statedb.Logs()) 219 } 220 221 if ctx.GlobalBool(StatDumpFlag.Name) { 222 var mem goruntime.MemStats 223 goruntime.ReadMemStats(&mem) 224 fmt.Fprintf(os.Stderr, `evm execution time: %v 225 heap objects: %d 226 allocations: %d 227 total allocations: %d 228 GC calls: %d 229 Gas used: %d 230 231 `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas) 232 } 233 if tracer != nil { 234 tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err) 235 } else { 236 fmt.Printf("0x%x\n", ret) 237 if err != nil { 238 fmt.Printf(" error: %v\n", err) 239 } 240 } 241 242 return nil 243 }