github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/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/ethereum/go-ethereum/cmd/evm/internal/compiler" 31 "github.com/ethereum/go-ethereum/cmd/utils" 32 "github.com/ethereum/go-ethereum/common" 33 "github.com/ethereum/go-ethereum/core" 34 "github.com/ethereum/go-ethereum/core/state" 35 "github.com/ethereum/go-ethereum/core/vm" 36 "github.com/ethereum/go-ethereum/core/vm/runtime" 37 "github.com/ethereum/go-ethereum/ethdb" 38 "github.com/ethereum/go-ethereum/log" 39 "github.com/ethereum/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 77 var ( 78 tracer vm.Tracer 79 debugLogger *vm.StructLogger 80 statedb *state.StateDB 81 chainConfig *params.ChainConfig 82 sender = common.StringToAddress("sender") 83 ) 84 if ctx.GlobalBool(MachineFlag.Name) { 85 tracer = NewJSONLogger(os.Stdout) 86 } else if ctx.GlobalBool(DebugFlag.Name) { 87 debugLogger = vm.NewStructLogger(nil) 88 tracer = debugLogger 89 } else { 90 debugLogger = vm.NewStructLogger(nil) 91 } 92 if ctx.GlobalString(GenesisFlag.Name) != "" { 93 gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) 94 _, statedb = gen.ToBlock() 95 chainConfig = gen.Config 96 } else { 97 var db, _ = ethdb.NewMemDatabase() 98 statedb, _ = state.New(common.Hash{}, db) 99 } 100 if ctx.GlobalString(SenderFlag.Name) != "" { 101 sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) 102 } 103 104 statedb.CreateAccount(sender) 105 106 var ( 107 code []byte 108 ret []byte 109 err error 110 ) 111 if fn := ctx.Args().First(); len(fn) > 0 { 112 src, err := ioutil.ReadFile(fn) 113 if err != nil { 114 return err 115 } 116 117 bin, err := compiler.Compile(fn, src, false) 118 if err != nil { 119 return err 120 } 121 code = common.Hex2Bytes(bin) 122 } else if ctx.GlobalString(CodeFlag.Name) != "" { 123 code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) 124 } else { 125 var hexcode []byte 126 if ctx.GlobalString(CodeFileFlag.Name) != "" { 127 var err error 128 hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)) 129 if err != nil { 130 fmt.Printf("Could not load code from file: %v\n", err) 131 os.Exit(1) 132 } 133 } else { 134 var err error 135 hexcode, err = ioutil.ReadAll(os.Stdin) 136 if err != nil { 137 fmt.Printf("Could not load code from stdin: %v\n", err) 138 os.Exit(1) 139 } 140 } 141 code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) 142 } 143 initialGas := ctx.GlobalUint64(GasFlag.Name) 144 runtimeConfig := runtime.Config{ 145 Origin: sender, 146 State: statedb, 147 GasLimit: initialGas, 148 GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), 149 Value: utils.GlobalBig(ctx, ValueFlag.Name), 150 EVMConfig: vm.Config{ 151 Tracer: tracer, 152 Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), 153 DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), 154 }, 155 } 156 157 if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { 158 f, err := os.Create(cpuProfilePath) 159 if err != nil { 160 fmt.Println("could not create CPU profile: ", err) 161 os.Exit(1) 162 } 163 if err := pprof.StartCPUProfile(f); err != nil { 164 fmt.Println("could not start CPU profile: ", err) 165 os.Exit(1) 166 } 167 defer pprof.StopCPUProfile() 168 } 169 170 if chainConfig != nil { 171 runtimeConfig.ChainConfig = chainConfig 172 } 173 tstart := time.Now() 174 var leftOverGas uint64 175 if ctx.GlobalBool(CreateFlag.Name) { 176 input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) 177 ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig) 178 } else { 179 receiver := common.StringToAddress("receiver") 180 statedb.SetCode(receiver, code) 181 182 ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig) 183 } 184 execTime := time.Since(tstart) 185 186 if ctx.GlobalBool(DumpFlag.Name) { 187 statedb.Commit(true) 188 fmt.Println(string(statedb.Dump())) 189 } 190 191 if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { 192 f, err := os.Create(memProfilePath) 193 if err != nil { 194 fmt.Println("could not create memory profile: ", err) 195 os.Exit(1) 196 } 197 if err := pprof.WriteHeapProfile(f); err != nil { 198 fmt.Println("could not write memory profile: ", err) 199 os.Exit(1) 200 } 201 f.Close() 202 } 203 204 if ctx.GlobalBool(DebugFlag.Name) { 205 if debugLogger != nil { 206 fmt.Fprintln(os.Stderr, "#### TRACE ####") 207 vm.WriteTrace(os.Stderr, debugLogger.StructLogs()) 208 } 209 fmt.Fprintln(os.Stderr, "#### LOGS ####") 210 vm.WriteLogs(os.Stderr, statedb.Logs()) 211 } 212 213 if ctx.GlobalBool(StatDumpFlag.Name) { 214 var mem goruntime.MemStats 215 goruntime.ReadMemStats(&mem) 216 fmt.Fprintf(os.Stderr, `evm execution time: %v 217 heap objects: %d 218 allocations: %d 219 total allocations: %d 220 GC calls: %d 221 Gas used: %d 222 223 `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas) 224 } 225 if tracer != nil { 226 tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime) 227 } else { 228 fmt.Printf("0x%x\n", ret) 229 } 230 231 if err != nil { 232 fmt.Printf(" error: %v\n", err) 233 } 234 return nil 235 }