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.
This commit is contained in:
Roman Khimov 2020-09-17 18:27:27 +03:00
parent 1dc93216ee
commit af6a6f5f30

View file

@ -228,7 +228,20 @@ func (s *service) eventLoop() {
case tx := <-s.transactions: case tx := <-s.transactions:
s.dbft.OnTransaction(tx) s.dbft.OnTransaction(tx)
case b := <-s.blockEvents: case b := <-s.blockEvents:
// We also receive our own blocks here, so check for index. 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 { if b.Index >= s.dbft.BlockIndex {
s.log.Debug("new block in the chain", s.log.Debug("new block in the chain",
zap.Uint32("dbft index", s.dbft.BlockIndex), zap.Uint32("dbft index", s.dbft.BlockIndex),
@ -236,8 +249,6 @@ func (s *service) eventLoop() {
s.dbft.InitializeConsensus(0) s.dbft.InitializeConsensus(0)
} }
} }
}
}
func (s *service) validatePayload(p *Payload) bool { func (s *service) validatePayload(p *Payload) bool {
validators := s.getValidators() validators := s.getValidators()