mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
core: speed up GenerateChain
Use a mock implementation of ChainReader instead of creating and destroying a BlockChain object for each generated block.
This commit is contained in:
parent
f951e23fb5
commit
7cae61ec8c
1 changed files with 28 additions and 16 deletions
|
|
@ -33,12 +33,11 @@ import (
|
||||||
// BlockGen creates blocks for testing.
|
// BlockGen creates blocks for testing.
|
||||||
// See GenerateChain for a detailed explanation.
|
// See GenerateChain for a detailed explanation.
|
||||||
type BlockGen struct {
|
type BlockGen struct {
|
||||||
i int
|
i int
|
||||||
parent *types.Block
|
parent *types.Block
|
||||||
chain []*types.Block
|
chain []*types.Block
|
||||||
chainReader consensus.ChainReader
|
header *types.Header
|
||||||
header *types.Header
|
statedb *state.StateDB
|
||||||
statedb *state.StateDB
|
|
||||||
|
|
||||||
gasPool *GasPool
|
gasPool *GasPool
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
|
|
@ -138,7 +137,7 @@ func (b *BlockGen) AddUncle(h *types.Header) {
|
||||||
// For index -1, PrevBlock returns the parent block given to GenerateChain.
|
// For index -1, PrevBlock returns the parent block given to GenerateChain.
|
||||||
func (b *BlockGen) PrevBlock(index int) *types.Block {
|
func (b *BlockGen) PrevBlock(index int) *types.Block {
|
||||||
if index >= b.i {
|
if index >= b.i {
|
||||||
panic("block index out of range")
|
panic(fmt.Errorf("block index %d out of range (%d,%d)", index, -1, b.i))
|
||||||
}
|
}
|
||||||
if index == -1 {
|
if index == -1 {
|
||||||
return b.parent
|
return b.parent
|
||||||
|
|
@ -154,7 +153,8 @@ func (b *BlockGen) OffsetTime(seconds int64) {
|
||||||
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
|
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
|
||||||
panic("block time out of range")
|
panic("block time out of range")
|
||||||
}
|
}
|
||||||
b.header.Difficulty = b.engine.CalcDifficulty(b.chainReader, b.header.Time.Uint64(), b.parent.Header())
|
chainreader := &fakeChainReader{config: b.config}
|
||||||
|
b.header.Difficulty = b.engine.CalcDifficulty(chainreader, b.header.Time.Uint64(), b.parent.Header())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateChain creates a chain of n blocks. The first block's
|
// GenerateChain creates a chain of n blocks. The first block's
|
||||||
|
|
@ -174,14 +174,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
config = params.TestChainConfig
|
config = params.TestChainConfig
|
||||||
}
|
}
|
||||||
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
||||||
|
chainreader := &fakeChainReader{config: config}
|
||||||
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
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.
|
b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine}
|
||||||
// It's nonetheless ugly to spin up a blockchain here. Get rid of this somehow.
|
b.header = makeHeader(chainreader, parent, statedb, b.engine)
|
||||||
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil)
|
|
||||||
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
|
// Mutate the state and block according to any hard-fork specs
|
||||||
if daoBlock := config.DAOForkBlock; daoBlock != nil {
|
if daoBlock := config.DAOForkBlock; daoBlock != nil {
|
||||||
|
|
@ -201,7 +197,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
}
|
}
|
||||||
if b.engine != nil {
|
if b.engine != nil {
|
||||||
// Finalize and seal the block
|
// Finalize and seal the block
|
||||||
block, _ := b.engine.Finalize(b.chainReader, b.header, statedb, b.txs, b.uncles, b.receipts)
|
block, _ := b.engine.Finalize(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts)
|
||||||
|
|
||||||
// Write state changes to db
|
// Write state changes to db
|
||||||
root, err := statedb.Commit(config.IsEIP158(b.header.Number))
|
root, err := statedb.Commit(config.IsEIP158(b.header.Number))
|
||||||
|
|
@ -269,3 +265,19 @@ func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethd
|
||||||
})
|
})
|
||||||
return blocks
|
return blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeChainReader struct {
|
||||||
|
config *params.ChainConfig
|
||||||
|
genesis *types.Block
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config returns the chain configuration.
|
||||||
|
func (cr *fakeChainReader) Config() *params.ChainConfig {
|
||||||
|
return cr.config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cr *fakeChainReader) CurrentHeader() *types.Header { return nil }
|
||||||
|
func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *types.Header { return nil }
|
||||||
|
func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *types.Header { return nil }
|
||||||
|
func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *types.Header { return nil }
|
||||||
|
func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue