Skip to content

Commit

Permalink
Write config blocks synchronously in Orderer
Browse files Browse the repository at this point in the history
Assume the config block contains a transaction which removes the
node from consenters, the consensus chain will switch to follower
chain which reads last config block from ledger directly. Because of
writing config block asynchronously, follower chain maybe read a
stale config block in which the node is still a consenter. So the
node will switch back to a consenter again.

Writting config blocks synchronously would fix this bug.

Signed-off-by: Alex-duzhichao <duzhichaomail@gmail.com>
  • Loading branch information
Alex-duzhichao authored and C0rWin committed Sep 30, 2021
1 parent 9636332 commit 295853b
Showing 1 changed file with 18 additions and 1 deletion.
19 changes: 18 additions & 1 deletion orderer/common/multichannel/blockwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (bw *BlockWriter) WriteConfigBlock(block *cb.Block, encodedMetadataValue []
logger.Panicf("Told to write a config block with unknown header type: %v", chdr.Type)
}

bw.WriteBlock(block, encodedMetadataValue)
bw.WriteBlockSync(block, encodedMetadataValue)
}

// WriteBlock should be invoked for blocks which contain normal transactions.
Expand All @@ -175,6 +175,23 @@ func (bw *BlockWriter) WriteBlock(block *cb.Block, encodedMetadataValue []byte)
}()
}

// WriteBlockSync is same as WriteBlock, but commits block synchronously.
// Note: WriteConfigBlock should use WriteBlockSync instead of WriteBlock.
// If the block contains a transaction that remove the node from consenters,
// the node will switch to follower and pull blocks from other nodes.
// Suppose writing block asynchronously, the block maybe not persist to disk
// when the follower chain starts working. The follower chain will read a block
// before the config block, in which the node is still a consenter, so the follower
// chain will switch to the consensus chain. That's a dead loop!
// So WriteConfigBlock should use WriteBlockSync instead of WriteBlock.
func (bw *BlockWriter) WriteBlockSync(block *cb.Block, encodedMetadataValue []byte) {
bw.committingBlock.Lock()
bw.lastBlock = block

defer bw.committingBlock.Unlock()
bw.commitBlock(encodedMetadataValue)
}

// commitBlock should only ever be invoked with the bw.committingBlock held
// this ensures that the encoded config sequence numbers stay in sync
func (bw *BlockWriter) commitBlock(encodedMetadataValue []byte) {
Expand Down

0 comments on commit 295853b

Please sign in to comment.