aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm')
-rw-r--r--core/vm/environment.go12
-rw-r--r--core/vm/instructions.go2
-rw-r--r--core/vm/jit.go23
-rw-r--r--core/vm/jit_test.go15
-rw-r--r--core/vm/jump_table.go10
-rw-r--r--core/vm/jump_table_test.go8
-rw-r--r--core/vm/logger.go2
-rw-r--r--core/vm/logger_test.go10
-rw-r--r--core/vm/runtime/env.go9
-rw-r--r--core/vm/runtime/runtime.go11
-rw-r--r--core/vm/util_test.go9
-rw-r--r--core/vm/vm.go15
-rw-r--r--core/vm/vm_jit_fake.go2
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{})
}