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