github.com/ylsgit/go-ethereum@v1.6.5/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  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"runtime/pprof"
    25  	"time"
    26  
    27  	goruntime "runtime"
    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/state"
    33  	"github.com/ethereum/go-ethereum/core/vm"
    34  	"github.com/ethereum/go-ethereum/core/vm/runtime"
    35  	"github.com/ethereum/go-ethereum/ethdb"
    36  	"github.com/ethereum/go-ethereum/log"
    37  	cli "gopkg.in/urfave/cli.v1"
    38  )
    39  
    40  var runCommand = cli.Command{
    41  	Action:      runCmd,
    42  	Name:        "run",
    43  	Usage:       "run arbitrary evm binary",
    44  	ArgsUsage:   "<code>",
    45  	Description: `The run command runs arbitrary EVM code.`,
    46  }
    47  
    48  func runCmd(ctx *cli.Context) error {
    49  	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
    50  	glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)))
    51  	log.Root().SetHandler(glogger)
    52  
    53  	var (
    54  		db, _      = ethdb.NewMemDatabase()
    55  		statedb, _ = state.New(common.Hash{}, db)
    56  		sender     = common.StringToAddress("sender")
    57  		logger     = vm.NewStructLogger(nil)
    58  	)
    59  	statedb.CreateAccount(sender)
    60  
    61  	var (
    62  		code []byte
    63  		ret  []byte
    64  		err  error
    65  	)
    66  	if fn := ctx.Args().First(); len(fn) > 0 {
    67  		src, err := ioutil.ReadFile(fn)
    68  		if err != nil {
    69  			return err
    70  		}
    71  
    72  		bin, err := compiler.Compile(fn, src, false)
    73  		if err != nil {
    74  			return err
    75  		}
    76  		code = common.Hex2Bytes(bin)
    77  	} else if ctx.GlobalString(CodeFlag.Name) != "" {
    78  		code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))
    79  	} else {
    80  		var hexcode []byte
    81  		if ctx.GlobalString(CodeFileFlag.Name) != "" {
    82  			var err error
    83  			hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name))
    84  			if err != nil {
    85  				fmt.Printf("Could not load code from file: %v\n", err)
    86  				os.Exit(1)
    87  			}
    88  		} else {
    89  			var err error
    90  			hexcode, err = ioutil.ReadAll(os.Stdin)
    91  			if err != nil {
    92  				fmt.Printf("Could not load code from stdin: %v\n", err)
    93  				os.Exit(1)
    94  			}
    95  		}
    96  		code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n")))
    97  	}
    98  
    99  	runtimeConfig := runtime.Config{
   100  		Origin:   sender,
   101  		State:    statedb,
   102  		GasLimit: ctx.GlobalUint64(GasFlag.Name),
   103  		GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
   104  		Value:    utils.GlobalBig(ctx, ValueFlag.Name),
   105  		EVMConfig: vm.Config{
   106  			Tracer:             logger,
   107  			Debug:              ctx.GlobalBool(DebugFlag.Name),
   108  			DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
   109  		},
   110  	}
   111  
   112  	if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" {
   113  		f, err := os.Create(cpuProfilePath)
   114  		if err != nil {
   115  			fmt.Println("could not create CPU profile: ", err)
   116  			os.Exit(1)
   117  		}
   118  		if err := pprof.StartCPUProfile(f); err != nil {
   119  			fmt.Println("could not start CPU profile: ", err)
   120  			os.Exit(1)
   121  		}
   122  		defer pprof.StopCPUProfile()
   123  	}
   124  
   125  	tstart := time.Now()
   126  	if ctx.GlobalBool(CreateFlag.Name) {
   127  		input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
   128  		ret, _, err = runtime.Create(input, &runtimeConfig)
   129  	} else {
   130  		receiver := common.StringToAddress("receiver")
   131  		statedb.SetCode(receiver, code)
   132  
   133  		ret, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig)
   134  	}
   135  	execTime := time.Since(tstart)
   136  
   137  	if ctx.GlobalBool(DumpFlag.Name) {
   138  		statedb.Commit(true)
   139  		fmt.Println(string(statedb.Dump()))
   140  	}
   141  
   142  	if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" {
   143  		f, err := os.Create(memProfilePath)
   144  		if err != nil {
   145  			fmt.Println("could not create memory profile: ", err)
   146  			os.Exit(1)
   147  		}
   148  		if err := pprof.WriteHeapProfile(f); err != nil {
   149  			fmt.Println("could not write memory profile: ", err)
   150  			os.Exit(1)
   151  		}
   152  		f.Close()
   153  	}
   154  
   155  	if ctx.GlobalBool(DebugFlag.Name) {
   156  		fmt.Fprintln(os.Stderr, "#### TRACE ####")
   157  		vm.WriteTrace(os.Stderr, logger.StructLogs())
   158  		fmt.Fprintln(os.Stderr, "#### LOGS ####")
   159  		vm.WriteLogs(os.Stderr, statedb.Logs())
   160  	}
   161  
   162  	if ctx.GlobalBool(StatDumpFlag.Name) {
   163  		var mem goruntime.MemStats
   164  		goruntime.ReadMemStats(&mem)
   165  		fmt.Fprintf(os.Stderr, `evm execution time: %v
   166  heap objects:       %d
   167  allocations:        %d
   168  total allocations:  %d
   169  GC calls:           %d
   170  
   171  `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC)
   172  	}
   173  
   174  	fmt.Printf("0x%x", ret)
   175  	if err != nil {
   176  		fmt.Printf(" error: %v", err)
   177  	}
   178  	fmt.Println()
   179  	return nil
   180  }