Unverified Commit bd791cc3 authored by yacovm's avatar yacovm Committed by Artem Barger
Browse files

[FAB-14142] NPE when onboarding without app channels



This change set fixes a null pointer panic that happens when onboarding
a node to a channel that has no application channels, and it only has
2 blocks in the system channel.

The null pointer panic happens because the LastConfigBlock index is 1,
and the previous index (0) was never pulled, so previous block passed
into the VerifyBlocks method is nil.

Although the genesis block of the system channel - cannot be verified
by the block puller in general - it can be verified by the block puller
that is used for listing the channels, because it doesn't perform signature
checks on system channel blocks, and instead - uses backward hash chain
verification using the bootstrap block.

Change-Id: I5aaaffa79da637463da1689b1c6167e586f64f44
Signed-off-by: default avataryacovm <yacovm@il.ibm.com>
parent cad881d2
......@@ -522,7 +522,7 @@ func (ci *ChainInspector) Channels() []ChannelGenesisBlock {
lastConfigBlockNum := ci.LastConfigBlock.Header.Number
var block *common.Block
var prevHash []byte
for seq := uint64(1); seq < lastConfigBlockNum; seq++ {
for seq := uint64(0); seq < lastConfigBlockNum; seq++ {
block = ci.Puller.PullBlock(seq)
if block == nil {
ci.Logger.Panicf("Failed pulling block %d from the system channel", seq)
......
......@@ -1383,13 +1383,13 @@ func TestChannels(t *testing.T) {
err = proto.Unmarshal(blockbytes, block)
assert.NoError(t, err)
systemChain[len(systemChain)/2] = block
systemChain[len(systemChain)/2-1] = block
assignHashes(systemChain)
},
assertion: func(t *testing.T, ci *cluster.ChainInspector) {
actual := cluster.GenesisBlocks(ci.Channels())
// Assert that the returned channels are returned in any order
assert.Contains(t, [][]string{{"mychannel", "bar"}, {"bar", "mychannel"}}, actual.Names())
assert.Contains(t, [][]string{{"mychannel2", "bar"}, {"bar", "mychannel2"}}, actual.Names())
},
},
{
......@@ -1400,7 +1400,7 @@ func TestChannels(t *testing.T) {
},
assertion: func(t *testing.T, ci *cluster.ChainInspector) {
panicValue := "System channel pulled doesn't match the boot last config block:" +
" block 4's hash (34762d9deefdea2514a85663856e92b5c7e1ae4669e6265b27b079d1f320e741)" +
" block 2's hash (bc4ef5cc8a61ac0747cc82df58bac9ad3278622c1cfc7a119b9b1068e422c9f1)" +
" mismatches 3's prev block hash ()"
assert.PanicsWithValue(t, panicValue, func() {
ci.Channels()
......@@ -1411,11 +1411,11 @@ func TestChannels(t *testing.T) {
name: "bad path - hash chain mismatch",
prepareSystemChain: func(systemChain []*common.Block) {
assignHashes(systemChain)
systemChain[len(systemChain)/2].Header.PreviousHash = nil
systemChain[len(systemChain)-2].Header.PreviousHash = nil
},
assertion: func(t *testing.T, ci *cluster.ChainInspector) {
panicValue := "Claimed previous hash of block 3 is but actual previous " +
"hash is ab6be2effec106c0324f9d6b1af2cf115c60c3f60e250658362991cb8e195a50"
panicValue := "Claimed previous hash of block 2 is but actual previous " +
"hash is 920faeb0bd8a02b3f2553247359fb3b684819c75c6e5487bc7eed632841ddc5f"
assert.PanicsWithValue(t, panicValue, func() {
ci.Channels()
})
......@@ -1428,7 +1428,7 @@ func TestChannels(t *testing.T) {
systemChain[len(systemChain)-2].Data.Data = [][]byte{{1, 2, 3}}
},
assertion: func(t *testing.T, ci *cluster.ChainInspector) {
panicValue := "Failed classifying block 3 : block data does not carry" +
panicValue := "Failed classifying block 2 : block data does not carry" +
" an envelope at index 0: error unmarshaling Envelope: " +
"proto: common.Envelope: illegal tag 0 (wire type 1)"
assert.PanicsWithValue(t, panicValue, func() {
......@@ -1445,7 +1445,7 @@ func TestChannels(t *testing.T) {
systemChain[len(systemChain)/2] = nil
},
assertion: func(t *testing.T, ci *cluster.ChainInspector) {
panicValue := "Failed pulling block 3 from the system channel"
panicValue := "Failed pulling block 2 from the system channel"
assert.PanicsWithValue(t, panicValue, func() {
ci.Channels()
})
......@@ -1462,13 +1462,13 @@ func TestChannels(t *testing.T) {
for i := 0; i < len(systemChain); i++ {
systemChain[i].Header.DataHash = systemChain[i].Data.Hash()
systemChain[i].Header.Number = uint64(i + 1)
systemChain[i].Header.Number = uint64(i)
}
testCase.prepareSystemChain(systemChain)
puller := &mocks.ChainPuller{}
puller.On("Close")
for seq := uint64(1); int(seq) <= len(systemChain); seq++ {
puller.On("PullBlock", seq).Return(systemChain[int(seq)-1])
for seq := uint64(0); int(seq) < len(systemChain)-1; seq++ {
puller.On("PullBlock", seq).Return(systemChain[int(seq)])
}
ci := &cluster.ChainInspector{
......
......@@ -326,7 +326,7 @@ func VerifyBlockHash(indexInBuffer int, blockBuff []*common.Block) error {
claimedPrevHash := hex.EncodeToString(block.Header.PreviousHash)
actualPrevHash := hex.EncodeToString(prevBlock.Header.Hash())
return errors.Errorf("block %d's hash (%s) mismatches %d's prev block hash (%s)",
currSeq, actualPrevHash, prevSeq, claimedPrevHash)
prevSeq, actualPrevHash, currSeq, claimedPrevHash)
}
}
return nil
......
......@@ -234,9 +234,9 @@ func TestVerifyBlockHash(t *testing.T) {
},
{
name: "prev hash mismatch",
errorContains: "block 13's hash " +
errorContains: "block 12's hash " +
"(866351705f1c2f13e10d52ead9d0ca3b80689ede8cc8bf70a6d60c67578323f4) " +
"mismatches 12's prev block hash (07)",
"mismatches 13's prev block hash (07)",
mutateBlockSequence: func(blockSequence []*common.Block) []*common.Block {
blockSequence[len(blockSequence)/2].Header.PreviousHash = []byte{7}
return blockSequence
......@@ -307,9 +307,9 @@ func TestVerifyBlocks(t *testing.T) {
blockSequence[len(blockSequence)/2].Header.PreviousHash = []byte{7}
return blockSequence
},
expectedError: "block 75's hash " +
expectedError: "block 74's hash " +
"(5cb4bd1b6a73f81afafd96387bb7ff4473c2425929d0862586f5fbfa12d762dd) " +
"mismatches 74's prev block hash (07)",
"mismatches 75's prev block hash (07)",
},
{
name: "bad signature",
......
......@@ -389,6 +389,12 @@ func TestOnboardingChannelUnavailable(t *testing.T) {
Block: bootBlock,
},
}
// Send the bootstrap block of the system channel
deliverServer.blockResponses <- &orderer.DeliverResponse{
Type: &orderer.DeliverResponse_Block{
Block: systemChannelGenesisBlock,
},
}
// Send a channel creation block (sequence 1) that denotes creation of 'testchainid'
deliverServer.blockResponses <- &orderer.DeliverResponse{
Type: &orderer.DeliverResponse_Block{
......@@ -454,12 +460,11 @@ func TestReplicate(t *testing.T) {
}
blocks := make([]*common.Block, 11)
// Genesis block can be anything... not important for channel traversal
// since it is skipped.
blocks[0] = &common.Block{Header: &common.BlockHeader{}}
for seq := uint64(1); seq <= uint64(10); seq++ {
for seq := uint64(0); seq <= uint64(10); seq++ {
block := copyBlock(&bootBlock, seq)
block.Header.PreviousHash = blocks[seq-1].Header.Hash()
if seq > 0 {
block.Header.PreviousHash = blocks[seq-1].Header.Hash()
}
blocks[seq] = &block
deliverServer.blockResponses <- &orderer.DeliverResponse{
Type: &orderer.DeliverResponse_Block{Block: &block},
......@@ -595,7 +600,7 @@ func TestReplicate(t *testing.T) {
},
{
name: "Explicit replication is requested, but the channel shouldn't be pulled",
verificationCount: 18,
verificationCount: 20,
shouldConnect: true,
systemLedgerHeight: 10,
bootBlock: &bootBlock,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment