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 }