diff options
Diffstat (limited to 'core/vm')
-rw-r--r-- | core/vm/environment.go | 12 | ||||
-rw-r--r-- | core/vm/instructions.go | 2 | ||||
-rw-r--r-- | core/vm/jit.go | 23 | ||||
-rw-r--r-- | core/vm/jit_test.go | 15 | ||||
-rw-r--r-- | core/vm/jump_table.go | 10 | ||||
-rw-r--r-- | core/vm/jump_table_test.go | 8 | ||||
-rw-r--r-- | core/vm/logger.go | 2 | ||||
-rw-r--r-- | core/vm/logger_test.go | 10 | ||||
-rw-r--r-- | core/vm/runtime/env.go | 9 | ||||
-rw-r--r-- | core/vm/runtime/runtime.go | 11 | ||||
-rw-r--r-- | core/vm/util_test.go | 9 | ||||
-rw-r--r-- | core/vm/vm.go | 15 | ||||
-rw-r--r-- | core/vm/vm_jit_fake.go | 2 |
13 files changed, 72 insertions, 56 deletions
diff --git a/core/vm/environment.go b/core/vm/environment.go index 568218edd..747627565 100644 --- a/core/vm/environment.go +++ b/core/vm/environment.go @@ -22,9 +22,17 @@ import ( "github.com/ethereum/go-ethereum/common" ) +// RuleSet is an interface that defines the current rule set during the +// execution of the EVM instructions (e.g. whether it's homestead) +type RuleSet interface { + IsHomestead(*big.Int) bool +} + // Environment is an EVM requirement and helper which allows access to outside // information such as states. type Environment interface { + // The current ruleset + RuleSet() RuleSet // The state database Db() Database // Creates a restorable snapshot @@ -53,10 +61,10 @@ type Environment interface { AddLog(*Log) // Type of the VM Vm() Vm - // Current calling depth + // Get the curret calling depth Depth() int + // Set the current calling depth SetDepth(i int) - // Call another contract Call(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) // Take another's contract code and execute within our own context diff --git a/core/vm/instructions.go b/core/vm/instructions.go index c4b4339a2..942fafde7 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -520,7 +520,7 @@ func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if params.IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError { + if env.RuleSet().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError { stack.push(new(big.Int)) } else if suberr != nil && suberr != CodeStoreOutOfGasError { stack.push(new(big.Int)) diff --git a/core/vm/jit.go b/core/vm/jit.go index 71ffcf0f6..ac2083f54 100644 --- a/core/vm/jit.go +++ b/core/vm/jit.go @@ -30,27 +30,24 @@ import ( "github.com/hashicorp/golang-lru" ) +// progStatus is the type for the JIT program status. type progStatus int32 const ( - progUnknown progStatus = iota - progCompile - progReady - progError + progUnknown progStatus = iota // unknown status + progCompile // compile status + progReady // ready for use status + progError // error status (usually caused during compilation) - defaultJitMaxCache int = 64 + defaultJitMaxCache int = 64 // maximum amount of jit cached programs ) -var ( - EnableJit bool // Enables the JIT VM - ForceJit bool // Force the JIT, skip byte VM - MaxProgSize int // Max cache size for JIT Programs -) +var MaxProgSize int // Max cache size for JIT programs -var programs *lru.Cache +var programs *lru.Cache // lru cache for the JIT programs. func init() { - programs, _ = lru.New(defaultJitMaxCache) + SetJITCacheSize(defaultJitMaxCache) } // SetJITCacheSize recreates the program cache with the max given size. Setting @@ -322,7 +319,7 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env }() } - homestead := params.IsHomestead(env.BlockNumber()) + homestead := env.RuleSet().IsHomestead(env.BlockNumber()) for pc < uint64(len(program.instructions)) { instrCount++ diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go index 43b1dee2a..c503a3a81 100644 --- a/core/vm/jit_test.go +++ b/core/vm/jit_test.go @@ -84,7 +84,7 @@ func TestCompiling(t *testing.T) { func TestResetInput(t *testing.T) { var sender account - env := NewEnv() + env := NewEnv(false, true) contract := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0)) contract.CodeAddr = &common.Address{} @@ -143,10 +143,7 @@ func runVmBench(test vmBench, b *testing.B) { if test.precompile && !test.forcejit { NewProgram(test.code) } - env := NewEnv() - - EnableJit = !test.nojit - ForceJit = test.forcejit + env := NewEnv(test.nojit, test.forcejit) b.ResetTimer() @@ -168,12 +165,16 @@ type Env struct { evm *EVM } -func NewEnv() *Env { +func NewEnv(noJit, forceJit bool) *Env { env := &Env{gasLimit: big.NewInt(10000), depth: 0} - env.evm = New(env, nil) + env.evm = New(env, Config{ + EnableJit: !noJit, + ForceJit: forceJit, + }) return env } +func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} } 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) } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 8297d3e1d..2c3796679 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -1,10 +1,6 @@ package vm -import ( - "math/big" - - "github.com/ethereum/go-ethereum/params" -) +import "math/big" type jumpPtr struct { fn instrFn @@ -13,12 +9,12 @@ type jumpPtr struct { type vmJumpTable [256]jumpPtr -func newJumpTable(blockNumber *big.Int) vmJumpTable { +func newJumpTable(ruleset RuleSet, blockNumber *big.Int) vmJumpTable { var jumpTable vmJumpTable // when initialising a new VM execution we must first check the homestead // changes. - if params.IsHomestead(blockNumber) { + if ruleset.IsHomestead(blockNumber) { jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true} } diff --git a/core/vm/jump_table_test.go b/core/vm/jump_table_test.go index 2ed1b26fc..2386a7525 100644 --- a/core/vm/jump_table_test.go +++ b/core/vm/jump_table_test.go @@ -3,20 +3,16 @@ package vm import ( "math/big" "testing" - - "github.com/ethereum/go-ethereum/params" ) func TestInit(t *testing.T) { - params.HomesteadBlock = big.NewInt(1) - - jumpTable := newJumpTable(big.NewInt(0)) + jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(0)) if jumpTable[DELEGATECALL].valid { t.Error("Expected DELEGATECALL not to be present") } for _, n := range []int64{1, 2, 100} { - jumpTable := newJumpTable(big.NewInt(n)) + jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(n)) if !jumpTable[DELEGATECALL].valid { t.Error("Expected DELEGATECALL to be present for block", n) } diff --git a/core/vm/logger.go b/core/vm/logger.go index 8d333dfd2..cbdc8a744 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -89,7 +89,7 @@ func newLogger(cfg LogConfig, env Environment) *Logger { // captureState logs a new structured log message and pushes it out to the environment // // captureState also tracks SSTORE ops to track dirty values. -func (l *Logger) captureState(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *stack, contract *Contract, err error) { +func (l *Logger) captureState(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *stack, contract *Contract, depth int, err error) { // short circuit if no log collector is present if l.cfg.Collector == nil { return diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index 77fee2c64..144569865 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -47,7 +47,7 @@ type dummyEnv struct { func newDummyEnv(ref *dummyContractRef) *dummyEnv { return &dummyEnv{ - Env: NewEnv(), + Env: NewEnv(true, false), ref: ref, } } @@ -58,7 +58,7 @@ func (d dummyEnv) AddStructLog(StructLog) {} func TestStoreCapture(t *testing.T) { var ( - env = NewEnv() + env = NewEnv(true, false) logger = newLogger(LogConfig{Collector: env}, env) mem = NewMemory() stack = newstack() @@ -69,7 +69,7 @@ func TestStoreCapture(t *testing.T) { var index common.Hash - logger.captureState(0, SSTORE, new(big.Int), new(big.Int), mem, stack, contract, nil) + logger.captureState(0, SSTORE, new(big.Int), new(big.Int), mem, stack, contract, 0, nil) if len(logger.changedValues[contract.Address()]) == 0 { t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()])) } @@ -91,13 +91,13 @@ func TestStorageCapture(t *testing.T) { stack = newstack() ) - logger.captureState(0, STOP, new(big.Int), new(big.Int), mem, stack, contract, nil) + logger.captureState(0, STOP, new(big.Int), new(big.Int), mem, stack, contract, 0, nil) if ref.calledForEach { t.Error("didn't expect for each to be called") } logger = newLogger(LogConfig{Collector: env, FullStorage: true}, env) - logger.captureState(0, STOP, new(big.Int), new(big.Int), mem, stack, contract, nil) + logger.captureState(0, STOP, new(big.Int), new(big.Int), mem, stack, contract, 0, nil) if !ref.calledForEach { t.Error("expected for each to be called") } diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index ce64d7117..1e943940b 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -27,8 +27,9 @@ import ( // Env is a basic runtime environment required for running the EVM. type Env struct { - depth int - state *state.StateDB + ruleSet vm.RuleSet + depth int + state *state.StateDB origin common.Address coinbase common.Address @@ -48,6 +49,7 @@ type Env struct { // NewEnv returns a new vm.Environment func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { env := &Env{ + ruleSet: cfg.RuleSet, state: state, origin: cfg.Origin, coinbase: cfg.Coinbase, @@ -56,7 +58,7 @@ func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { difficulty: cfg.Difficulty, gasLimit: cfg.GasLimit, } - env.evm = vm.New(env, &vm.Config{ + env.evm = vm.New(env, vm.Config{ Debug: cfg.Debug, EnableJit: !cfg.DisableJit, ForceJit: !cfg.DisableJit, @@ -77,6 +79,7 @@ func (self *Env) AddStructLog(log vm.StructLog) { self.logs = append(self.logs, log) } +func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet } 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 } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index f88a20170..553864a83 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -22,13 +22,20 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" ) +// The default, always homestead, rule set for the vm env +type ruleSet struct{} + +func (ruleSet) IsHomestead(*big.Int) bool { return true } + // Config is a basic type specifying certain configuration flags for running // the EVM. type Config struct { + RuleSet vm.RuleSet Difficulty *big.Int Origin common.Address Coinbase common.Address @@ -46,6 +53,10 @@ type Config struct { // sets defaults on the config func setDefaults(cfg *Config) { + if cfg.RuleSet == nil { + cfg.RuleSet = ruleSet{} + } + if cfg.Difficulty == nil { cfg.Difficulty = new(big.Int) } diff --git a/core/vm/util_test.go b/core/vm/util_test.go new file mode 100644 index 000000000..3da742bfa --- /dev/null +++ b/core/vm/util_test.go @@ -0,0 +1,9 @@ +package vm + +import "math/big" + +type ruleSet struct { + hs *big.Int +} + +func (r ruleSet) IsHomestead(n *big.Int) bool { return n.Cmp(r.hs) >= 0 } diff --git a/core/vm/vm.go b/core/vm/vm.go index f72c853a2..0f93715d6 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -43,18 +43,13 @@ type Config struct { type EVM struct { env Environment jumpTable vmJumpTable - cfg *Config + cfg Config logger *Logger } // New returns a new instance of the EVM. -func New(env Environment, cfg *Config) *EVM { - // initialise a default config if none is present - if cfg == nil { - cfg = new(Config) - } - +func New(env Environment, cfg Config) *EVM { var logger *Logger if cfg.Debug { logger = newLogger(cfg.Logger, env) @@ -62,7 +57,7 @@ func New(env Environment, cfg *Config) *EVM { return &EVM{ env: env, - jumpTable: newJumpTable(env.BlockNumber()), + jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()), cfg: cfg, logger: logger, } @@ -154,7 +149,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return. defer func() { if err != nil && evm.cfg.Debug { - evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, err) + evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), err) } }() @@ -196,7 +191,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { mem.Resize(newMemSize.Uint64()) // Add a log message if evm.cfg.Debug { - evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, nil) + evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), nil) } if opPtr := evm.jumpTable[op]; opPtr.valid { diff --git a/core/vm/vm_jit_fake.go b/core/vm/vm_jit_fake.go index b26cf1ad0..4fa98ccd9 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, nil) + return New(env, Config{}) } |