Skip to content

Commit

Permalink
[FAB-4330] Orderer panic on restart
Browse files Browse the repository at this point in the history
On restart, the orderer is failing to properly re-initialize the config
sequence number, which causes it to inappropriately flag new non-config
blocks as config blocks.

On second restart, the incorrect last config index causes the orderer to
attempt to treat a normal transaction as a config transaction.  The
error checking recognizes this as a fatal error and panics.

This CR moves the initialization out of the "new channel" path, and into
the common path shared by both startup and restart.

It also enhances the log messages to make detection of this sort of
scenario easier.

Change-Id: I0d730eb5180f21ee6913bc8633ff540128bc6899
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jun 3, 2017
1 parent 7717a2e commit 5ca811d
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 6 deletions.
15 changes: 14 additions & 1 deletion orderer/multichain/chainsupport.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,28 @@ func newChainSupport(
signer: signer,
}

cs.lastConfigSeq = cs.Sequence()

var err error

lastBlock := ledger.GetBlock(cs.Reader(), cs.Reader().Height()-1)

// If this is the genesis block, the lastconfig field may be empty, and, the last config is necessary 0
// so no need to initialize lastConfig
if lastBlock.Header.Number != 0 {
cs.lastConfig, err = utils.GetLastConfigIndexFromBlock(lastBlock)
if err != nil {
logger.Fatalf("[channel: %s] Error extracting last config block from block metadata: %s", cs.ChainID(), err)
}
}

metadata, err := utils.GetMetadataFromBlock(lastBlock, cb.BlockMetadataIndex_ORDERER)
// Assuming a block created with cb.NewBlock(), this should not
// error even if the orderer metadata is an empty byte slice
if err != nil {
logger.Fatalf("[channel: %s] Error extracting orderer metadata: %s", cs.ChainID(), err)
}
logger.Debugf("[channel: %s] Retrieved metadata for tip of chain (block #%d): %+v", cs.ChainID(), cs.Reader().Height()-1, metadata)
logger.Debugf("[channel: %s] Retrieved metadata for tip of chain (blockNumber=%d, lastConfig=%d, lastConfigSeq=%d): %+v", cs.ChainID(), lastBlock.Header.Number, cs.lastConfig, cs.lastConfigSeq, metadata)

cs.chain, err = consenter.HandleChain(cs, metadata)
if err != nil {
Expand Down Expand Up @@ -222,6 +234,7 @@ func (cs *chainSupport) addBlockSignature(block *cb.Block) {
func (cs *chainSupport) addLastConfigSignature(block *cb.Block) {
configSeq := cs.Sequence()
if configSeq > cs.lastConfigSeq {
logger.Debugf("[channel: %s] Detected lastConfigSeq transitioning from %d to %d, setting lastConfig from %d to %d", cs.ChainID(), cs.lastConfigSeq, configSeq, cs.lastConfig, block.Header.Number)
cs.lastConfig = block.Header.Number
cs.lastConfigSeq = configSeq
}
Expand Down
5 changes: 0 additions & 5 deletions orderer/multichain/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,6 @@ func (ml *multiLedger) newChain(configtx *cb.Envelope) {

logger.Infof("Created and starting new chain %s", chainID)

cs.lastConfigSeq = cs.Sequence()
// The sequence number on the genesis block of the system channel will be 0.
// The sequence number on the genesis block of every non-system channel will be 1.
logger.Debugf("[channel: %s] Last config set to %d", chainID, cs.lastConfigSeq)

newChains[string(chainID)] = cs
cs.start()

Expand Down
9 changes: 9 additions & 0 deletions orderer/multichain/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,15 @@ func TestNewChain(t *testing.T) {
case <-time.After(time.Second):
t.Fatalf("Block 1 not produced after timeout on new chain")
}

testRestartedChainSupport(t, chainSupport, consenters, expectedLastConfigSeq)
}

func testRestartedChainSupport(t *testing.T, cs ChainSupport, consenters map[string]Consenter, expectedLastConfigSeq uint64) {
ccs, ok := cs.(*chainSupport)
assert.True(t, ok, "Casting error")
rcs := newChainSupport(ccs.filters, ccs.ledgerResources, consenters, mockCrypto())
assert.Equal(t, expectedLastConfigSeq, rcs.lastConfigSeq, "On restart, incorrect lastConfigSeq")
}

func testLastConfigBlockNumber(t *testing.T, block *cb.Block, expectedBlockNumber uint64) {
Expand Down

0 comments on commit 5ca811d

Please sign in to comment.