github.com/mprishchepo/go-ethereum@v1.9.7-0.20191031044858-21506be82b68/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 "time" 29 30 "github.com/Fantom-foundation/go-ethereum/cmd/evm/internal/compiler" 31 "github.com/Fantom-foundation/go-ethereum/cmd/utils" 32 "github.com/Fantom-foundation/go-ethereum/common" 33 "github.com/Fantom-foundation/go-ethereum/core" 34 "github.com/Fantom-foundation/go-ethereum/core/rawdb" 35 "github.com/Fantom-foundation/go-ethereum/core/state" 36 "github.com/Fantom-foundation/go-ethereum/core/vm" 37 "github.com/Fantom-foundation/go-ethereum/core/vm/runtime" 38 "github.com/Fantom-foundation/go-ethereum/log" 39 "github.com/Fantom-foundation/go-ethereum/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 Debug: ctx.GlobalBool(DebugFlag.Name), 80 } 81 82 var ( 83 tracer vm.Tracer 84 debugLogger *vm.StructLogger 85 statedb *state.StateDB 86 chainConfig *params.ChainConfig 87 sender = common.BytesToAddress([]byte("sender")) 88 receiver = common.BytesToAddress([]byte("receiver")) 89 genesisConfig *core.Genesis 90 ) 91 if ctx.GlobalBool(MachineFlag.Name) { 92 tracer = vm.NewJSONLogger(logconfig, os.Stdout) 93 } else if ctx.GlobalBool(DebugFlag.Name) { 94 debugLogger = vm.NewStructLogger(logconfig) 95 tracer = debugLogger 96 } else { 97 debugLogger = vm.NewStructLogger(logconfig) 98 } 99 if ctx.GlobalString(GenesisFlag.Name) != "" { 100 gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) 101 genesisConfig = gen 102 db := rawdb.NewMemoryDatabase() 103 genesis := gen.ToBlock(db) 104 statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) 105 chainConfig = gen.Config 106 } else { 107 statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) 108 genesisConfig = new(core.Genesis) 109 } 110 if ctx.GlobalString(SenderFlag.Name) != "" { 111 sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) 112 } 113 statedb.CreateAccount(sender) 114 115 if ctx.GlobalString(ReceiverFlag.Name) != "" { 116 receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) 117 } 118 119 var ( 120 code []byte 121 ret []byte 122 err error 123 ) 124 codeFileFlag := ctx.GlobalString(CodeFileFlag.Name) 125 codeFlag := ctx.GlobalString(CodeFlag.Name) 126 127 // The '--code' or '--codefile' flag overrides code in state 128 if codeFileFlag != "" || codeFlag != "" { 129 var hexcode []byte 130 if codeFileFlag != "" { 131 var err error 132 // If - is specified, it means that code comes from stdin 133 if codeFileFlag == "-" { 134 //Try reading from stdin 135 if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil { 136 fmt.Printf("Could not load code from stdin: %v\n", err) 137 os.Exit(1) 138 } 139 } else { 140 // Codefile with hex assembly 141 if hexcode, err = ioutil.ReadFile(codeFileFlag); err != nil { 142 fmt.Printf("Could not load code from file: %v\n", err) 143 os.Exit(1) 144 } 145 } 146 } else { 147 hexcode = []byte(codeFlag) 148 } 149 hexcode = bytes.TrimSpace(hexcode) 150 if len(hexcode)%2 != 0 { 151 fmt.Printf("Invalid input length for hex data (%d)\n", len(hexcode)) 152 os.Exit(1) 153 } 154 code = common.FromHex(string(hexcode)) 155 } else if fn := ctx.Args().First(); len(fn) > 0 { 156 // EASM-file to compile 157 src, err := ioutil.ReadFile(fn) 158 if err != nil { 159 return err 160 } 161 bin, err := compiler.Compile(fn, src, false) 162 if err != nil { 163 return err 164 } 165 code = common.Hex2Bytes(bin) 166 } 167 initialGas := ctx.GlobalUint64(GasFlag.Name) 168 if genesisConfig.GasLimit != 0 { 169 initialGas = genesisConfig.GasLimit 170 } 171 runtimeConfig := runtime.Config{ 172 Origin: sender, 173 State: statedb, 174 GasLimit: initialGas, 175 GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), 176 Value: utils.GlobalBig(ctx, ValueFlag.Name), 177 Difficulty: genesisConfig.Difficulty, 178 Time: new(big.Int).SetUint64(genesisConfig.Timestamp), 179 Coinbase: genesisConfig.Coinbase, 180 BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), 181 EVMConfig: vm.Config{ 182 Tracer: tracer, 183 Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), 184 EVMInterpreter: ctx.GlobalString(EVMInterpreterFlag.Name), 185 }, 186 } 187 188 if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { 189 f, err := os.Create(cpuProfilePath) 190 if err != nil { 191 fmt.Println("could not create CPU profile: ", err) 192 os.Exit(1) 193 } 194 if err := pprof.StartCPUProfile(f); err != nil { 195 fmt.Println("could not start CPU profile: ", err) 196 os.Exit(1) 197 } 198 defer pprof.StopCPUProfile() 199 } 200 201 if chainConfig != nil { 202 runtimeConfig.ChainConfig = chainConfig 203 } else { 204 runtimeConfig.ChainConfig = params.AllEthashProtocolChanges 205 } 206 tstart := time.Now() 207 var leftOverGas uint64 208 if ctx.GlobalBool(CreateFlag.Name) { 209 input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) 210 ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig) 211 } else { 212 if len(code) > 0 { 213 statedb.SetCode(receiver, code) 214 } 215 ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig) 216 } 217 execTime := time.Since(tstart) 218 219 if ctx.GlobalBool(DumpFlag.Name) { 220 statedb.Commit(true) 221 statedb.IntermediateRoot(true) 222 fmt.Println(string(statedb.Dump(false, false, true))) 223 } 224 225 if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { 226 f, err := os.Create(memProfilePath) 227 if err != nil { 228 fmt.Println("could not create memory profile: ", err) 229 os.Exit(1) 230 } 231 if err := pprof.WriteHeapProfile(f); err != nil { 232 fmt.Println("could not write memory profile: ", err) 233 os.Exit(1) 234 } 235 f.Close() 236 } 237 238 if ctx.GlobalBool(DebugFlag.Name) { 239 if debugLogger != nil { 240 fmt.Fprintln(os.Stderr, "#### TRACE ####") 241 vm.WriteTrace(os.Stderr, debugLogger.StructLogs()) 242 } 243 fmt.Fprintln(os.Stderr, "#### LOGS ####") 244 vm.WriteLogs(os.Stderr, statedb.Logs()) 245 } 246 247 if ctx.GlobalBool(StatDumpFlag.Name) { 248 var mem goruntime.MemStats 249 goruntime.ReadMemStats(&mem) 250 fmt.Fprintf(os.Stderr, `evm execution time: %v 251 heap objects: %d 252 allocations: %d 253 total allocations: %d 254 GC calls: %d 255 Gas used: %d 256 257 `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas) 258 } 259 if tracer == nil { 260 fmt.Printf("0x%x\n", ret) 261 if err != nil { 262 fmt.Printf(" error: %v\n", err) 263 } 264 } 265 266 return nil 267 }