aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMission Liao <mission.liao@dexon.org>2018-10-30 14:39:15 +0800
committerGitHub <noreply@github.com>2018-10-30 14:39:15 +0800
commit4409c9cc55af2168da4d273d9d7e1f3eea4dc818 (patch)
tree9b1d4e3f60a46a4414cf1ec51f95f68157f339ed
parent39a1c5bf189a2be4d0bc9b9c50cc73f1599ce732 (diff)
downloadtangerine-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar
tangerine-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.gz
tangerine-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.bz2
tangerine-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.lz
tangerine-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.xz
tangerine-consensus-4409c9cc55af2168da4d273d9d7e1f3eea4dc818.tar.zst
tangerine-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.go2
-rw-r--r--core/lattice-data.go13
-rw-r--r--core/total-ordering.go28
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
}