diff options
author | Mission Liao <mission.liao@dexon.org> | 2018-12-28 17:51:01 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-28 17:51:01 +0800 |
commit | f12b6cf891181a72914b3aec8caf7ae0879f6000 (patch) | |
tree | 1900be3bbb2dcdb1b6ee9cc7e363a4b1e907369e | |
parent | 17884041681c4723d67792c19a1716b9e21fc146 (diff) | |
download | dexon-consensus-f12b6cf891181a72914b3aec8caf7ae0879f6000.tar dexon-consensus-f12b6cf891181a72914b3aec8caf7ae0879f6000.tar.gz dexon-consensus-f12b6cf891181a72914b3aec8caf7ae0879f6000.tar.bz2 dexon-consensus-f12b6cf891181a72914b3aec8caf7ae0879f6000.tar.lz dexon-consensus-f12b6cf891181a72914b3aec8caf7ae0879f6000.tar.xz dexon-consensus-f12b6cf891181a72914b3aec8caf7ae0879f6000.tar.zst dexon-consensus-f12b6cf891181a72914b3aec8caf7ae0879f6000.zip |
sync: fix panic (#388)
* Merge several CRS notifications into one.
* Sync config when new CRS is found
-rw-r--r-- | core/syncer/consensus.go | 79 |
1 files changed, 47 insertions, 32 deletions
diff --git a/core/syncer/consensus.go b/core/syncer/consensus.go index bd58231..d334bbd 100644 --- a/core/syncer/consensus.go +++ b/core/syncer/consensus.go @@ -262,6 +262,9 @@ func (con *Consensus) ensureAgreementOverlapRound() bool { for r = range tipRoundMap { break } + con.logger.Info("check agreement round cut", + "tip-round", r, + "configs", len(con.configs)) if tipRoundMap[r] == con.configs[r].NumChains { con.agreementRoundCut = r con.logger.Debug("agreement round cut found, round", r) @@ -558,28 +561,12 @@ func (con *Consensus) buildEmptyBlock(b *types.Block, parent *types.Block) { b.Acks = common.NewSortedHashes(common.Hashes{parent.Hash}) } -// setupConfigs is called by SyncBlocks with blocks from compaction chain. In -// the first time, setupConfigs setups from round 0. -func (con *Consensus) setupConfigs(blocks []*types.Block) { - // Find max round in blocks. - var maxRound uint64 - for _, b := range blocks { - if b.Position.Round > maxRound { - maxRound = b.Position.Round - } - } - // Get configs from governance. - // - // In fullnode, the notification of new round is yet another TX, which - // needs to be executed after corresponding block delivered. Thus, the - // configuration for 'maxRound + core.ConfigRoundShift' won't be ready when - // seeing this block. - untilRound := maxRound + core.ConfigRoundShift - 1 +func (con *Consensus) setupConfigsUntilRound(round uint64) { curMaxNumChains := uint32(0) func() { con.lock.Lock() defer con.lock.Unlock() - for r := uint64(len(con.configs)); r <= untilRound; r++ { + for r := uint64(len(con.configs)); r <= round; r++ { cfg := utils.GetConfigWithPanic(con.gov, r, con.logger) con.configs = append(con.configs, cfg) con.roundBeginTimes = append( @@ -589,19 +576,41 @@ func (con *Consensus) setupConfigs(blocks []*types.Block) { curMaxNumChains = cfg.NumChains } } + // Notify core.Lattice for new configs. + if con.lattice != nil { + for con.latticeLastRound+1 <= round { + con.latticeLastRound++ + if err := con.lattice.AppendConfig( + con.latticeLastRound, + con.configs[con.latticeLastRound]); err != nil { + panic(err) + } + } + } }() con.resizeByNumChains(curMaxNumChains) - // Notify core.Lattice for new configs. - if con.lattice != nil { - for con.latticeLastRound+1 <= untilRound { - con.latticeLastRound++ - if err := con.lattice.AppendConfig( - con.latticeLastRound, - con.configs[con.latticeLastRound]); err != nil { - panic(err) - } +} + +// setupConfigs is called by SyncBlocks with blocks from compaction chain. In +// the first time, setupConfigs setups from round 0. +func (con *Consensus) setupConfigs(blocks []*types.Block) { + // Find max round in blocks. + var maxRound uint64 + for _, b := range blocks { + if b.Position.Round > maxRound { + maxRound = b.Position.Round } } + con.logger.Info("syncer setupConfigs", + "max", maxRound, + "lattice", con.latticeLastRound) + // Get configs from governance. + // + // In fullnode, the notification of new round is yet another TX, which + // needs to be executed after corresponding block delivered. Thus, the + // configuration for 'maxRound + core.ConfigRoundShift' won't be ready when + // seeing this block. + con.setupConfigsUntilRound(maxRound + core.ConfigRoundShift - 1) } // resizeByNumChains resizes fake lattice and agreement if numChains increases. @@ -719,12 +728,13 @@ func (con *Consensus) startCRSMonitor() { var lastNotifiedRound uint64 // Notify all agreements for new CRS. notifyNewCRS := func(round uint64) { + con.setupConfigsUntilRound(round) + con.lock.Lock() + defer con.lock.Unlock() if round == lastNotifiedRound { return } - con.logger.Debug("CRS is ready", "round", round) - con.lock.RLock() - defer con.lock.RUnlock() + con.logger.Info("CRS is ready", "round", round) lastNotifiedRound = round for _, a := range con.agreements { a.inputChan <- round @@ -741,8 +751,13 @@ func (con *Consensus) startCRSMonitor() { } // Notify agreement modules for the latest round that CRS is // available if the round is not notified yet. - if (con.gov.CRS(lastNotifiedRound+1) != common.Hash{}) { - notifyNewCRS(lastNotifiedRound + 1) + checked := lastNotifiedRound + 1 + for (con.gov.CRS(checked) != common.Hash{}) { + checked++ + } + checked-- + if checked > lastNotifiedRound { + notifyNewCRS(checked) } } }() |