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