main.go 5.35 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2014 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 13 14
// GNU General Public License for more details.
//
// 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/>.
obscuren's avatar
obscuren committed
16

17
// evm executes EVM code snippets.
obscuren's avatar
obscuren committed
18 19 20 21
package main

import (
	"fmt"
22
	"io/ioutil"
obscuren's avatar
obscuren committed
23
	"os"
24
	goruntime "runtime"
obscuren's avatar
obscuren committed
25 26
	"time"

27
	"github.com/ethereum/go-ethereum/cmd/utils"
obscuren's avatar
obscuren committed
28
	"github.com/ethereum/go-ethereum/common"
obscuren's avatar
obscuren committed
29 30
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/core/vm"
31
	"github.com/ethereum/go-ethereum/core/vm/runtime"
32
	"github.com/ethereum/go-ethereum/crypto"
obscuren's avatar
obscuren committed
33
	"github.com/ethereum/go-ethereum/ethdb"
34
	"github.com/ethereum/go-ethereum/logger/glog"
35
	"gopkg.in/urfave/cli.v1"
obscuren's avatar
obscuren committed
36 37
)

38 39
var gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags)

obscuren's avatar
obscuren committed
40
var (
41 42
	app = utils.NewApp(gitCommit, "the evm command line interface")

43 44 45 46
	DebugFlag = cli.BoolFlag{
		Name:  "debug",
		Usage: "output full trace logs",
	}
47 48 49 50 51 52 53 54
	ForceJitFlag = cli.BoolFlag{
		Name:  "forcejit",
		Usage: "forces jit compilation",
	}
	DisableJitFlag = cli.BoolFlag{
		Name:  "nojit",
		Usage: "disabled jit compilation",
	}
55 56 57 58
	CodeFlag = cli.StringFlag{
		Name:  "code",
		Usage: "EVM code",
	}
59 60 61 62
	CodeFileFlag = cli.StringFlag{
		Name:  "codefile",
		Usage: "file containing EVM code",
	}
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
	GasFlag = cli.StringFlag{
		Name:  "gas",
		Usage: "gas limit for the evm",
		Value: "10000000000",
	}
	PriceFlag = cli.StringFlag{
		Name:  "price",
		Usage: "price set for the evm",
		Value: "0",
	}
	ValueFlag = cli.StringFlag{
		Name:  "value",
		Usage: "value set for the evm",
		Value: "0",
	}
	DumpFlag = cli.BoolFlag{
		Name:  "dump",
		Usage: "dumps the state after the run",
	}
	InputFlag = cli.StringFlag{
		Name:  "input",
		Usage: "input for the EVM",
	}
	SysStatFlag = cli.BoolFlag{
		Name:  "sysstat",
		Usage: "display system stats",
	}
90 91 92 93
	VerbosityFlag = cli.IntFlag{
		Name:  "verbosity",
		Usage: "sets the verbosity level",
	}
94 95 96 97
	CreateFlag = cli.BoolFlag{
		Name:  "create",
		Usage: "indicates the action should be create rather than call",
	}
obscuren's avatar
obscuren committed
98 99
)

100 101
func init() {
	app.Flags = []cli.Flag{
102
		CreateFlag,
103
		DebugFlag,
104
		VerbosityFlag,
105 106
		ForceJitFlag,
		DisableJitFlag,
107 108
		SysStatFlag,
		CodeFlag,
109
		CodeFileFlag,
110 111 112 113 114 115 116
		GasFlag,
		PriceFlag,
		ValueFlag,
		DumpFlag,
		InputFlag,
	}
	app.Action = run
obscuren's avatar
obscuren committed
117 118
}

119
func run(ctx *cli.Context) error {
120
	glog.SetToStderr(true)
121
	glog.SetV(ctx.GlobalInt(VerbosityFlag.Name))
obscuren's avatar
obscuren committed
122

obscuren's avatar
obscuren committed
123
	db, _ := ethdb.NewMemDatabase()
124
	statedb, _ := state.New(common.Hash{}, db)
obscuren's avatar
obscuren committed
125
	sender := statedb.CreateAccount(common.StringToAddress("sender"))
obscuren's avatar
obscuren committed
126

127 128
	logger := vm.NewStructLogger(nil)

obscuren's avatar
obscuren committed
129
	tstart := time.Now()
130 131

	var (
132 133 134
		code []byte
		ret  []byte
		err  error
135
	)
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
	if ctx.GlobalString(CodeFlag.Name) != "" {
		code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))
	} else {
		var hexcode []byte
		if ctx.GlobalString(CodeFileFlag.Name) != "" {
			var err error
			hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name))
			if err != nil {
				fmt.Printf("Could not load code from file: %v\n", err)
				os.Exit(1)
			}
		} else {
			var err error
			hexcode, err = ioutil.ReadAll(os.Stdin)
			if err != nil {
				fmt.Printf("Could not load code from stdin: %v\n", err)
				os.Exit(1)
			}
		}
		code = common.Hex2Bytes(string(hexcode[:]))
	}

159
	if ctx.GlobalBool(CreateFlag.Name) {
160
		input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
161 162 163 164 165 166 167 168 169 170
		ret, _, err = runtime.Create(input, &runtime.Config{
			Origin:   sender.Address(),
			State:    statedb,
			GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
			GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
			Value:    common.Big(ctx.GlobalString(ValueFlag.Name)),
			EVMConfig: vm.Config{
				Tracer: logger,
			},
		})
171 172
	} else {
		receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
173
		receiver.SetCode(crypto.Keccak256Hash(code), code)
174 175 176 177 178 179 180 181 182 183 184

		ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
			Origin:   sender.Address(),
			State:    statedb,
			GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
			GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
			Value:    common.Big(ctx.GlobalString(ValueFlag.Name)),
			EVMConfig: vm.Config{
				Tracer: logger,
			},
		})
185
	}
186
	vmdone := time.Since(tstart)
obscuren's avatar
obscuren committed
187

188
	if ctx.GlobalBool(DumpFlag.Name) {
189
		statedb.Commit(true)
obscuren's avatar
obscuren committed
190
		fmt.Println(string(statedb.Dump()))
obscuren's avatar
obscuren committed
191
	}
192
	vm.StdErrFormat(logger.StructLogs())
193

194
	if ctx.GlobalBool(SysStatFlag.Name) {
195 196
		var mem goruntime.MemStats
		goruntime.ReadMemStats(&mem)
197 198
		fmt.Printf("vm took %v\n", vmdone)
		fmt.Printf(`alloc:      %d
obscuren's avatar
obscuren committed
199 200 201 202 203 204
tot alloc:  %d
no. malloc: %d
heap alloc: %d
heap objs:  %d
num gc:     %d
`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC)
205
	}
obscuren's avatar
obscuren committed
206

207
	fmt.Printf("OUT: 0x%x", ret)
208 209
	if err != nil {
		fmt.Printf(" error: %v", err)
210 211
	}
	fmt.Println()
212
	return nil
213 214 215 216 217 218 219
}

func main() {
	if err := app.Run(os.Args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
obscuren's avatar
obscuren committed
220
}