github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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 "log" 23 "math/big" 24 "os" 25 "path/filepath" 26 "runtime" 27 "time" 28 29 "gopkg.in/urfave/cli.v1" 30 31 "github.com/ethereumproject/go-ethereum/common" 32 "github.com/ethereumproject/go-ethereum/core" 33 "github.com/ethereumproject/go-ethereum/core/state" 34 "github.com/ethereumproject/go-ethereum/core/types" 35 "github.com/ethereumproject/go-ethereum/core/vm" 36 "github.com/ethereumproject/go-ethereum/crypto" 37 "github.com/ethereumproject/go-ethereum/ethdb" 38 "github.com/ethereumproject/go-ethereum/logger/glog" 39 ) 40 41 // Version is the application revision identifier. It can be set with the linker 42 // as in: go build -ldflags "-X main.Version="`git describe --tags` 43 var Version = "unknown" 44 45 var ( 46 DebugFlag = cli.BoolFlag{ 47 Name: "debug", 48 Usage: "output full trace logs", 49 } 50 ForceJitFlag = cli.BoolFlag{ 51 Name: "forcejit", 52 Usage: "forces jit compilation", 53 } 54 DisableJitFlag = cli.BoolFlag{ 55 Name: "nojit", 56 Usage: "disabled jit compilation", 57 } 58 CodeFlag = cli.StringFlag{ 59 Name: "code", 60 Usage: "EVM code", 61 } 62 GasFlag = cli.StringFlag{ 63 Name: "gas", 64 Usage: "gas limit for the evm", 65 Value: "10000000000", 66 } 67 PriceFlag = cli.StringFlag{ 68 Name: "price", 69 Usage: "price set for the evm", 70 Value: "0", 71 } 72 ValueFlag = cli.StringFlag{ 73 Name: "value", 74 Usage: "value set for the evm", 75 Value: "0", 76 } 77 DumpFlag = cli.BoolFlag{ 78 Name: "dump", 79 Usage: "dumps the state after the run", 80 } 81 InputFlag = cli.StringFlag{ 82 Name: "input", 83 Usage: "input for the EVM", 84 } 85 SysStatFlag = cli.BoolFlag{ 86 Name: "sysstat", 87 Usage: "display system stats", 88 } 89 VerbosityFlag = cli.IntFlag{ 90 Name: "verbosity", 91 Usage: "sets the verbosity level", 92 } 93 CreateFlag = cli.BoolFlag{ 94 Name: "create", 95 Usage: "indicates the action should be create rather than call", 96 } 97 ) 98 99 var app *cli.App 100 101 func init() { 102 app = cli.NewApp() 103 app.Name = filepath.Base(os.Args[0]) 104 app.Version = Version 105 app.Usage = "the evm command line interface" 106 app.Action = run 107 app.Flags = []cli.Flag{ 108 CreateFlag, 109 DebugFlag, 110 VerbosityFlag, 111 ForceJitFlag, 112 DisableJitFlag, 113 SysStatFlag, 114 CodeFlag, 115 GasFlag, 116 PriceFlag, 117 ValueFlag, 118 DumpFlag, 119 InputFlag, 120 } 121 } 122 123 func run(ctx *cli.Context) error { 124 glog.SetToStderr(true) 125 glog.SetV(ctx.GlobalInt(VerbosityFlag.Name)) 126 127 db, _ := ethdb.NewMemDatabase() 128 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) 129 sender := statedb.CreateAccount(common.StringToAddress("sender")) 130 131 valueFlag, _ := new(big.Int).SetString(ctx.GlobalString(ValueFlag.Name), 0) 132 if valueFlag == nil { 133 log.Fatalf("malformed %s flag value %q", ValueFlag.Name, ctx.GlobalString(ValueFlag.Name)) 134 } 135 vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), valueFlag) 136 137 tstart := time.Now() 138 139 var ( 140 ret []byte 141 err error 142 ) 143 144 gasFlag, _ := new(big.Int).SetString(ctx.GlobalString(GasFlag.Name), 0) 145 if gasFlag == nil { 146 log.Fatalf("malformed %s flag value %q", GasFlag.Name, ctx.GlobalString(GasFlag.Name)) 147 } 148 priceFlag, _ := new(big.Int).SetString(ctx.GlobalString(PriceFlag.Name), 0) 149 if priceFlag == nil { 150 log.Fatalf("malformed %s flag value %q", PriceFlag.Name, ctx.GlobalString(PriceFlag.Name)) 151 } 152 153 if ctx.GlobalBool(CreateFlag.Name) { 154 input := append(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) 155 ret, _, err = vmenv.Create(sender, input, gasFlag, priceFlag, valueFlag) 156 } else { 157 receiver := statedb.CreateAccount(common.StringToAddress("receiver")) 158 159 code := common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) 160 receiver.SetCode(crypto.Keccak256Hash(code), code) 161 ret, err = vmenv.Call(sender, receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), gasFlag, priceFlag, valueFlag) 162 } 163 vmdone := time.Since(tstart) 164 165 if ctx.GlobalBool(DumpFlag.Name) { 166 statedb.CommitTo(db, false) 167 fmt.Println(string(statedb.Dump([]common.Address{}))) 168 } 169 170 if ctx.GlobalBool(SysStatFlag.Name) { 171 var mem runtime.MemStats 172 runtime.ReadMemStats(&mem) 173 fmt.Printf("vm took %v\n", vmdone) 174 fmt.Printf(`alloc: %d 175 tot alloc: %d 176 no. malloc: %d 177 heap alloc: %d 178 heap objs: %d 179 num gc: %d 180 `, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC) 181 } 182 183 fmt.Printf("OUT: 0x%x", ret) 184 if err != nil { 185 fmt.Printf(" error: %v", err) 186 } 187 fmt.Println() 188 return nil 189 } 190 191 func main() { 192 if err := app.Run(os.Args); err != nil { 193 fmt.Fprintln(os.Stderr, err) 194 os.Exit(1) 195 } 196 } 197 198 type VMEnv struct { 199 state *state.StateDB 200 block *types.Block 201 202 transactor *common.Address 203 value *big.Int 204 205 depth int 206 Gas *big.Int 207 time *big.Int 208 209 evm *vm.EVM 210 } 211 212 func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VMEnv { 213 env := &VMEnv{ 214 state: state, 215 transactor: &transactor, 216 value: value, 217 time: big.NewInt(time.Now().Unix()), 218 } 219 220 env.evm = vm.New(env) 221 return env 222 } 223 224 // ruleSet implements vm.RuleSet and will always default to the homestead rule set. 225 type ruleSet struct{} 226 227 func (ruleSet) IsHomestead(*big.Int) bool { return true } 228 229 func (ruleSet) GasTable(*big.Int) *vm.GasTable { 230 return &vm.GasTable{ 231 ExtcodeSize: big.NewInt(700), 232 ExtcodeCopy: big.NewInt(700), 233 Balance: big.NewInt(400), 234 SLoad: big.NewInt(200), 235 Calls: big.NewInt(700), 236 Suicide: big.NewInt(5000), 237 ExpByte: big.NewInt(10), 238 CreateBySuicide: big.NewInt(25000), 239 } 240 } 241 242 func (self *VMEnv) RuleSet() vm.RuleSet { return ruleSet{} } 243 func (self *VMEnv) Vm() vm.Vm { return self.evm } 244 func (self *VMEnv) Db() vm.Database { return self.state } 245 func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() } 246 func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) } 247 func (self *VMEnv) Origin() common.Address { return *self.transactor } 248 func (self *VMEnv) BlockNumber() *big.Int { return new(big.Int) } 249 func (self *VMEnv) Coinbase() common.Address { return *self.transactor } 250 func (self *VMEnv) Time() *big.Int { return self.time } 251 func (self *VMEnv) Difficulty() *big.Int { return common.Big1 } 252 func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) } 253 func (self *VMEnv) Value() *big.Int { return self.value } 254 func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) } 255 func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy } 256 func (self *VMEnv) Depth() int { return 0 } 257 func (self *VMEnv) SetDepth(i int) { self.depth = i } 258 func (self *VMEnv) GetHash(n uint64) common.Hash { 259 if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 { 260 return self.block.Hash() 261 } 262 return common.Hash{} 263 } 264 func (self *VMEnv) AddLog(log *vm.Log) { 265 self.state.AddLog(*log) 266 } 267 func (self *VMEnv) CanTransfer(from common.Address, balance *big.Int) bool { 268 return self.state.GetBalance(from).Cmp(balance) >= 0 269 } 270 func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) { 271 core.Transfer(from, to, amount) 272 } 273 274 func (self *VMEnv) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { 275 self.Gas = gas 276 return core.Call(self, caller, addr, data, gas, price, value) 277 } 278 279 func (self *VMEnv) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { 280 return core.CallCode(self, caller, addr, data, gas, price, value) 281 } 282 283 func (self *VMEnv) DelegateCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { 284 return core.DelegateCall(self, caller, addr, data, gas, price) 285 } 286 287 func (self *VMEnv) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { 288 return core.Create(self, caller, data, gas, price, value) 289 }