github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/cmd/evm/runner.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package main
    13  
    14  import (
    15  	"bytes"
    16  	"encoding/json"
    17  	"fmt"
    18  	"io/ioutil"
    19  	"os"
    20  	"runtime/pprof"
    21  	"time"
    22  
    23  	goruntime "runtime"
    24  
    25  	"github.com/Sberex/go-sberex/cmd/evm/internal/compiler"
    26  	"github.com/Sberex/go-sberex/cmd/utils"
    27  	"github.com/Sberex/go-sberex/common"
    28  	"github.com/Sberex/go-sberex/core"
    29  	"github.com/Sberex/go-sberex/core/state"
    30  	"github.com/Sberex/go-sberex/core/vm"
    31  	"github.com/Sberex/go-sberex/core/vm/runtime"
    32  	"github.com/Sberex/go-sberex/ethdb"
    33  	"github.com/Sberex/go-sberex/log"
    34  	"github.com/Sberex/go-sberex/params"
    35  	cli "gopkg.in/urfave/cli.v1"
    36  )
    37  
    38  var runCommand = cli.Command{
    39  	Action:      runCmd,
    40  	Name:        "run",
    41  	Usage:       "run arbitrary evm binary",
    42  	ArgsUsage:   "<code>",
    43  	Description: `The run command runs arbitrary EVM code.`,
    44  }
    45  
    46  // readGenesis will read the given JSON format genesis file and return
    47  // the initialized Genesis structure
    48  func readGenesis(genesisPath string) *core.Genesis {
    49  	// Make sure we have a valid genesis JSON
    50  	//genesisPath := ctx.Args().First()
    51  	if len(genesisPath) == 0 {
    52  		utils.Fatalf("Must supply path to genesis JSON file")
    53  	}
    54  	file, err := os.Open(genesisPath)
    55  	if err != nil {
    56  		utils.Fatalf("Failed to read genesis file: %v", err)
    57  	}
    58  	defer file.Close()
    59  
    60  	genesis := new(core.Genesis)
    61  	if err := json.NewDecoder(file).Decode(genesis); err != nil {
    62  		utils.Fatalf("invalid genesis file: %v", err)
    63  	}
    64  	return genesis
    65  }
    66  
    67  func runCmd(ctx *cli.Context) error {
    68  	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
    69  	glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)))
    70  	log.Root().SetHandler(glogger)
    71  	logconfig := &vm.LogConfig{
    72  		DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name),
    73  		DisableStack:  ctx.GlobalBool(DisableStackFlag.Name),
    74  	}
    75  
    76  	var (
    77  		tracer      vm.Tracer
    78  		debugLogger *vm.StructLogger
    79  		statedb     *state.StateDB
    80  		chainConfig *params.ChainConfig
    81  		sender      = common.StringToAddress("sender")
    82  		receiver    = common.StringToAddress("receiver")
    83  	)
    84  	if ctx.GlobalBool(MachineFlag.Name) {
    85  		tracer = NewJSONLogger(logconfig, os.Stdout)
    86  	} else if ctx.GlobalBool(DebugFlag.Name) {
    87  		debugLogger = vm.NewStructLogger(logconfig)
    88  		tracer = debugLogger
    89  	} else {
    90  		debugLogger = vm.NewStructLogger(logconfig)
    91  	}
    92  	if ctx.GlobalString(GenesisFlag.Name) != "" {
    93  		gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
    94  		db, _ := ethdb.NewMemDatabase()
    95  		genesis := gen.ToBlock(db)
    96  		statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
    97  		chainConfig = gen.Config
    98  	} else {
    99  		db, _ := ethdb.NewMemDatabase()
   100  		statedb, _ = state.New(common.Hash{}, state.NewDatabase(db))
   101  	}
   102  	if ctx.GlobalString(SenderFlag.Name) != "" {
   103  		sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name))
   104  	}
   105  	statedb.CreateAccount(sender)
   106  
   107  	if ctx.GlobalString(ReceiverFlag.Name) != "" {
   108  		receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name))
   109  	}
   110  
   111  	var (
   112  		code []byte
   113  		ret  []byte
   114  		err  error
   115  	)
   116  	// The '--code' or '--codefile' flag overrides code in state
   117  	if ctx.GlobalString(CodeFileFlag.Name) != "" {
   118  		var hexcode []byte
   119  		var err error
   120  		// If - is specified, it means that code comes from stdin
   121  		if ctx.GlobalString(CodeFileFlag.Name) == "-" {
   122  			//Try reading from stdin
   123  			if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil {
   124  				fmt.Printf("Could not load code from stdin: %v\n", err)
   125  				os.Exit(1)
   126  			}
   127  		} else {
   128  			// Codefile with hex assembly
   129  			if hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)); err != nil {
   130  				fmt.Printf("Could not load code from file: %v\n", err)
   131  				os.Exit(1)
   132  			}
   133  		}
   134  		code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n")))
   135  
   136  	} else if ctx.GlobalString(CodeFlag.Name) != "" {
   137  		code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))
   138  	} else if fn := ctx.Args().First(); len(fn) > 0 {
   139  		// EASM-file to compile
   140  		src, err := ioutil.ReadFile(fn)
   141  		if err != nil {
   142  			return err
   143  		}
   144  		bin, err := compiler.Compile(fn, src, false)
   145  		if err != nil {
   146  			return err
   147  		}
   148  		code = common.Hex2Bytes(bin)
   149  	}
   150  
   151  	initialGas := ctx.GlobalUint64(GasFlag.Name)
   152  	runtimeConfig := runtime.Config{
   153  		Origin:   sender,
   154  		State:    statedb,
   155  		GasLimit: initialGas,
   156  		GasPrice: utils.GlobalBig(ctx, PriceFlag.Name),
   157  		Value:    utils.GlobalBig(ctx, ValueFlag.Name),
   158  		EVMConfig: vm.Config{
   159  			Tracer:             tracer,
   160  			Debug:              ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
   161  			DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
   162  		},
   163  	}
   164  
   165  	if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" {
   166  		f, err := os.Create(cpuProfilePath)
   167  		if err != nil {
   168  			fmt.Println("could not create CPU profile: ", err)
   169  			os.Exit(1)
   170  		}
   171  		if err := pprof.StartCPUProfile(f); err != nil {
   172  			fmt.Println("could not start CPU profile: ", err)
   173  			os.Exit(1)
   174  		}
   175  		defer pprof.StopCPUProfile()
   176  	}
   177  
   178  	if chainConfig != nil {
   179  		runtimeConfig.ChainConfig = chainConfig
   180  	}
   181  	tstart := time.Now()
   182  	var leftOverGas uint64
   183  	if ctx.GlobalBool(CreateFlag.Name) {
   184  		input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
   185  		ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig)
   186  	} else {
   187  		if len(code) > 0 {
   188  			statedb.SetCode(receiver, code)
   189  		}
   190  		ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig)
   191  	}
   192  	execTime := time.Since(tstart)
   193  
   194  	if ctx.GlobalBool(DumpFlag.Name) {
   195  		statedb.IntermediateRoot(true)
   196  		fmt.Println(string(statedb.Dump()))
   197  	}
   198  
   199  	if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" {
   200  		f, err := os.Create(memProfilePath)
   201  		if err != nil {
   202  			fmt.Println("could not create memory profile: ", err)
   203  			os.Exit(1)
   204  		}
   205  		if err := pprof.WriteHeapProfile(f); err != nil {
   206  			fmt.Println("could not write memory profile: ", err)
   207  			os.Exit(1)
   208  		}
   209  		f.Close()
   210  	}
   211  
   212  	if ctx.GlobalBool(DebugFlag.Name) {
   213  		if debugLogger != nil {
   214  			fmt.Fprintln(os.Stderr, "#### TRACE ####")
   215  			vm.WriteTrace(os.Stderr, debugLogger.StructLogs())
   216  		}
   217  		fmt.Fprintln(os.Stderr, "#### LOGS ####")
   218  		vm.WriteLogs(os.Stderr, statedb.Logs())
   219  	}
   220  
   221  	if ctx.GlobalBool(StatDumpFlag.Name) {
   222  		var mem goruntime.MemStats
   223  		goruntime.ReadMemStats(&mem)
   224  		fmt.Fprintf(os.Stderr, `evm execution time: %v
   225  heap objects:       %d
   226  allocations:        %d
   227  total allocations:  %d
   228  GC calls:           %d
   229  Gas used:           %d
   230  
   231  `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas)
   232  	}
   233  	if tracer != nil {
   234  		tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err)
   235  	} else {
   236  		fmt.Printf("0x%x\n", ret)
   237  		if err != nil {
   238  			fmt.Printf(" error: %v\n", err)
   239  		}
   240  	}
   241  
   242  	return nil
   243  }