core, consensus: pluggable consensus engines (#3817)
This commit adds pluggable consensus engines to go-ethereum. In short, it introduces a generic consensus interface, and refactors the entire codebase to use this interface.
This commit is contained in:
committed by
Felix Lange
parent
e50a5b7771
commit
09777952ee
@ -24,13 +24,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/pow"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
)
|
||||
@ -64,14 +64,13 @@ type LightChain struct {
|
||||
procInterrupt int32 // interrupt signaler for block processing
|
||||
wg sync.WaitGroup
|
||||
|
||||
pow pow.PoW
|
||||
validator core.HeaderValidator
|
||||
engine consensus.Engine
|
||||
}
|
||||
|
||||
// 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 *params.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*LightChain, error) {
|
||||
func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, mux *event.TypeMux) (*LightChain, error) {
|
||||
bodyCache, _ := lru.New(bodyCacheLimit)
|
||||
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
||||
blockCache, _ := lru.New(blockCacheLimit)
|
||||
@ -84,21 +83,17 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
|
||||
bodyCache: bodyCache,
|
||||
bodyRLPCache: bodyRLPCache,
|
||||
blockCache: blockCache,
|
||||
pow: pow,
|
||||
engine: engine,
|
||||
}
|
||||
|
||||
var err error
|
||||
bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.Validator, bc.getProcInterrupt)
|
||||
bc.SetValidator(core.NewHeaderValidator(config, bc.hc, pow))
|
||||
bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
|
||||
if bc.genesisBlock == nil {
|
||||
return nil, core.ErrNoGenesis
|
||||
}
|
||||
|
||||
if bc.genesisBlock.Hash() == params.MainNetGenesisHash {
|
||||
// add trusted CHT
|
||||
WriteTrustedCht(bc.chainDb, TrustedCht{Number: 805, Root: common.HexToHash("85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f")})
|
||||
@ -145,9 +140,6 @@ func (self *LightChain) loadLastState() error {
|
||||
headerTd := self.GetTd(header.Hash(), header.Number.Uint64())
|
||||
log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd)
|
||||
|
||||
// Try to be smart and issue a pow verification for the head to pre-generate caches
|
||||
go self.pow.Verify(types.NewBlockWithHeader(header))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -188,20 +180,6 @@ func (self *LightChain) Status() (td *big.Int, currentBlock common.Hash, genesis
|
||||
return self.GetTd(hash, header.Number.Uint64()), hash, self.genesisBlock.Hash()
|
||||
}
|
||||
|
||||
// SetValidator sets the validator which is used to validate incoming headers.
|
||||
func (self *LightChain) SetValidator(validator core.HeaderValidator) {
|
||||
self.procmu.Lock()
|
||||
defer self.procmu.Unlock()
|
||||
self.validator = validator
|
||||
}
|
||||
|
||||
// Validator returns the current header validator.
|
||||
func (self *LightChain) Validator() core.HeaderValidator {
|
||||
self.procmu.RLock()
|
||||
defer self.procmu.RUnlock()
|
||||
return self.validator
|
||||
}
|
||||
|
||||
// State returns a new mutable state based on the current HEAD block.
|
||||
func (self *LightChain) State() *LightState {
|
||||
return NewLightState(StateTrieID(self.hc.CurrentHeader()), self.odr)
|
||||
|
@ -23,12 +23,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"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"
|
||||
)
|
||||
|
||||
// So we can deterministically seed different blockchains
|
||||
@ -49,18 +49,15 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
|
||||
return headers
|
||||
}
|
||||
|
||||
func testChainConfig() *params.ChainConfig {
|
||||
return ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)}
|
||||
}
|
||||
|
||||
// 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) (ethdb.Database, *LightChain, error) {
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
gspec := core.Genesis{Config: testChainConfig()}
|
||||
gspec := core.Genesis{Config: params.TestChainConfig}
|
||||
genesis := gspec.MustCommit(db)
|
||||
blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.FakePow{}, new(event.TypeMux))
|
||||
blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFaker(), new(event.TypeMux))
|
||||
|
||||
// Create and inject the requested chain
|
||||
if n == 0 {
|
||||
return db, blockchain, nil
|
||||
@ -76,14 +73,13 @@ func newTestLightChain() *LightChain {
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
gspec := &core.Genesis{
|
||||
Difficulty: big.NewInt(1),
|
||||
Config: testChainConfig(),
|
||||
Config: params.TestChainConfig,
|
||||
}
|
||||
gspec.MustCommit(db)
|
||||
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
|
||||
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), new(event.TypeMux))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
lc.SetValidator(bproc{})
|
||||
return lc
|
||||
}
|
||||
|
||||
@ -130,17 +126,17 @@ func printChain(bc *LightChain) {
|
||||
|
||||
// testHeaderChainImport tries to process a chain of header, writing them into
|
||||
// the database if successful.
|
||||
func testHeaderChainImport(chain []*types.Header, LightChain *LightChain) error {
|
||||
func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error {
|
||||
for _, header := range chain {
|
||||
// Try and validate the header
|
||||
if err := LightChain.Validator().ValidateHeader(header, LightChain.GetHeaderByHash(header.ParentHash), false); err != nil {
|
||||
if err := lightchain.engine.VerifyHeader(lightchain.hc, header, true); err != nil {
|
||||
return err
|
||||
}
|
||||
// Manually insert the header into the database, but don't reorganize (allows subsequent testing)
|
||||
LightChain.mu.Lock()
|
||||
core.WriteTd(LightChain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, LightChain.GetTdByHash(header.ParentHash)))
|
||||
core.WriteHeader(LightChain.chainDb, header)
|
||||
LightChain.mu.Unlock()
|
||||
lightchain.mu.Lock()
|
||||
core.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, lightchain.GetTdByHash(header.ParentHash)))
|
||||
core.WriteHeader(lightchain.chainDb, header)
|
||||
lightchain.mu.Unlock()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -257,10 +253,6 @@ func TestBrokenHeaderChain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type bproc struct{}
|
||||
|
||||
func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return nil }
|
||||
|
||||
func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {
|
||||
var chain []*types.Header
|
||||
for i, difficulty := range d {
|
||||
@ -359,7 +351,7 @@ func TestReorgBadHeaderHashes(t *testing.T) {
|
||||
defer func() { delete(core.BadHashes, headers[3].Hash()) }()
|
||||
|
||||
// Create a new LightChain and check that it rolled back the state.
|
||||
ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, testChainConfig(), pow.FakePow{}, new(event.TypeMux))
|
||||
ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new chain manager: %v", err)
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
@ -34,7 +35,6 @@ import (
|
||||
"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/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
@ -248,7 +248,6 @@ func testChainGen(i int, block *core.BlockGen) {
|
||||
func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
|
||||
var (
|
||||
evmux = new(event.TypeMux)
|
||||
pow = new(pow.FakePow)
|
||||
sdb, _ = ethdb.NewMemDatabase()
|
||||
ldb, _ = ethdb.NewMemDatabase()
|
||||
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
|
||||
@ -256,16 +255,14 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
|
||||
)
|
||||
gspec.MustCommit(ldb)
|
||||
// Assemble the test environment
|
||||
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
|
||||
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
|
||||
gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, 4, testChainGen)
|
||||
blockchain, _ := core.NewBlockChain(sdb, params.TestChainConfig, ethash.NewFullFaker(), evmux, vm.Config{})
|
||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, sdb, 4, testChainGen)
|
||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
odr := &testOdr{sdb: sdb, ldb: ldb}
|
||||
lightchain, _ := NewLightChain(odr, testChainConfig(), pow, evmux)
|
||||
lightchain.SetValidator(bproc{})
|
||||
lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), evmux)
|
||||
headers := make([]*types.Header, len(gchain))
|
||||
for i, block := range gchain {
|
||||
headers[i] = block.Header()
|
||||
|
@ -24,13 +24,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"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/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/pow"
|
||||
)
|
||||
|
||||
type testTxRelay struct {
|
||||
@ -83,7 +83,6 @@ func TestTxPool(t *testing.T) {
|
||||
|
||||
var (
|
||||
evmux = new(event.TypeMux)
|
||||
pow = new(pow.FakePow)
|
||||
sdb, _ = ethdb.NewMemDatabase()
|
||||
ldb, _ = ethdb.NewMemDatabase()
|
||||
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
|
||||
@ -91,9 +90,8 @@ func TestTxPool(t *testing.T) {
|
||||
)
|
||||
gspec.MustCommit(ldb)
|
||||
// Assemble the test environment
|
||||
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
|
||||
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
|
||||
gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
|
||||
blockchain, _ := core.NewBlockChain(sdb, params.TestChainConfig, ethash.NewFullFaker(), evmux, vm.Config{})
|
||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
|
||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -104,10 +102,9 @@ func TestTxPool(t *testing.T) {
|
||||
discard: make(chan int, 1),
|
||||
mined: make(chan int, 1),
|
||||
}
|
||||
lightchain, _ := NewLightChain(odr, testChainConfig(), pow, evmux)
|
||||
lightchain.SetValidator(bproc{})
|
||||
lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), evmux)
|
||||
txPermanent = 50
|
||||
pool := NewTxPool(testChainConfig(), evmux, lightchain, relay)
|
||||
pool := NewTxPool(params.TestChainConfig, evmux, lightchain, relay)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
|
||||
|
Reference in New Issue
Block a user