github.com/lzy4123/fabric@v2.1.1+incompatible/protoutil/blockutils_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package protoutil_test 8 9 import ( 10 "crypto/sha256" 11 "encoding/asn1" 12 "math" 13 "testing" 14 15 "github.com/golang/protobuf/proto" 16 "github.com/hyperledger/fabric-protos-go/common" 17 cb "github.com/hyperledger/fabric-protos-go/common" 18 configtxtest "github.com/hyperledger/fabric/common/configtx/test" 19 "github.com/hyperledger/fabric/protoutil" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 ) 23 24 var testChannelID = "myuniquetestchainid" 25 26 func TestNewBlock(t *testing.T) { 27 var block *cb.Block 28 assert.Nil(t, block.GetHeader()) 29 assert.Nil(t, block.GetData()) 30 assert.Nil(t, block.GetMetadata()) 31 32 data := &cb.BlockData{ 33 Data: [][]byte{{0, 1, 2}}, 34 } 35 block = protoutil.NewBlock(uint64(0), []byte("datahash")) 36 assert.Equal(t, []byte("datahash"), block.Header.PreviousHash, "Incorrect previous hash") 37 assert.NotNil(t, block.GetData()) 38 assert.NotNil(t, block.GetMetadata()) 39 block.GetHeader().DataHash = protoutil.BlockDataHash(data) 40 41 asn1Bytes, err := asn1.Marshal(struct { 42 Number int64 43 PreviousHash []byte 44 DataHash []byte 45 }{ 46 Number: 0, 47 DataHash: protoutil.BlockDataHash(data), 48 PreviousHash: []byte("datahash"), 49 }) 50 headerHash := sha256.Sum256(asn1Bytes) 51 assert.NoError(t, err) 52 assert.Equal(t, asn1Bytes, protoutil.BlockHeaderBytes(block.Header), "Incorrect marshaled blockheader bytes") 53 assert.Equal(t, headerHash[:], protoutil.BlockHeaderHash(block.Header), "Incorrect blockheader hash") 54 } 55 56 func TestGoodBlockHeaderBytes(t *testing.T) { 57 goodBlockHeader := &common.BlockHeader{ 58 Number: 1, 59 PreviousHash: []byte("foo"), 60 DataHash: []byte("bar"), 61 } 62 63 _ = protoutil.BlockHeaderBytes(goodBlockHeader) // Should not panic 64 65 goodBlockHeaderMaxNumber := &common.BlockHeader{ 66 Number: math.MaxUint64, 67 PreviousHash: []byte("foo"), 68 DataHash: []byte("bar"), 69 } 70 71 _ = protoutil.BlockHeaderBytes(goodBlockHeaderMaxNumber) // Should not panic 72 } 73 74 func TestGetChainIDFromBlockBytes(t *testing.T) { 75 gb, err := configtxtest.MakeGenesisBlock(testChannelID) 76 assert.NoError(t, err, "Failed to create test configuration block") 77 bytes, err := proto.Marshal(gb) 78 cid, err := protoutil.GetChainIDFromBlockBytes(bytes) 79 assert.NoError(t, err) 80 assert.Equal(t, testChannelID, cid, "Failed to return expected chain ID") 81 82 // bad block bytes 83 _, err = protoutil.GetChainIDFromBlockBytes([]byte("bad block")) 84 assert.Error(t, err, "Expected error with malformed block bytes") 85 } 86 87 func TestGetChainIDFromBlock(t *testing.T) { 88 var err error 89 var gb *common.Block 90 var cid string 91 92 // nil block 93 _, err = protoutil.GetChainIDFromBlock(gb) 94 assert.Error(t, err, "Expected error getting channel id from nil block") 95 96 gb, err = configtxtest.MakeGenesisBlock(testChannelID) 97 assert.NoError(t, err, "Failed to create test configuration block") 98 99 cid, err = protoutil.GetChainIDFromBlock(gb) 100 assert.NoError(t, err, "Failed to get chain ID from block") 101 assert.Equal(t, testChannelID, cid, "Failed to return expected chain ID") 102 103 // missing data 104 badBlock := gb 105 badBlock.Data = nil 106 _, err = protoutil.GetChainIDFromBlock(badBlock) 107 assert.Error(t, err, "Expected error with missing block data") 108 109 // no envelope 110 badBlock = &cb.Block{ 111 Data: &cb.BlockData{ 112 Data: [][]byte{[]byte("bad envelope")}, 113 }, 114 } 115 _, err = protoutil.GetChainIDFromBlock(badBlock) 116 assert.Error(t, err, "Expected error with no envelope in data") 117 118 // bad payload 119 env, _ := proto.Marshal(&cb.Envelope{ 120 Payload: []byte("bad payload"), 121 }) 122 badBlock = &cb.Block{ 123 Data: &cb.BlockData{ 124 Data: [][]byte{env}, 125 }, 126 } 127 _, err = protoutil.GetChainIDFromBlock(badBlock) 128 assert.Error(t, err, "Expected error - malformed payload") 129 130 // bad channel header 131 payload, _ := proto.Marshal(&cb.Payload{ 132 Header: &cb.Header{ 133 ChannelHeader: []byte("bad header"), 134 }, 135 }) 136 env, _ = proto.Marshal(&cb.Envelope{ 137 Payload: payload, 138 }) 139 badBlock = &cb.Block{ 140 Data: &cb.BlockData{ 141 Data: [][]byte{env}, 142 }, 143 } 144 _, err = protoutil.GetChainIDFromBlock(badBlock) 145 assert.Error(t, err, "Expected error with malformed channel header") 146 147 // nil payload header 148 payload, _ = proto.Marshal(&cb.Payload{}) 149 env, _ = proto.Marshal(&cb.Envelope{ 150 Payload: payload, 151 }) 152 badBlock = &cb.Block{ 153 Data: &cb.BlockData{ 154 Data: [][]byte{env}, 155 }, 156 } 157 _, err = protoutil.GetChainIDFromBlock(badBlock) 158 assert.Error(t, err, "Expected error when payload header is nil") 159 } 160 161 func TestGetBlockFromBlockBytes(t *testing.T) { 162 testChainID := "myuniquetestchainid" 163 gb, err := configtxtest.MakeGenesisBlock(testChainID) 164 assert.NoError(t, err, "Failed to create test configuration block") 165 blockBytes, err := protoutil.Marshal(gb) 166 assert.NoError(t, err, "Failed to marshal block") 167 _, err = protoutil.UnmarshalBlock(blockBytes) 168 assert.NoError(t, err, "to get block from block bytes") 169 170 // bad block bytes 171 _, err = protoutil.UnmarshalBlock([]byte("bad block")) 172 assert.Error(t, err, "Expected error for malformed block bytes") 173 } 174 175 func TestGetMetadataFromBlock(t *testing.T) { 176 t.Run("new block", func(t *testing.T) { 177 block := protoutil.NewBlock(0, nil) 178 md, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_ORDERER) 179 assert.NoError(t, err, "Unexpected error extracting metadata from new block") 180 assert.Nil(t, md.Value, "Expected metadata field value to be nil") 181 assert.Equal(t, 0, len(md.Value), "Expected length of metadata field value to be 0") 182 md = protoutil.GetMetadataFromBlockOrPanic(block, cb.BlockMetadataIndex_ORDERER) 183 assert.NotNil(t, md, "Expected to get metadata from block") 184 }) 185 t.Run("no metadata", func(t *testing.T) { 186 block := protoutil.NewBlock(0, nil) 187 block.Metadata = nil 188 _, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_ORDERER) 189 assert.Error(t, err, "Expected error with nil metadata") 190 assert.Contains(t, err.Error(), "no metadata in block") 191 }) 192 t.Run("no metadata at index", func(t *testing.T) { 193 block := protoutil.NewBlock(0, nil) 194 block.Metadata.Metadata = [][]byte{{1, 2, 3}} 195 _, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_LAST_CONFIG) 196 assert.Error(t, err, "Expected error with nil metadata") 197 assert.Contains(t, err.Error(), "no metadata at index") 198 }) 199 t.Run("malformed metadata", func(t *testing.T) { 200 block := protoutil.NewBlock(0, nil) 201 block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = []byte("bad metadata") 202 _, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_ORDERER) 203 assert.Error(t, err, "Expected error with malformed metadata") 204 assert.Contains(t, err.Error(), "error unmarshaling metadata at index [ORDERER]") 205 assert.Panics(t, func() { 206 _ = protoutil.GetMetadataFromBlockOrPanic(block, cb.BlockMetadataIndex_ORDERER) 207 }, "Expected panic with malformed metadata") 208 }) 209 } 210 211 func TestGetConsenterkMetadataFromBlock(t *testing.T) { 212 var cases = []struct { 213 name string 214 value []byte 215 signatures []byte 216 orderer []byte 217 pass bool 218 }{ 219 { 220 name: "empty", 221 value: nil, 222 signatures: nil, 223 orderer: nil, 224 pass: true, 225 }, 226 { 227 name: "signature only", 228 value: []byte("hello"), 229 signatures: protoutil.MarshalOrPanic(&cb.Metadata{ 230 Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{ 231 ConsenterMetadata: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("hello")}), 232 }), 233 }), 234 orderer: nil, 235 pass: true, 236 }, 237 { 238 name: "orderer only", 239 value: []byte("hello"), 240 signatures: nil, 241 orderer: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("hello")}), 242 pass: true, 243 }, 244 { 245 name: "both signatures and orderer", 246 value: []byte("hello"), 247 signatures: protoutil.MarshalOrPanic(&cb.Metadata{ 248 Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{ 249 ConsenterMetadata: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("hello")}), 250 }), 251 }), 252 orderer: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("hello")}), 253 pass: true, 254 }, 255 { 256 name: "malformed OrdererBlockMetadata", 257 signatures: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("malformed")}), 258 orderer: nil, 259 pass: false, 260 }, 261 } 262 263 for _, test := range cases { 264 block := protoutil.NewBlock(0, nil) 265 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = test.signatures 266 block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = test.orderer 267 result, err := protoutil.GetConsenterMetadataFromBlock(block) 268 269 if test.pass { 270 require.NoError(t, err) 271 require.Equal(t, result.Value, test.value) 272 } else { 273 require.Error(t, err) 274 } 275 } 276 } 277 278 func TestInitBlockMeta(t *testing.T) { 279 // block with no metadata 280 block := &cb.Block{} 281 protoutil.InitBlockMetadata(block) 282 // should have 3 entries 283 assert.Equal(t, 5, len(block.Metadata.Metadata), "Expected block to have 5 metadata entries") 284 285 // block with a single entry 286 block = &cb.Block{ 287 Metadata: &cb.BlockMetadata{}, 288 } 289 block.Metadata.Metadata = append(block.Metadata.Metadata, []byte{}) 290 protoutil.InitBlockMetadata(block) 291 // should have 3 entries 292 assert.Equal(t, 5, len(block.Metadata.Metadata), "Expected block to have 5 metadata entries") 293 } 294 295 func TestCopyBlockMetadata(t *testing.T) { 296 srcBlock := protoutil.NewBlock(0, nil) 297 dstBlock := &cb.Block{} 298 299 metadata, _ := proto.Marshal(&cb.Metadata{ 300 Value: []byte("orderer metadata"), 301 }) 302 srcBlock.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = metadata 303 protoutil.CopyBlockMetadata(srcBlock, dstBlock) 304 305 // check that the copy worked 306 assert.Equal(t, len(srcBlock.Metadata.Metadata), len(dstBlock.Metadata.Metadata), 307 "Expected target block to have same number of metadata entries after copy") 308 assert.Equal(t, metadata, dstBlock.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER], 309 "Unexpected metadata from target block") 310 } 311 312 func TestGetLastConfigIndexFromBlock(t *testing.T) { 313 index := uint64(2) 314 block := protoutil.NewBlock(0, nil) 315 316 t.Run("block with last config metadata in signatures field", func(t *testing.T) { 317 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{ 318 Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{ 319 LastConfig: &cb.LastConfig{Index: 2}, 320 }), 321 }) 322 result, err := protoutil.GetLastConfigIndexFromBlock(block) 323 assert.NoError(t, err, "Unexpected error returning last config index") 324 assert.Equal(t, index, result, "Unexpected last config index returned from block") 325 result = protoutil.GetLastConfigIndexFromBlockOrPanic(block) 326 assert.Equal(t, index, result, "Unexpected last config index returned from block") 327 }) 328 329 t.Run("block with malformed signatures", func(t *testing.T) { 330 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = []byte("apple") 331 _, err := protoutil.GetLastConfigIndexFromBlock(block) 332 assert.Error(t, err) 333 assert.Contains(t, err.Error(), "failed to retrieve metadata: error unmarshaling metadata at index [SIGNATURES]") 334 }) 335 336 t.Run("block with malformed orderer block metadata", func(t *testing.T) { 337 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("banana")}) 338 _, err := protoutil.GetLastConfigIndexFromBlock(block) 339 assert.Error(t, err) 340 assert.Contains(t, err.Error(), "failed to unmarshal orderer block metadata") 341 }) 342 343 // TODO: FAB-15864 remove the tests below when we stop supporting upgrade from 344 // pre-1.4.1 orderer 345 t.Run("block with deprecated (pre-1.4.1) last config", func(t *testing.T) { 346 block = protoutil.NewBlock(0, nil) 347 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&cb.Metadata{ 348 Value: protoutil.MarshalOrPanic(&cb.LastConfig{ 349 Index: index, 350 }), 351 }) 352 result, err := protoutil.GetLastConfigIndexFromBlock(block) 353 assert.NoError(t, err, "Unexpected error returning last config index") 354 assert.Equal(t, index, result, "Unexpected last config index returned from block") 355 result = protoutil.GetLastConfigIndexFromBlockOrPanic(block) 356 assert.Equal(t, index, result, "Unexpected last config index returned from block") 357 }) 358 359 t.Run("malformed metadata", func(t *testing.T) { 360 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = []byte("bad metadata") 361 _, err := protoutil.GetLastConfigIndexFromBlock(block) 362 assert.Error(t, err) 363 assert.Contains(t, err.Error(), "failed to retrieve metadata: error unmarshaling metadata at index [LAST_CONFIG]") 364 }) 365 366 t.Run("malformed last config", func(t *testing.T) { 367 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&cb.Metadata{ 368 Value: []byte("bad last config"), 369 }) 370 _, err := protoutil.GetLastConfigIndexFromBlock(block) 371 assert.Error(t, err, "Expected error with malformed last config metadata") 372 assert.Contains(t, err.Error(), "error unmarshaling LastConfig") 373 assert.Panics(t, func() { 374 _ = protoutil.GetLastConfigIndexFromBlockOrPanic(block) 375 }, "Expected panic with malformed last config metadata") 376 }) 377 }