forked from cerc-io/plugeth
core, core/vm, tests: changed the initialisation behaviour of the EVM
The EVM was previously initialised and created for every CALL, CALLCODE, DELEGATECALL and CREATE. This PR changes this behaviour so that the same EVM can be used through the session and beyond as long as the Environment sticks around.
This commit is contained in:
parent
2855a93ede
commit
342ae7ce7d
@ -33,6 +33,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -174,17 +175,23 @@ type VMEnv struct {
|
|||||||
Gas *big.Int
|
Gas *big.Int
|
||||||
time *big.Int
|
time *big.Int
|
||||||
logs []vm.StructLog
|
logs []vm.StructLog
|
||||||
|
|
||||||
|
evm *vm.Vm
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VMEnv {
|
func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VMEnv {
|
||||||
return &VMEnv{
|
params.HomesteadBlock = new(big.Int)
|
||||||
|
env := &VMEnv{
|
||||||
state: state,
|
state: state,
|
||||||
transactor: &transactor,
|
transactor: &transactor,
|
||||||
value: value,
|
value: value,
|
||||||
time: big.NewInt(time.Now().Unix()),
|
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) Db() vm.Database { return self.state }
|
||||||
func (self *VMEnv) MakeSnapshot() vm.Database { return self.state.Copy() }
|
func (self *VMEnv) MakeSnapshot() vm.Database { return self.state.Copy() }
|
||||||
func (self *VMEnv) SetSnapshot(db vm.Database) { self.state.Set(db.(*state.StateDB)) }
|
func (self *VMEnv) SetSnapshot(db vm.Database) { self.state.Set(db.(*state.StateDB)) }
|
||||||
|
@ -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) {
|
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
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
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) {
|
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
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,19 +50,6 @@ var (
|
|||||||
max = big.NewInt(math.MaxInt64) // Maximum 64 bit integer
|
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
|
// calculates the memory size required for a step
|
||||||
func calcMemSize(off, l *big.Int) *big.Int {
|
func calcMemSize(off, l *big.Int) *big.Int {
|
||||||
if l.Cmp(common.Big0) == 0 {
|
if l.Cmp(common.Big0) == 0 {
|
||||||
|
@ -58,10 +58,8 @@ type Environment interface {
|
|||||||
AddStructLog(StructLog)
|
AddStructLog(StructLog)
|
||||||
// Returns all coalesced structured logs
|
// Returns all coalesced structured logs
|
||||||
StructLogs() []StructLog
|
StructLogs() []StructLog
|
||||||
|
|
||||||
// Type of the VM
|
// Type of the VM
|
||||||
VmType() Type
|
Vm() *Vm
|
||||||
|
|
||||||
// Current calling depth
|
// Current calling depth
|
||||||
Depth() int
|
Depth() int
|
||||||
SetDepth(i int)
|
SetDepth(i int)
|
||||||
|
@ -597,7 +597,6 @@ func opDelegateCall(instr instruction, pc *uint64, env Environment, contract *Co
|
|||||||
toAddr := common.BigToAddress(to)
|
toAddr := common.BigToAddress(to)
|
||||||
args := memory.Get(inOffset.Int64(), inSize.Int64())
|
args := memory.Get(inOffset.Int64(), inSize.Int64())
|
||||||
ret, err := env.DelegateCall(contract, toAddr, args, gas, contract.Price)
|
ret, err := env.DelegateCall(contract, toAddr, args, gas, contract.Price)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
} else {
|
} else {
|
||||||
|
@ -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 := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0))
|
||||||
context.Code = test.code
|
context.Code = test.code
|
||||||
context.CodeAddr = &common.Address{}
|
context.CodeAddr = &common.Address{}
|
||||||
_, err := New(env).Run(context, test.input)
|
_, err := env.Vm().Run(context, test.input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
b.FailNow()
|
b.FailNow()
|
||||||
@ -165,12 +165,16 @@ func runVmBench(test vmBench, b *testing.B) {
|
|||||||
type Env struct {
|
type Env struct {
|
||||||
gasLimit *big.Int
|
gasLimit *big.Int
|
||||||
depth int
|
depth int
|
||||||
|
evm *Vm
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv() *Env {
|
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) Origin() common.Address { return common.Address{} }
|
||||||
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
|
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
|
||||||
func (self *Env) AddStructLog(log StructLog) {
|
func (self *Env) AddStructLog(log StructLog) {
|
||||||
|
@ -13,19 +13,15 @@ type jumpPtr struct {
|
|||||||
|
|
||||||
type vmJumpTable [256]jumpPtr
|
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
|
// when initialising a new VM execution we must first check the homestead
|
||||||
// changes.
|
// changes.
|
||||||
if params.IsHomestead(blockNumber) {
|
if params.IsHomestead(blockNumber) {
|
||||||
jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true}
|
jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true}
|
||||||
} else {
|
|
||||||
jumpTable[DELEGATECALL] = jumpPtr{nil, false}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var jumpTable vmJumpTable
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
jumpTable[ADD] = jumpPtr{opAdd, true}
|
jumpTable[ADD] = jumpPtr{opAdd, true}
|
||||||
jumpTable[SUB] = jumpPtr{opSub, true}
|
jumpTable[SUB] = jumpPtr{opSub, true}
|
||||||
jumpTable[MUL] = jumpPtr{opMul, true}
|
jumpTable[MUL] = jumpPtr{opMul, true}
|
||||||
@ -156,4 +152,6 @@ func init() {
|
|||||||
jumpTable[JUMP] = jumpPtr{nil, true}
|
jumpTable[JUMP] = jumpPtr{nil, true}
|
||||||
jumpTable[JUMPI] = jumpPtr{nil, true}
|
jumpTable[JUMPI] = jumpPtr{nil, true}
|
||||||
jumpTable[STOP] = jumpPtr{nil, true}
|
jumpTable[STOP] = jumpPtr{nil, true}
|
||||||
|
|
||||||
|
return jumpTable
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,13 @@ import (
|
|||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
params.HomesteadBlock = big.NewInt(1)
|
params.HomesteadBlock = big.NewInt(1)
|
||||||
|
|
||||||
jumpTable.init(big.NewInt(0))
|
jumpTable := newJumpTable(big.NewInt(0))
|
||||||
if jumpTable[DELEGATECALL].valid {
|
if jumpTable[DELEGATECALL].valid {
|
||||||
t.Error("Expected DELEGATECALL not to be present")
|
t.Error("Expected DELEGATECALL not to be present")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, n := range []int64{1, 2, 100} {
|
for _, n := range []int64{1, 2, 100} {
|
||||||
jumpTable.init(big.NewInt(n))
|
jumpTable := newJumpTable(big.NewInt(n))
|
||||||
if !jumpTable[DELEGATECALL].valid {
|
if !jumpTable[DELEGATECALL].valid {
|
||||||
t.Error("Expected DELEGATECALL to be present for block", n)
|
t.Error("Expected DELEGATECALL to be present for block", n)
|
||||||
}
|
}
|
||||||
|
@ -41,11 +41,13 @@ type Env struct {
|
|||||||
logs []vm.StructLog
|
logs []vm.StructLog
|
||||||
|
|
||||||
getHashFn func(uint64) common.Hash
|
getHashFn func(uint64) common.Hash
|
||||||
|
|
||||||
|
evm *vm.Vm
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEnv returns a new vm.Environment
|
// NewEnv returns a new vm.Environment
|
||||||
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
|
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
|
||||||
return &Env{
|
env := &Env{
|
||||||
state: state,
|
state: state,
|
||||||
origin: cfg.Origin,
|
origin: cfg.Origin,
|
||||||
coinbase: cfg.Coinbase,
|
coinbase: cfg.Coinbase,
|
||||||
@ -54,6 +56,9 @@ func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
|
|||||||
difficulty: cfg.Difficulty,
|
difficulty: cfg.Difficulty,
|
||||||
gasLimit: cfg.GasLimit,
|
gasLimit: cfg.GasLimit,
|
||||||
}
|
}
|
||||||
|
env.evm = vm.EVM(env)
|
||||||
|
|
||||||
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) StructLogs() []vm.StructLog {
|
func (self *Env) StructLogs() []vm.StructLog {
|
||||||
@ -64,6 +69,7 @@ func (self *Env) AddStructLog(log vm.StructLog) {
|
|||||||
self.logs = append(self.logs, log)
|
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) Origin() common.Address { return self.origin }
|
||||||
func (self *Env) BlockNumber() *big.Int { return self.number }
|
func (self *Env) BlockNumber() *big.Int { return self.number }
|
||||||
func (self *Env) Coinbase() common.Address { return self.coinbase }
|
func (self *Env) Coinbase() common.Address { return self.coinbase }
|
||||||
|
@ -31,14 +31,11 @@ import (
|
|||||||
// Vm is an EVM and implements VirtualMachine
|
// Vm is an EVM and implements VirtualMachine
|
||||||
type Vm struct {
|
type Vm struct {
|
||||||
env Environment
|
env Environment
|
||||||
|
jumpTable vmJumpTable
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Vm
|
func EVM(env Environment) *Vm {
|
||||||
func New(env Environment) *Vm {
|
return &Vm{env: env, jumpTable: newJumpTable(env.BlockNumber())}
|
||||||
// init the jump table. Also prepares the homestead changes
|
|
||||||
jumpTable.init(env.BlockNumber())
|
|
||||||
|
|
||||||
return &Vm{env: env}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run loops and evaluates the contract's code with the given input data
|
// 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())
|
mem.Resize(newMemSize.Uint64())
|
||||||
// Add a log message
|
// Add a log message
|
||||||
self.log(pc, op, contract.Gas, cost, mem, stack, contract, nil)
|
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 {
|
if opPtr.fn != nil {
|
||||||
opPtr.fn(instruction{}, &pc, self.env, contract, mem, stack)
|
opPtr.fn(instruction{}, &pc, self.env, contract, mem, stack)
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,5 +22,5 @@ import "fmt"
|
|||||||
|
|
||||||
func NewJitVm(env Environment) VirtualMachine {
|
func NewJitVm(env Environment) VirtualMachine {
|
||||||
fmt.Printf("Warning! EVM JIT not enabled.\n")
|
fmt.Printf("Warning! EVM JIT not enabled.\n")
|
||||||
return New(env)
|
return EVM(env)
|
||||||
}
|
}
|
||||||
|
@ -51,10 +51,11 @@ type VMEnv struct {
|
|||||||
getHashFn func(uint64) common.Hash
|
getHashFn func(uint64) common.Hash
|
||||||
// structured logging
|
// structured logging
|
||||||
logs []vm.StructLog
|
logs []vm.StructLog
|
||||||
|
evm *vm.Vm
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB, chain *BlockChain, msg Message, header *types.Header) *VMEnv {
|
func NewEnv(state *state.StateDB, chain *BlockChain, msg Message, header *types.Header) *VMEnv {
|
||||||
return &VMEnv{
|
env := &VMEnv{
|
||||||
chain: chain,
|
chain: chain,
|
||||||
state: state,
|
state: state,
|
||||||
header: header,
|
header: header,
|
||||||
@ -62,8 +63,11 @@ func NewEnv(state *state.StateDB, chain *BlockChain, msg Message, header *types.
|
|||||||
typ: vm.StdVmTy,
|
typ: vm.StdVmTy,
|
||||||
getHashFn: GetHashFn(header.ParentHash, chain),
|
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) Origin() common.Address { f, _ := self.msg.From(); return f }
|
||||||
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
|
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
|
||||||
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
|
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
|
||||||
|
@ -143,12 +143,15 @@ type Env struct {
|
|||||||
logs []vm.StructLog
|
logs []vm.StructLog
|
||||||
|
|
||||||
vmTest bool
|
vmTest bool
|
||||||
|
|
||||||
|
evm *vm.Vm
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB) *Env {
|
func NewEnv(state *state.StateDB) *Env {
|
||||||
return &Env{
|
env := &Env{
|
||||||
state: state,
|
state: state,
|
||||||
}
|
}
|
||||||
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) StructLogs() []vm.StructLog {
|
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.gasLimit = common.Big(envValues["currentGasLimit"])
|
||||||
env.Gas = new(big.Int)
|
env.Gas = new(big.Int)
|
||||||
|
|
||||||
|
env.evm = vm.EVM(env)
|
||||||
|
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Env) Vm() *vm.Vm { return self.evm }
|
||||||
func (self *Env) Origin() common.Address { return self.origin }
|
func (self *Env) Origin() common.Address { return self.origin }
|
||||||
func (self *Env) BlockNumber() *big.Int { return self.number }
|
func (self *Env) BlockNumber() *big.Int { return self.number }
|
||||||
func (self *Env) Coinbase() common.Address { return self.coinbase }
|
func (self *Env) Coinbase() common.Address { return self.coinbase }
|
||||||
|
Loading…
Reference in New Issue
Block a user