diff options
Diffstat (limited to 'core')
31 files changed, 295 insertions, 159 deletions
diff --git a/core/bench_test.go b/core/bench_test.go index 0ff847ed5..ac5b57bc8 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -168,7 +168,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. evmux := new(event.TypeMux) - chainman, _ := NewBlockChain(db, FakePow{}, evmux) + chainman, _ := NewBlockChain(db, &ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() diff --git a/core/block_validator.go b/core/block_validator.go index 4d710ae3f..747e61ccc 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -41,15 +41,17 @@ var ( // // BlockValidator implements Validator. type BlockValidator struct { - bc *BlockChain // Canonical block chain - Pow pow.PoW // Proof of work used for validating + config *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(blockchain *BlockChain, pow pow.PoW) *BlockValidator { +func NewBlockValidator(config *ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator { validator := &BlockValidator{ - Pow: pow, - bc: blockchain, + config: config, + Pow: pow, + bc: blockchain, } return validator } @@ -80,7 +82,7 @@ func (v *BlockValidator) ValidateBlock(block *types.Block) error { header := block.Header() // validate the block header - if err := ValidateHeader(v.Pow, header, parent.Header(), false, false); err != nil { + if err := ValidateHeader(v.config, v.Pow, header, parent.Header(), false, false); err != nil { return err } // verify the uncles are correctly rewarded @@ -175,7 +177,7 @@ func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error { return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4]) } - if err := ValidateHeader(v.Pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil { + if err := ValidateHeader(v.config, v.Pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil { return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err)) } } @@ -195,13 +197,13 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b if v.bc.HasHeader(header.Hash()) { return nil } - return ValidateHeader(v.Pow, header, parent, checkPow, false) + return ValidateHeader(v.config, v.Pow, header, parent, checkPow, false) } // Validates a header. Returns an error if the header is invalid. // // See YP section 4.3.4. "Block Header Validity" -func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error { +func ValidateHeader(config *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)) } @@ -219,7 +221,7 @@ func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, che return BlockEqualTSErr } - expd := CalcDifficulty(header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty) + expd := CalcDifficulty(config, header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty) if expd.Cmp(header.Difficulty) != 0 { return fmt.Errorf("Difficulty check failed for header %v, %v", header.Difficulty, expd) } @@ -251,8 +253,8 @@ func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, che // 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(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { - if params.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) { +func CalcDifficulty(config *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 { return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff) @@ -363,11 +365,11 @@ func CalcGasLimit(parent *types.Block) *big.Int { gl = gl.Add(gl, contrib) gl.Set(common.BigMax(gl, params.MinGasLimit)) - // however, if we're now below the target (GenesisGasLimit) we increase the + // however, if we're now below the target (TargetGasLimit) we increase the // limit as much as we can (parentGasLimit / 1024 -1) - if gl.Cmp(params.GenesisGasLimit) < 0 { + if gl.Cmp(params.TargetGasLimit) < 0 { gl.Add(parent.GasLimit(), decay) - gl.Set(common.BigMin(gl, params.GenesisGasLimit)) + gl.Set(common.BigMin(gl, params.TargetGasLimit)) } return gl } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 2c4a97b45..aa29717b1 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -27,15 +27,20 @@ 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: params.MainNetHomesteadBlock} +} + func proc() (Validator, *BlockChain) { db, _ := ethdb.NewMemDatabase() var mux event.TypeMux WriteTestNetGenesisBlock(db) - blockchain, err := NewBlockChain(db, thePow(), &mux) + blockchain, err := NewBlockChain(db, testChainConfig(), thePow(), &mux) if err != nil { fmt.Println(err) } @@ -49,13 +54,14 @@ func TestNumber(t *testing.T) { statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb) header := makeHeader(chain.Genesis(), statedb) header.Number = big.NewInt(3) - err := ValidateHeader(pow, header, chain.Genesis().Header(), false, false) + cfg := testChainConfig() + 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) - err = ValidateHeader(pow, header, chain.Genesis().Header(), false, false) + err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false) if err == BlockNumberErr { t.Errorf("didn't expect block number error") } diff --git a/core/blockchain.go b/core/blockchain.go index 2c3c2bb5c..177a3bbce 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -80,11 +80,12 @@ const ( // included in the canonical one where as GetBlockByNumber always represents the // canonical chain. type BlockChain struct { + config *ChainConfig // chain & network configuration + hc *HeaderChain chainDb ethdb.Database eventMux *event.TypeMux genesisBlock *types.Block - vmConfig *vm.Config mu sync.RWMutex // global mutex for locking chain operations chainmu sync.RWMutex // blockchain insertion lock @@ -113,13 +114,14 @@ 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, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) { +func NewBlockChain(chainDb ethdb.Database, config *ChainConfig, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) { bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) blockCache, _ := lru.New(blockCacheLimit) futureBlocks, _ := lru.New(maxFutureBlocks) bc := &BlockChain{ + config: config, chainDb: chainDb, eventMux: mux, quit: make(chan struct{}), @@ -129,24 +131,21 @@ func NewBlockChain(chainDb ethdb.Database, pow pow.PoW, mux *event.TypeMux) (*Bl futureBlocks: futureBlocks, pow: pow, } - bc.SetValidator(NewBlockValidator(bc, pow)) - bc.SetProcessor(NewStateProcessor(bc)) + bc.SetValidator(NewBlockValidator(config, bc, pow)) + bc.SetProcessor(NewStateProcessor(config, bc)) gv := func() HeaderValidator { return bc.Validator() } var err error - bc.hc, err = NewHeaderChain(chainDb, gv, bc.getProcInterrupt) + bc.hc, err = NewHeaderChain(chainDb, config, gv, bc.getProcInterrupt) if err != nil { return nil, err } bc.genesisBlock = bc.GetBlockByNumber(0) if bc.genesisBlock == nil { - bc.genesisBlock, err = WriteDefaultGenesisBlock(chainDb) - if err != nil { - return nil, err - } - glog.V(logger.Info).Infoln("WARNING: Wrote default ethereum genesis block") + return nil, ErrNoGenesis } + if err := bc.loadLastState(); err != nil { return nil, err } @@ -163,10 +162,6 @@ func NewBlockChain(chainDb ethdb.Database, pow pow.PoW, mux *event.TypeMux) (*Bl return bc, nil } -func (self *BlockChain) SetConfig(vmConfig *vm.Config) { - self.vmConfig = vmConfig -} - func (self *BlockChain) getProcInterrupt() bool { return atomic.LoadInt32(&self.procInterrupt) == 1 } @@ -896,7 +891,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, statedb, self.vmConfig) + receipts, logs, usedGas, err := self.processor.Process(block, statedb, self.config.VmConfig) if err != nil { reportBlock(block, err) return i, err diff --git a/core/blockchain_test.go b/core/blockchain_test.go index d7cd24fa8..9e59b2ff6 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -53,7 +53,7 @@ func thePow() pow.PoW { func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain { var eventMux event.TypeMux WriteTestNetGenesisBlock(db) - blockchain, err := NewBlockChain(db, thePow(), &eventMux) + blockchain, err := NewBlockChain(db, testChainConfig(), thePow(), &eventMux) if err != nil { t.Error("failed creating blockchain:", err) t.FailNow() @@ -141,7 +141,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } - receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, nil) + receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, vm.Config{}) if err != nil { reportBlock(block, err) return err @@ -435,7 +435,7 @@ func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return n func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error { return nil } -func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg *vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { +func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { return nil, nil, nil, nil } @@ -473,13 +473,14 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B func chm(genesis *types.Block, db ethdb.Database) *BlockChain { var eventMux event.TypeMux bc := &BlockChain{ - chainDb: db, + chainDb: db, genesisBlock: genesis, - eventMux: &eventMux, - pow: FakePow{}, + eventMux: &eventMux, + pow: FakePow{}, + config: testChainConfig(), } valFn := func() HeaderValidator { return bc.Validator() } - bc.hc, _ = NewHeaderChain(db, valFn, bc.getProcInterrupt) + bc.hc, _ = NewHeaderChain(db, testChainConfig(), valFn, bc.getProcInterrupt) bc.bodyCache, _ = lru.New(100) bc.bodyRLPCache, _ = lru.New(100) bc.blockCache, _ = lru.New(100) @@ -613,7 +614,7 @@ func testReorgBadHashes(t *testing.T, full bool) { defer func() { delete(BadHashes, headers[3].Hash()) }() } // Create a new chain manager and check it rolled back the state - ncm, err := NewBlockChain(db, FakePow{}, new(event.TypeMux)) + ncm, err := NewBlockChain(db, testChainConfig(), FakePow{}, new(event.TypeMux)) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -667,7 +668,7 @@ func testInsertNonceError(t *testing.T, full bool) { failHash = headers[failAt].Hash() blockchain.pow = failPow{failNum} - blockchain.validator = NewBlockValidator(blockchain, failPow{failNum}) + blockchain.validator = NewBlockValidator(testChainConfig(), blockchain, failPow{failNum}) failRes, err = blockchain.InsertHeaderChain(headers, 1) } @@ -733,7 +734,7 @@ func TestFastVsFullChains(t *testing.T) { archiveDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds}) - archive, _ := NewBlockChain(archiveDb, FakePow{}, new(event.TypeMux)) + archive, _ := NewBlockChain(archiveDb, testChainConfig(), FakePow{}, new(event.TypeMux)) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) @@ -741,7 +742,7 @@ func TestFastVsFullChains(t *testing.T) { // Fast import the chain as a non-archive node to test fastDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds}) - fast, _ := NewBlockChain(fastDb, FakePow{}, new(event.TypeMux)) + fast, _ := NewBlockChain(fastDb, testChainConfig(), FakePow{}, new(event.TypeMux)) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -817,7 +818,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds}) - archive, _ := NewBlockChain(archiveDb, FakePow{}, new(event.TypeMux)) + archive, _ := NewBlockChain(archiveDb, testChainConfig(), FakePow{}, new(event.TypeMux)) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) @@ -829,7 +830,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds}) - fast, _ := NewBlockChain(fastDb, FakePow{}, new(event.TypeMux)) + fast, _ := NewBlockChain(fastDb, testChainConfig(), FakePow{}, new(event.TypeMux)) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -848,7 +849,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a light node and ensure all pointers are updated lightDb, _ := ethdb.NewMemDatabase() WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds}) - light, _ := NewBlockChain(lightDb, FakePow{}, new(event.TypeMux)) + light, _ := NewBlockChain(lightDb, testChainConfig(), FakePow{}, new(event.TypeMux)) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) @@ -913,7 +914,7 @@ func TestChainTxReorgs(t *testing.T) { }) // Import the chain. This runs all block validation rules. evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, FakePow{}, evmux) + blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -986,7 +987,7 @@ func TestLogReorgs(t *testing.T) { ) evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, FakePow{}, evmux) + blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) subs := evmux.Subscribe(RemovedLogsEvent{}) chain, _ := GenerateChain(genesis, db, 2, func(i int, gen *BlockGen) { @@ -1022,7 +1023,7 @@ func TestReorgSideEvent(t *testing.T) { ) evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, FakePow{}, evmux) + blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux) chain, _ := GenerateChain(genesis, db, 3, func(i int, gen *BlockGen) { if i == 2 { diff --git a/core/chain_makers.go b/core/chain_makers.go index 7ae3c98b0..c740f9c37 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -23,11 +23,30 @@ import ( "github.com/ethereum/go-ethereum/common" "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/event" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/pow" ) +/* + * TODO: move this to another package. + */ + +// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings. +func MakeChainConfig(testnet bool) *ChainConfig { + homesteadBlock := params.MainNetHomesteadBlock + // set a different default homestead block for the testnet + if testnet { + homesteadBlock = params.TestNetHomesteadBlock + } + + return &ChainConfig{ + HomesteadBlock: homesteadBlock, + } +} + // FakePow is a non-validating proof of work implementation. // It returns true from Verify for any block. type FakePow struct{} @@ -91,7 +110,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(nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, nil) + receipt, _, _, err := ApplyTransaction(MakeChainConfig(true), nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{}) if err != nil { panic(err) } @@ -148,7 +167,7 @@ func (b *BlockGen) OffsetTime(seconds int64) { if b.header.Time.Cmp(b.parent.Header().Time) <= 0 { panic("block time out of range") } - b.header.Difficulty = CalcDifficulty(b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty()) + b.header.Difficulty = CalcDifficulty(MakeChainConfig(true), b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty()) } // GenerateChain creates a chain of n blocks. The first block's @@ -203,7 +222,7 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header { Root: state.IntermediateRoot(), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), - Difficulty: CalcDifficulty(time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()), + Difficulty: CalcDifficulty(MakeChainConfig(true), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()), GasLimit: CalcGasLimit(parent), GasUsed: new(big.Int), Number: new(big.Int).Add(parent.Number(), common.Big1), @@ -222,7 +241,7 @@ func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) { // Initialize a fresh chain with only a genesis block genesis, _ := WriteTestNetGenesisBlock(db) - blockchain, _ := NewBlockChain(db, FakePow{}, evmux) + blockchain, _ := NewBlockChain(db, MakeChainConfig(false), FakePow{}, evmux) // Create and inject the requested chain if n == 0 { return db, blockchain, nil diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index b9c1d89b7..86949246b 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -77,7 +77,7 @@ func ExampleGenerateChain() { // Import the chain. This runs all block validation rules. evmux := &event.TypeMux{} - blockchain, _ := NewBlockChain(db, FakePow{}, evmux) + blockchain, _ := NewBlockChain(db, MakeChainConfig(true), FakePow{}, evmux) if i, err := blockchain.InsertChain(chain); err != nil { fmt.Printf("insert error (block %d): %v\n", i, err) return diff --git a/core/config.go b/core/config.go new file mode 100644 index 000000000..81ca76aa3 --- /dev/null +++ b/core/config.go @@ -0,0 +1,46 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// 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 + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/core/vm" +) + +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 +// that any network, identified by its genesis block, can have its own +// set of configuration options. +type ChainConfig struct { + HomesteadBlock *big.Int // homestead switch block + + VmConfig vm.Config `json:"-"` +} + +// IsHomestead returns whether num is either equal to the homestead block or greater. +func (c *ChainConfig) IsHomestead(num *big.Int) bool { + if num == nil { + return false + } + + return num.Cmp(c.HomesteadBlock) >= 0 +} diff --git a/core/database_util.go b/core/database_util.go index fd2b4c312..e1e8136d1 100644 --- a/core/database_util.go +++ b/core/database_util.go @@ -19,6 +19,7 @@ package core import ( "bytes" "encoding/binary" + "encoding/json" "fmt" "math/big" @@ -50,6 +51,8 @@ var ( MIPMapLevels = []uint64{1000000, 500000, 100000, 50000, 1000} blockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually] + + configPrefix = []byte("ethereum-config-") // config prefix for the db ) // GetCanonicalHash retrieves a hash assigned to a canonical block number. @@ -527,3 +530,34 @@ func WriteBlockChainVersion(db ethdb.Database, vsn int) { enc, _ := rlp.EncodeToBytes(uint(vsn)) db.Put([]byte("BlockchainVersion"), enc) } + +// WriteChainConfig writes the chain config settings to the database. +func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *ChainConfig) error { + // short circuit and ignore if nil config. GetChainConfig + // will return a default. + if cfg == nil { + return nil + } + + jsonChainConfig, err := json.Marshal(cfg) + if err != nil { + return err + } + + return db.Put(append(configPrefix, hash[:]...), jsonChainConfig) +} + +// GetChainConfig will fetch the network settings based on the given hash. +func GetChainConfig(db ethdb.Database, hash common.Hash) (*ChainConfig, error) { + jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...)) + if len(jsonChainConfig) == 0 { + return nil, ChainConfigNotFoundErr + } + + var config ChainConfig + if err := json.Unmarshal(jsonChainConfig, &config); err != nil { + return nil, err + } + + return &config, nil +} diff --git a/core/execution.go b/core/execution.go index d90dceafc..82143443c 100644 --- a/core/execution.go +++ b/core/execution.go @@ -126,7 +126,7 @@ 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 && (params.IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError) { + if err != nil && (env.RuleSet().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError) { contract.UseGas(contract.Gas) env.SetSnapshot(snapshotPreTransfer) diff --git a/core/genesis.go b/core/genesis.go index d8c6e9cea..5c69b216c 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -43,15 +43,16 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, } var genesis struct { - Nonce string - Timestamp string - ParentHash string - ExtraData string - GasLimit string - Difficulty string - Mixhash string - Coinbase string - Alloc map[string]struct { + ChainConfig *ChainConfig + Nonce string + Timestamp string + ParentHash string + ExtraData string + GasLimit string + Difficulty string + Mixhash string + Coinbase string + Alloc map[string]struct { Code string Storage map[string]string Balance string @@ -114,6 +115,10 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil { return nil, err } + if err := WriteChainConfig(chainDb, block.Hash(), genesis.ChainConfig); err != nil { + return nil, err + } + return block, nil } diff --git a/core/headerchain.go b/core/headerchain.go index 255139dde..21fc6e80a 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -40,6 +40,8 @@ import ( // It is not thread safe either, the encapsulating chain structures should do // the necessary mutex locking/unlocking. type HeaderChain struct { + config *ChainConfig + chainDb ethdb.Database genesisHeader *types.Header @@ -62,7 +64,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, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) { +func NewHeaderChain(chainDb ethdb.Database, config *ChainConfig, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) { headerCache, _ := lru.New(headerCacheLimit) tdCache, _ := lru.New(tdCacheLimit) @@ -73,6 +75,7 @@ func NewHeaderChain(chainDb ethdb.Database, getValidator getHeaderValidatorFn, p } hc := &HeaderChain{ + config: config, chainDb: chainDb, headerCache: headerCache, tdCache: tdCache, @@ -436,15 +439,17 @@ func (hc *HeaderChain) SetGenesis(head *types.Header) { // // headerValidator implements HeaderValidator. type headerValidator struct { - hc *HeaderChain // Canonical header chain - Pow pow.PoW // Proof of work used for validating + config *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(chain *HeaderChain, pow pow.PoW) HeaderValidator { +func NewHeaderValidator(config *ChainConfig, chain *HeaderChain, pow pow.PoW) HeaderValidator { return &headerValidator{ - Pow: pow, - hc: chain, + config: config, + Pow: pow, + hc: chain, } } @@ -460,5 +465,5 @@ func (v *headerValidator) ValidateHeader(header, parent *types.Header, checkPow if v.hc.HasHeader(header.Hash()) { return nil } - return ValidateHeader(v.Pow, header, parent, checkPow, false) + return ValidateHeader(v.config, v.Pow, header, parent, checkPow, false) } diff --git a/core/state_processor.go b/core/state_processor.go index 38cd0e675..441f6a7a8 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -16,12 +16,21 @@ var ( big32 = big.NewInt(32) ) +// StateProcessor is a basic Processor, which takes care of transitioning +// state from one point to another. +// +// StateProcessor implements Processor. type StateProcessor struct { - bc *BlockChain + config *ChainConfig + bc *BlockChain } -func NewStateProcessor(bc *BlockChain) *StateProcessor { - return &StateProcessor{bc} +// NewStateProcessor initialises a new StateProcessor. +func NewStateProcessor(config *ChainConfig, bc *BlockChain) *StateProcessor { + return &StateProcessor{ + config: config, + bc: bc, + } } // Process processes the state changes according to the Ethereum rules by running @@ -31,7 +40,7 @@ func NewStateProcessor(bc *BlockChain) *StateProcessor { // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg *vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { var ( receipts types.Receipts totalUsedGas = big.NewInt(0) @@ -43,7 +52,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for i, tx := range block.Transactions() { statedb.StartRecord(tx.Hash(), block.Hash(), i) - receipt, logs, _, err := ApplyTransaction(p.bc, gp, statedb, header, tx, totalUsedGas, cfg) + receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) if err != nil { return nil, nil, totalUsedGas, err } @@ -60,8 +69,8 @@ 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(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, bc, tx, header, cfg), tx, gp) +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) { + _, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp) if err != nil { return nil, nil, nil, err } diff --git a/core/state_transition.go b/core/state_transition.go index cc357aaca..60ac7d8cb 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -124,7 +124,7 @@ func (self *StateTransition) from() (vm.Account, error) { f common.Address err error ) - if params.IsHomestead(self.env.BlockNumber()) { + if self.env.RuleSet().IsHomestead(self.env.BlockNumber()) { f, err = self.msg.From() } else { f, err = self.msg.FromFrontier() @@ -216,7 +216,7 @@ func (self *StateTransition) transitionDb() (ret []byte, usedGas *big.Int, err e msg := self.msg sender, _ := self.from() // err checked in preCheck - homestead := params.IsHomestead(self.env.BlockNumber()) + homestead := self.env.RuleSet().IsHomestead(self.env.BlockNumber()) contractCreation := MessageCreatesContract(msg) // Pay intrinsic gas if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil { diff --git a/core/tx_pool.go b/core/tx_pool.go index f4e964bf7..e997e8cd0 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -30,7 +30,6 @@ 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" ) var ( @@ -60,6 +59,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 quit chan bool // Quitting channel currentState stateFn // The state function which will allow us to do some pre checks pendingState *state.ManagedState @@ -75,8 +75,9 @@ type TxPool struct { homestead bool } -func NewTxPool(eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool { +func NewTxPool(config *ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool { pool := &TxPool{ + config: config, pending: make(map[common.Hash]*types.Transaction), queue: make(map[common.Address]map[common.Hash]*types.Transaction), quit: make(chan bool), @@ -102,7 +103,7 @@ func (pool *TxPool) eventLoop() { switch ev := ev.Data.(type) { case ChainHeadEvent: pool.mu.Lock() - if ev.Block != nil && params.IsHomestead(ev.Block.Number()) { + if ev.Block != nil && pool.config.IsHomestead(ev.Block.Number()) { pool.homestead = true } diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index fa1a740dc..ed9bea75f 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -40,7 +40,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { var m event.TypeMux key, _ := crypto.GenerateKey() - newPool := NewTxPool(&m, func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + newPool := NewTxPool(testChainConfig(), &m, func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) newPool.resetState() return newPool, key } diff --git a/core/types.go b/core/types.go index af9bc567b..e2b31643a 100644 --- a/core/types.go +++ b/core/types.go @@ -61,7 +61,7 @@ type HeaderValidator interface { // of gas used in the process and return an error if any of the internal rules // failed. type Processor interface { - Process(block *types.Block, statedb *state.StateDB, cfg *vm.Config) (types.Receipts, vm.Logs, *big.Int, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) } // Backend is an interface defining the basic functionality for an operable node diff --git a/core/vm/environment.go b/core/vm/environment.go index 568218edd..747627565 100644 --- a/core/vm/environment.go +++ b/core/vm/environment.go @@ -22,9 +22,17 @@ import ( "github.com/ethereum/go-ethereum/common" ) +// RuleSet is an interface that defines the current rule set during the +// execution of the EVM instructions (e.g. whether it's homestead) +type RuleSet interface { + IsHomestead(*big.Int) bool +} + // Environment is an EVM requirement and helper which allows access to outside // information such as states. type Environment interface { + // The current ruleset + RuleSet() RuleSet // The state database Db() Database // Creates a restorable snapshot @@ -53,10 +61,10 @@ type Environment interface { AddLog(*Log) // Type of the VM Vm() Vm - // Current calling depth + // Get the curret calling depth Depth() int + // Set the current calling depth SetDepth(i int) - // Call another contract Call(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) // Take another's contract code and execute within our own context diff --git a/core/vm/instructions.go b/core/vm/instructions.go index c4b4339a2..942fafde7 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -520,7 +520,7 @@ func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if params.IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError { + if env.RuleSet().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError { stack.push(new(big.Int)) } else if suberr != nil && suberr != CodeStoreOutOfGasError { stack.push(new(big.Int)) diff --git a/core/vm/jit.go b/core/vm/jit.go index 71ffcf0f6..ac2083f54 100644 --- a/core/vm/jit.go +++ b/core/vm/jit.go @@ -30,27 +30,24 @@ import ( "github.com/hashicorp/golang-lru" ) +// progStatus is the type for the JIT program status. type progStatus int32 const ( - progUnknown progStatus = iota - progCompile - progReady - progError + progUnknown progStatus = iota // unknown status + progCompile // compile status + progReady // ready for use status + progError // error status (usually caused during compilation) - defaultJitMaxCache int = 64 + defaultJitMaxCache int = 64 // maximum amount of jit cached programs ) -var ( - EnableJit bool // Enables the JIT VM - ForceJit bool // Force the JIT, skip byte VM - MaxProgSize int // Max cache size for JIT Programs -) +var MaxProgSize int // Max cache size for JIT programs -var programs *lru.Cache +var programs *lru.Cache // lru cache for the JIT programs. func init() { - programs, _ = lru.New(defaultJitMaxCache) + SetJITCacheSize(defaultJitMaxCache) } // SetJITCacheSize recreates the program cache with the max given size. Setting @@ -322,7 +319,7 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env }() } - homestead := params.IsHomestead(env.BlockNumber()) + homestead := env.RuleSet().IsHomestead(env.BlockNumber()) for pc < uint64(len(program.instructions)) { instrCount++ diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go index 43b1dee2a..c503a3a81 100644 --- a/core/vm/jit_test.go +++ b/core/vm/jit_test.go @@ -84,7 +84,7 @@ func TestCompiling(t *testing.T) { func TestResetInput(t *testing.T) { var sender account - env := NewEnv() + env := NewEnv(false, true) contract := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0)) contract.CodeAddr = &common.Address{} @@ -143,10 +143,7 @@ func runVmBench(test vmBench, b *testing.B) { if test.precompile && !test.forcejit { NewProgram(test.code) } - env := NewEnv() - - EnableJit = !test.nojit - ForceJit = test.forcejit + env := NewEnv(test.nojit, test.forcejit) b.ResetTimer() @@ -168,12 +165,16 @@ type Env struct { evm *EVM } -func NewEnv() *Env { +func NewEnv(noJit, forceJit bool) *Env { env := &Env{gasLimit: big.NewInt(10000), depth: 0} - env.evm = New(env, nil) + env.evm = New(env, Config{ + EnableJit: !noJit, + ForceJit: forceJit, + }) return env } +func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} } func (self *Env) Vm() Vm { return self.evm } func (self *Env) Origin() common.Address { return common.Address{} } func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 8297d3e1d..2c3796679 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -1,10 +1,6 @@ package vm -import ( - "math/big" - - "github.com/ethereum/go-ethereum/params" -) +import "math/big" type jumpPtr struct { fn instrFn @@ -13,12 +9,12 @@ type jumpPtr struct { type vmJumpTable [256]jumpPtr -func newJumpTable(blockNumber *big.Int) vmJumpTable { +func newJumpTable(ruleset RuleSet, blockNumber *big.Int) vmJumpTable { var jumpTable vmJumpTable // when initialising a new VM execution we must first check the homestead // changes. - if params.IsHomestead(blockNumber) { + if ruleset.IsHomestead(blockNumber) { jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true} } diff --git a/core/vm/jump_table_test.go b/core/vm/jump_table_test.go index 2ed1b26fc..2386a7525 100644 --- a/core/vm/jump_table_test.go +++ b/core/vm/jump_table_test.go @@ -3,20 +3,16 @@ package vm import ( "math/big" "testing" - - "github.com/ethereum/go-ethereum/params" ) func TestInit(t *testing.T) { - params.HomesteadBlock = big.NewInt(1) - - jumpTable := newJumpTable(big.NewInt(0)) + jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(0)) if jumpTable[DELEGATECALL].valid { t.Error("Expected DELEGATECALL not to be present") } for _, n := range []int64{1, 2, 100} { - jumpTable := newJumpTable(big.NewInt(n)) + jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(n)) if !jumpTable[DELEGATECALL].valid { t.Error("Expected DELEGATECALL to be present for block", n) } diff --git a/core/vm/logger.go b/core/vm/logger.go index 8d333dfd2..cbdc8a744 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -89,7 +89,7 @@ func newLogger(cfg LogConfig, env Environment) *Logger { // captureState logs a new structured log message and pushes it out to the environment // // captureState also tracks SSTORE ops to track dirty values. -func (l *Logger) captureState(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *stack, contract *Contract, err error) { +func (l *Logger) captureState(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *stack, contract *Contract, depth int, err error) { // short circuit if no log collector is present if l.cfg.Collector == nil { return diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index 77fee2c64..144569865 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -47,7 +47,7 @@ type dummyEnv struct { func newDummyEnv(ref *dummyContractRef) *dummyEnv { return &dummyEnv{ - Env: NewEnv(), + Env: NewEnv(true, false), ref: ref, } } @@ -58,7 +58,7 @@ func (d dummyEnv) AddStructLog(StructLog) {} func TestStoreCapture(t *testing.T) { var ( - env = NewEnv() + env = NewEnv(true, false) logger = newLogger(LogConfig{Collector: env}, env) mem = NewMemory() stack = newstack() @@ -69,7 +69,7 @@ func TestStoreCapture(t *testing.T) { var index common.Hash - logger.captureState(0, SSTORE, new(big.Int), new(big.Int), mem, stack, contract, nil) + logger.captureState(0, SSTORE, new(big.Int), new(big.Int), mem, stack, contract, 0, nil) if len(logger.changedValues[contract.Address()]) == 0 { t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()])) } @@ -91,13 +91,13 @@ func TestStorageCapture(t *testing.T) { stack = newstack() ) - logger.captureState(0, STOP, new(big.Int), new(big.Int), mem, stack, contract, nil) + logger.captureState(0, STOP, new(big.Int), new(big.Int), mem, stack, contract, 0, nil) if ref.calledForEach { t.Error("didn't expect for each to be called") } logger = newLogger(LogConfig{Collector: env, FullStorage: true}, env) - logger.captureState(0, STOP, new(big.Int), new(big.Int), mem, stack, contract, nil) + logger.captureState(0, STOP, new(big.Int), new(big.Int), mem, stack, contract, 0, nil) if !ref.calledForEach { t.Error("expected for each to be called") } diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index ce64d7117..1e943940b 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -27,8 +27,9 @@ import ( // Env is a basic runtime environment required for running the EVM. type Env struct { - depth int - state *state.StateDB + ruleSet vm.RuleSet + depth int + state *state.StateDB origin common.Address coinbase common.Address @@ -48,6 +49,7 @@ type Env struct { // NewEnv returns a new vm.Environment func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { env := &Env{ + ruleSet: cfg.RuleSet, state: state, origin: cfg.Origin, coinbase: cfg.Coinbase, @@ -56,7 +58,7 @@ func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { difficulty: cfg.Difficulty, gasLimit: cfg.GasLimit, } - env.evm = vm.New(env, &vm.Config{ + env.evm = vm.New(env, vm.Config{ Debug: cfg.Debug, EnableJit: !cfg.DisableJit, ForceJit: !cfg.DisableJit, @@ -77,6 +79,7 @@ func (self *Env) AddStructLog(log vm.StructLog) { self.logs = append(self.logs, log) } +func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet } func (self *Env) Vm() vm.Vm { return self.evm } func (self *Env) Origin() common.Address { return self.origin } func (self *Env) BlockNumber() *big.Int { return self.number } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index f88a20170..553864a83 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -22,13 +22,20 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" ) +// The default, always homestead, rule set for the vm env +type ruleSet struct{} + +func (ruleSet) IsHomestead(*big.Int) bool { return true } + // Config is a basic type specifying certain configuration flags for running // the EVM. type Config struct { + RuleSet vm.RuleSet Difficulty *big.Int Origin common.Address Coinbase common.Address @@ -46,6 +53,10 @@ type Config struct { // sets defaults on the config func setDefaults(cfg *Config) { + if cfg.RuleSet == nil { + cfg.RuleSet = ruleSet{} + } + if cfg.Difficulty == nil { cfg.Difficulty = new(big.Int) } diff --git a/core/vm/util_test.go b/core/vm/util_test.go new file mode 100644 index 000000000..3da742bfa --- /dev/null +++ b/core/vm/util_test.go @@ -0,0 +1,9 @@ +package vm + +import "math/big" + +type ruleSet struct { + hs *big.Int +} + +func (r ruleSet) IsHomestead(n *big.Int) bool { return n.Cmp(r.hs) >= 0 } diff --git a/core/vm/vm.go b/core/vm/vm.go index f72c853a2..0f93715d6 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -43,18 +43,13 @@ type Config struct { type EVM struct { env Environment jumpTable vmJumpTable - cfg *Config + cfg Config logger *Logger } // New returns a new instance of the EVM. -func New(env Environment, cfg *Config) *EVM { - // initialise a default config if none is present - if cfg == nil { - cfg = new(Config) - } - +func New(env Environment, cfg Config) *EVM { var logger *Logger if cfg.Debug { logger = newLogger(cfg.Logger, env) @@ -62,7 +57,7 @@ func New(env Environment, cfg *Config) *EVM { return &EVM{ env: env, - jumpTable: newJumpTable(env.BlockNumber()), + jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()), cfg: cfg, logger: logger, } @@ -154,7 +149,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return. defer func() { if err != nil && evm.cfg.Debug { - evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, err) + evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), err) } }() @@ -196,7 +191,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { mem.Resize(newMemSize.Uint64()) // Add a log message if evm.cfg.Debug { - evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, nil) + evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), nil) } if opPtr := evm.jumpTable[op]; opPtr.valid { diff --git a/core/vm/vm_jit_fake.go b/core/vm/vm_jit_fake.go index b26cf1ad0..4fa98ccd9 100644 --- a/core/vm/vm_jit_fake.go +++ b/core/vm/vm_jit_fake.go @@ -22,5 +22,5 @@ import "fmt" func NewJitVm(env Environment) VirtualMachine { fmt.Printf("Warning! EVM JIT not enabled.\n") - return New(env, nil) + return New(env, Config{}) } diff --git a/core/vm_env.go b/core/vm_env.go index 880baa7b0..f50140c68 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -41,30 +41,26 @@ func GetHashFn(ref common.Hash, chain *BlockChain) func(n uint64) common.Hash { } type VMEnv struct { - 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 *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 logs []vm.StructLog // Logs for the custom structured logger getHashFn func(uint64) common.Hash // getHashFn callback is used to retrieve block hashes - } -func NewEnv(state *state.StateDB, chain *BlockChain, msg Message, header *types.Header, cfg *vm.Config) *VMEnv { +func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv { env := &VMEnv{ - chain: chain, - state: state, - header: header, - msg: msg, - getHashFn: GetHashFn(header.ParentHash, chain), - } - - // initialise a default config if none present - if cfg == nil { - cfg = new(vm.Config) + chainConfig: chainConfig, + chain: chain, + state: state, + header: header, + msg: msg, + getHashFn: GetHashFn(header.ParentHash, chain), } // if no log collector is present set self as the collector @@ -76,6 +72,7 @@ func NewEnv(state *state.StateDB, chain *BlockChain, msg Message, header *types. 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 } |