瀏覽代碼

core, core/state, trie: EIP158, reprice & skip empty account write

This commit implements EIP158 part 1, 2, 3 & 4

1. If an account is empty it's no longer written to the trie. An empty
  account is defined as (balance=0, nonce=0, storage=0, code=0).
2. Delete an empty account if it's touched
3. An empty account is redefined as either non-existent or empty.
4. Zero value calls and zero value suicides no longer consume the 25k
  reation costs.

params: moved core/config to params

Signed-off-by: Jeffrey Wilcke <jeffrey@ethereum.org>
Jeffrey Wilcke 9 年之前
父節點
當前提交
445feaeef5
共有 74 個文件被更改,包括 717 次插入561 次删除
  1. 6 3
      accounts/abi/bind/backends/simulated.go
  2. 1 1
      cmd/ethtest/main.go
  3. 18 18
      cmd/evm/main.go
  4. 1 2
      cmd/gethrpctest/main.go
  5. 16 15
      cmd/utils/flags.go
  6. 4 3
      common/registrar/ethreg/api.go
  7. 2 2
      console/console_test.go
  8. 2 2
      core/bench_test.go
  9. 10 10
      core/block_validator.go
  10. 7 5
      core/block_validator_test.go
  11. 6 5
      core/blockchain.go
  12. 10 10
      core/blockchain_test.go
  13. 12 10
      core/chain_makers.go
  14. 5 2
      core/chain_makers_test.go
  15. 4 3
      core/chain_pow_test.go
  16. 1 1
      core/dao.go
  17. 3 3
      core/dao_test.go
  18. 7 3
      core/database_util.go
  19. 3 2
      core/database_util_test.go
  20. 102 62
      core/execution.go
  21. 3 3
      core/genesis.go
  22. 5 4
      core/headerchain.go
  23. 12 1
      core/state/state_object.go
  24. 3 3
      core/state/state_test.go
  25. 18 9
      core/state/statedb.go
  26. 4 4
      core/state/statedb_test.go
  27. 1 1
      core/state/sync_test.go
  28. 5 4
      core/state_processor.go
  29. 2 2
      core/state_transition.go
  30. 3 2
      core/tx_pool.go
  31. 4 10
      core/vm/environment.go
  32. 2 2
      core/vm/instructions.go
  33. 1 1
      core/vm/jit.go
  34. 4 1
      core/vm/jit_test.go
  35. 6 2
      core/vm/jump_table.go
  36. 4 2
      core/vm/jump_table_test.go
  37. 22 21
      core/vm/runtime/env.go
  38. 3 4
      core/vm/runtime/runtime.go
  39. 26 6
      core/vm/vm.go
  40. 19 18
      core/vm_env.go
  41. 3 2
      eth/api.go
  42. 1 1
      eth/api_backend.go
  43. 3 7
      eth/backend.go
  44. 2 1
      eth/backend_test.go
  45. 1 1
      eth/downloader/downloader_test.go
  46. 1 1
      eth/fetcher/fetcher_test.go
  47. 2 1
      eth/filters/filter_system_test.go
  48. 3 2
      eth/filters/filter_test.go
  49. 3 2
      eth/handler.go
  50. 2 2
      eth/handler_test.go
  51. 3 2
      eth/helper_test.go
  52. 3 6
      internal/ethapi/tracer_test.go
  53. 1 1
      les/api_backend.go
  54. 2 6
      les/backend.go
  55. 3 2
      les/handler.go
  56. 2 2
      les/helper_test.go
  57. 9 7
      les/odr_test.go
  58. 2 1
      light/lightchain.go
  59. 4 3
      light/lightchain_test.go
  60. 2 1
      light/odr_test.go
  61. 1 1
      light/state_test.go
  62. 3 2
      light/txpool.go
  63. 2 1
      light/txpool_test.go
  64. 14 13
      light/vm_env.go
  65. 1 1
      miner/miner.go
  66. 6 13
      miner/worker.go
  67. 34 13
      params/config.go
  68. 22 0
      params/gas_table.go
  69. 3 2
      tests/block_test_util.go
  70. 177 148
      tests/state_test.go
  71. 17 16
      tests/state_test_util.go
  72. 1 2
      tests/transaction_test_util.go
  73. 16 35
      tests/util.go
  74. 1 1
      tests/vm_test_util.go

+ 6 - 3
accounts/abi/bind/backends/simulated.go

@@ -31,11 +31,12 @@ import (
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/params"
 	"golang.org/x/net/context"
 )
 
 // Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
-var chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)}
+var chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
 
 // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
 var _ bind.ContractBackend = (*SimulatedBackend)(nil)
@@ -51,6 +52,8 @@ type SimulatedBackend struct {
 	mu           sync.Mutex
 	pendingBlock *types.Block   // Currently pending block that will be imported on request
 	pendingState *state.StateDB // Currently pending state that will be the active on on request
+
+	config *params.ChainConfig
 }
 
 // NewSimulatedBackend creates a new binding backend using a simulated blockchain
@@ -85,7 +88,7 @@ func (b *SimulatedBackend) Rollback() {
 }
 
 func (b *SimulatedBackend) rollback() {
-	blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
+	blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
 	b.pendingBlock = blocks[0]
 	b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
 }
@@ -243,7 +246,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
 		panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
 	}
 
-	blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
+	blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
 		for _, tx := range b.pendingBlock.Transactions() {
 			block.AddTx(tx)
 		}

+ 1 - 1
cmd/ethtest/main.go

@@ -76,7 +76,7 @@ func runTestWithReader(test string, r io.Reader) error {
 	case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
 		err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, params.MainNetHomesteadGasRepriceBlock, r, skipTests)
 	case "st", "state", "statetest", "statetests":
-		rs := tests.RuleSet{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true}
+		rs := &params.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true, EIP150Block: params.MainNetHomesteadGasRepriceBlock}
 		err = tests.RunStateTestWithReader(rs, r, skipTests)
 	case "tx", "transactiontest", "transactiontests":
 		err = tests.RunTransactionTestsWithReader(r, skipTests)

+ 18 - 18
cmd/evm/main.go

@@ -191,7 +191,7 @@ func run(ctx *cli.Context) error {
 	vmdone := time.Since(tstart)
 
 	if ctx.GlobalBool(DumpFlag.Name) {
-		statedb.Commit()
+		statedb.Commit(true)
 		fmt.Println(string(statedb.Dump()))
 	}
 	vm.StdErrFormat(logger.StructLogs())
@@ -251,7 +251,7 @@ func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int, cfg
 	return env
 }
 
-// ruleSet implements vm.RuleSet and will always default to the homestead rule set.
+// ruleSet implements vm.ChainConfig and will always default to the homestead rule set.
 type ruleSet struct{}
 
 func (ruleSet) IsHomestead(*big.Int) bool { return true }
@@ -259,22 +259,22 @@ func (ruleSet) GasTable(*big.Int) params.GasTable {
 	return params.GasTableHomesteadGasRepriceFork
 }
 
-func (self *VMEnv) RuleSet() vm.RuleSet       { return ruleSet{} }
-func (self *VMEnv) Vm() vm.Vm                 { return self.evm }
-func (self *VMEnv) Db() vm.Database           { return self.state }
-func (self *VMEnv) SnapshotDatabase() int     { return self.state.Snapshot() }
-func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) }
-func (self *VMEnv) Origin() common.Address    { return *self.transactor }
-func (self *VMEnv) BlockNumber() *big.Int     { return common.Big0 }
-func (self *VMEnv) Coinbase() common.Address  { return *self.transactor }
-func (self *VMEnv) Time() *big.Int            { return self.time }
-func (self *VMEnv) Difficulty() *big.Int      { return common.Big1 }
-func (self *VMEnv) BlockHash() []byte         { return make([]byte, 32) }
-func (self *VMEnv) Value() *big.Int           { return self.value }
-func (self *VMEnv) GasLimit() *big.Int        { return big.NewInt(1000000000) }
-func (self *VMEnv) VmType() vm.Type           { return vm.StdVmTy }
-func (self *VMEnv) Depth() int                { return 0 }
-func (self *VMEnv) SetDepth(i int)            { self.depth = i }
+func (self *VMEnv) ChainConfig() *params.ChainConfig { return params.TestChainConfig }
+func (self *VMEnv) Vm() vm.Vm                        { return self.evm }
+func (self *VMEnv) Db() vm.Database                  { return self.state }
+func (self *VMEnv) SnapshotDatabase() int            { return self.state.Snapshot() }
+func (self *VMEnv) RevertToSnapshot(snap int)        { self.state.RevertToSnapshot(snap) }
+func (self *VMEnv) Origin() common.Address           { return *self.transactor }
+func (self *VMEnv) BlockNumber() *big.Int            { return common.Big0 }
+func (self *VMEnv) Coinbase() common.Address         { return *self.transactor }
+func (self *VMEnv) Time() *big.Int                   { return self.time }
+func (self *VMEnv) Difficulty() *big.Int             { return common.Big1 }
+func (self *VMEnv) BlockHash() []byte                { return make([]byte, 32) }
+func (self *VMEnv) Value() *big.Int                  { return self.value }
+func (self *VMEnv) GasLimit() *big.Int               { return big.NewInt(1000000000) }
+func (self *VMEnv) VmType() vm.Type                  { return vm.StdVmTy }
+func (self *VMEnv) Depth() int                       { return 0 }
+func (self *VMEnv) SetDepth(i int)                   { self.depth = i }
 func (self *VMEnv) GetHash(n uint64) common.Hash {
 	if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 {
 		return self.block.Hash()

+ 1 - 2
cmd/gethrpctest/main.go

@@ -23,7 +23,6 @@ import (
 	"os"
 	"os/signal"
 
-	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/ethdb"
@@ -122,7 +121,7 @@ func MakeSystemNode(privkey string, test *tests.BlockTest) (*node.Node, error) {
 	ethConf := &eth.Config{
 		TestGenesisState: db,
 		TestGenesisBlock: test.Genesis,
-		ChainConfig:      &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock},
+		ChainConfig:      &params.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock},
 	}
 	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
 		return nil, err

+ 16 - 15
cmd/utils/flags.go

@@ -801,7 +801,7 @@ func SetupNetwork(ctx *cli.Context) {
 }
 
 // MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
-func MakeChainConfig(ctx *cli.Context, stack *node.Node) *core.ChainConfig {
+func MakeChainConfig(ctx *cli.Context, stack *node.Node) *params.ChainConfig {
 	db := MakeChainDatabase(ctx, stack)
 	defer db.Close()
 
@@ -809,9 +809,9 @@ func MakeChainConfig(ctx *cli.Context, stack *node.Node) *core.ChainConfig {
 }
 
 // MakeChainConfigFromDb reads the chain configuration from the given database.
-func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfig {
+func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainConfig {
 	// If the chain is already initialized, use any existing chain configs
-	config := new(core.ChainConfig)
+	config := new(params.ChainConfig)
 
 	genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0)
 	if genesis != nil {
@@ -849,19 +849,20 @@ func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfi
 			}
 			config.DAOForkSupport = true
 		}
-		if config.HomesteadGasRepriceBlock == nil {
-			if ctx.GlobalBool(TestNetFlag.Name) {
-				config.HomesteadGasRepriceBlock = params.TestNetHomesteadGasRepriceBlock
-			} else {
-				config.HomesteadGasRepriceBlock = params.MainNetHomesteadGasRepriceBlock
-			}
+		config.DAOForkSupport = true
+	}
+	if config.EIP150Block == nil {
+		if ctx.GlobalBool(TestNetFlag.Name) {
+			config.EIP150Block = params.TestNetHomesteadGasRepriceBlock
+		} else {
+			config.EIP150Block = params.MainNetHomesteadGasRepriceBlock
 		}
-		if config.HomesteadGasRepriceHash == (common.Hash{}) {
-			if ctx.GlobalBool(TestNetFlag.Name) {
-				config.HomesteadGasRepriceHash = params.TestNetHomesteadGasRepriceHash
-			} else {
-				config.HomesteadGasRepriceHash = params.MainNetHomesteadGasRepriceHash
-			}
+	}
+	if config.EIP150Hash == (common.Hash{}) {
+		if ctx.GlobalBool(TestNetFlag.Name) {
+			config.EIP150Hash = params.TestNetHomesteadGasRepriceHash
+		} else {
+			config.EIP150Hash = params.MainNetHomesteadGasRepriceHash
 		}
 	}
 	// Force override any existing configs if explicitly requested

+ 4 - 3
common/registrar/ethreg/api.go

@@ -32,11 +32,12 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 // registryAPIBackend is a backend for an Ethereum Registry.
 type registryAPIBackend struct {
-	config  *core.ChainConfig
+	config  *params.ChainConfig
 	bc      *core.BlockChain
 	chainDb ethdb.Database
 	txPool  *core.TxPool
@@ -45,12 +46,12 @@ type registryAPIBackend struct {
 
 // PrivateRegistarAPI offers various functions to access the Ethereum registry.
 type PrivateRegistarAPI struct {
-	config *core.ChainConfig
+	config *params.ChainConfig
 	be     *registryAPIBackend
 }
 
 // NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance.
-func NewPrivateRegistarAPI(config *core.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI {
+func NewPrivateRegistarAPI(config *params.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI {
 	return &PrivateRegistarAPI{
 		config: config,
 		be: &registryAPIBackend{

+ 2 - 2
console/console_test.go

@@ -28,10 +28,10 @@ import (
 	"time"
 
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/internal/jsre"
 	"github.com/ethereum/go-ethereum/node"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 const (
@@ -97,7 +97,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
 		t.Fatalf("failed to create node: %v", err)
 	}
 	ethConf := &eth.Config{
-		ChainConfig: &core.ChainConfig{HomesteadBlock: new(big.Int)},
+		ChainConfig: &params.ChainConfig{HomesteadBlock: new(big.Int)},
 		Etherbase:   common.HexToAddress(testAddress),
 		PowTest:     true,
 	}

+ 2 - 2
core/bench_test.go

@@ -163,12 +163,12 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
 	// Generate a chain of b.N blocks using the supplied block
 	// generator function.
 	genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
-	chain, _ := GenerateChain(nil, genesis, db, b.N, gen)
+	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, b.N, gen)
 
 	// Time the insertion of the new chain.
 	// State and blocks are stored in the same DB.
 	evmux := new(event.TypeMux)
-	chainman, _ := NewBlockChain(db, &ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux)
+	chainman, _ := NewBlockChain(db, &params.ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux)
 	defer chainman.Stop()
 	b.ReportAllocs()
 	b.ResetTimer()

+ 10 - 10
core/block_validator.go

@@ -41,13 +41,13 @@ var (
 //
 // BlockValidator implements Validator.
 type BlockValidator struct {
-	config *ChainConfig // Chain configuration options
-	bc     *BlockChain  // Canonical block chain
-	Pow    pow.PoW      // Proof of work used for validating
+	config *params.ChainConfig // Chain configuration options
+	bc     *BlockChain         // Canonical block chain
+	Pow    pow.PoW             // Proof of work used for validating
 }
 
 // NewBlockValidator returns a new block validator which is safe for re-use
-func NewBlockValidator(config *ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator {
+func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator {
 	validator := &BlockValidator{
 		config: config,
 		Pow:    pow,
@@ -128,7 +128,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
 	}
 	// Validate the state root against the received state root and throw
 	// an error if they don't match.
-	if root := statedb.IntermediateRoot(); header.Root != root {
+	if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
 		return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
 	}
 	return nil
@@ -203,7 +203,7 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b
 // Validates a header. Returns an error if the header is invalid.
 //
 // See YP section 4.3.4. "Block Header Validity"
-func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
+func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
 	if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
 		return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
 	}
@@ -251,9 +251,9 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
 	if err := ValidateDAOHeaderExtraData(config, header); err != nil {
 		return err
 	}
-	if config.HomesteadGasRepriceBlock != nil && config.HomesteadGasRepriceBlock.Cmp(header.Number) == 0 {
-		if config.HomesteadGasRepriceHash != (common.Hash{}) && config.HomesteadGasRepriceHash != header.Hash() {
-			return ValidationError("Homestead gas reprice fork hash mismatch: have 0x%x, want 0x%x", header.Hash(), config.HomesteadGasRepriceHash)
+	if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 {
+		if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() {
+			return ValidationError("Homestead gas reprice fork hash mismatch: have 0x%x, want 0x%x", header.Hash(), config.EIP150Hash)
 		}
 	}
 	return nil
@@ -262,7 +262,7 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
 // CalcDifficulty is the difficulty adjustment algorithm. It returns
 // the difficulty that a new block should have when created at time
 // given the parent block's time and difficulty.
-func CalcDifficulty(config *ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
+func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
 	if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
 		return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
 	} else {

+ 7 - 5
core/block_validator_test.go

@@ -27,11 +27,13 @@ import (
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow/ezp"
 )
 
-func testChainConfig() *ChainConfig {
-	return &ChainConfig{HomesteadBlock: big.NewInt(0)}
+func testChainConfig() *params.ChainConfig {
+	return params.TestChainConfig
+	//return &params.ChainConfig{HomesteadBlock: big.NewInt(0)}
 }
 
 func proc() (Validator, *BlockChain) {
@@ -51,15 +53,15 @@ func TestNumber(t *testing.T) {
 	_, chain := proc()
 
 	statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
-	header := makeHeader(chain.Genesis(), statedb)
-	header.Number = big.NewInt(3)
 	cfg := testChainConfig()
+	header := makeHeader(cfg, chain.Genesis(), statedb)
+	header.Number = big.NewInt(3)
 	err := ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
 	if err != BlockNumberErr {
 		t.Errorf("expected block number error, got %q", err)
 	}
 
-	header = makeHeader(chain.Genesis(), statedb)
+	header = makeHeader(cfg, chain.Genesis(), statedb)
 	err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
 	if err == BlockNumberErr {
 		t.Errorf("didn't expect block number error")

+ 6 - 5
core/blockchain.go

@@ -38,6 +38,7 @@ import (
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/metrics"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/trie"
@@ -78,7 +79,7 @@ const (
 // included in the canonical one where as GetBlockByNumber always represents the
 // canonical chain.
 type BlockChain struct {
-	config *ChainConfig // chain & network configuration
+	config *params.ChainConfig // chain & network configuration
 
 	hc           *HeaderChain
 	chainDb      ethdb.Database
@@ -113,7 +114,7 @@ type BlockChain struct {
 // NewBlockChain returns a fully initialised block chain using information
 // available in the database. It initialiser the default Ethereum Validator and
 // Processor.
-func NewBlockChain(chainDb ethdb.Database, config *ChainConfig, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) {
+func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) {
 	bodyCache, _ := lru.New(bodyCacheLimit)
 	bodyRLPCache, _ := lru.New(bodyCacheLimit)
 	blockCache, _ := lru.New(blockCacheLimit)
@@ -924,7 +925,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 			return i, err
 		}
 		// Process block using the parent state as reference point.
-		receipts, logs, usedGas, err := self.processor.Process(block, self.stateCache, self.config.VmConfig)
+		receipts, logs, usedGas, err := self.processor.Process(block, self.stateCache, vm.Config{})
 		if err != nil {
 			reportBlock(block, err)
 			return i, err
@@ -936,7 +937,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 			return i, err
 		}
 		// Write state changes to database
-		_, err = self.stateCache.Commit()
+		_, err = self.stateCache.Commit(self.config.IsEIP158(block.Number()))
 		if err != nil {
 			return i, err
 		}
@@ -1309,4 +1310,4 @@ func (self *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
 }
 
 // Config retrieves the blockchain's chain configuration.
-func (self *BlockChain) Config() *ChainConfig { return self.config }
+func (self *BlockChain) Config() *params.ChainConfig { return self.config }

+ 10 - 10
core/blockchain_test.go

@@ -154,7 +154,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
 		blockchain.mu.Lock()
 		WriteTd(blockchain.chainDb, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash())))
 		WriteBlock(blockchain.chainDb, block)
-		statedb.Commit()
+		statedb.Commit(false)
 		blockchain.mu.Unlock()
 	}
 	return nil
@@ -712,7 +712,7 @@ func TestFastVsFullChains(t *testing.T) {
 		funds    = big.NewInt(1000000000)
 		genesis  = GenesisBlockForTesting(gendb, address, funds)
 	)
-	blocks, receipts := GenerateChain(nil, genesis, gendb, 1024, func(i int, block *BlockGen) {
+	blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) {
 		block.SetCoinbase(common.Address{0x00})
 
 		// If the block number is multiple of 3, send a few bonus transactions to the miner
@@ -795,7 +795,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 		genesis  = GenesisBlockForTesting(gendb, address, funds)
 	)
 	height := uint64(1024)
-	blocks, receipts := GenerateChain(nil, genesis, gendb, int(height), nil)
+	blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, int(height), nil)
 
 	// Configure a subchain to roll back
 	remove := []common.Hash{}
@@ -895,7 +895,7 @@ func TestChainTxReorgs(t *testing.T) {
 	//  - futureAdd: transaction added after the reorg has already finished
 	var pastAdd, freshAdd, futureAdd *types.Transaction
 
-	chain, _ := GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {
+	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
 		switch i {
 		case 0:
 			pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2)
@@ -920,7 +920,7 @@ func TestChainTxReorgs(t *testing.T) {
 	}
 
 	// overwrite the old chain
-	chain, _ = GenerateChain(nil, genesis, db, 5, func(i int, gen *BlockGen) {
+	chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
 		switch i {
 		case 0:
 			pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3)
@@ -990,7 +990,7 @@ func TestLogReorgs(t *testing.T) {
 	blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
 
 	subs := evmux.Subscribe(RemovedLogsEvent{})
-	chain, _ := GenerateChain(nil, genesis, db, 2, func(i int, gen *BlockGen) {
+	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
 		if i == 1 {
 			tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(key1)
 			if err != nil {
@@ -1003,7 +1003,7 @@ func TestLogReorgs(t *testing.T) {
 		t.Fatalf("failed to insert chain: %v", err)
 	}
 
-	chain, _ = GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {})
+	chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
 	if _, err := blockchain.InsertChain(chain); err != nil {
 		t.Fatalf("failed to insert forked chain: %v", err)
 	}
@@ -1025,12 +1025,12 @@ func TestReorgSideEvent(t *testing.T) {
 	evmux := &event.TypeMux{}
 	blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
 
-	chain, _ := GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {})
+	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
 	if _, err := blockchain.InsertChain(chain); err != nil {
 		t.Fatalf("failed to insert chain: %v", err)
 	}
 
-	replacementBlocks, _ := GenerateChain(nil, genesis, db, 4, func(i int, gen *BlockGen) {
+	replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
 		tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(key1)
 		if i == 2 {
 			gen.OffsetTime(-1)
@@ -1101,7 +1101,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
 	evmux := &event.TypeMux{}
 	blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
 
-	chain, _ := GenerateChain(nil, genesis, db, 10, func(i int, gen *BlockGen) {})
+	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
 
 	for i, _ := range chain {
 		go func(block *types.Block) {

+ 12 - 10
core/chain_makers.go

@@ -35,8 +35,8 @@ import (
  */
 
 // MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
-func MakeChainConfig() *ChainConfig {
-	return &ChainConfig{
+func MakeChainConfig() *params.ChainConfig {
+	return &params.ChainConfig{
 		HomesteadBlock: big.NewInt(0),
 		DAOForkBlock:   nil,
 		DAOForkSupport: true,
@@ -73,6 +73,8 @@ type BlockGen struct {
 	txs      []*types.Transaction
 	receipts []*types.Receipt
 	uncles   []*types.Header
+
+	config *params.ChainConfig
 }
 
 // SetCoinbase sets the coinbase of the generated block.
@@ -106,7 +108,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
 		b.SetCoinbase(common.Address{})
 	}
 	b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
-	receipt, _, _, err := ApplyTransaction(MakeChainConfig(), nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
+	receipt, _, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
 	if err != nil {
 		panic(err)
 	}
@@ -178,10 +180,10 @@ func (b *BlockGen) OffsetTime(seconds int64) {
 // Blocks created by GenerateChain do not contain valid proof of work
 // values. Inserting them into BlockChain requires use of FakePow or
 // a similar non-validating proof of work implementation.
-func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
+func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
 	blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
 	genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
-		b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb}
+		b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config}
 
 		// Mutate the state and block according to any hard-fork specs
 		if config == nil {
@@ -203,7 +205,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
 			gen(i, b)
 		}
 		AccumulateRewards(statedb, h, b.uncles)
-		root, err := statedb.Commit()
+		root, err := statedb.Commit(config.IsEIP158(h.Number))
 		if err != nil {
 			panic(fmt.Sprintf("state write error: %v", err))
 		}
@@ -215,7 +217,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
 		if err != nil {
 			panic(err)
 		}
-		header := makeHeader(parent, statedb)
+		header := makeHeader(config, parent, statedb)
 		block, receipt := genblock(i, header, statedb)
 		blocks[i] = block
 		receipts[i] = receipt
@@ -224,7 +226,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
 	return blocks, receipts
 }
 
-func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
+func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.StateDB) *types.Header {
 	var time *big.Int
 	if parent.Time() == nil {
 		time = big.NewInt(10)
@@ -232,7 +234,7 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
 		time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
 	}
 	return &types.Header{
-		Root:       state.IntermediateRoot(),
+		Root:       state.IntermediateRoot(config.IsEIP158(parent.Number())),
 		ParentHash: parent.Hash(),
 		Coinbase:   parent.Coinbase(),
 		Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
@@ -283,7 +285,7 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
 
 // makeBlockChain creates a deterministic chain of blocks rooted at parent.
 func makeBlockChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block {
-	blocks, _ := GenerateChain(nil, parent, db, n, func(i int, b *BlockGen) {
+	blocks, _ := GenerateChain(params.TestChainConfig, parent, db, n, func(i int, b *BlockGen) {
 		b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
 	})
 	return blocks

+ 5 - 2
core/chain_makers_test.go

@@ -41,13 +41,16 @@ func ExampleGenerateChain() {
 		db, _   = ethdb.NewMemDatabase()
 	)
 
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+	}
 	// Ensure that key1 has some funds in the genesis block.
 	genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)})
 
 	// This call generates a chain of 5 blocks. The function runs for
 	// each block and adds different features to gen based on the
 	// block index.
-	chain, _ := GenerateChain(nil, genesis, db, 5, func(i int, gen *BlockGen) {
+	chain, _ := GenerateChain(chainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
 		switch i {
 		case 0:
 			// In block 1, addr1 sends addr2 some ether.
@@ -77,7 +80,7 @@ func ExampleGenerateChain() {
 
 	// Import the chain. This runs all block validation rules.
 	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, MakeChainConfig(), FakePow{}, evmux)
+	blockchain, _ := NewBlockChain(db, chainConfig, FakePow{}, evmux)
 	if i, err := blockchain.InsertChain(chain); err != nil {
 		fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
 		return

+ 4 - 3
core/chain_pow_test.go

@@ -25,6 +25,7 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/ethdb"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
 )
 
@@ -60,7 +61,7 @@ func TestPowVerification(t *testing.T) {
 	var (
 		testdb, _ = ethdb.NewMemDatabase()
 		genesis   = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
-		blocks, _ = GenerateChain(nil, genesis, testdb, 8, nil)
+		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
 	)
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {
@@ -115,7 +116,7 @@ func testPowConcurrentVerification(t *testing.T, threads int) {
 	var (
 		testdb, _ = ethdb.NewMemDatabase()
 		genesis   = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
-		blocks, _ = GenerateChain(nil, genesis, testdb, 8, nil)
+		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
 	)
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {
@@ -186,7 +187,7 @@ func testPowConcurrentAbortion(t *testing.T, threads int) {
 	var (
 		testdb, _ = ethdb.NewMemDatabase()
 		genesis   = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
-		blocks, _ = GenerateChain(nil, genesis, testdb, 1024, nil)
+		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 1024, nil)
 	)
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {

+ 1 - 1
core/dao.go

@@ -33,7 +33,7 @@ import (
 //      with the fork specific extra-data set
 //   b) if the node is pro-fork, require blocks in the specific range to have the
 //      unique extra-data set.
-func ValidateDAOHeaderExtraData(config *ChainConfig, header *types.Header) error {
+func ValidateDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) error {
 	// Short circuit validation if the node doesn't care about the DAO fork
 	if config.DAOForkBlock == nil {
 		return nil

+ 3 - 3
core/dao_test.go

@@ -33,17 +33,17 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	// Generate a common prefix for both pro-forkers and non-forkers
 	db, _ := ethdb.NewMemDatabase()
 	genesis := WriteGenesisBlockForTesting(db)
-	prefix, _ := GenerateChain(nil, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
+	prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
 
 	// Create the concurrent, conflicting two nodes
 	proDb, _ := ethdb.NewMemDatabase()
 	WriteGenesisBlockForTesting(proDb)
-	proConf := &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
+	proConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
 	proBc, _ := NewBlockChain(proDb, proConf, new(FakePow), new(event.TypeMux))
 
 	conDb, _ := ethdb.NewMemDatabase()
 	WriteGenesisBlockForTesting(conDb)
-	conConf := &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
+	conConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
 	conBc, _ := NewBlockChain(conDb, conConf, new(FakePow), new(event.TypeMux))
 
 	if _, err := proBc.InsertChain(prefix); err != nil {

+ 7 - 3
core/database_util.go

@@ -20,6 +20,7 @@ import (
 	"bytes"
 	"encoding/binary"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"math/big"
 
@@ -28,6 +29,7 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rlp"
 )
 
@@ -59,6 +61,8 @@ var (
 	oldBlockNumPrefix      = []byte("block-num-")
 	oldBlockReceiptsPrefix = []byte("receipts-block-")
 	oldBlockHashPrefix     = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
+
+	ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
 )
 
 // encodeBlockNumber encodes a block number as big endian uint64
@@ -600,7 +604,7 @@ func WriteBlockChainVersion(db ethdb.Database, vsn int) {
 }
 
 // WriteChainConfig writes the chain config settings to the database.
-func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *ChainConfig) error {
+func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *params.ChainConfig) error {
 	// short circuit and ignore if nil config. GetChainConfig
 	// will return a default.
 	if cfg == nil {
@@ -616,13 +620,13 @@ func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *ChainConfig) err
 }
 
 // GetChainConfig will fetch the network settings based on the given hash.
-func GetChainConfig(db ethdb.Database, hash common.Hash) (*ChainConfig, error) {
+func GetChainConfig(db ethdb.Database, hash common.Hash) (*params.ChainConfig, error) {
 	jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...))
 	if len(jsonChainConfig) == 0 {
 		return nil, ChainConfigNotFoundErr
 	}
 
-	var config ChainConfig
+	var config params.ChainConfig
 	if err := json.Unmarshal(jsonChainConfig, &config); err != nil {
 		return nil, err
 	}

+ 3 - 2
core/database_util_test.go

@@ -30,6 +30,7 @@ import (
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto/sha3"
 	"github.com/ethereum/go-ethereum/ethdb"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rlp"
 )
 
@@ -75,7 +76,7 @@ func TestCalcDifficulty(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	config := &ChainConfig{HomesteadBlock: big.NewInt(1150000)}
+	config := &params.ChainConfig{HomesteadBlock: big.NewInt(1150000)}
 	for name, test := range tests {
 		number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
 		diff := CalcDifficulty(config, test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty)
@@ -562,7 +563,7 @@ func TestMipmapChain(t *testing.T) {
 	defer db.Close()
 
 	genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)})
-	chain, receipts := GenerateChain(nil, genesis, db, 1010, func(i int, gen *BlockGen) {
+	chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
 		var receipts types.Receipts
 		switch i {
 		case 1:

+ 102 - 62
core/execution.go

@@ -27,40 +27,93 @@ import (
 
 // Call executes within the given contract
 func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
-	ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
+	// Depth check execution. Fail if we're trying to execute above the
+	// limit.
+	if env.Depth() > int(params.CallCreateDepth.Int64()) {
+		caller.ReturnGas(gas, gasPrice)
+
+		return nil, vm.DepthError
+	}
+	if !env.CanTransfer(caller.Address(), value) {
+		caller.ReturnGas(gas, gasPrice)
+
+		return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
+	}
+
+	snapshotPreTransfer := env.SnapshotDatabase()
+	var (
+		from = env.Db().GetAccount(caller.Address())
+		to   vm.Account
+	)
+	if !env.Db().Exist(addr) {
+		if vm.Precompiled[addr.Str()] == nil && env.ChainConfig().IsEIP158(env.BlockNumber()) && value.BitLen() == 0 {
+			caller.ReturnGas(gas, gasPrice)
+			return nil, nil
+		}
+
+		to = env.Db().CreateAccount(addr)
+	} else {
+		to = env.Db().GetAccount(addr)
+	}
+	env.Transfer(from, to, value)
+
+	// initialise a new contract and set the code that is to be used by the
+	// EVM. The contract is a scoped environment for this execution context
+	// only.
+	contract := vm.NewContract(caller, to, value, gas, gasPrice)
+	contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
+	defer contract.Finalise()
+
+	ret, err = env.Vm().Run(contract, input)
+	// When an error was returned by the EVM or when setting the creation code
+	// above we revert to the snapshot and consume any gas remaining. Additionally
+	// when we're in homestead this also counts for code storage gas errors.
+	if err != nil {
+		contract.UseGas(contract.Gas)
+
+		env.RevertToSnapshot(snapshotPreTransfer)
+	}
 	return ret, err
 }
 
 // CallCode executes the given address' code as the given contract address
 func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
-	callerAddr := caller.Address()
-	ret, _, err = exec(env, caller, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
-	return ret, err
-}
+	// Depth check execution. Fail if we're trying to execute above the
+	// limit.
+	if env.Depth() > int(params.CallCreateDepth.Int64()) {
+		caller.ReturnGas(gas, gasPrice)
 
-// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
-func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
-	callerAddr := caller.Address()
-	originAddr := env.Origin()
-	callerValue := caller.Value()
-	ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, callerValue)
-	return ret, err
-}
+		return nil, vm.DepthError
+	}
+	if !env.CanTransfer(caller.Address(), value) {
+		caller.ReturnGas(gas, gasPrice)
 
-// Create creates a new contract with the given code
-func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
-	ret, address, err = exec(env, caller, nil, nil, crypto.Keccak256Hash(code), nil, code, gas, gasPrice, value)
-	// Here we get an error if we run into maximum stack depth,
-	// See: https://github.com/ethereum/yellowpaper/pull/131
-	// and YP definitions for CREATE instruction
+		return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
+	}
+
+	var (
+		snapshotPreTransfer = env.SnapshotDatabase()
+		to                  = env.Db().GetAccount(caller.Address())
+	)
+	// initialise a new contract and set the code that is to be used by the
+	// EVM. The contract is a scoped environment for this execution context
+	// only.
+	contract := vm.NewContract(caller, to, value, gas, gasPrice)
+	contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
+	defer contract.Finalise()
+
+	ret, err = env.Vm().Run(contract, input)
 	if err != nil {
-		return nil, address, err
+		contract.UseGas(contract.Gas)
+
+		env.RevertToSnapshot(snapshotPreTransfer)
 	}
-	return ret, address, err
+
+	return ret, err
 }
 
-func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
-	evm := env.Vm()
+// Create creates a new contract with the given code
+func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
 	// Depth check execution. Fail if we're trying to execute above the
 	// limit.
 	if env.Depth() > int(params.CallCreateDepth.Int64()) {
@@ -68,36 +121,24 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
 
 		return nil, common.Address{}, vm.DepthError
 	}
-
 	if !env.CanTransfer(caller.Address(), value) {
 		caller.ReturnGas(gas, gasPrice)
 
 		return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
 	}
 
-	var createAccount bool
-	if address == nil {
-		// Create a new account on the state
-		nonce := env.Db().GetNonce(caller.Address())
-		env.Db().SetNonce(caller.Address(), nonce+1)
-		addr = crypto.CreateAddress(caller.Address(), nonce)
-		address = &addr
-		createAccount = true
-	}
+	// Create a new account on the state
+	nonce := env.Db().GetNonce(caller.Address())
+	env.Db().SetNonce(caller.Address(), nonce+1)
 
 	snapshotPreTransfer := env.SnapshotDatabase()
 	var (
+		addr = crypto.CreateAddress(caller.Address(), nonce)
 		from = env.Db().GetAccount(caller.Address())
-		to   vm.Account
+		to   = env.Db().CreateAccount(addr)
 	)
-	if createAccount {
-		to = env.Db().CreateAccount(*address)
-	} else {
-		if !env.Db().Exist(*address) {
-			to = env.Db().CreateAccount(*address)
-		} else {
-			to = env.Db().GetAccount(*address)
-		}
+	if env.ChainConfig().IsEIP158(env.BlockNumber()) {
+		env.Db().SetNonce(addr, 1)
 	}
 	env.Transfer(from, to, value)
 
@@ -105,19 +146,19 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
 	// EVM. The contract is a scoped environment for this execution context
 	// only.
 	contract := vm.NewContract(caller, to, value, gas, gasPrice)
-	contract.SetCallCode(codeAddr, codeHash, code)
+	contract.SetCallCode(&addr, crypto.Keccak256Hash(code), code)
 	defer contract.Finalise()
 
-	ret, err = evm.Run(contract, input)
+	ret, err = env.Vm().Run(contract, nil)
 	// if the contract creation ran successfully and no errors were returned
 	// calculate the gas required to store the code. If the code could not
 	// be stored due to not enough gas set an error and let it be handled
 	// by the error checking condition below.
-	if err == nil && createAccount {
+	if err == nil {
 		dataGas := big.NewInt(int64(len(ret)))
 		dataGas.Mul(dataGas, params.CreateDataGas)
 		if contract.UseGas(dataGas) {
-			env.Db().SetCode(*address, ret)
+			env.Db().SetCode(addr, ret)
 		} else {
 			err = vm.CodeStoreOutOfGasError
 		}
@@ -126,46 +167,45 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
 	// When an error was returned by the EVM or when setting the creation code
 	// above we revert to the snapshot and consume any gas remaining. Additionally
 	// when we're in homestead this also counts for code storage gas errors.
-	if err != nil && (env.RuleSet().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError) {
+	if err != nil && (env.ChainConfig().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError) {
 		contract.UseGas(contract.Gas)
 
 		env.RevertToSnapshot(snapshotPreTransfer)
+
+		// Nothing should be returned when an error is thrown.
+		return nil, addr, err
 	}
 
 	return ret, addr, err
 }
 
-func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
-	evm := env.Vm()
+// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
+func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
 	// Depth check execution. Fail if we're trying to execute above the
 	// limit.
 	if env.Depth() > int(params.CallCreateDepth.Int64()) {
 		caller.ReturnGas(gas, gasPrice)
-		return nil, common.Address{}, vm.DepthError
+		return nil, vm.DepthError
 	}
 
-	snapshot := env.SnapshotDatabase()
-
-	var to vm.Account
-	if !env.Db().Exist(*toAddr) {
-		to = env.Db().CreateAccount(*toAddr)
-	} else {
-		to = env.Db().GetAccount(*toAddr)
-	}
+	var (
+		snapshot = env.SnapshotDatabase()
+		to       = env.Db().GetAccount(caller.Address())
+	)
 
 	// Iinitialise a new contract and make initialise the delegate values
-	contract := vm.NewContract(caller, to, value, gas, gasPrice).AsDelegate()
-	contract.SetCallCode(codeAddr, codeHash, code)
+	contract := vm.NewContract(caller, to, caller.Value(), gas, gasPrice).AsDelegate()
+	contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
 	defer contract.Finalise()
 
-	ret, err = evm.Run(contract, input)
+	ret, err = env.Vm().Run(contract, input)
 	if err != nil {
 		contract.UseGas(contract.Gas)
 
 		env.RevertToSnapshot(snapshot)
 	}
 
-	return ret, addr, err
+	return ret, err
 }
 
 // generic transfer method

+ 3 - 3
core/genesis.go

@@ -43,7 +43,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
 	}
 
 	var genesis struct {
-		ChainConfig *ChainConfig `json:"config"`
+		ChainConfig *params.ChainConfig `json:"config"`
 		Nonce       string
 		Timestamp   string
 		ParentHash  string
@@ -73,7 +73,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
 			statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
 		}
 	}
-	root, stateBatch := statedb.CommitBatch()
+	root, stateBatch := statedb.CommitBatch(false)
 
 	difficulty := common.String2Big(genesis.Difficulty)
 	block := types.NewBlock(&types.Header{
@@ -128,7 +128,7 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big
 	statedb, _ := state.New(common.Hash{}, db)
 	obj := statedb.GetOrNewStateObject(addr)
 	obj.SetBalance(balance)
-	root, err := statedb.Commit()
+	root, err := statedb.Commit(false)
 	if err != nil {
 		panic(fmt.Sprintf("cannot write state: %v", err))
 	}

+ 5 - 4
core/headerchain.go

@@ -32,6 +32,7 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
 	"github.com/hashicorp/golang-lru"
 )
@@ -48,7 +49,7 @@ const (
 // It is not thread safe either, the encapsulating chain structures should do
 // the necessary mutex locking/unlocking.
 type HeaderChain struct {
-	config *ChainConfig
+	config *params.ChainConfig
 
 	chainDb       ethdb.Database
 	genesisHeader *types.Header
@@ -73,7 +74,7 @@ type getHeaderValidatorFn func() HeaderValidator
 //  getValidator should return the parent's validator
 //  procInterrupt points to the parent's interrupt semaphore
 //  wg points to the parent's shutdown wait group
-func NewHeaderChain(chainDb ethdb.Database, config *ChainConfig, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) {
+func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) {
 	headerCache, _ := lru.New(headerCacheLimit)
 	tdCache, _ := lru.New(tdCacheLimit)
 	numberCache, _ := lru.New(numberCacheLimit)
@@ -490,13 +491,13 @@ func (hc *HeaderChain) SetGenesis(head *types.Header) {
 //
 // headerValidator implements HeaderValidator.
 type headerValidator struct {
-	config *ChainConfig
+	config *params.ChainConfig
 	hc     *HeaderChain // Canonical header chain
 	Pow    pow.PoW      // Proof of work used for validating
 }
 
 // NewBlockValidator returns a new block validator which is safe for re-use
-func NewHeaderValidator(config *ChainConfig, chain *HeaderChain, pow pow.PoW) HeaderValidator {
+func NewHeaderValidator(config *params.ChainConfig, chain *HeaderChain, pow pow.PoW) HeaderValidator {
 	return &headerValidator{
 		config: config,
 		Pow:    pow,

+ 12 - 1
core/state/state_object.go

@@ -91,6 +91,11 @@ type StateObject struct {
 	onDirty   func(addr common.Address) // Callback method to mark a state object newly dirty
 }
 
+// empty returns whether the account is considered empty.
+func (s *StateObject) empty() bool {
+	return s.data.Nonce == 0 && s.data.Balance.BitLen() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
+}
+
 // Account is the Ethereum consensus representation of accounts.
 // These objects are stored in the main account trie.
 type Account struct {
@@ -221,8 +226,12 @@ func (self *StateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) e
 	return err
 }
 
+// AddBalance removes amount from c's balance.
+// It is used to add funds to the destination account of a transfer.
 func (c *StateObject) AddBalance(amount *big.Int) {
-	if amount.Cmp(common.Big0) == 0 {
+	// EIP158: We must check emptiness for the objects such that the account
+	// clearing (0,0,0 objects) can take effect.
+	if amount.Cmp(common.Big0) == 0 && !c.empty() {
 		return
 	}
 	c.SetBalance(new(big.Int).Add(c.Balance(), amount))
@@ -232,6 +241,8 @@ func (c *StateObject) AddBalance(amount *big.Int) {
 	}
 }
 
+// SubBalance removes amount from c's balance.
+// It is used to remove funds from the origin account of a transfer.
 func (c *StateObject) SubBalance(amount *big.Int) {
 	if amount.Cmp(common.Big0) == 0 {
 		return

+ 3 - 3
core/state/state_test.go

@@ -48,7 +48,7 @@ func (s *StateSuite) TestDump(c *checker.C) {
 	// write some of them to the trie
 	s.state.updateStateObject(obj1)
 	s.state.updateStateObject(obj2)
-	s.state.Commit()
+	s.state.Commit(false)
 
 	// check that dump contains the state objects that are in trie
 	got := string(s.state.Dump())
@@ -100,7 +100,7 @@ func TestNull(t *testing.T) {
 	//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
 	var value common.Hash
 	state.SetState(address, common.Hash{}, value)
-	state.Commit()
+	state.Commit(false)
 	value = state.GetState(address, common.Hash{})
 	if !common.EmptyHash(value) {
 		t.Errorf("expected empty hash. got %x", value)
@@ -160,7 +160,7 @@ func TestSnapshot2(t *testing.T) {
 	so0.deleted = false
 	state.setStateObject(so0)
 
-	root, _ := state.Commit()
+	root, _ := state.Commit(false)
 	state.Reset(root)
 
 	// and one with deleted == true

+ 18 - 9
core/state/statedb.go

@@ -213,6 +213,13 @@ func (self *StateDB) Exist(addr common.Address) bool {
 	return self.GetStateObject(addr) != nil
 }
 
+// Empty returns whether the state object is either non-existant
+// or empty according to the EIP161 specification (balance = nonce = code = 0)
+func (self *StateDB) Empty(addr common.Address) bool {
+	so := self.GetStateObject(addr)
+	return so == nil || so.empty()
+}
+
 func (self *StateDB) GetAccount(addr common.Address) vm.Account {
 	return self.GetStateObject(addr)
 }
@@ -516,10 +523,10 @@ func (self *StateDB) GetRefund() *big.Int {
 // IntermediateRoot computes the current root hash of the state trie.
 // It is called in between transactions to get the root hash that
 // goes into transaction receipts.
-func (s *StateDB) IntermediateRoot() common.Hash {
+func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
 	for addr, _ := range s.stateObjectsDirty {
 		stateObject := s.stateObjects[addr]
-		if stateObject.suicided {
+		if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
 			s.deleteStateObject(stateObject)
 		} else {
 			stateObject.updateRoot(s.db)
@@ -553,17 +560,17 @@ func (s *StateDB) DeleteSuicides() {
 }
 
 // Commit commits all state changes to the database.
-func (s *StateDB) Commit() (root common.Hash, err error) {
-	root, batch := s.CommitBatch()
+func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) {
+	root, batch := s.CommitBatch(deleteEmptyObjects)
 	return root, batch.Write()
 }
 
 // CommitBatch commits all state changes to a write batch but does not
 // execute the batch. It is used to validate state changes against
 // the root hash stored in a block.
-func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) {
+func (s *StateDB) CommitBatch(deleteEmptyObjects bool) (root common.Hash, batch ethdb.Batch) {
 	batch = s.db.NewBatch()
-	root, _ = s.commit(batch)
+	root, _ = s.commit(batch, deleteEmptyObjects)
 
 	glog.V(logger.Debug).Infof("Trie cache stats: %d misses, %d unloads", trie.CacheMisses(), trie.CacheUnloads())
 	return root, batch
@@ -575,16 +582,18 @@ func (s *StateDB) clearJournalAndRefund() {
 	s.refund = new(big.Int)
 }
 
-func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) {
+func (s *StateDB) commit(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
 	defer s.clearJournalAndRefund()
 
 	// Commit objects to the trie.
 	for addr, stateObject := range s.stateObjects {
-		if stateObject.suicided {
+		_, isDirty := s.stateObjectsDirty[addr]
+		switch {
+		case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()):
 			// If the object has been removed, don't bother syncing it
 			// and just mark it for deletion in the trie.
 			s.deleteStateObject(stateObject)
-		} else if _, ok := s.stateObjectsDirty[addr]; ok {
+		case isDirty:
 			// Write any contract code associated with the state object
 			if stateObject.code != nil && stateObject.dirtyCode {
 				if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil {

+ 4 - 4
core/state/statedb_test.go

@@ -51,7 +51,7 @@ func TestUpdateLeaks(t *testing.T) {
 		if i%3 == 0 {
 			state.SetCode(addr, []byte{i, i, i, i, i})
 		}
-		state.IntermediateRoot()
+		state.IntermediateRoot(false)
 	}
 	// Ensure that no data was leaked into the database
 	for _, key := range db.Keys() {
@@ -86,7 +86,7 @@ func TestIntermediateLeaks(t *testing.T) {
 		modify(transState, common.Address{byte(i)}, i, 0)
 	}
 	// Write modifications to trie.
-	transState.IntermediateRoot()
+	transState.IntermediateRoot(false)
 
 	// Overwrite all the data with new values in the transient database.
 	for i := byte(0); i < 255; i++ {
@@ -95,10 +95,10 @@ func TestIntermediateLeaks(t *testing.T) {
 	}
 
 	// Commit and cross check the databases.
-	if _, err := transState.Commit(); err != nil {
+	if _, err := transState.Commit(false); err != nil {
 		t.Fatalf("failed to commit transition state: %v", err)
 	}
-	if _, err := finalState.Commit(); err != nil {
+	if _, err := finalState.Commit(false); err != nil {
 		t.Fatalf("failed to commit final state: %v", err)
 	}
 	for _, key := range finalDb.Keys() {

+ 1 - 1
core/state/sync_test.go

@@ -60,7 +60,7 @@ func makeTestState() (ethdb.Database, common.Hash, []*testAccount) {
 		state.updateStateObject(obj)
 		accounts = append(accounts, acc)
 	}
-	root, _ := state.Commit()
+	root, _ := state.Commit(false)
 
 	// Return the generated state
 	return db, root, accounts

+ 5 - 4
core/state_processor.go

@@ -25,6 +25,7 @@ import (
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 var (
@@ -37,12 +38,12 @@ var (
 //
 // StateProcessor implements Processor.
 type StateProcessor struct {
-	config *ChainConfig
+	config *params.ChainConfig
 	bc     *BlockChain
 }
 
 // NewStateProcessor initialises a new StateProcessor.
-func NewStateProcessor(config *ChainConfig, bc *BlockChain) *StateProcessor {
+func NewStateProcessor(config *params.ChainConfig, bc *BlockChain) *StateProcessor {
 	return &StateProcessor{
 		config: config,
 		bc:     bc,
@@ -89,7 +90,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
 //
 // ApplyTransactions returns the generated receipts and vm logs during the
 // execution of the state transition phase.
-func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
+func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
 	_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp)
 	if err != nil {
 		return nil, nil, nil, err
@@ -97,7 +98,7 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb
 
 	// Update the state with pending changes
 	usedGas.Add(usedGas, gas)
-	receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)
+	receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas)
 	receipt.TxHash = tx.Hash()
 	receipt.GasUsed = new(big.Int).Set(gas)
 	if MessageCreatesContract(tx) {

+ 2 - 2
core/state_transition.go

@@ -139,7 +139,7 @@ func (self *StateTransition) from() (vm.Account, error) {
 		f   common.Address
 		err error
 	)
-	if self.env.RuleSet().IsHomestead(self.env.BlockNumber()) {
+	if self.env.ChainConfig().IsHomestead(self.env.BlockNumber()) {
 		f, err = self.msg.From()
 	} else {
 		f, err = self.msg.FromFrontier()
@@ -234,7 +234,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
 	msg := self.msg
 	sender, _ := self.from() // err checked in preCheck
 
-	homestead := self.env.RuleSet().IsHomestead(self.env.BlockNumber())
+	homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber())
 	contractCreation := MessageCreatesContract(msg)
 	// Pay intrinsic gas
 	if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {

+ 3 - 2
core/tx_pool.go

@@ -31,6 +31,7 @@ import (
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/metrics"
+	"github.com/ethereum/go-ethereum/params"
 	"gopkg.in/karalabe/cookiejar.v2/collections/prque"
 )
 
@@ -83,7 +84,7 @@ type stateFn func() (*state.StateDB, error)
 // current state) and future transactions. Transactions move between those
 // two states over time as they are received and processed.
 type TxPool struct {
-	config       *ChainConfig
+	config       *params.ChainConfig
 	currentState stateFn // The state function which will allow us to do some pre checks
 	pendingState *state.ManagedState
 	gasLimit     func() *big.Int // The current gas limit function callback
@@ -104,7 +105,7 @@ type TxPool struct {
 	homestead bool
 }
 
-func NewTxPool(config *ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
+func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
 	pool := &TxPool{
 		config:       config,
 		pending:      make(map[common.Address]*txList),

+ 4 - 10
core/vm/environment.go

@@ -23,20 +23,11 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 )
 
-// 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
-	// GasTable returns the gas prices for this phase, which is based on
-	// block number passed in.
-	GasTable(*big.Int) params.GasTable
-}
-
 // Environment is an EVM requirement and helper which allows access to outside
 // information such as states.
 type Environment interface {
 	// The current ruleset
-	RuleSet() RuleSet
+	ChainConfig() *params.ChainConfig
 	// The state database
 	Db() Database
 	// Creates a restorable snapshot
@@ -115,6 +106,9 @@ type Database interface {
 	// Exist reports whether the given account exists in state.
 	// Notably this should also return true for suicided accounts.
 	Exist(common.Address) bool
+	// Empty returns whether the given account is empty. Empty
+	// is defined according to EIP161 (balance = nonce = code = 0).
+	Empty(common.Address) bool
 }
 
 // Account represents a contract or basic ethereum account.

+ 2 - 2
core/vm/instructions.go

@@ -515,7 +515,7 @@ func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract
 		input        = memory.Get(offset.Int64(), size.Int64())
 		gas          = new(big.Int).Set(contract.Gas)
 	)
-	if env.RuleSet().GasTable(env.BlockNumber()).CreateBySuicide != nil {
+	if env.ChainConfig().IsEIP150(env.BlockNumber()) {
 		gas.Div(gas, n64)
 		gas = gas.Sub(contract.Gas, gas)
 	}
@@ -526,7 +526,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 env.RuleSet().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError {
+	if env.ChainConfig().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError {
 		stack.push(new(big.Int))
 	} else if suberr != nil && suberr != CodeStoreOutOfGasError {
 		stack.push(new(big.Int))

+ 1 - 1
core/vm/jit.go

@@ -319,7 +319,7 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *Stack, env
 		}()
 	}
 
-	homestead := env.RuleSet().IsHomestead(env.BlockNumber())
+	homestead := env.ChainConfig().IsHomestead(env.BlockNumber())
 	for pc < uint64(len(program.instructions)) {
 		instrCount++
 

+ 4 - 1
core/vm/jit_test.go

@@ -23,6 +23,7 @@ import (
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 const maxRun = 1000
@@ -172,7 +173,9 @@ func NewEnv(config *Config) *Env {
 	return env
 }
 
-func (self *Env) RuleSet() RuleSet       { return ruleSet{new(big.Int)} }
+func (self *Env) ChainConfig() *params.ChainConfig {
+	return &params.ChainConfig{new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, 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) }

+ 6 - 2
core/vm/jump_table.go

@@ -16,7 +16,11 @@
 
 package vm
 
-import "math/big"
+import (
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/params"
+)
 
 type jumpPtr struct {
 	fn    instrFn
@@ -25,7 +29,7 @@ type jumpPtr struct {
 
 type vmJumpTable [256]jumpPtr
 
-func newJumpTable(ruleset RuleSet, blockNumber *big.Int) vmJumpTable {
+func newJumpTable(ruleset *params.ChainConfig, blockNumber *big.Int) vmJumpTable {
 	var jumpTable vmJumpTable
 
 	// when initialising a new VM execution we must first check the homestead

+ 4 - 2
core/vm/jump_table_test.go

@@ -19,16 +19,18 @@ package vm
 import (
 	"math/big"
 	"testing"
+
+	"github.com/ethereum/go-ethereum/params"
 )
 
 func TestInit(t *testing.T) {
-	jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(0))
+	jumpTable := newJumpTable(&params.ChainConfig{HomesteadBlock: 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(ruleSet{big.NewInt(1)}, big.NewInt(n))
+		jumpTable := newJumpTable(&params.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(n))
 		if !jumpTable[DELEGATECALL].valid {
 			t.Error("Expected DELEGATECALL to be present for block", n)
 		}

+ 22 - 21
core/vm/runtime/env.go

@@ -23,13 +23,14 @@ import (
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/vm"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 // Env is a basic runtime environment required for running the EVM.
 type Env struct {
-	ruleSet vm.RuleSet
-	depth   int
-	state   *state.StateDB
+	chainConfig *params.ChainConfig
+	depth       int
+	state       *state.StateDB
 
 	origin   common.Address
 	coinbase common.Address
@@ -47,14 +48,14 @@ 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,
-		number:     cfg.BlockNumber,
-		time:       cfg.Time,
-		difficulty: cfg.Difficulty,
-		gasLimit:   cfg.GasLimit,
+		chainConfig: cfg.ChainConfig,
+		state:       state,
+		origin:      cfg.Origin,
+		coinbase:    cfg.Coinbase,
+		number:      cfg.BlockNumber,
+		time:        cfg.Time,
+		difficulty:  cfg.Difficulty,
+		gasLimit:    cfg.GasLimit,
 	}
 	env.evm = vm.New(env, vm.Config{
 		Debug:     cfg.Debug,
@@ -65,16 +66,16 @@ func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
 	return env
 }
 
-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 }
-func (self *Env) Coinbase() common.Address { return self.coinbase }
-func (self *Env) Time() *big.Int           { return self.time }
-func (self *Env) Difficulty() *big.Int     { return self.difficulty }
-func (self *Env) Db() vm.Database          { return self.state }
-func (self *Env) GasLimit() *big.Int       { return self.gasLimit }
-func (self *Env) VmType() vm.Type          { return vm.StdVmTy }
+func (self *Env) ChainConfig() *params.ChainConfig { return self.chainConfig }
+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 }
+func (self *Env) Time() *big.Int                   { return self.time }
+func (self *Env) Difficulty() *big.Int             { return self.difficulty }
+func (self *Env) Db() vm.Database                  { return self.state }
+func (self *Env) GasLimit() *big.Int               { return self.gasLimit }
+func (self *Env) VmType() vm.Type                  { return vm.StdVmTy }
 func (self *Env) GetHash(n uint64) common.Hash {
 	return self.getHashFn(n)
 }

+ 3 - 4
core/vm/runtime/runtime.go

@@ -22,7 +22,6 @@ 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"
 	"github.com/ethereum/go-ethereum/params"
@@ -39,7 +38,7 @@ func (ruleSet) GasTable(*big.Int) params.GasTable {
 // Config is a basic type specifying certain configuration flags for running
 // the EVM.
 type Config struct {
-	RuleSet     vm.RuleSet
+	ChainConfig *params.ChainConfig
 	Difficulty  *big.Int
 	Origin      common.Address
 	Coinbase    common.Address
@@ -57,8 +56,8 @@ type Config struct {
 
 // sets defaults on the config
 func setDefaults(cfg *Config) {
-	if cfg.RuleSet == nil {
-		cfg.RuleSet = ruleSet{}
+	if cfg.ChainConfig == nil {
+		cfg.ChainConfig = &params.ChainConfig{new(big.Int), new(big.Int), false, new(big.Int), common.Hash{}, new(big.Int)}
 	}
 
 	if cfg.Difficulty == nil {

+ 26 - 6
core/vm/vm.go

@@ -51,9 +51,9 @@ type EVM struct {
 func New(env Environment, cfg Config) *EVM {
 	return &EVM{
 		env:       env,
-		jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()),
+		jumpTable: newJumpTable(env.ChainConfig(), env.BlockNumber()),
 		cfg:       cfg,
-		gasTable:  env.RuleSet().GasTable(env.BlockNumber()),
+		gasTable:  env.ChainConfig().GasTable(env.BlockNumber()),
 	}
 }
 
@@ -172,6 +172,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
 
 		// Get the memory location of pc
 		op = contract.GetOp(pc)
+		//fmt.Printf("OP %d %v\n", op, op)
 		// calculate the new memory size and gas price for the current executing opcode
 		newMemSize, cost, err = calculateGasAndSize(evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack)
 		if err != nil {
@@ -254,10 +255,20 @@ func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Co
 	// stack Check, memory resize & gas phase
 	switch op {
 	case SUICIDE:
-		// if suicide is not nil: homestead gas fork
+		// EIP150 homestead gas reprice fork:
 		if gasTable.CreateBySuicide != nil {
 			gas.Set(gasTable.Suicide)
-			if !env.Db().Exist(common.BigToAddress(stack.data[len(stack.data)-1])) {
+			var (
+				address = common.BigToAddress(stack.data[len(stack.data)-1])
+				eip158  = env.ChainConfig().IsEIP158(env.BlockNumber())
+			)
+
+			if eip158 {
+				// if empty and transfers value
+				if env.Db().Empty(address) && statedb.GetBalance(contract.Address()).BitLen() > 0 {
+					gas.Add(gas, gasTable.CreateBySuicide)
+				}
+			} else if !env.Db().Exist(address) {
 				gas.Add(gas, gasTable.CreateBySuicide)
 			}
 		}
@@ -378,12 +389,21 @@ func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Co
 	case CALL, CALLCODE:
 		gas.Set(gasTable.Calls)
 
+		transfersValue := stack.data[len(stack.data)-3].BitLen() > 0
 		if op == CALL {
-			if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) {
+			var (
+				address = common.BigToAddress(stack.data[len(stack.data)-2])
+				eip158  = env.ChainConfig().IsEIP158(env.BlockNumber())
+			)
+			if eip158 {
+				if env.Db().Empty(address) && transfersValue {
+					gas.Add(gas, params.CallNewAccountGas)
+				}
+			} else if !env.Db().Exist(address) {
 				gas.Add(gas, params.CallNewAccountGas)
 			}
 		}
-		if len(stack.data[stack.len()-3].Bytes()) > 0 {
+		if transfersValue {
 			gas.Add(gas, params.CallValueTransferGas)
 		}
 		x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])

+ 19 - 18
core/vm_env.go

@@ -23,6 +23,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 // GetHashFn returns a function for which the VM env can query block hashes through
@@ -41,18 +42,18 @@ func GetHashFn(ref common.Hash, chain *BlockChain) func(n uint64) common.Hash {
 }
 
 type VMEnv struct {
-	chainConfig *ChainConfig   // Chain configuration
-	state       *state.StateDB // State to use for executing
-	evm         *vm.EVM        // The Ethereum Virtual Machine
-	depth       int            // Current execution depth
-	msg         Message        // Message appliod
+	chainConfig *params.ChainConfig // Chain configuration
+	state       *state.StateDB      // State to use for executing
+	evm         *vm.EVM             // The Ethereum Virtual Machine
+	depth       int                 // Current execution depth
+	msg         Message             // Message appliod
 
 	header    *types.Header            // Header information
 	chain     *BlockChain              // Blockchain handle
 	getHashFn func(uint64) common.Hash // getHashFn callback is used to retrieve block hashes
 }
 
-func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
+func NewEnv(state *state.StateDB, chainConfig *params.ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
 	env := &VMEnv{
 		chainConfig: chainConfig,
 		chain:       chain,
@@ -66,18 +67,18 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
 	return env
 }
 
-func (self *VMEnv) RuleSet() vm.RuleSet      { return self.chainConfig }
-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 }
-func (self *VMEnv) Time() *big.Int           { return self.header.Time }
-func (self *VMEnv) Difficulty() *big.Int     { return self.header.Difficulty }
-func (self *VMEnv) GasLimit() *big.Int       { return self.header.GasLimit }
-func (self *VMEnv) Value() *big.Int          { return self.msg.Value() }
-func (self *VMEnv) Db() vm.Database          { return self.state }
-func (self *VMEnv) Depth() int               { return self.depth }
-func (self *VMEnv) SetDepth(i int)           { self.depth = i }
+func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig }
+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 }
+func (self *VMEnv) Time() *big.Int                   { return self.header.Time }
+func (self *VMEnv) Difficulty() *big.Int             { return self.header.Difficulty }
+func (self *VMEnv) GasLimit() *big.Int               { return self.header.GasLimit }
+func (self *VMEnv) Value() *big.Int                  { return self.msg.Value() }
+func (self *VMEnv) Db() vm.Database                  { return self.state }
+func (self *VMEnv) Depth() int                       { return self.depth }
+func (self *VMEnv) SetDepth(i int)                   { self.depth = i }
 func (self *VMEnv) GetHash(n uint64) common.Hash {
 	return self.getHashFn(n)
 }

+ 3 - 2
eth/api.go

@@ -37,6 +37,7 @@ import (
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/miner"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rpc"
 	"golang.org/x/net/context"
@@ -303,13 +304,13 @@ func (api *PublicDebugAPI) DumpBlock(number uint64) (state.Dump, error) {
 // PrivateDebugAPI is the collection of Etheruem full node APIs exposed over
 // the private debugging endpoint.
 type PrivateDebugAPI struct {
-	config *core.ChainConfig
+	config *params.ChainConfig
 	eth    *Ethereum
 }
 
 // NewPrivateDebugAPI creates a new API definition for the full node-related
 // private debug methods of the Ethereum service.
-func NewPrivateDebugAPI(config *core.ChainConfig, eth *Ethereum) *PrivateDebugAPI {
+func NewPrivateDebugAPI(config *params.ChainConfig, eth *Ethereum) *PrivateDebugAPI {
 	return &PrivateDebugAPI{config: config, eth: eth}
 }
 

+ 1 - 1
eth/api_backend.go

@@ -103,7 +103,7 @@ func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state et
 	from := statedb.GetOrNewStateObject(addr)
 	from.SetBalance(common.MaxBig)
 	vmError := func() error { return nil }
-	return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig), vmError, nil
+	return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{}), vmError, nil
 }
 
 func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {

+ 3 - 7
eth/backend.go

@@ -35,7 +35,6 @@ import (
 	"github.com/ethereum/go-ethereum/common/registrar/ethreg"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/eth/downloader"
 	"github.com/ethereum/go-ethereum/eth/filters"
 	"github.com/ethereum/go-ethereum/eth/gasprice"
@@ -47,6 +46,7 @@ import (
 	"github.com/ethereum/go-ethereum/miner"
 	"github.com/ethereum/go-ethereum/node"
 	"github.com/ethereum/go-ethereum/p2p"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rpc"
 )
 
@@ -64,7 +64,7 @@ var (
 )
 
 type Config struct {
-	ChainConfig *core.ChainConfig // chain configuration
+	ChainConfig *params.ChainConfig // chain configuration
 
 	NetworkId  int    // Network ID to use for selecting peers to connect to
 	Genesis    string // Genesis JSON to seed the chain database with
@@ -112,7 +112,7 @@ type LesServer interface {
 
 // Ethereum implements the Ethereum full node service.
 type Ethereum struct {
-	chainConfig *core.ChainConfig
+	chainConfig *params.ChainConfig
 	// Channel for shutting down the service
 	shutdownChan  chan bool // Channel for shutting down the ethereum
 	stopDbUpgrade func()    // stop chain db sequential key upgrade
@@ -217,10 +217,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 	core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
 
 	eth.chainConfig = config.ChainConfig
-	eth.chainConfig.VmConfig = vm.Config{
-		EnableJit: config.EnableJit,
-		ForceJit:  config.ForceJit,
-	}
 
 	eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux())
 	if err != nil {

+ 2 - 1
eth/backend_test.go

@@ -25,6 +25,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 func TestMipmapUpgrade(t *testing.T) {
@@ -32,7 +33,7 @@ func TestMipmapUpgrade(t *testing.T) {
 	addr := common.BytesToAddress([]byte("jeff"))
 	genesis := core.WriteGenesisBlockForTesting(db)
 
-	chain, receipts := core.GenerateChain(nil, genesis, db, 10, func(i int, gen *core.BlockGen) {
+	chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
 		var receipts types.Receipts
 		switch i {
 		case 1:

+ 1 - 1
eth/downloader/downloader_test.go

@@ -109,7 +109,7 @@ func newTester() *downloadTester {
 // reassembly.
 func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Receipts, heavy bool) ([]common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]types.Receipts) {
 	// Generate the block chain
-	blocks, receipts := core.GenerateChain(nil, parent, dl.peerDb, n, func(i int, block *core.BlockGen) {
+	blocks, receipts := core.GenerateChain(params.TestChainConfig, parent, dl.peerDb, n, func(i int, block *core.BlockGen) {
 		block.SetCoinbase(common.Address{seed})
 
 		// If a heavy chain is requested, delay blocks to raise difficulty

+ 1 - 1
eth/fetcher/fetcher_test.go

@@ -45,7 +45,7 @@ var (
 // contains a transaction and every 5th an uncle to allow testing correct block
 // reassembly.
 func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) {
-	blocks, _ := core.GenerateChain(nil, parent, testdb, n, func(i int, block *core.BlockGen) {
+	blocks, _ := core.GenerateChain(params.TestChainConfig, parent, testdb, n, func(i int, block *core.BlockGen) {
 		block.SetCoinbase(common.Address{seed})
 
 		// If the block number is multiple of 3, send a bonus transaction to the miner

+ 2 - 1
eth/filters/filter_system_test.go

@@ -30,6 +30,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rpc"
 )
 
@@ -81,7 +82,7 @@ func TestBlockSubscription(t *testing.T) {
 
 	var (
 		genesis     = core.WriteGenesisBlockForTesting(db)
-		chain, _    = core.GenerateChain(nil, genesis, db, 10, func(i int, gen *core.BlockGen) {})
+		chain, _    = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
 		chainEvents = []core.ChainEvent{}
 	)
 

+ 3 - 2
eth/filters/filter_test.go

@@ -30,6 +30,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 func makeReceipt(addr common.Address) *types.Receipt {
@@ -60,7 +61,7 @@ func BenchmarkMipmaps(b *testing.B) {
 	defer db.Close()
 
 	genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)})
-	chain, receipts := core.GenerateChain(nil, genesis, db, 100010, func(i int, gen *core.BlockGen) {
+	chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) {
 		var receipts types.Receipts
 		switch i {
 		case 2403:
@@ -137,7 +138,7 @@ func TestFilters(t *testing.T) {
 	defer db.Close()
 
 	genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)})
-	chain, receipts := core.GenerateChain(nil, genesis, db, 1000, func(i int, gen *core.BlockGen) {
+	chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) {
 		var receipts types.Receipts
 		switch i {
 		case 1:

+ 3 - 2
eth/handler.go

@@ -37,6 +37,7 @@ import (
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p/discover"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 )
@@ -67,7 +68,7 @@ type ProtocolManager struct {
 	txpool      txPool
 	blockchain  *core.BlockChain
 	chaindb     ethdb.Database
-	chainconfig *core.ChainConfig
+	chainconfig *params.ChainConfig
 	maxPeers    int
 
 	downloader *downloader.Downloader
@@ -95,7 +96,7 @@ type ProtocolManager struct {
 
 // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
 // with the ethereum network.
-func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
+func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
 	// Create the protocol manager with the base fields
 	manager := &ProtocolManager{
 		networkId:   networkId,

+ 2 - 2
eth/handler_test.go

@@ -466,7 +466,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
 		pow           = new(core.FakePow)
 		db, _         = ethdb.NewMemDatabase()
 		genesis       = core.WriteGenesisBlockForTesting(db)
-		config        = &core.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
+		config        = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
 		blockchain, _ = core.NewBlockChain(db, config, pow, evmux)
 	)
 	pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)
@@ -491,7 +491,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
 	}
 	// Create a block to reply to the challenge if no timeout is simualted
 	if !timeout {
-		blocks, _ := core.GenerateChain(nil, genesis, db, 1, func(i int, block *core.BlockGen) {
+		blocks, _ := core.GenerateChain(&params.ChainConfig{}, genesis, db, 1, func(i int, block *core.BlockGen) {
 			if remoteForked {
 				block.SetExtra(params.DAOForkBlockExtra)
 			}

+ 3 - 2
eth/helper_test.go

@@ -35,6 +35,7 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p/discover"
+	"github.com/ethereum/go-ethereum/params"
 )
 
 var (
@@ -54,10 +55,10 @@ func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core
 		pow           = new(core.FakePow)
 		db, _         = ethdb.NewMemDatabase()
 		genesis       = core.WriteGenesisBlockForTesting(db, testBank)
-		chainConfig   = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
+		chainConfig   = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
 		blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux)
 	)
-	chain, _ := core.GenerateChain(nil, genesis, db, blocks, generator)
+	chain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
 	if _, err := blockchain.InsertChain(chain); err != nil {
 		panic(err)
 	}

+ 3 - 6
internal/ethapi/tracer_test.go

@@ -29,11 +29,6 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 )
 
-type ruleSet struct{}
-
-func (self *ruleSet) IsHomestead(*big.Int) bool    { return true }
-func (*ruleSet) GasTable(*big.Int) params.GasTable { return params.GasTableHomesteadGasRepriceFork }
-
 type Env struct {
 	gasLimit *big.Int
 	depth    int
@@ -46,7 +41,9 @@ func NewEnv(config *vm.Config) *Env {
 	return env
 }
 
-func (self *Env) RuleSet() vm.RuleSet    { return &ruleSet{} }
+func (self *Env) ChainConfig() *params.ChainConfig {
+	return params.TestChainConfig
+}
 func (self *Env) Vm() vm.Vm              { return self.evm }
 func (self *Env) Origin() common.Address { return common.Address{} }
 func (self *Env) BlockNumber() *big.Int  { return big.NewInt(0) }

+ 1 - 1
les/api_backend.go

@@ -87,7 +87,7 @@ func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state et
 		return nil, nil, err
 	}
 	from.SetBalance(common.MaxBig)
-	env := light.NewEnv(ctx, stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig)
+	env := light.NewEnv(ctx, stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{})
 	return env, env.Error, nil
 }
 

+ 2 - 6
les/backend.go

@@ -29,7 +29,6 @@ import (
 	"github.com/ethereum/go-ethereum/common/httpclient"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/eth/downloader"
 	"github.com/ethereum/go-ethereum/eth/filters"
@@ -42,13 +41,14 @@ import (
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/node"
 	"github.com/ethereum/go-ethereum/p2p"
+	"github.com/ethereum/go-ethereum/params"
 	rpc "github.com/ethereum/go-ethereum/rpc"
 )
 
 type LightEthereum struct {
 	odr         *LesOdr
 	relay       *LesTxRelay
-	chainConfig *core.ChainConfig
+	chainConfig *params.ChainConfig
 	// Channel for shutting down the service
 	shutdownChan chan bool
 	// Handlers
@@ -107,10 +107,6 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
 		return nil, errors.New("missing chain config")
 	}
 	eth.chainConfig = config.ChainConfig
-	eth.chainConfig.VmConfig = vm.Config{
-		EnableJit: config.EnableJit,
-		ForceJit:  config.ForceJit,
-	}
 	eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
 	if err != nil {
 		if err == core.ErrNoGenesis {

+ 3 - 2
les/handler.go

@@ -38,6 +38,7 @@ import (
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/p2p/discv5"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/trie"
@@ -95,7 +96,7 @@ type ProtocolManager struct {
 	txpool      txPool
 	txrelay     *LesTxRelay
 	networkId   int
-	chainConfig *core.ChainConfig
+	chainConfig *params.ChainConfig
 	blockchain  BlockChain
 	chainDb     ethdb.Database
 	odr         *LesOdr
@@ -129,7 +130,7 @@ type ProtocolManager struct {
 
 // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
 // with the ethereum network.
-func NewProtocolManager(chainConfig *core.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, pow pow.PoW, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
+func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, pow pow.PoW, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
 	// Create the protocol manager with the base fields
 	manager := &ProtocolManager{
 		lightSync:   lightSync,

+ 2 - 2
les/helper_test.go

@@ -131,7 +131,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
 		pow         = new(core.FakePow)
 		db, _       = ethdb.NewMemDatabase()
 		genesis     = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
-		chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
+		chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
 		odr         *LesOdr
 		chain       BlockChain
 	)
@@ -141,7 +141,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
 		chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux)
 	} else {
 		blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux)
-		gchain, _ := core.GenerateChain(nil, genesis, db, blocks, generator)
+		gchain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
 		if _, err := blockchain.InsertChain(gchain); err != nil {
 			panic(err)
 		}

+ 9 - 7
les/odr_test.go

@@ -26,17 +26,19 @@ import (
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/light"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rlp"
 	"golang.org/x/net/context"
 )
 
-type odrTestFn func(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
+type odrTestFn func(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
 
 func TestOdrGetBlockLes1(t *testing.T) { testOdr(t, 1, 1, odrGetBlock) }
 
-func odrGetBlock(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
+func odrGetBlock(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
 	var block *types.Block
 	if bc != nil {
 		block = bc.GetBlockByHash(bhash)
@@ -52,7 +54,7 @@ func odrGetBlock(ctx context.Context, db ethdb.Database, config *core.ChainConfi
 
 func TestOdrGetReceiptsLes1(t *testing.T) { testOdr(t, 1, 1, odrGetReceipts) }
 
-func odrGetReceipts(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
+func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
 	var receipts types.Receipts
 	if bc != nil {
 		receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash))
@@ -68,7 +70,7 @@ func odrGetReceipts(ctx context.Context, db ethdb.Database, config *core.ChainCo
 
 func TestOdrAccountsLes1(t *testing.T) { testOdr(t, 1, 1, odrAccounts) }
 
-func odrAccounts(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
+func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
 	dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678")
 	acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
 
@@ -138,7 +140,7 @@ func (m lightcallmsg) Gas() *big.Int                         { return m.gas }
 func (m lightcallmsg) Value() *big.Int                       { return m.value }
 func (m lightcallmsg) Data() []byte                          { return m.data }
 
-func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
+func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
 	data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
 
 	var res []byte
@@ -160,7 +162,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainC
 					to:       &testContractAddr,
 				}
 
-				vmenv := core.NewEnv(statedb, config, bc, msg, header, config.VmConfig)
+				vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
 				gp := new(core.GasPool).AddGas(common.MaxBig)
 				ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
 				res = append(res, ret...)
@@ -181,7 +183,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainC
 					to:       &testContractAddr,
 				}
 
-				vmenv := light.NewEnv(ctx, state, config, lc, msg, header, config.VmConfig)
+				vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{})
 				gp := new(core.GasPool).AddGas(common.MaxBig)
 				ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
 				if vmenv.Error() == nil {

+ 2 - 1
light/lightchain.go

@@ -29,6 +29,7 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/hashicorp/golang-lru"
@@ -71,7 +72,7 @@ type LightChain struct {
 // NewLightChain returns a fully initialised light chain using information
 // available in the database. It initialises the default Ethereum header
 // validator.
-func NewLightChain(odr OdrBackend, config *core.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*LightChain, error) {
+func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*LightChain, error) {
 	bodyCache, _ := lru.New(bodyCacheLimit)
 	bodyRLPCache, _ := lru.New(bodyCacheLimit)
 	blockCache, _ := lru.New(blockCacheLimit)

+ 4 - 3
light/lightchain_test.go

@@ -28,6 +28,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/pow"
 	"github.com/hashicorp/golang-lru"
 	"golang.org/x/net/context"
@@ -41,7 +42,7 @@ var (
 
 // makeHeaderChain creates a deterministic chain of headers rooted at parent.
 func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header {
-	blocks, _ := core.GenerateChain(nil, types.NewBlockWithHeader(parent), db, n, func(i int, b *core.BlockGen) {
+	blocks, _ := core.GenerateChain(params.TestChainConfig, types.NewBlockWithHeader(parent), db, n, func(i int, b *core.BlockGen) {
 		b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
 	})
 	headers := make([]*types.Header, len(blocks))
@@ -51,8 +52,8 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
 	return headers
 }
 
-func testChainConfig() *core.ChainConfig {
-	return &core.ChainConfig{HomesteadBlock: big.NewInt(0)}
+func testChainConfig() *params.ChainConfig {
+	return &params.ChainConfig{HomesteadBlock: big.NewInt(0)}
 }
 
 // newCanonical creates a chain database, and injects a deterministic canonical

+ 2 - 1
light/odr_test.go

@@ -294,7 +294,8 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
 	core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
 	// Assemble the test environment
 	blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux)
-	gchain, _ := core.GenerateChain(nil, genesis, sdb, 4, testChainGen)
+	chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}
+	gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, 4, testChainGen)
 	if _, err := blockchain.InsertChain(gchain); err != nil {
 		panic(err)
 	}

+ 1 - 1
light/state_test.go

@@ -41,7 +41,7 @@ func makeTestState() (common.Hash, ethdb.Database) {
 		st.AddBalance(addr, big.NewInt(int64(i)))
 		st.SetCode(addr, []byte{i, i, i})
 	}
-	root, _ := st.Commit()
+	root, _ := st.Commit(false)
 	return root, sdb
 }
 

+ 3 - 2
light/txpool.go

@@ -28,6 +28,7 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rlp"
 	"golang.org/x/net/context"
 )
@@ -42,7 +43,7 @@ var txPermanent = uint64(500)
 // always receive all locally signed transactions in the same order as they are
 // created.
 type TxPool struct {
-	config   *core.ChainConfig
+	config   *params.ChainConfig
 	quit     chan bool
 	eventMux *event.TypeMux
 	events   event.Subscription
@@ -76,7 +77,7 @@ type TxRelayBackend interface {
 }
 
 // NewTxPool creates a new light transaction pool
-func NewTxPool(config *core.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool {
+func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool {
 	pool := &TxPool{
 		config:   config,
 		nonce:    make(map[common.Address]uint64),

+ 2 - 1
light/txpool_test.go

@@ -87,7 +87,8 @@ func TestTxPool(t *testing.T) {
 	core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
 	// Assemble the test environment
 	blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux)
-	gchain, _ := core.GenerateChain(nil, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
+	chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}
+	gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
 	if _, err := blockchain.InsertChain(gchain); err != nil {
 		panic(err)
 	}

+ 14 - 13
light/vm_env.go

@@ -24,6 +24,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/params"
 	"golang.org/x/net/context"
 )
 
@@ -34,7 +35,7 @@ import (
 type VMEnv struct {
 	vm.Environment
 	ctx         context.Context
-	chainConfig *core.ChainConfig
+	chainConfig *params.ChainConfig
 	evm         *vm.EVM
 	state       *VMState
 	header      *types.Header
@@ -45,7 +46,7 @@ type VMEnv struct {
 }
 
 // NewEnv creates a new execution environment based on an ODR capable light state
-func NewEnv(ctx context.Context, state *LightState, chainConfig *core.ChainConfig, chain *LightChain, msg core.Message, header *types.Header, cfg vm.Config) *VMEnv {
+func NewEnv(ctx context.Context, state *LightState, chainConfig *params.ChainConfig, chain *LightChain, msg core.Message, header *types.Header, cfg vm.Config) *VMEnv {
 	env := &VMEnv{
 		chainConfig: chainConfig,
 		chain:       chain,
@@ -58,17 +59,17 @@ func NewEnv(ctx context.Context, state *LightState, chainConfig *core.ChainConfi
 	return env
 }
 
-func (self *VMEnv) RuleSet() vm.RuleSet      { return self.chainConfig }
-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 }
-func (self *VMEnv) Time() *big.Int           { return self.header.Time }
-func (self *VMEnv) Difficulty() *big.Int     { return self.header.Difficulty }
-func (self *VMEnv) GasLimit() *big.Int       { return self.header.GasLimit }
-func (self *VMEnv) Db() vm.Database          { return self.state }
-func (self *VMEnv) Depth() int               { return self.depth }
-func (self *VMEnv) SetDepth(i int)           { self.depth = i }
+func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig }
+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 }
+func (self *VMEnv) Time() *big.Int                   { return self.header.Time }
+func (self *VMEnv) Difficulty() *big.Int             { return self.header.Difficulty }
+func (self *VMEnv) GasLimit() *big.Int               { return self.header.GasLimit }
+func (self *VMEnv) Db() vm.Database                  { return self.state }
+func (self *VMEnv) Depth() int                       { return self.depth }
+func (self *VMEnv) SetDepth(i int)                   { self.depth = i }
 func (self *VMEnv) GetHash(n uint64) common.Hash {
 	for header := self.chain.GetHeader(self.header.ParentHash, self.header.Number.Uint64()-1); header != nil; header = self.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
 		if header.Number.Uint64() == n {

+ 1 - 1
miner/miner.go

@@ -62,7 +62,7 @@ type Miner struct {
 	shouldStart int32 // should start indicates whether we should start after sync
 }
 
-func New(eth Backend, config *core.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner {
+func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner {
 	miner := &Miner{
 		eth:      eth,
 		mux:      mux,

+ 6 - 13
miner/worker.go

@@ -63,7 +63,7 @@ type uint64RingBuffer struct {
 // Work is the workers current environment and holds
 // all of the current state information
 type Work struct {
-	config           *core.ChainConfig
+	config           *params.ChainConfig
 	state            *state.StateDB // apply state changes here
 	ancestors        *set.Set       // ancestor set (used for checking uncle parent validity)
 	family           *set.Set       // family set (used for checking uncle invalidity)
@@ -90,7 +90,7 @@ type Result struct {
 
 // worker is the main object which takes care of applying messages to the new state
 type worker struct {
-	config *core.ChainConfig
+	config *params.ChainConfig
 
 	mu sync.Mutex
 
@@ -128,7 +128,7 @@ type worker struct {
 	fullValidation bool
 }
 
-func newWorker(config *core.ChainConfig, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
+func newWorker(config *params.ChainConfig, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
 	worker := &worker{
 		config:         config,
 		eth:            eth,
@@ -276,7 +276,7 @@ func (self *worker) wait() {
 				}
 				go self.mux.Post(core.NewMinedBlockEvent{Block: block})
 			} else {
-				work.state.Commit()
+				work.state.Commit(self.config.IsEIP158(block.Number()))
 				parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
 				if parent == nil {
 					glog.V(logger.Error).Infoln("Invalid block found during mining")
@@ -528,7 +528,7 @@ func (self *worker) commitNewWork() {
 	if atomic.LoadInt32(&self.mining) == 1 {
 		// commit state root after all state transitions.
 		core.AccumulateRewards(work.state, header, uncles)
-		header.Root = work.state.IntermediateRoot()
+		header.Root = work.state.IntermediateRoot(self.config.IsEIP158(header.Number))
 	}
 
 	// create the new block whose nonce will be mined.
@@ -620,14 +620,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
 func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) {
 	snap := env.state.Snapshot()
 
-	// this is a bit of a hack to force jit for the miners
-	config := env.config.VmConfig
-	if !(config.EnableJit && config.ForceJit) {
-		config.EnableJit = false
-	}
-	config.ForceJit = false // disable forcing jit
-
-	receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, config)
+	receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, vm.Config{})
 	if err != nil {
 		env.state.RevertToSnapshot(snap)
 		return err, nil

+ 34 - 13
core/config.go → params/config.go

@@ -14,19 +14,14 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-package core
+package params
 
 import (
-	"errors"
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core/vm"
-	"github.com/ethereum/go-ethereum/params"
 )
 
-var ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
-
 // ChainConfig is the core config which determines the blockchain settings.
 //
 // ChainConfig is stored in the database on a per block basis. This means
@@ -37,12 +32,15 @@ type ChainConfig struct {
 	DAOForkBlock   *big.Int `json:"daoForkBlock"`   // TheDAO hard-fork switch block (nil = no fork)
 	DAOForkSupport bool     `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
 
-	HomesteadGasRepriceBlock *big.Int    `json:"homesteadGasRepriceBlock"` // Homestead gas reprice switch block (nil = no fork)
-	HomesteadGasRepriceHash  common.Hash `json:"homesteadGasRepriceHash"`  // Homestead gas reprice switch block hash (fast sync aid)
+	// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
+	EIP150Block *big.Int    `json:"EIP150Block"` // EIP150 HF block (nil = no fork)
+	EIP150Hash  common.Hash `json:"EIP150Hash"`  // EIP150 HF hash (fast sync aid)
 
-	VmConfig vm.Config `json:"-"`
+	EIP158Block *big.Int `json:"EIP158Block"` // EIP158 HF block
 }
 
+var TestChainConfig = &ChainConfig{new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int)}
+
 // IsHomestead returns whether num is either equal to the homestead block or greater.
 func (c *ChainConfig) IsHomestead(num *big.Int) bool {
 	if c.HomesteadBlock == nil || num == nil {
@@ -54,10 +52,33 @@ func (c *ChainConfig) IsHomestead(num *big.Int) bool {
 // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
 //
 // The returned GasTable's fields shouldn't, under any circumstances, be changed.
-func (c *ChainConfig) GasTable(num *big.Int) params.GasTable {
-	if c.HomesteadGasRepriceBlock == nil || num == nil || num.Cmp(c.HomesteadGasRepriceBlock) < 0 {
-		return params.GasTableHomestead
+func (c *ChainConfig) GasTable(num *big.Int) GasTable {
+	if num == nil {
+		return GasTableHomestead
+	}
+
+	switch {
+	case c.EIP158Block != nil && num.Cmp(c.EIP158Block) >= 0:
+		return GasTableEIP158
+	case c.EIP150Block != nil && num.Cmp(c.EIP150Block) >= 0:
+		return GasTableHomesteadGasRepriceFork
+	default:
+		return GasTableHomestead
+	}
+}
+
+func (c *ChainConfig) IsEIP150(num *big.Int) bool {
+	if c.EIP150Block == nil || num == nil {
+		return false
+	}
+	return num.Cmp(c.EIP150Block) >= 0
+
+}
+
+func (c *ChainConfig) IsEIP158(num *big.Int) bool {
+	if c.EIP158Block == nil || num == nil {
+		return false
 	}
+	return num.Cmp(c.EIP158Block) >= 0
 
-	return params.GasTableHomesteadGasRepriceFork
 }

+ 22 - 0
params/gas_table.go

@@ -26,6 +26,10 @@ type GasTable struct {
 	Calls       *big.Int
 	Suicide     *big.Int
 
+	Exp        *big.Int
+	ExpOneByte *big.Int
+	Exp256     *big.Int
+
 	// CreateBySuicide occurs when the
 	// refunded account is one that does
 	// not exist. This logic is similar
@@ -44,6 +48,7 @@ var (
 		SLoad:       big.NewInt(50),
 		Calls:       big.NewInt(40),
 		Suicide:     big.NewInt(0),
+		Exp:         big.NewInt(20),
 
 		// explicitly set to nil to indicate
 		// this rule does not apply to homestead.
@@ -52,6 +57,8 @@ var (
 
 	// GasTableHomestead contain the gas re-prices for
 	// the homestead phase.
+	//
+	// TODO rename to GasTableEIP150
 	GasTableHomesteadGasRepriceFork = GasTable{
 		ExtcodeSize: big.NewInt(700),
 		ExtcodeCopy: big.NewInt(700),
@@ -59,6 +66,21 @@ var (
 		SLoad:       big.NewInt(200),
 		Calls:       big.NewInt(700),
 		Suicide:     big.NewInt(5000),
+		Exp:         big.NewInt(20),
+
+		CreateBySuicide: big.NewInt(25000),
+	}
+
+	GasTableEIP158 = GasTable{
+		ExtcodeSize: big.NewInt(700),
+		ExtcodeCopy: big.NewInt(700),
+		Balance:     big.NewInt(400),
+		SLoad:       big.NewInt(200),
+		Calls:       big.NewInt(700),
+		Suicide:     big.NewInt(5000),
+		Exp:         big.NewInt(80),
+		ExpOneByte:  big.NewInt(160),
+		Exp256:      big.NewInt(2640),
 
 		CreateBySuicide: big.NewInt(25000),
 	}

+ 3 - 2
tests/block_test_util.go

@@ -35,6 +35,7 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rlp"
 )
 
@@ -170,7 +171,7 @@ func runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, test *Blo
 	core.WriteCanonicalHash(db, test.Genesis.Hash(), test.Genesis.NumberU64())
 	core.WriteHeadBlockHash(db, test.Genesis.Hash())
 	evmux := new(event.TypeMux)
-	config := &core.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, HomesteadGasRepriceBlock: gasPriceFork}
+	config := &params.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, EIP150Block: gasPriceFork}
 	chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux)
 	if err != nil {
 		return err
@@ -228,7 +229,7 @@ func (t *BlockTest) InsertPreState(db ethdb.Database) (*state.StateDB, error) {
 		}
 	}
 
-	root, err := statedb.Commit()
+	root, err := statedb.Commit(false)
 	if err != nil {
 		return nil, fmt.Errorf("error writing state: %v", err)
 	}

+ 177 - 148
tests/state_test.go

@@ -21,6 +21,8 @@ import (
 	"os"
 	"path/filepath"
 	"testing"
+
+	"github.com/ethereum/go-ethereum/params"
 )
 
 func BenchmarkStateCall1024(b *testing.B) {
@@ -31,172 +33,172 @@ func BenchmarkStateCall1024(b *testing.B) {
 }
 
 func TestStateSystemOperations(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stSystemOperationsTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateExample(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stExample.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStatePreCompiledContracts(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stPreCompiledContracts.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateRecursiveCreate(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stRecursiveCreate.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateSpecial(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stSpecialTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateRefund(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stRefundTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateBlockHash(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stBlockHashTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateInitCode(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stInitCodeTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateLog(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stLogTests.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateTransaction(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stTransactionTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateTransition(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stTransitionTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestCallCreateCallCode(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stCallCreateCallCodeTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestCallCodes(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stCallCodes.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestDelegateCall(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stDelegatecallTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestMemory(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stMemoryTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestMemoryStress(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
@@ -204,13 +206,13 @@ func TestMemoryStress(t *testing.T) {
 		t.Skip()
 	}
 	fn := filepath.Join(stateTestDir, "stMemoryStressTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestQuadraticComplexity(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
@@ -218,41 +220,41 @@ func TestQuadraticComplexity(t *testing.T) {
 		t.Skip()
 	}
 	fn := filepath.Join(stateTestDir, "stQuadraticComplexityTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestSolidity(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stSolidityTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestWallet(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fn := filepath.Join(stateTestDir, "stWalletTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestStateTestsRandom(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: big.NewInt(1150000),
 	}
 
 	fns, _ := filepath.Glob("./files/StateTests/RandomTests/*")
 	for _, fn := range fns {
-		if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+		if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 			t.Error(fn, err)
 		}
 	}
@@ -260,117 +262,117 @@ func TestStateTestsRandom(t *testing.T) {
 
 // homestead tests
 func TestHomesteadStateSystemOperations(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stSystemOperationsTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadStatePreCompiledContracts(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stPreCompiledContracts.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadStateRecursiveCreate(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stSpecialTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadStateRefund(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stRefundTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadStateInitCode(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stInitCodeTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadStateLog(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stLogTests.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadStateTransaction(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stTransactionTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadCallCreateCallCode(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stCallCreateCallCodeTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadCallCodes(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stCallCodes.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadMemory(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stMemoryTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadMemoryStress(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
@@ -378,13 +380,13 @@ func TestHomesteadMemoryStress(t *testing.T) {
 		t.Skip()
 	}
 	fn := filepath.Join(stateTestDir, "Homestead", "stMemoryStressTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadQuadraticComplexity(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
@@ -392,286 +394,313 @@ func TestHomesteadQuadraticComplexity(t *testing.T) {
 		t.Skip()
 	}
 	fn := filepath.Join(stateTestDir, "Homestead", "stQuadraticComplexityTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadWallet(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stWalletTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadDelegateCodes(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stCallDelegateCodes.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadDelegateCodesCallCode(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stCallDelegateCodesCallCode.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestHomesteadBounds(t *testing.T) {
-	ruleSet := RuleSet{
+	chainConfig := &params.ChainConfig{
 		HomesteadBlock: new(big.Int),
 	}
 
 	fn := filepath.Join(stateTestDir, "Homestead", "stBoundsTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 // EIP150 tests
 func TestEIP150Specific(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "stEIPSpecificTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150SingleCodeGasPrice(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "stEIPSingleCodeGasPrices.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150MemExpandingCalls(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "stMemExpandingEIPCalls.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadStateSystemOperations(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stSystemOperationsTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadStatePreCompiledContracts(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stPreCompiledContracts.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadStateRecursiveCreate(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stSpecialTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadStateRefund(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stRefundTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadStateInitCode(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stInitCodeTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadStateLog(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stLogTests.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadStateTransaction(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stTransactionTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadCallCreateCallCode(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallCreateCallCodeTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadCallCodes(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallCodes.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadMemory(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stMemoryTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadMemoryStress(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	if os.Getenv("TEST_VM_COMPLEX") == "" {
 		t.Skip()
 	}
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stMemoryStressTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadQuadraticComplexity(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	if os.Getenv("TEST_VM_COMPLEX") == "" {
 		t.Skip()
 	}
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stQuadraticComplexityTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadWallet(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stWalletTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadDelegateCodes(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallDelegateCodes.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadDelegateCodesCallCode(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stCallDelegateCodesCallCode.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }
 
 func TestEIP150HomesteadBounds(t *testing.T) {
-	ruleSet := RuleSet{
-		HomesteadBlock:           new(big.Int),
-		HomesteadGasRepriceBlock: big.NewInt(2457000),
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
 	}
 
 	fn := filepath.Join(stateTestDir, "EIP150", "Homestead", "stBoundsTest.json")
-	if err := RunStateTest(ruleSet, fn, StateSkipTests); err != nil {
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
+		t.Error(err)
+	}
+}
+
+// EIP158 tests
+func TestEIP158Create(t *testing.T) {
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
+		EIP158Block:    big.NewInt(3500000),
+	}
+
+	fn := filepath.Join(stateTestDir, "EIP158", "stCreateTest.json")
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
+		t.Error(err)
+	}
+}
+
+func TestEIP158Specific(t *testing.T) {
+	chainConfig := &params.ChainConfig{
+		HomesteadBlock: new(big.Int),
+		EIP150Block:    big.NewInt(2457000),
+		EIP158Block:    big.NewInt(3500000),
+	}
+
+	fn := filepath.Join(stateTestDir, "EIP158", "stEIP158SpecificTest.json")
+	if err := RunStateTest(chainConfig, fn, StateSkipTests); err != nil {
 		t.Error(err)
 	}
 }

+ 17 - 16
tests/state_test_util.go

@@ -33,28 +33,29 @@ import (
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
 )
 
-func RunStateTestWithReader(ruleSet RuleSet, r io.Reader, skipTests []string) error {
+func RunStateTestWithReader(chainConfig *params.ChainConfig, r io.Reader, skipTests []string) error {
 	tests := make(map[string]VmTest)
 	if err := readJson(r, &tests); err != nil {
 		return err
 	}
 
-	if err := runStateTests(ruleSet, tests, skipTests); err != nil {
+	if err := runStateTests(chainConfig, tests, skipTests); err != nil {
 		return err
 	}
 
 	return nil
 }
 
-func RunStateTest(ruleSet RuleSet, p string, skipTests []string) error {
+func RunStateTest(chainConfig *params.ChainConfig, p string, skipTests []string) error {
 	tests := make(map[string]VmTest)
 	if err := readJsonFile(p, &tests); err != nil {
 		return err
 	}
 
-	if err := runStateTests(ruleSet, tests, skipTests); err != nil {
+	if err := runStateTests(chainConfig, tests, skipTests); err != nil {
 		return err
 	}
 
@@ -62,7 +63,7 @@ func RunStateTest(ruleSet RuleSet, p string, skipTests []string) error {
 
 }
 
-func BenchStateTest(ruleSet RuleSet, p string, conf bconf, b *testing.B) error {
+func BenchStateTest(chainConfig *params.ChainConfig, p string, conf bconf, b *testing.B) error {
 	tests := make(map[string]VmTest)
 	if err := readJsonFile(p, &tests); err != nil {
 		return err
@@ -87,22 +88,22 @@ func BenchStateTest(ruleSet RuleSet, p string, conf bconf, b *testing.B) error {
 
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		benchStateTest(ruleSet, test, env, b)
+		benchStateTest(chainConfig, test, env, b)
 	}
 
 	return nil
 }
 
-func benchStateTest(ruleSet RuleSet, test VmTest, env map[string]string, b *testing.B) {
+func benchStateTest(chainConfig *params.ChainConfig, test VmTest, env map[string]string, b *testing.B) {
 	b.StopTimer()
 	db, _ := ethdb.NewMemDatabase()
 	statedb := makePreState(db, test.Pre)
 	b.StartTimer()
 
-	RunState(ruleSet, statedb, env, test.Exec)
+	RunState(chainConfig, statedb, env, test.Exec)
 }
 
-func runStateTests(ruleSet RuleSet, tests map[string]VmTest, skipTests []string) error {
+func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, skipTests []string) error {
 	skipTest := make(map[string]bool, len(skipTests))
 	for _, name := range skipTests {
 		skipTest[name] = true
@@ -115,7 +116,7 @@ func runStateTests(ruleSet RuleSet, tests map[string]VmTest, skipTests []string)
 		}
 
 		//fmt.Println("StateTest:", name)
-		if err := runStateTest(ruleSet, test); err != nil {
+		if err := runStateTest(chainConfig, test); err != nil {
 			return fmt.Errorf("%s: %s\n", name, err.Error())
 		}
 
@@ -126,7 +127,7 @@ func runStateTests(ruleSet RuleSet, tests map[string]VmTest, skipTests []string)
 
 }
 
-func runStateTest(ruleSet RuleSet, test VmTest) error {
+func runStateTest(chainConfig *params.ChainConfig, test VmTest) error {
 	db, _ := ethdb.NewMemDatabase()
 	statedb := makePreState(db, test.Pre)
 
@@ -150,7 +151,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
 		logs vm.Logs
 	)
 
-	ret, logs, _, _ = RunState(ruleSet, statedb, env, test.Transaction)
+	ret, logs, _, _ = RunState(chainConfig, statedb, env, test.Transaction)
 
 	// Compare expected and actual return
 	var rexp []byte
@@ -189,7 +190,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
 		}
 	}
 
-	root, _ := statedb.Commit()
+	root, _ := statedb.Commit(false)
 	if common.HexToHash(test.PostStateRoot) != root {
 		return fmt.Errorf("Post state root error. Expected: %s have: %x", test.PostStateRoot, root)
 	}
@@ -204,7 +205,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
 	return nil
 }
 
-func RunState(ruleSet RuleSet, statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Logs, *big.Int, error) {
+func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Logs, *big.Int, error) {
 	var (
 		data  = common.FromHex(tx["data"])
 		gas   = common.Big(tx["gasLimit"])
@@ -226,13 +227,13 @@ func RunState(ruleSet RuleSet, statedb *state.StateDB, env, tx map[string]string
 	key, _ := hex.DecodeString(tx["secretKey"])
 	addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
 	message := NewMessage(addr, to, data, value, gas, price, nonce)
-	vmenv := NewEnvFromMap(ruleSet, statedb, env, tx)
+	vmenv := NewEnvFromMap(chainConfig, statedb, env, tx)
 	vmenv.origin = addr
 	ret, _, err := core.ApplyMessage(vmenv, message, gaspool)
 	if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) {
 		statedb.RevertToSnapshot(snapshot)
 	}
-	statedb.Commit()
+	statedb.Commit(chainConfig.IsEIP158(vmenv.BlockNumber()))
 
 	return ret, vmenv.state.Logs(), vmenv.Gas, err
 }

+ 1 - 2
tests/transaction_test_util.go

@@ -24,7 +24,6 @@ import (
 	"runtime"
 
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/params"
@@ -164,7 +163,7 @@ func verifyTxFields(txTest TransactionTest, decodedTx *types.Transaction) (err e
 		decodedSender common.Address
 	)
 
-	chainConfig := &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock}
+	chainConfig := &params.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock}
 	if chainConfig.IsHomestead(common.String2Big(txTest.Blocknumber)) {
 		decodedSender, err = decodedTx.From()
 	} else {

+ 16 - 35
tests/util.go

@@ -148,27 +148,8 @@ type VmTest struct {
 	PostStateRoot string
 }
 
-type RuleSet struct {
-	HomesteadBlock           *big.Int
-	DAOForkBlock             *big.Int
-	DAOForkSupport           bool
-	HomesteadGasRepriceBlock *big.Int
-}
-
-func (r RuleSet) IsHomestead(n *big.Int) bool {
-	return n.Cmp(r.HomesteadBlock) >= 0
-}
-
-func (r RuleSet) GasTable(num *big.Int) params.GasTable {
-	if r.HomesteadGasRepriceBlock == nil || num == nil || num.Cmp(r.HomesteadGasRepriceBlock) < 0 {
-		return params.GasTableHomestead
-	}
-
-	return params.GasTableHomesteadGasRepriceFork
-}
-
 type Env struct {
-	ruleSet      RuleSet
+	chainConfig  *params.ChainConfig
 	depth        int
 	state        *state.StateDB
 	skipTransfer bool
@@ -189,16 +170,16 @@ type Env struct {
 	evm *vm.EVM
 }
 
-func NewEnv(ruleSet RuleSet, state *state.StateDB) *Env {
+func NewEnv(chainConfig *params.ChainConfig, state *state.StateDB) *Env {
 	env := &Env{
-		ruleSet: ruleSet,
-		state:   state,
+		chainConfig: chainConfig,
+		state:       state,
 	}
 	return env
 }
 
-func NewEnvFromMap(ruleSet RuleSet, state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env {
-	env := NewEnv(ruleSet, state)
+func NewEnvFromMap(chainConfig *params.ChainConfig, state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env {
+	env := NewEnv(chainConfig, state)
 
 	env.origin = common.HexToAddress(exeValues["caller"])
 	env.parent = common.HexToHash(envValues["previousHash"])
@@ -217,16 +198,16 @@ func NewEnvFromMap(ruleSet RuleSet, state *state.StateDB, envValues map[string]s
 	return env
 }
 
-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 }
-func (self *Env) Coinbase() common.Address { return self.coinbase }
-func (self *Env) Time() *big.Int           { return self.time }
-func (self *Env) Difficulty() *big.Int     { return self.difficulty }
-func (self *Env) Db() vm.Database          { return self.state }
-func (self *Env) GasLimit() *big.Int       { return self.gasLimit }
-func (self *Env) VmType() vm.Type          { return vm.StdVmTy }
+func (self *Env) ChainConfig() *params.ChainConfig { return self.chainConfig }
+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 }
+func (self *Env) Time() *big.Int                   { return self.time }
+func (self *Env) Difficulty() *big.Int             { return self.difficulty }
+func (self *Env) Db() vm.Database                  { return self.state }
+func (self *Env) GasLimit() *big.Int               { return self.gasLimit }
+func (self *Env) VmType() vm.Type                  { return vm.StdVmTy }
 func (self *Env) GetHash(n uint64) common.Hash {
 	return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String())))
 }

+ 1 - 1
tests/vm_test_util.go

@@ -225,7 +225,7 @@ func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs,
 
 	caller := state.GetOrNewStateObject(from)
 
-	vmenv := NewEnvFromMap(RuleSet{params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, true, nil}, state, env, exec)
+	vmenv := NewEnvFromMap(&params.ChainConfig{params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, true, nil, common.Hash{}, nil}, state, env, exec)
 	vmenv.vmTest = true
 	vmenv.skipTransfer = true
 	vmenv.initial = true