diff options
author | Mission Liao <mission.liao@dexon.org> | 2018-10-30 14:39:15 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-30 14:39:15 +0800 |
commit | 4409c9cc55af2168da4d273d9d7e1f3eea4dc818 (patch) | |
tree | 9b1d4e3f60a46a4414cf1ec51f95f68157f339ed | |
parent | 39a1c5bf189a2be4d0bc9b9c50cc73f1599ce732 (diff) | |
download | dexon-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar dexon-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.gz dexon-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.bz2 dexon-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.lz dexon-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.xz dexon-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.zst dexon-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.zip |
core: fix lattice bugs (#274)
* Fix bug: the block pool is not resized.
* Fix forward acking.
* Fix panic when total ordering
* Fix total ordering flush hang
The blocks arrived first might be not delivered before other block.
Therefore, if some last block of previous round arrived before last
blocks in other chains, and are not delivered when entering flush mode.
Their corresponding flush-ready flag won't be turned on.
* Fix bug in core.latticeData
Invalid chainID is not thrown when preparing blocks.
-rw-r--r-- | core/blockpool.go | 2 | ||||
-rw-r--r-- | core/lattice-data.go | 13 | ||||
-rw-r--r-- | core/total-ordering.go | 28 |
3 files changed, 38 insertions, 5 deletions
diff --git a/core/blockpool.go b/core/blockpool.go index 7441cf9..60b8f5d 100644 --- a/core/blockpool.go +++ b/core/blockpool.go @@ -38,7 +38,7 @@ func newBlockPool(chainNum uint32) (pool blockPool) { // resize the pool if new chain is added. func (p *blockPool) resize(num uint32) { - if uint32(len(*p)) < num { + if uint32(len(*p)) >= num { return } newPool := make([]types.ByPosition, num) diff --git a/core/lattice-data.go b/core/lattice-data.go index 2a3ec29..dd0b534 100644 --- a/core/lattice-data.go +++ b/core/lattice-data.go @@ -389,6 +389,10 @@ func (data *latticeData) prepareBlock(b *types.Block) error { if config = data.getConfig(b.Position.Round); config == nil { return ErrUnknownRoundID } + // When this chain is illegal in this round, reject it. + if b.Position.ChainID >= config.numChains { + return ErrInvalidChainID + } // Reset fields to make sure we got these information from parent block. b.Position.Height = 0 b.ParentHash = common.Hash{} @@ -449,9 +453,12 @@ func (data *latticeData) prepareBlock(b *types.Block) error { // The reference block is already acked. continue } - // Can't ack block too old or too new to us. - if DiffUint64( - status.tip.Position.Round, b.Position.Round) > 1 { + if status.tip.Position.Round > b.Position.Round { + // Avoid forward acking: acking some block from later rounds. + continue + } + if b.Position.Round > status.tip.Position.Round+1 { + // Can't ack block too old or too new to us. continue } acks = append(acks, status.tip.Hash) diff --git a/core/total-ordering.go b/core/total-ordering.go index ec9e643..480cdd4 100644 --- a/core/total-ordering.go +++ b/core/total-ordering.go @@ -214,6 +214,11 @@ func (cache *totalOrderingObjectCache) requestAckedStatus() ( // recycleAckedStatys recycles the structure to record acking status. func (cache *totalOrderingObjectCache) recycleAckedStatus( acked []*totalOrderingHeightRecord) { + // If the recycled objects supports lower numChains than we required, + // don't recycle it. + if uint32(len(acked)) != cache.numChains { + return + } cache.ackedStatus = append(cache.ackedStatus, acked) } @@ -231,6 +236,11 @@ func (cache *totalOrderingObjectCache) recycleWinRecord( if win == nil { return } + // If the recycled objects supports lower numChains than we required, + // don't recycle it. + if uint32(len(win.wins)) != cache.numChains { + return + } cache.winRecordPool.Put(win) } @@ -253,6 +263,11 @@ func (cache *totalOrderingObjectCache) requestHeightVector() (hv []uint64) { // recycleHeightVector recycles an instance to record acking heights // of one candidate. func (cache *totalOrderingObjectCache) recycleHeightVector(hv []uint64) { + // If the recycled objects supports lower numChains than we required, + // don't recycle it. + if uint32(len(hv)) != cache.numChains { + return + } cache.heightVectors = append(cache.heightVectors, hv) } @@ -275,6 +290,11 @@ func (cache *totalOrderingObjectCache) requestWinRecordContainer() ( // recycleWinRecordContainer recycles a map of totalOrderingWinRecord. func (cache *totalOrderingObjectCache) recycleWinRecordContainer( con []*totalOrderingWinRecord) { + // If the recycled objects supports lower numChains than we required, + // don't recycle it. + if uint32(len(con)) != cache.numChains { + return + } cache.winRecordContainers = append(cache.winRecordContainers, con) } @@ -1292,9 +1312,15 @@ func (to *totalOrdering) deliverBlocks() ( if !cfg.isValidLastBlock(b) { continue } - to.flushReadyChains[b.Position.ChainID] = struct{}{} to.flushed[b.Position.ChainID] = struct{}{} } + // Some last blocks for the round to be flushed might not be delivered + // yet. + for _, tip := range to.globalVector.tips[:cfg.numChains] { + if tip.Position.Round > to.curRound || cfg.isValidLastBlock(tip) { + to.flushReadyChains[tip.Position.ChainID] = struct{}{} + } + } } return } |