diff --git a/cmd/evm/main.go b/cmd/evm/main.go index ef679e373..0ba6820e0 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/params" ) var ( @@ -174,17 +175,23 @@ type VMEnv struct { Gas *big.Int time *big.Int logs []vm.StructLog + + evm *vm.Vm } func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VMEnv { - return &VMEnv{ + params.HomesteadBlock = new(big.Int) + env := &VMEnv{ state: state, transactor: &transactor, value: value, time: big.NewInt(time.Now().Unix()), } + env.evm = vm.EVM(env) + return env } +func (self *VMEnv) Vm() *vm.Vm { return self.evm } func (self *VMEnv) Db() vm.Database { return self.state } func (self *VMEnv) MakeSnapshot() vm.Database { return self.state.Copy() } func (self *VMEnv) SetSnapshot(db vm.Database) { self.state.Set(db.(*state.StateDB)) } diff --git a/core/execution.go b/core/execution.go index 24c0c93ae..d90dceafc 100644 --- a/core/execution.go +++ b/core/execution.go @@ -60,7 +60,7 @@ func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPric } func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) { - evm := vm.NewVm(env) + evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the // limit. if env.Depth() > int(params.CallCreateDepth.Int64()) { @@ -136,7 +136,7 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A } func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) { - evm := vm.NewVm(env) + evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the // limit. if env.Depth() > int(params.CallCreateDepth.Int64()) { diff --git a/core/vm/common.go b/core/vm/common.go index 395ed0471..f73bc1527 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -21,7 +21,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/params" ) @@ -51,19 +50,6 @@ var ( max = big.NewInt(math.MaxInt64) // Maximum 64 bit integer ) -// NewVm returns a new VM based on the Environment -func NewVm(env Environment) VirtualMachine { - switch env.VmType() { - case JitVmTy: - return NewJitVm(env) - default: - glog.V(0).Infoln("unsupported vm type %d", env.VmType()) - fallthrough - case StdVmTy: - return New(env) - } -} - // calculates the memory size required for a step func calcMemSize(off, l *big.Int) *big.Int { if l.Cmp(common.Big0) == 0 { diff --git a/core/vm/environment.go b/core/vm/environment.go index d5d21a45b..3c530962b 100644 --- a/core/vm/environment.go +++ b/core/vm/environment.go @@ -58,10 +58,8 @@ type Environment interface { AddStructLog(StructLog) // Returns all coalesced structured logs StructLogs() []StructLog - // Type of the VM - VmType() Type - + Vm() *Vm // Current calling depth Depth() int SetDepth(i int) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 1e1086b13..c4b4339a2 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -597,7 +597,6 @@ func opDelegateCall(instr instruction, pc *uint64, env Environment, contract *Co toAddr := common.BigToAddress(to) args := memory.Get(inOffset.Int64(), inSize.Int64()) ret, err := env.DelegateCall(contract, toAddr, args, gas, contract.Price) - if err != nil { stack.push(new(big.Int)) } else { diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go index 19261827b..5fac0156f 100644 --- a/core/vm/jit_test.go +++ b/core/vm/jit_test.go @@ -154,7 +154,7 @@ func runVmBench(test vmBench, b *testing.B) { context := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0)) context.Code = test.code context.CodeAddr = &common.Address{} - _, err := New(env).Run(context, test.input) + _, err := env.Vm().Run(context, test.input) if err != nil { b.Error(err) b.FailNow() @@ -165,12 +165,16 @@ func runVmBench(test vmBench, b *testing.B) { type Env struct { gasLimit *big.Int depth int + evm *Vm } func NewEnv() *Env { - return &Env{big.NewInt(10000), 0} + env := &Env{gasLimit: big.NewInt(10000), depth: 0} + env.evm = EVM(env) + return env } +func (self *Env) Vm() *Vm { return self.evm } func (self *Env) Origin() common.Address { return common.Address{} } func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) } func (self *Env) AddStructLog(log StructLog) { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 37d7bb160..8297d3e1d 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -13,19 +13,15 @@ type jumpPtr struct { type vmJumpTable [256]jumpPtr -func (jt vmJumpTable) init(blockNumber *big.Int) { +func newJumpTable(blockNumber *big.Int) vmJumpTable { + var jumpTable vmJumpTable + // when initialising a new VM execution we must first check the homestead // changes. if params.IsHomestead(blockNumber) { jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true} - } else { - jumpTable[DELEGATECALL] = jumpPtr{nil, false} } -} -var jumpTable vmJumpTable - -func init() { jumpTable[ADD] = jumpPtr{opAdd, true} jumpTable[SUB] = jumpPtr{opSub, true} jumpTable[MUL] = jumpPtr{opMul, true} @@ -156,4 +152,6 @@ func init() { jumpTable[JUMP] = jumpPtr{nil, true} jumpTable[JUMPI] = jumpPtr{nil, true} jumpTable[STOP] = jumpPtr{nil, true} + + return jumpTable } diff --git a/core/vm/jump_table_test.go b/core/vm/jump_table_test.go index 98d34bef2..2ed1b26fc 100644 --- a/core/vm/jump_table_test.go +++ b/core/vm/jump_table_test.go @@ -10,13 +10,13 @@ import ( func TestInit(t *testing.T) { params.HomesteadBlock = big.NewInt(1) - jumpTable.init(big.NewInt(0)) + jumpTable := newJumpTable(big.NewInt(0)) if jumpTable[DELEGATECALL].valid { t.Error("Expected DELEGATECALL not to be present") } for _, n := range []int64{1, 2, 100} { - jumpTable.init(big.NewInt(n)) + jumpTable := newJumpTable(big.NewInt(n)) if !jumpTable[DELEGATECALL].valid { t.Error("Expected DELEGATECALL to be present for block", n) } diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 77519df81..e9bf828ea 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -41,11 +41,13 @@ type Env struct { logs []vm.StructLog getHashFn func(uint64) common.Hash + + evm *vm.Vm } // NewEnv returns a new vm.Environment func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { - return &Env{ + env := &Env{ state: state, origin: cfg.Origin, coinbase: cfg.Coinbase, @@ -54,6 +56,9 @@ func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { difficulty: cfg.Difficulty, gasLimit: cfg.GasLimit, } + env.evm = vm.EVM(env) + + return env } func (self *Env) StructLogs() []vm.StructLog { @@ -64,6 +69,7 @@ func (self *Env) AddStructLog(log vm.StructLog) { self.logs = append(self.logs, log) } +func (self *Env) Vm() *vm.Vm { return self.evm } func (self *Env) Origin() common.Address { return self.origin } func (self *Env) BlockNumber() *big.Int { return self.number } func (self *Env) Coinbase() common.Address { return self.coinbase } diff --git a/core/vm/vm.go b/core/vm/vm.go index 95d27c64c..26df8aef4 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -30,15 +30,12 @@ import ( // Vm is an EVM and implements VirtualMachine type Vm struct { - env Environment + env Environment + jumpTable vmJumpTable } -// New returns a new Vm -func New(env Environment) *Vm { - // init the jump table. Also prepares the homestead changes - jumpTable.init(env.BlockNumber()) - - return &Vm{env: env} +func EVM(env Environment) *Vm { + return &Vm{env: env, jumpTable: newJumpTable(env.BlockNumber())} } // Run loops and evaluates the contract's code with the given input data @@ -169,7 +166,7 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) { mem.Resize(newMemSize.Uint64()) // Add a log message self.log(pc, op, contract.Gas, cost, mem, stack, contract, nil) - if opPtr := jumpTable[op]; opPtr.valid { + if opPtr := self.jumpTable[op]; opPtr.valid { if opPtr.fn != nil { opPtr.fn(instruction{}, &pc, self.env, contract, mem, stack) } else { diff --git a/core/vm/vm_jit_fake.go b/core/vm/vm_jit_fake.go index 456fcb8d4..192f3615d 100644 --- a/core/vm/vm_jit_fake.go +++ b/core/vm/vm_jit_fake.go @@ -22,5 +22,5 @@ import "fmt" func NewJitVm(env Environment) VirtualMachine { fmt.Printf("Warning! EVM JIT not enabled.\n") - return New(env) + return EVM(env) } diff --git a/core/vm_env.go b/core/vm_env.go index 7b9a1a0f9..0fab4a090 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -51,10 +51,11 @@ type VMEnv struct { getHashFn func(uint64) common.Hash // structured logging logs []vm.StructLog + evm *vm.Vm } func NewEnv(state *state.StateDB, chain *BlockChain, msg Message, header *types.Header) *VMEnv { - return &VMEnv{ + env := &VMEnv{ chain: chain, state: state, header: header, @@ -62,8 +63,11 @@ func NewEnv(state *state.StateDB, chain *BlockChain, msg Message, header *types. typ: vm.StdVmTy, getHashFn: GetHashFn(header.ParentHash, chain), } + env.evm = vm.EVM(env) + return env } +func (self *VMEnv) Vm() *vm.Vm { return self.evm } func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f } func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } diff --git a/tests/util.go b/tests/util.go index 29f4c9b72..2c749edba 100644 --- a/tests/util.go +++ b/tests/util.go @@ -143,12 +143,15 @@ type Env struct { logs []vm.StructLog vmTest bool + + evm *vm.Vm } func NewEnv(state *state.StateDB) *Env { - return &Env{ + env := &Env{ state: state, } + return env } func (self *Env) StructLogs() []vm.StructLog { @@ -171,9 +174,12 @@ func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues env.gasLimit = common.Big(envValues["currentGasLimit"]) env.Gas = new(big.Int) + env.evm = vm.EVM(env) + return env } +func (self *Env) Vm() *vm.Vm { return self.evm } func (self *Env) Origin() common.Address { return self.origin } func (self *Env) BlockNumber() *big.Int { return self.number } func (self *Env) Coinbase() common.Address { return self.coinbase }