From af6a6f5f30dfabbb3f84b1979ac02942ef7c726a Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 17 Sep 2020 18:27:27 +0300 Subject: [PATCH] consensus: fix potential system deadlock There is a notification pushed into the channel when block is being added, that notification is read by special goroutine that then forwards it to all subscribers to that particular event. Consensus goroutine is one of that subscribers, so for the system to properly function it has to read these events, but at the same time it can generate new blocks inside, so in some cases it can generate two blocks without ever reading from the subscription channel and this will lead to a deadlock. To avoid that we need to check subscription channel for events on every loop. --- pkg/consensus/consensus.go | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/pkg/consensus/consensus.go b/pkg/consensus/consensus.go index ca2afd04d..024f74d4b 100644 --- a/pkg/consensus/consensus.go +++ b/pkg/consensus/consensus.go @@ -228,14 +228,25 @@ func (s *service) eventLoop() { case tx := <-s.transactions: s.dbft.OnTransaction(tx) case b := <-s.blockEvents: - // We also receive our own blocks here, so check for index. - if b.Index >= s.dbft.BlockIndex { - s.log.Debug("new block in the chain", - zap.Uint32("dbft index", s.dbft.BlockIndex), - zap.Uint32("chain index", s.Chain.BlockHeight())) - s.dbft.InitializeConsensus(0) - } + s.handleChainBlock(b) } + // Always process block event if there is any, we can add one above. + select { + case b := <-s.blockEvents: + s.handleChainBlock(b) + default: + } + + } +} + +func (s *service) handleChainBlock(b *coreb.Block) { + // We can get our own block here, so check for index. + if b.Index >= s.dbft.BlockIndex { + s.log.Debug("new block in the chain", + zap.Uint32("dbft index", s.dbft.BlockIndex), + zap.Uint32("chain index", s.Chain.BlockHeight())) + s.dbft.InitializeConsensus(0) } }