diff options
Diffstat (limited to 'core/chain_makers.go')
-rw-r--r-- | core/chain_makers.go | 76 |
1 files changed, 44 insertions, 32 deletions
diff --git a/core/chain_makers.go b/core/chain_makers.go index 59af633df..0e5e3791e 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -21,7 +21,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -39,11 +39,12 @@ var ( // BlockGen creates blocks for testing. // See GenerateChain for a detailed explanation. type BlockGen struct { - i int - parent *types.Block - chain []*types.Block - header *types.Header - statedb *state.StateDB + i int + parent *types.Block + chain []*types.Block + chainReader consensus.ChainReader + header *types.Header + statedb *state.StateDB gasPool *GasPool txs []*types.Transaction @@ -51,6 +52,7 @@ type BlockGen struct { uncles []*types.Header config *params.ChainConfig + engine consensus.Engine } // SetCoinbase sets the coinbase of the generated block. @@ -141,7 +143,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 = ethash.CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Header()) + b.header.Difficulty = b.engine.CalcDifficulty(b.chainReader, b.header.Time.Uint64(), b.parent.Header()) } // GenerateChain creates a chain of n blocks. The first block's @@ -156,44 +158,54 @@ 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 *params.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, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) { if config == nil { config = params.TestChainConfig } 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, config: config} + genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { + // TODO(karalabe): This is needed for clique, which depends on multiple blocks. + // It's nonetheless ugly to spin up a blockchain here. Get rid of this somehow. + blockchain, _ := NewBlockChain(db, config, engine, vm.Config{}) + defer blockchain.Stop() + + b := &BlockGen{i: i, parent: parent, chain: blocks, chainReader: blockchain, statedb: statedb, config: config, engine: engine} + b.header = makeHeader(b.chainReader, parent, statedb, b.engine) + // Mutate the state and block according to any hard-fork specs if daoBlock := config.DAOForkBlock; daoBlock != nil { limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) - if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 { + if b.header.Number.Cmp(daoBlock) >= 0 && b.header.Number.Cmp(limit) < 0 { if config.DAOForkSupport { - h.Extra = common.CopyBytes(params.DAOForkBlockExtra) + b.header.Extra = common.CopyBytes(params.DAOForkBlockExtra) } } } - if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(h.Number) == 0 { + if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 { misc.ApplyDAOHardFork(statedb) } // Execute any user modifications to the block and finalize it if gen != nil { gen(i, b) } - ethash.AccumulateRewards(config, statedb, h, b.uncles) - root, err := statedb.CommitTo(db, config.IsEIP158(h.Number)) - if err != nil { - panic(fmt.Sprintf("state write error: %v", err)) + + if b.engine != nil { + block, _ := b.engine.Finalize(b.chainReader, b.header, statedb, b.txs, b.uncles, b.receipts) + // Write state changes to db + _, err := statedb.CommitTo(db, config.IsEIP158(b.header.Number)) + if err != nil { + panic(fmt.Sprintf("state write error: %v", err)) + } + return block, b.receipts } - h.Root = root - return types.NewBlock(h, b.txs, b.uncles, b.receipts), b.receipts + return nil, nil } for i := 0; i < n; i++ { statedb, err := state.New(parent.Root(), state.NewDatabase(db)) if err != nil { panic(err) } - header := makeHeader(config, parent, statedb) - block, receipt := genblock(i, header, statedb) + block, receipt := genblock(i, parent, statedb) blocks[i] = block receipts[i] = receipt parent = block @@ -201,7 +213,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Dat return blocks, receipts } -func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.StateDB) *types.Header { +func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { var time *big.Int if parent.Time() == nil { time = big.NewInt(10) @@ -210,10 +222,10 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St } return &types.Header{ - Root: state.IntermediateRoot(config.IsEIP158(parent.Number())), + Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), - Difficulty: ethash.CalcDifficulty(config, time.Uint64(), &types.Header{ + Difficulty: engine.CalcDifficulty(chain, time.Uint64(), &types.Header{ Number: parent.Number(), Time: new(big.Int).Sub(time, big.NewInt(10)), Difficulty: parent.Difficulty(), @@ -229,32 +241,32 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St // newCanonical creates a chain database, and injects a deterministic canonical // chain. Depending on the full flag, if creates either a full block chain or a // header only chain. -func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) { +func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { // Initialize a fresh chain with only a genesis block gspec := new(Genesis) db, _ := ethdb.NewMemDatabase() genesis := gspec.MustCommit(db) - blockchain, _ := NewBlockChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, params.AllEthashProtocolChanges, engine, vm.Config{}) // Create and inject the requested chain if n == 0 { return db, blockchain, nil } if full { // Full block-chain requested - blocks := makeBlockChain(genesis, n, db, canonicalSeed) + blocks := makeBlockChain(genesis, n, engine, db, canonicalSeed) _, err := blockchain.InsertChain(blocks) return db, blockchain, err } // Header-only chain requested - headers := makeHeaderChain(genesis.Header(), n, db, canonicalSeed) + headers := makeHeaderChain(genesis.Header(), n, engine, db, canonicalSeed) _, err := blockchain.InsertHeaderChain(headers, 1) return db, blockchain, err } // 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 := makeBlockChain(types.NewBlockWithHeader(parent), n, db, seed) +func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header { + blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { headers[i] = block.Header() @@ -263,8 +275,8 @@ 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(params.TestChainConfig, parent, db, n, func(i int, b *BlockGen) { +func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Block { + blocks, _ := GenerateChain(params.TestChainConfig, parent, engine, db, n, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) }) return blocks |