Skip to content

Commit 300e509

Browse files
committed
[FAB-12926] Validate hash chain when listing blocks
This change set adds validation of the hash chain to the ChainInspector. We need to validate the hash chain (backward hash pointers) when iterating over the system channel when inspecting the channels that exist (which is what the ChainInspector does). Even though the block puller that fetches the channels validates the hash chain in batches, it doesn't verify the hash pointers between the batches themselves. Since the onboarding puller (unlike the etcdraft one) is equipped with a no-op signature validator and relies on the validity of the bootstrap block in conjunction with the integrity of the pulled hash chain, it doesn't verify the signature of the last block of a pulled batch, thus we need to add this check into the code of the channel lister. Change-Id: I8320d093f8d6f5a81291e6377536b0ebdcc83c48 Signed-off-by: yacovm <yacovm@il.ibm.com>
1 parent 385f437 commit 300e509

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

orderer/common/cluster/replication.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,15 +366,19 @@ func (ci *ChainInspector) Channels() []string {
366366
channels := make(map[string]struct{})
367367
lastConfigBlockNum := ci.LastConfigBlock.Header.Number
368368
var block *common.Block
369+
var prevHash []byte
369370
for seq := uint64(1); seq < lastConfigBlockNum; seq++ {
370371
block = ci.Puller.PullBlock(seq)
372+
ci.validateHashPointer(block, prevHash)
371373
channel, err := IsNewChannelBlock(block)
372374
if err != nil {
373375
// If we failed to classify a block, something is wrong in the system chain
374376
// we're trying to pull, so abort.
375377
ci.Logger.Panic("Failed classifying block", seq, ":", err)
376378
continue
377379
}
380+
// Set the previous hash for the next iteration
381+
prevHash = block.Header.Hash()
378382
if channel == "" {
379383
ci.Logger.Info("Block", seq, "doesn't contain a new channel")
380384
continue
@@ -395,6 +399,17 @@ func (ci *ChainInspector) Channels() []string {
395399
return flattenChannelMap(channels)
396400
}
397401

402+
func (ci *ChainInspector) validateHashPointer(block *common.Block, prevHash []byte) {
403+
if prevHash == nil {
404+
return
405+
}
406+
if bytes.Equal(block.Header.PreviousHash, prevHash) {
407+
return
408+
}
409+
ci.Logger.Panicf("Claimed previous hash of block %d is %x but actual previous hash is %x",
410+
block.Header.Number, block.Header.PreviousHash, prevHash)
411+
}
412+
398413
func flattenChannelMap(m map[string]struct{}) []string {
399414
var res []string
400415
for channel := range m {

orderer/common/cluster/replication_test.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,17 +1039,34 @@ func TestChannels(t *testing.T) {
10391039
},
10401040
},
10411041
{
1042-
name: "bad path - pulled chain's hash is mismatched",
1043-
prepareSystemChain: func(_ []*common.Block) {},
1042+
name: "bad path - pulled chain's last block hash doesn't match the last config block",
1043+
prepareSystemChain: func(systemChain []*common.Block) {
1044+
assignHashes(systemChain)
1045+
systemChain[len(systemChain)-1].Header.PreviousHash = nil
1046+
},
10441047
assertion: func(t *testing.T, ci *cluster.ChainInspector) {
10451048
panicValue := "System channel pulled doesn't match the boot last config block:" +
1046-
" block 4's hash (d8553eb97aa57e3c795a185f30efdbe8d88ae4b1e44b984b311159beac9bd5f4)" +
1049+
" block 4's hash (34762d9deefdea2514a85663856e92b5c7e1ae4669e6265b27b079d1f320e741)" +
10471050
" mismatches 3's prev block hash ()"
10481051
assert.PanicsWithValue(t, panicValue, func() {
10491052
ci.Channels()
10501053
})
10511054
},
10521055
},
1056+
{
1057+
name: "bad path - hash chain mismatch",
1058+
prepareSystemChain: func(systemChain []*common.Block) {
1059+
assignHashes(systemChain)
1060+
systemChain[len(systemChain)/2].Header.PreviousHash = nil
1061+
},
1062+
assertion: func(t *testing.T, ci *cluster.ChainInspector) {
1063+
panicValue := "Claimed previous hash of block 3 is but actual previous " +
1064+
"hash is ab6be2effec106c0324f9d6b1af2cf115c60c3f60e250658362991cb8e195a50"
1065+
assert.PanicsWithValue(t, panicValue, func() {
1066+
ci.Channels()
1067+
})
1068+
},
1069+
},
10531070
{
10541071
name: "bad path - a block cannot be classified",
10551072
prepareSystemChain: func(systemChain []*common.Block) {
@@ -1080,6 +1097,7 @@ func TestChannels(t *testing.T) {
10801097
}
10811098
testCase.prepareSystemChain(systemChain)
10821099
puller := &mocks.ChainPuller{}
1100+
puller.On("Close")
10831101
for seq := uint64(1); int(seq) <= len(systemChain); seq++ {
10841102
puller.On("PullBlock", seq).Return(systemChain[int(seq)-1])
10851103
}
@@ -1089,6 +1107,8 @@ func TestChannels(t *testing.T) {
10891107
Puller: puller,
10901108
LastConfigBlock: systemChain[len(systemChain)-1],
10911109
}
1110+
defer puller.AssertNumberOfCalls(t, "Close", 1)
1111+
defer ci.Close()
10921112
testCase.assertion(t, ci)
10931113
})
10941114
}

0 commit comments

Comments
 (0)