github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/cmd/evm/main.go (about)

     1  // Copyright 2014 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  // evm executes EVM code snippets.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"math/big"
    23  	"os"
    24  	"runtime"
    25  	"time"
    26  
    27  	"github.com/codegangsta/cli"
    28  	"github.com/ethereum/go-ethereum/cmd/utils"
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/core"
    31  	"github.com/ethereum/go-ethereum/core/state"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/core/vm"
    34  	"github.com/ethereum/go-ethereum/ethdb"
    35  	"github.com/ethereum/go-ethereum/logger/glog"
    36  )
    37  
    38  var (
    39  	app       *cli.App
    40  	DebugFlag = cli.BoolFlag{
    41  		Name:  "debug",
    42  		Usage: "output full trace logs",
    43  	}
    44  	ForceJitFlag = cli.BoolFlag{
    45  		Name:  "forcejit",
    46  		Usage: "forces jit compilation",
    47  	}
    48  	DisableJitFlag = cli.BoolFlag{
    49  		Name:  "nojit",
    50  		Usage: "disabled jit compilation",
    51  	}
    52  	CodeFlag = cli.StringFlag{
    53  		Name:  "code",
    54  		Usage: "EVM code",
    55  	}
    56  	GasFlag = cli.StringFlag{
    57  		Name:  "gas",
    58  		Usage: "gas limit for the evm",
    59  		Value: "10000000000",
    60  	}
    61  	PriceFlag = cli.StringFlag{
    62  		Name:  "price",
    63  		Usage: "price set for the evm",
    64  		Value: "0",
    65  	}
    66  	ValueFlag = cli.StringFlag{
    67  		Name:  "value",
    68  		Usage: "value set for the evm",
    69  		Value: "0",
    70  	}
    71  	DumpFlag = cli.BoolFlag{
    72  		Name:  "dump",
    73  		Usage: "dumps the state after the run",
    74  	}
    75  	InputFlag = cli.StringFlag{
    76  		Name:  "input",
    77  		Usage: "input for the EVM",
    78  	}
    79  	SysStatFlag = cli.BoolFlag{
    80  		Name:  "sysstat",
    81  		Usage: "display system stats",
    82  	}
    83  )
    84  
    85  func init() {
    86  	app = utils.NewApp("0.2", "the evm command line interface")
    87  	app.Flags = []cli.Flag{
    88  		DebugFlag,
    89  		ForceJitFlag,
    90  		DisableJitFlag,
    91  		SysStatFlag,
    92  		CodeFlag,
    93  		GasFlag,
    94  		PriceFlag,
    95  		ValueFlag,
    96  		DumpFlag,
    97  		InputFlag,
    98  	}
    99  	app.Action = run
   100  }
   101  
   102  func run(ctx *cli.Context) {
   103  	vm.Debug = ctx.GlobalBool(DebugFlag.Name)
   104  	vm.ForceJit = ctx.GlobalBool(ForceJitFlag.Name)
   105  	vm.EnableJit = !ctx.GlobalBool(DisableJitFlag.Name)
   106  
   107  	glog.SetToStderr(true)
   108  
   109  	db, _ := ethdb.NewMemDatabase()
   110  	statedb := state.New(common.Hash{}, db)
   111  	sender := statedb.CreateAccount(common.StringToAddress("sender"))
   112  	receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
   113  	receiver.SetCode(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)))
   114  
   115  	vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name)))
   116  
   117  	tstart := time.Now()
   118  	ret, e := vmenv.Call(
   119  		sender,
   120  		receiver.Address(),
   121  		common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)),
   122  		common.Big(ctx.GlobalString(GasFlag.Name)),
   123  		common.Big(ctx.GlobalString(PriceFlag.Name)),
   124  		common.Big(ctx.GlobalString(ValueFlag.Name)),
   125  	)
   126  	vmdone := time.Since(tstart)
   127  
   128  	if ctx.GlobalBool(DumpFlag.Name) {
   129  		fmt.Println(string(statedb.Dump()))
   130  	}
   131  	vm.StdErrFormat(vmenv.StructLogs())
   132  
   133  	if ctx.GlobalBool(SysStatFlag.Name) {
   134  		var mem runtime.MemStats
   135  		runtime.ReadMemStats(&mem)
   136  		fmt.Printf("vm took %v\n", vmdone)
   137  		fmt.Printf(`alloc:      %d
   138  tot alloc:  %d
   139  no. malloc: %d
   140  heap alloc: %d
   141  heap objs:  %d
   142  num gc:     %d
   143  `, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC)
   144  	}
   145  
   146  	fmt.Printf("OUT: 0x%x", ret)
   147  	if e != nil {
   148  		fmt.Printf(" error: %v", e)
   149  	}
   150  	fmt.Println()
   151  }
   152  
   153  func main() {
   154  	if err := app.Run(os.Args); err != nil {
   155  		fmt.Fprintln(os.Stderr, err)
   156  		os.Exit(1)
   157  	}
   158  }
   159  
   160  type VMEnv struct {
   161  	state *state.StateDB
   162  	block *types.Block
   163  
   164  	transactor *common.Address
   165  	value      *big.Int
   166  
   167  	depth int
   168  	Gas   *big.Int
   169  	time  *big.Int
   170  	logs  []vm.StructLog
   171  }
   172  
   173  func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VMEnv {
   174  	return &VMEnv{
   175  		state:      state,
   176  		transactor: &transactor,
   177  		value:      value,
   178  		time:       big.NewInt(time.Now().Unix()),
   179  	}
   180  }
   181  
   182  func (self *VMEnv) State() *state.StateDB    { return self.state }
   183  func (self *VMEnv) Origin() common.Address   { return *self.transactor }
   184  func (self *VMEnv) BlockNumber() *big.Int    { return common.Big0 }
   185  func (self *VMEnv) Coinbase() common.Address { return *self.transactor }
   186  func (self *VMEnv) Time() *big.Int           { return self.time }
   187  func (self *VMEnv) Difficulty() *big.Int     { return common.Big1 }
   188  func (self *VMEnv) BlockHash() []byte        { return make([]byte, 32) }
   189  func (self *VMEnv) Value() *big.Int          { return self.value }
   190  func (self *VMEnv) GasLimit() *big.Int       { return big.NewInt(1000000000) }
   191  func (self *VMEnv) VmType() vm.Type          { return vm.StdVmTy }
   192  func (self *VMEnv) Depth() int               { return 0 }
   193  func (self *VMEnv) SetDepth(i int)           { self.depth = i }
   194  func (self *VMEnv) GetHash(n uint64) common.Hash {
   195  	if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 {
   196  		return self.block.Hash()
   197  	}
   198  	return common.Hash{}
   199  }
   200  func (self *VMEnv) AddStructLog(log vm.StructLog) {
   201  	self.logs = append(self.logs, log)
   202  }
   203  func (self *VMEnv) StructLogs() []vm.StructLog {
   204  	return self.logs
   205  }
   206  func (self *VMEnv) AddLog(log *state.Log) {
   207  	self.state.AddLog(log)
   208  }
   209  func (self *VMEnv) CanTransfer(from vm.Account, balance *big.Int) bool {
   210  	return from.Balance().Cmp(balance) >= 0
   211  }
   212  func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
   213  	return vm.Transfer(from, to, amount)
   214  }
   215  
   216  func (self *VMEnv) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *core.Execution {
   217  	return core.NewExecution(self, addr, data, gas, price, value)
   218  }
   219  
   220  func (self *VMEnv) Call(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
   221  	exe := self.vm(&addr, data, gas, price, value)
   222  	ret, err := exe.Call(addr, caller)
   223  	self.Gas = exe.Gas
   224  
   225  	return ret, err
   226  }
   227  func (self *VMEnv) CallCode(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
   228  	a := caller.Address()
   229  	exe := self.vm(&a, data, gas, price, value)
   230  	return exe.Call(addr, caller)
   231  }
   232  
   233  func (self *VMEnv) Create(caller vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
   234  	exe := self.vm(nil, data, gas, price, value)
   235  	return exe.Create(caller)
   236  }