github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/cmd/evm/runner.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2017 Go Ethereum作者
    10  //此文件是Go以太坊的一部分。
    11  //
    12  //Go以太坊是免费软件:您可以重新发布和/或修改它
    13  //根据GNU通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊的分布希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //
    21  //
    22  //你应该已经收到一份GNU通用公共许可证的副本
    23  //一起去以太坊吧。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package main
    26  
    27  import (
    28  	"bytes"
    29  	"encoding/json"
    30  	"fmt"
    31  	"io/ioutil"
    32  	"math/big"
    33  	"os"
    34  	goruntime "runtime"
    35  	"runtime/pprof"
    36  	"time"
    37  
    38  	"github.com/ethereum/go-ethereum/cmd/evm/internal/compiler"
    39  	"github.com/ethereum/go-ethereum/cmd/utils"
    40  	"github.com/ethereum/go-ethereum/common"
    41  	"github.com/ethereum/go-ethereum/core"
    42  	"github.com/ethereum/go-ethereum/core/state"
    43  	"github.com/ethereum/go-ethereum/core/vm"
    44  	"github.com/ethereum/go-ethereum/core/vm/runtime"
    45  	"github.com/ethereum/go-ethereum/ethdb"
    46  	"github.com/ethereum/go-ethereum/log"
    47  	"github.com/ethereum/go-ethereum/params"
    48  	cli "gopkg.in/urfave/cli.v1"
    49  )
    50  
    51  var runCommand = cli.Command{
    52  	Action:      runCmd,
    53  	Name:        "run",
    54  	Usage:       "run arbitrary evm binary",
    55  	ArgsUsage:   "<code>",
    56  	Description: `The run command runs arbitrary EVM code.`,
    57  }
    58  
    59  //read genesis将读取给定的JSON格式genesis文件并返回
    60  //初始化的Genesis结构
    61  func readGenesis(genesisPath string) *core.Genesis {
    62  //确保我们有一个有效的Genesis JSON
    63  //genesPath:=ctx.args().first())
    64  	if len(genesisPath) == 0 {
    65  		utils.Fatalf("Must supply path to genesis JSON file")
    66  	}
    67  	file, err := os.Open(genesisPath)
    68  	if err != nil {
    69  		utils.Fatalf("Failed to read genesis file: %v", err)
    70  	}
    71  	defer file.Close()
    72  
    73  	genesis := new(core.Genesis)
    74  	if err := json.NewDecoder(file).Decode(genesis); err != nil {
    75  		utils.Fatalf("invalid genesis file: %v", err)
    76  	}
    77  	return genesis
    78  }
    79  
    80  func runCmd(ctx *cli.Context) error {
    81  	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
    82  	glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)))
    83  	log.Root().SetHandler(glogger)
    84  	logconfig := &vm.LogConfig{
    85  		DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name),
    86  		DisableStack:  ctx.GlobalBool(DisableStackFlag.Name),
    87  		Debug:         ctx.GlobalBool(DebugFlag.Name),
    88  	}
    89  
    90  	var (
    91  		tracer      vm.Tracer
    92  		debugLogger *vm.StructLogger
    93  		statedb     *state.StateDB
    94  		chainConfig *params.ChainConfig
    95  		sender      = common.BytesToAddress([]byte("sender"))
    96  		receiver    = common.BytesToAddress([]byte("receiver"))
    97  		blockNumber uint64
    98  	)
    99  	if ctx.GlobalBool(MachineFlag.Name) {
   100  		tracer = NewJSONLogger(logconfig, os.Stdout)
   101  	} else if ctx.GlobalBool(DebugFlag.Name) {
   102  		debugLogger = vm.NewStructLogger(logconfig)
   103  		tracer = debugLogger
   104  	} else {
   105  		debugLogger = vm.NewStructLogger(logconfig)
   106  	}
   107  	if ctx.GlobalString(GenesisFlag.Name) != "" {
   108  		gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
   109  		db := ethdb.NewMemDatabase()
   110  		genesis := gen.ToBlock(db)
   111  		statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
   112  		chainConfig = gen.Config
   113  		blockNumber = gen.Number
   114  	} else {
   115  		statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
   116  	}
   117  	if ctx.GlobalString(SenderFlag.Name) != "" {
   118  		sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name))
   119  	}
   120  	statedb.CreateAccount(sender)
   121  
   122  	if ctx.GlobalString(ReceiverFlag.Name) != "" {
   123  		receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name))
   124  	}
   125  
   126  	var (
   127  		code []byte
   128  		ret  []byte
   129  		err  error
   130  	)
   131  //“--code”或“--codefile”标志重写处于状态的代码
   132  	if ctx.GlobalString(CodeFileFlag.Name) != "" {
   133  		var hexcode []byte
   134  		var err error
   135  //如果指定了-则表示代码来自stdin
   136  		if ctx.GlobalString(CodeFileFlag.Name) == "-" {
   137  //尝试从stdin读取
   138  			if hexcode, err = ioutil.ReadAll(os.Stdin); err != nil {
   139  				fmt.Printf("Could not load code from stdin: %v\n", err)
   140  				os.Exit(1)
   141  			}
   142  		} else {
   143  //带十六进制程序集的代码文件
   144  			if hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)); err != nil {
   145  				fmt.Printf("Could not load code from file: %v\n", err)
   146  				os.Exit(1)
   147  			}
   148  		}
   149  		code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n")))
   150  
   151  	} else if ctx.GlobalString(CodeFlag.Name) != "" {
   152  		code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))
   153  	} else if fn := ctx.Args().First(); len(fn) > 0 {
   154  //要编译的EASM文件
   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  
   166  	initialGas := ctx.GlobalUint64(GasFlag.Name)
   167  	runtimeConfig := runtime.Config{
   168  		Origin:      sender,
   169  		State:       statedb,
   170  		GasLimit:    initialGas,
   171  		GasPrice:    utils.GlobalBig(ctx, PriceFlag.Name),
   172  		Value:       utils.GlobalBig(ctx, ValueFlag.Name),
   173  		BlockNumber: new(big.Int).SetUint64(blockNumber),
   174  		EVMConfig: vm.Config{
   175  			Tracer: tracer,
   176  			Debug:  ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name),
   177  		},
   178  	}
   179  
   180  	if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" {
   181  		f, err := os.Create(cpuProfilePath)
   182  		if err != nil {
   183  			fmt.Println("could not create CPU profile: ", err)
   184  			os.Exit(1)
   185  		}
   186  		if err := pprof.StartCPUProfile(f); err != nil {
   187  			fmt.Println("could not start CPU profile: ", err)
   188  			os.Exit(1)
   189  		}
   190  		defer pprof.StopCPUProfile()
   191  	}
   192  
   193  	if chainConfig != nil {
   194  		runtimeConfig.ChainConfig = chainConfig
   195  	}
   196  	tstart := time.Now()
   197  	var leftOverGas uint64
   198  	if ctx.GlobalBool(CreateFlag.Name) {
   199  		input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
   200  		ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig)
   201  	} else {
   202  		if len(code) > 0 {
   203  			statedb.SetCode(receiver, code)
   204  		}
   205  		ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig)
   206  	}
   207  	execTime := time.Since(tstart)
   208  
   209  	if ctx.GlobalBool(DumpFlag.Name) {
   210  		statedb.IntermediateRoot(true)
   211  		fmt.Println(string(statedb.Dump()))
   212  	}
   213  
   214  	if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" {
   215  		f, err := os.Create(memProfilePath)
   216  		if err != nil {
   217  			fmt.Println("could not create memory profile: ", err)
   218  			os.Exit(1)
   219  		}
   220  		if err := pprof.WriteHeapProfile(f); err != nil {
   221  			fmt.Println("could not write memory profile: ", err)
   222  			os.Exit(1)
   223  		}
   224  		f.Close()
   225  	}
   226  
   227  	if ctx.GlobalBool(DebugFlag.Name) {
   228  		if debugLogger != nil {
   229  			fmt.Fprintln(os.Stderr, "#### TRACE ####")
   230  			vm.WriteTrace(os.Stderr, debugLogger.StructLogs())
   231  		}
   232  		fmt.Fprintln(os.Stderr, "#### LOGS ####")
   233  		vm.WriteLogs(os.Stderr, statedb.Logs())
   234  	}
   235  
   236  	if ctx.GlobalBool(StatDumpFlag.Name) {
   237  		var mem goruntime.MemStats
   238  		goruntime.ReadMemStats(&mem)
   239  		fmt.Fprintf(os.Stderr, `evm execution time: %v
   240  heap objects:       %d
   241  allocations:        %d
   242  total allocations:  %d
   243  GC calls:           %d
   244  Gas used:           %d
   245  
   246  `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas)
   247  	}
   248  	if tracer == nil {
   249  		fmt.Printf("0x%x\n", ret)
   250  		if err != nil {
   251  			fmt.Printf(" error: %v\n", err)
   252  		}
   253  	}
   254  
   255  	return nil
   256  }