From 4409c9cc55af2168da4d273d9d7e1f3eea4dc818 Mon Sep 17 00:00:00 2001 From: Mission Liao Date: Tue, 30 Oct 2018 14:39:15 +0800 Subject: 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. --- core/blockpool.go | 2 +- core/lattice-data.go | 13 ++++++++++--- 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 } -- cgit v1.2.3