From 8cb40bd72ed4b8d3016c22a5edfb8d5779cba4da Mon Sep 17 00:00:00 2001 From: Jimmy Hu Date: Fri, 30 Nov 2018 19:07:36 +0800 Subject: vendor: update to latest core (#71) --- .../dexon-consensus/common/types.go | 17 --- .../dexon-consensus/core/agreement-mgr.go | 7 +- .../dexon-consensus/core/compaction-chain.go | 133 ++++----------------- .../dexon-consensus/core/consensus.go | 77 +----------- .../dexon-consensus/core/interfaces.go | 3 - .../dexon-consensus/core/lattice.go | 34 +++++- .../dexon-consensus/core/nonblocking.go | 13 -- .../dexon-consensus/core/total-ordering.go | 17 +-- .../dexon-foundation/dexon-consensus/core/utils.go | 45 +++++++ 9 files changed, 118 insertions(+), 228 deletions(-) (limited to 'vendor/github.com/dexon-foundation') diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/common/types.go b/vendor/github.com/dexon-foundation/dexon-consensus/common/types.go index a5dfab10e..883492bf3 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/common/types.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/common/types.go @@ -15,23 +15,6 @@ // along with the dexon-consensus library. If not, see // . -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus 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 dexon-consensus 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 dexon-consensus library. If not, see -// . - package common import ( diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go index f695e36cc..6f50bfc16 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go @@ -387,7 +387,12 @@ Loop: for { nextHeight, err = mgr.lattice.NextHeight(recv.round, setting.chainID) if err != nil { - panic(err) + mgr.logger.Debug("Error getting next height", + "error", err, + "round", recv.round, + "chainID", setting.chainID) + err = nil + nextHeight = oldPos.Height } if isStop(oldPos) || nextHeight == 0 { break diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go index 20a7bdd4a..89ba978d0 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/compaction-chain.go @@ -18,7 +18,6 @@ package core import ( - "container/heap" "fmt" "sync" "time" @@ -50,40 +49,40 @@ type pendingRandomnessResult struct { type finalizedBlockHeap = types.ByFinalizationHeight type compactionChain struct { - gov Governance - chainUnsynced uint32 - tsigVerifier *TSigVerifierCache - blocks map[common.Hash]*types.Block - blockRandomness map[common.Hash][]byte - pendingRandomness map[common.Hash]pendingRandomnessResult - pendingBlocks []*types.Block - pendingFinalizedBlocks *finalizedBlockHeap - lock sync.RWMutex - prevBlock *types.Block + gov Governance + chainUnsynced uint32 + tsigVerifier *TSigVerifierCache + blocks map[common.Hash]*types.Block + blockRandomness map[common.Hash][]byte + pendingRandomness map[common.Hash]pendingRandomnessResult + pendingBlocks []*types.Block + lock sync.RWMutex + prevBlock *types.Block } func newCompactionChain(gov Governance) *compactionChain { - pendingFinalizedBlocks := &finalizedBlockHeap{} - heap.Init(pendingFinalizedBlocks) return &compactionChain{ - gov: gov, - tsigVerifier: NewTSigVerifierCache(gov, 7), - blocks: make(map[common.Hash]*types.Block), - blockRandomness: make(map[common.Hash][]byte), - pendingRandomness: make(map[common.Hash]pendingRandomnessResult), - pendingFinalizedBlocks: pendingFinalizedBlocks, + gov: gov, + tsigVerifier: NewTSigVerifierCache(gov, 7), + blocks: make(map[common.Hash]*types.Block), + blockRandomness: make(map[common.Hash][]byte), + pendingRandomness: make(map[common.Hash]pendingRandomnessResult), } } +// init the compaction chain module with a finalized block, or just an empty +// block for bootstrap case. func (cc *compactionChain) init(initBlock *types.Block) { cc.lock.Lock() defer cc.lock.Unlock() cc.prevBlock = initBlock cc.pendingBlocks = []*types.Block{} + // It's the bootstrap case, compactionChain would only deliver blocks until + // tips of all chains are received. if initBlock.Finalization.Height == 0 { cc.chainUnsynced = cc.gov.Configuration(uint64(0)).NumChains - cc.pendingBlocks = append(cc.pendingBlocks, initBlock) } + cc.pendingBlocks = append(cc.pendingBlocks, initBlock) } func (cc *compactionChain) registerBlock(block *types.Block) { @@ -190,16 +189,14 @@ func (cc *compactionChain) verifyRandomness( Signature: randomness}), nil } -func (cc *compactionChain) processFinalizedBlock(block *types.Block) { +func (cc *compactionChain) processFinalizedBlock(block *types.Block) error { if block.Finalization.Height <= cc.lastBlock().Finalization.Height { - return + return nil } - // Block of round 0 should not have randomness. if block.Position.Round == 0 && len(block.Finalization.Randomness) != 0 { - return + return nil } - cc.lock.Lock() defer cc.lock.Unlock() // The randomness result is missed previously. @@ -207,95 +204,13 @@ func (cc *compactionChain) processFinalizedBlock(block *types.Block) { ok, err := cc.verifyRandomness( block.Hash, block.Position.Round, block.Finalization.Randomness) if err != nil { - panic(err) + return err } if ok { cc.blockRandomness[block.Hash] = block.Finalization.Randomness } - return - } - - heap.Push(cc.pendingFinalizedBlocks, block) - - return -} - -func (cc *compactionChain) extractFinalizedBlocks() []*types.Block { - prevBlock := cc.lastBlock() - - blocks := func() []*types.Block { - cc.lock.Lock() - defer cc.lock.Unlock() - blocks := []*types.Block{} - prevHeight := prevBlock.Finalization.Height - for cc.pendingFinalizedBlocks.Len() != 0 { - tip := (*cc.pendingFinalizedBlocks)[0] - // Pop blocks that are already confirmed. - if tip.Finalization.Height <= prevBlock.Finalization.Height { - heap.Pop(cc.pendingFinalizedBlocks) - continue - } - // Since we haven't verified the finalized block, - // it is possible to be forked. - if tip.Finalization.Height == prevHeight || - tip.Finalization.Height == prevHeight+1 { - prevHeight = tip.Finalization.Height - blocks = append(blocks, tip) - heap.Pop(cc.pendingFinalizedBlocks) - } else { - break - } - } - return blocks - }() - toPending := []*types.Block{} - confirmed := []*types.Block{} - for _, b := range blocks { - if b.Hash == prevBlock.Hash && - b.Finalization.Height == prevBlock.Finalization.Height { - continue - } - ok, err := cc.verifyRandomness( - b.Hash, b.Position.Round, b.Finalization.Randomness) - if err != nil { - toPending = append(toPending, b) - continue - } - if !ok { - continue - } - // Fork resolution: choose block with smaller hash. - if prevBlock.Finalization.Height == b.Finalization.Height { - //TODO(jimmy-dexon): remove this panic after test. - if true { - // workaround to `go vet` error - panic(fmt.Errorf( - "forked finalized block %s,%s", prevBlock.Hash, b.Hash)) - } - if b.Hash.Less(prevBlock.Hash) { - confirmed = confirmed[:len(confirmed)-1] - } else { - continue - } - } - if b.Finalization.Height-prevBlock.Finalization.Height > 1 { - toPending = append(toPending, b) - continue - } - confirmed = append(confirmed, b) - prevBlock = b } - cc.lock.Lock() - defer cc.lock.Unlock() - if len(confirmed) != 0 && cc.prevBlock.Finalization.Height == 0 { - // Pop the initBlock inserted when bootstrapping. - cc.pendingBlocks = cc.pendingBlocks[1:] - } - cc.prevBlock = prevBlock - for _, b := range toPending { - heap.Push(cc.pendingFinalizedBlocks, b) - } - return confirmed + return nil } func (cc *compactionChain) processBlockRandomnessResult( diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go index af4041766..253c9a59f 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go @@ -401,7 +401,7 @@ func NewConsensus( ID: ID, ccModule: newCompactionChain(gov), lattice: lattice, - app: app, + app: newNonBlocking(app, debugApp), gov: gov, db: db, network: network, @@ -639,9 +639,9 @@ func (con *Consensus) initialRound( // Stop the Consensus core. func (con *Consensus) Stop() { + con.ctxCancel() con.baMgr.stop() con.event.Reset() - con.ctxCancel() } func (con *Consensus) processMsg(msgChan <-chan interface{}) { @@ -761,44 +761,9 @@ func (con *Consensus) ProcessVote(vote *types.Vote) (err error) { func (con *Consensus) ProcessAgreementResult( rand *types.AgreementResult) error { // Sanity Check. - notarySet, err := con.nodeSetCache.GetNotarySet( - rand.Position.Round, rand.Position.ChainID) - if err != nil { + if err := VerifyAgreementResult(rand, con.nodeSetCache); err != nil { return err } - if len(rand.Votes) < len(notarySet)/3*2+1 { - return ErrNotEnoughVotes - } - if len(rand.Votes) > len(notarySet) { - return ErrIncorrectVoteProposer - } - for _, vote := range rand.Votes { - if rand.IsEmptyBlock { - if (vote.BlockHash != common.Hash{}) { - return ErrIncorrectVoteBlockHash - } - } else { - if vote.BlockHash != rand.BlockHash { - return ErrIncorrectVoteBlockHash - } - } - if vote.Type != types.VoteCom { - return ErrIncorrectVoteType - } - if vote.Position != rand.Position { - return ErrIncorrectVotePosition - } - if _, exist := notarySet[vote.ProposerID]; !exist { - return ErrIncorrectVoteProposer - } - ok, err := verifyVoteSignature(&vote) - if err != nil { - return err - } - if !ok { - return ErrIncorrectVoteSignature - } - } // Syncing BA Module. if err := con.baMgr.processAgreementResult(rand); err != nil { return err @@ -956,39 +921,9 @@ func (con *Consensus) processBlock(block *types.Block) (err error) { return } -// processFinalizedBlock is the entry point for syncing blocks. -func (con *Consensus) processFinalizedBlock(block *types.Block) (err error) { - if err = con.lattice.SanityCheck(block); err != nil { - if err != ErrRetrySanityCheckLater { - return - } - err = nil - } - con.ccModule.processFinalizedBlock(block) - for { - confirmed := con.ccModule.extractFinalizedBlocks() - if len(confirmed) == 0 { - break - } - if err = con.lattice.ctModule.processBlocks(confirmed); err != nil { - return - } - for _, b := range confirmed { - if err = con.db.Put(*b); err != nil { - if err != blockdb.ErrBlockExists { - return - } - err = nil - } - con.lattice.ProcessFinalizedBlock(b) - // TODO(jimmy): BlockConfirmed and DeliverBlock may not be removed if - // application implements state snapshot. - con.logger.Debug("Calling Application.BlockConfirmed", "block", b) - con.app.BlockConfirmed(*b.Clone()) - con.deliverBlock(b) - } - } - return +// processFinalizedBlock is the entry point for handling finalized blocks. +func (con *Consensus) processFinalizedBlock(block *types.Block) error { + return con.ccModule.processFinalizedBlock(block) } // PrepareBlock would setup header fields of block based on its ProposerID. diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go index e07476d44..69798540f 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go @@ -49,9 +49,6 @@ type Application interface { // Debug describes the application interface that requires // more detailed consensus execution. type Debug interface { - // StronglyAcked is called when a block is strongly acked. - StronglyAcked(blockHash common.Hash) - // TotalOrderingDelivered is called when the total ordering algorithm deliver // a set of block. TotalOrderingDelivered(common.Hashes, uint32) diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go index f76813d82..e578e3f4f 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/lattice.go @@ -39,7 +39,6 @@ type Lattice struct { app Application debug Debug pool blockPool - retryAdd bool data *latticeData toModule *totalOrdering ctModule *consensusTimestamp @@ -64,7 +63,7 @@ func NewLattice( debug: debug, pool: newBlockPool(cfg.NumChains), data: newLatticeData(db, dMoment, round, cfg), - toModule: newTotalOrdering(dMoment, cfg), + toModule: newTotalOrdering(dMoment, round, cfg), ctModule: newConsensusTimestamp(dMoment, round, cfg.NumChains), logger: logger, } @@ -211,10 +210,6 @@ func (l *Lattice) addBlockToLattice( } for _, b := range outputBlocks { - // TODO(jimmy-dexon): change this name of classic DEXON algorithm. - if l.debug != nil { - l.debug.StronglyAcked(b.Hash) - } l.logger.Debug("Calling Application.BlockConfirmed", "block", b) l.app.BlockConfirmed(*b.Clone()) // Purge blocks in pool with the same chainID and lower height. @@ -310,4 +305,31 @@ func (l *Lattice) AppendConfig(round uint64, config *types.Config) (err error) { // ProcessFinalizedBlock is used for syncing lattice data. func (l *Lattice) ProcessFinalizedBlock(b *types.Block) { + l.lock.Lock() + defer l.lock.Unlock() + // Syncing state for core.latticeData module. + if err := l.data.addFinalizedBlock(b); err != nil { + panic(err) + } + l.pool.purgeBlocks(b.Position.ChainID, b.Position.Height) + // Syncing state for core.totalOrdering module. + toDelivered, deliveredMode, err := l.toModule.processBlock(b) + if err != nil { + panic(err) + } + if len(toDelivered) == 0 { + return + } + hashes := make(common.Hashes, len(toDelivered)) + for idx := range toDelivered { + hashes[idx] = toDelivered[idx].Hash + } + if l.debug != nil { + l.debug.TotalOrderingDelivered(hashes, deliveredMode) + } + // Sync core.consensusTimestamp module. + if err = l.ctModule.processBlocks(toDelivered); err != nil { + panic(err) + } + return } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go index a73331fae..f94d3c631 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go @@ -29,10 +29,6 @@ type blockConfirmedEvent struct { block *types.Block } -type stronglyAckedEvent struct { - blockHash common.Hash -} - type totalOrderingDeliveredEvent struct { blockHashes common.Hashes mode uint32 @@ -93,8 +89,6 @@ func (nb *nonBlocking) run() { nb.running.Add(1) }() switch e := event.(type) { - case stronglyAckedEvent: - nb.debug.StronglyAcked(e.blockHash) case blockConfirmedEvent: nb.app.BlockConfirmed(*e.block) case totalOrderingDeliveredEvent: @@ -139,13 +133,6 @@ func (nb *nonBlocking) BlockConfirmed(block types.Block) { nb.addEvent(blockConfirmedEvent{&block}) } -// StronglyAcked is called when a block is strongly acked. -func (nb *nonBlocking) StronglyAcked(blockHash common.Hash) { - if nb.debug != nil { - nb.addEvent(stronglyAckedEvent{blockHash}) - } -} - // TotalOrderingDelivered is called when the total ordering algorithm deliver // a set of block. func (nb *nonBlocking) TotalOrderingDelivered( diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go index 90848ce7a..52f927005 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/total-ordering.go @@ -44,9 +44,9 @@ const ( ) var ( - // ErrNotValidDAG would be reported when block subbmitted to totalOrdering + // ErrInvalidDAG is reported when block subbmitted to totalOrdering // didn't form a DAG. - ErrNotValidDAG = errors.New("not a valid dag") + ErrInvalidDAG = errors.New("invalid dag") // ErrFutureRoundDelivered means some blocks from later rounds are // delivered, this means program error. ErrFutureRoundDelivered = errors.New("future round delivered") @@ -347,7 +347,7 @@ func (v *totalOrderingCandidateInfo) addBlock(b *types.Block) error { rec.count = 1 } else { if b.Position.Height <= rec.minHeight { - return ErrNotValidDAG + return ErrInvalidDAG } rec.count++ } @@ -640,12 +640,12 @@ func (global *totalOrderingGlobalVector) addBlock( if tip != nil { // Perform light weight sanity check based on tip. if tip.Position.Round > b.Position.Round { - err = ErrNotValidDAG + err = ErrInvalidDAG return } if DiffUint64(tip.Position.Round, b.Position.Round) > 1 { if b.Position.Height != 0 { - err = ErrNotValidDAG + err = ErrInvalidDAG return } // Add breakpoint. @@ -657,7 +657,7 @@ func (global *totalOrderingGlobalVector) addBlock( }) } else { if b.Position.Height != tip.Position.Height+1 { - err = ErrNotValidDAG + err = ErrInvalidDAG return } } @@ -792,9 +792,9 @@ type totalOrdering struct { } // newTotalOrdering constructs an totalOrdering instance. -func newTotalOrdering(dMoment time.Time, cfg *types.Config) *totalOrdering { +func newTotalOrdering(dMoment time.Time, round uint64, cfg *types.Config) *totalOrdering { config := &totalOrderingConfig{} - config.fromConfig(0, cfg) + config.fromConfig(round, cfg) config.setRoundBeginTime(dMoment) candidates := make([]*totalOrderingCandidateInfo, config.numChains) to := &totalOrdering{ @@ -816,6 +816,7 @@ func newTotalOrdering(dMoment time.Time, cfg *types.Config) *totalOrdering { // round R, next time you can only add the config for round R+1. func (to *totalOrdering) appendConfig( round uint64, config *types.Config) error { + if round != uint64(len(to.configs))+to.configs[0].roundID { return ErrRoundNotIncreasing } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go index 441aac174..bc5e33636 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go @@ -167,6 +167,51 @@ func VerifyBlock(b *types.Block) (err error) { return } +// VerifyAgreementResult perform sanity check against a types.AgreementResult +// instance. +func VerifyAgreementResult( + res *types.AgreementResult, cache *utils.NodeSetCache) error { + notarySet, err := cache.GetNotarySet( + res.Position.Round, res.Position.ChainID) + if err != nil { + return err + } + if len(res.Votes) < len(notarySet)/3*2+1 { + return ErrNotEnoughVotes + } + if len(res.Votes) > len(notarySet) { + return ErrIncorrectVoteProposer + } + for _, vote := range res.Votes { + if res.IsEmptyBlock { + if (vote.BlockHash != common.Hash{}) { + return ErrIncorrectVoteBlockHash + } + } else { + if vote.BlockHash != res.BlockHash { + return ErrIncorrectVoteBlockHash + } + } + if vote.Type != types.VoteCom { + return ErrIncorrectVoteType + } + if vote.Position != res.Position { + return ErrIncorrectVotePosition + } + if _, exist := notarySet[vote.ProposerID]; !exist { + return ErrIncorrectVoteProposer + } + ok, err := verifyVoteSignature(&vote) + if err != nil { + return err + } + if !ok { + return ErrIncorrectVoteSignature + } + } + return nil +} + // DiffUint64 calculates difference between two uint64. func DiffUint64(a, b uint64) uint64 { if a > b { -- cgit v1.2.3