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