| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | // Copyright 2017 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of go-ethereum. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2017-05-23 09:34:04 +02:00
										 |  |  | 	"runtime/pprof" | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	goruntime "runtime" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 11:52:57 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/cmd/utils" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/state" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/vm" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/vm/runtime" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	cli "gopkg.in/urfave/cli.v1" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var runCommand = cli.Command{ | 
					
						
							|  |  |  | 	Action:      runCmd, | 
					
						
							|  |  |  | 	Name:        "run", | 
					
						
							|  |  |  | 	Usage:       "run arbitrary evm binary", | 
					
						
							|  |  |  | 	ArgsUsage:   "<code>", | 
					
						
							|  |  |  | 	Description: `The run command runs arbitrary EVM code.`, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | // readGenesis will read the given JSON format genesis file and return | 
					
						
							|  |  |  | // the initialized Genesis structure | 
					
						
							|  |  |  | func readGenesis(genesisPath string) *core.Genesis { | 
					
						
							|  |  |  | 	// Make sure we have a valid genesis JSON | 
					
						
							|  |  |  | 	//genesisPath := ctx.Args().First() | 
					
						
							|  |  |  | 	if len(genesisPath) == 0 { | 
					
						
							|  |  |  | 		utils.Fatalf("Must supply path to genesis JSON file") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	file, err := os.Open(genesisPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("Failed to read genesis file: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer file.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	genesis := new(core.Genesis) | 
					
						
							|  |  |  | 	if err := json.NewDecoder(file).Decode(genesis); err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("invalid genesis file: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return genesis | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | func runCmd(ctx *cli.Context) error { | 
					
						
							|  |  |  | 	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) | 
					
						
							|  |  |  | 	glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) | 
					
						
							|  |  |  | 	log.Root().SetHandler(glogger) | 
					
						
							| 
									
										
										
										
											2017-06-21 14:52:31 +02:00
										 |  |  | 	logconfig := &vm.LogConfig{ | 
					
						
							|  |  |  | 		DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name), | 
					
						
							|  |  |  | 		DisableStack:  ctx.GlobalBool(DisableStackFlag.Name), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 		tracer      vm.Tracer | 
					
						
							|  |  |  | 		debugLogger *vm.StructLogger | 
					
						
							|  |  |  | 		statedb     *state.StateDB | 
					
						
							|  |  |  | 		chainConfig *params.ChainConfig | 
					
						
							|  |  |  | 		sender      = common.StringToAddress("sender") | 
					
						
							| 
									
										
										
										
											2017-08-15 11:31:36 +02:00
										 |  |  | 		receiver    = common.StringToAddress("receiver") | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	if ctx.GlobalBool(MachineFlag.Name) { | 
					
						
							| 
									
										
										
										
											2017-06-21 14:52:31 +02:00
										 |  |  | 		tracer = NewJSONLogger(logconfig, os.Stdout) | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	} else if ctx.GlobalBool(DebugFlag.Name) { | 
					
						
							| 
									
										
										
										
											2017-06-21 14:52:31 +02:00
										 |  |  | 		debugLogger = vm.NewStructLogger(logconfig) | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 		tracer = debugLogger | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-06-21 14:52:31 +02:00
										 |  |  | 		debugLogger = vm.NewStructLogger(logconfig) | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if ctx.GlobalString(GenesisFlag.Name) != "" { | 
					
						
							|  |  |  | 		gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) | 
					
						
							| 
									
										
										
										
											2018-02-05 18:40:32 +02:00
										 |  |  | 		db, _ := ethdb.NewMemDatabase() | 
					
						
							|  |  |  | 		genesis := gen.ToBlock(db) | 
					
						
							|  |  |  | 		statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 		chainConfig = gen.Config | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 		db, _ := ethdb.NewMemDatabase() | 
					
						
							|  |  |  | 		statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if ctx.GlobalString(SenderFlag.Name) != "" { | 
					
						
							|  |  |  | 		sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	statedb.CreateAccount(sender) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 11:31:36 +02:00
										 |  |  | 	if ctx.GlobalString(ReceiverFlag.Name) != "" { | 
					
						
							|  |  |  | 		receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		code []byte | 
					
						
							|  |  |  | 		ret  []byte | 
					
						
							|  |  |  | 		err  error | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2017-08-15 11:31:36 +02:00
										 |  |  | 	// The '--code' or '--codefile' flag overrides code in state | 
					
						
							|  |  |  | 	if ctx.GlobalString(CodeFileFlag.Name) != "" { | 
					
						
							|  |  |  | 		var hexcode []byte | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 		// If - is specified, it means that code comes from stdin | 
					
						
							|  |  |  | 		if ctx.GlobalString(CodeFileFlag.Name) == "-" { | 
					
						
							|  |  |  | 			//Try reading from stdin | 
					
						
							|  |  |  | 			if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil { | 
					
						
							|  |  |  | 				fmt.Printf("Could not load code from stdin: %v\n", err) | 
					
						
							|  |  |  | 				os.Exit(1) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// Codefile with hex assembly | 
					
						
							|  |  |  | 			if hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)); err != nil { | 
					
						
							|  |  |  | 				fmt.Printf("Could not load code from file: %v\n", err) | 
					
						
							|  |  |  | 				os.Exit(1) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else if ctx.GlobalString(CodeFlag.Name) != "" { | 
					
						
							|  |  |  | 		code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) | 
					
						
							|  |  |  | 	} else if fn := ctx.Args().First(); len(fn) > 0 { | 
					
						
							|  |  |  | 		// EASM-file to compile | 
					
						
							| 
									
										
										
										
											2017-03-01 11:52:57 +01:00
										 |  |  | 		src, err := ioutil.ReadFile(fn) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		bin, err := compiler.Compile(fn, src, false) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		code = common.Hex2Bytes(bin) | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-15 11:31:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	initialGas := ctx.GlobalUint64(GasFlag.Name) | 
					
						
							| 
									
										
										
										
											2017-03-01 10:19:15 +01:00
										 |  |  | 	runtimeConfig := runtime.Config{ | 
					
						
							|  |  |  | 		Origin:   sender, | 
					
						
							|  |  |  | 		State:    statedb, | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 		GasLimit: initialGas, | 
					
						
							| 
									
										
										
										
											2017-03-01 10:19:15 +01:00
										 |  |  | 		GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), | 
					
						
							|  |  |  | 		Value:    utils.GlobalBig(ctx, ValueFlag.Name), | 
					
						
							|  |  |  | 		EVMConfig: vm.Config{ | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 			Tracer:             tracer, | 
					
						
							|  |  |  | 			Debug:              ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), | 
					
						
							| 
									
										
										
										
											2017-03-01 10:19:15 +01:00
										 |  |  | 			DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-23 09:34:04 +02:00
										 |  |  | 	if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { | 
					
						
							|  |  |  | 		f, err := os.Create(cpuProfilePath) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			fmt.Println("could not create CPU profile: ", err) | 
					
						
							|  |  |  | 			os.Exit(1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := pprof.StartCPUProfile(f); err != nil { | 
					
						
							|  |  |  | 			fmt.Println("could not start CPU profile: ", err) | 
					
						
							|  |  |  | 			os.Exit(1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		defer pprof.StopCPUProfile() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	if chainConfig != nil { | 
					
						
							|  |  |  | 		runtimeConfig.ChainConfig = chainConfig | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-01 10:19:15 +01:00
										 |  |  | 	tstart := time.Now() | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	var leftOverGas uint64 | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	if ctx.GlobalBool(CreateFlag.Name) { | 
					
						
							|  |  |  | 		input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 		ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig) | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-08-15 11:31:36 +02:00
										 |  |  | 		if len(code) > 0 { | 
					
						
							|  |  |  | 			statedb.SetCode(receiver, code) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 		ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig) | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-01 11:52:57 +01:00
										 |  |  | 	execTime := time.Since(tstart) | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if ctx.GlobalBool(DumpFlag.Name) { | 
					
						
							| 
									
										
										
										
											2017-06-27 15:57:06 +02:00
										 |  |  | 		statedb.IntermediateRoot(true) | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 		fmt.Println(string(statedb.Dump())) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-01 10:19:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-23 09:34:04 +02:00
										 |  |  | 	if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { | 
					
						
							|  |  |  | 		f, err := os.Create(memProfilePath) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			fmt.Println("could not create memory profile: ", err) | 
					
						
							|  |  |  | 			os.Exit(1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := pprof.WriteHeapProfile(f); err != nil { | 
					
						
							|  |  |  | 			fmt.Println("could not write memory profile: ", err) | 
					
						
							|  |  |  | 			os.Exit(1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		f.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 10:19:15 +01:00
										 |  |  | 	if ctx.GlobalBool(DebugFlag.Name) { | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 		if debugLogger != nil { | 
					
						
							|  |  |  | 			fmt.Fprintln(os.Stderr, "#### TRACE ####") | 
					
						
							|  |  |  | 			vm.WriteTrace(os.Stderr, debugLogger.StructLogs()) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-01 10:19:15 +01:00
										 |  |  | 		fmt.Fprintln(os.Stderr, "#### LOGS ####") | 
					
						
							|  |  |  | 		vm.WriteLogs(os.Stderr, statedb.Logs()) | 
					
						
							| 
									
										
										
										
											2017-05-23 09:34:04 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-23 09:34:04 +02:00
										 |  |  | 	if ctx.GlobalBool(StatDumpFlag.Name) { | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 		var mem goruntime.MemStats | 
					
						
							|  |  |  | 		goruntime.ReadMemStats(&mem) | 
					
						
							| 
									
										
										
										
											2017-03-01 11:52:57 +01:00
										 |  |  | 		fmt.Fprintf(os.Stderr, `evm execution time: %v | 
					
						
							|  |  |  | heap objects:       %d | 
					
						
							|  |  |  | allocations:        %d | 
					
						
							|  |  |  | total allocations:  %d | 
					
						
							|  |  |  | GC calls:           %d | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | Gas used:           %d | 
					
						
							| 
									
										
										
										
											2017-03-01 11:52:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if tracer != nil { | 
					
						
							| 
									
										
										
										
											2017-08-23 13:37:18 +02:00
										 |  |  | 		tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err) | 
					
						
							| 
									
										
										
										
											2017-06-07 17:09:08 +02:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		fmt.Printf("0x%x\n", ret) | 
					
						
							| 
									
										
										
										
											2017-08-23 13:37:18 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			fmt.Printf(" error: %v\n", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-01 01:11:24 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |