github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/common/configtx/test" 19 "github.com/osdi23p228/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 TestGetChannelIDFromBlockBytes(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 assert.NoError(t, err) 79 cid, err := protoutil.GetChannelIDFromBlockBytes(bytes) 80 assert.NoError(t, err) 81 assert.Equal(t, testChannelID, cid, "Failed to return expected chain ID") 82 83 // bad block bytes 84 _, err = protoutil.GetChannelIDFromBlockBytes([]byte("bad block")) 85 assert.Error(t, err, "Expected error with malformed block bytes") 86 } 87 88 func TestGetChannelIDFromBlock(t *testing.T) { 89 var err error 90 var gb *common.Block 91 var cid string 92 93 // nil block 94 _, err = protoutil.GetChannelIDFromBlock(gb) 95 assert.Error(t, err, "Expected error getting channel id from nil block") 96 97 gb, err = configtxtest.MakeGenesisBlock(testChannelID) 98 assert.NoError(t, err, "Failed to create test configuration block") 99 100 cid, err = protoutil.GetChannelIDFromBlock(gb) 101 assert.NoError(t, err, "Failed to get chain ID from block") 102 assert.Equal(t, testChannelID, cid, "Failed to return expected chain ID") 103 104 // missing data 105 badBlock := gb 106 badBlock.Data = nil 107 _, err = protoutil.GetChannelIDFromBlock(badBlock) 108 assert.Error(t, err, "Expected error with missing block data") 109 110 // no envelope 111 badBlock = &cb.Block{ 112 Data: &cb.BlockData{ 113 Data: [][]byte{[]byte("bad envelope")}, 114 }, 115 } 116 _, err = protoutil.GetChannelIDFromBlock(badBlock) 117 assert.Error(t, err, "Expected error with no envelope in data") 118 119 // bad payload 120 env, _ := proto.Marshal(&cb.Envelope{ 121 Payload: []byte("bad payload"), 122 }) 123 badBlock = &cb.Block{ 124 Data: &cb.BlockData{ 125 Data: [][]byte{env}, 126 }, 127 } 128 _, err = protoutil.GetChannelIDFromBlock(badBlock) 129 assert.Error(t, err, "Expected error - malformed payload") 130 131 // bad channel header 132 payload, _ := proto.Marshal(&cb.Payload{ 133 Header: &cb.Header{ 134 ChannelHeader: []byte("bad header"), 135 }, 136 }) 137 env, _ = proto.Marshal(&cb.Envelope{ 138 Payload: payload, 139 }) 140 badBlock = &cb.Block{ 141 Data: &cb.BlockData{ 142 Data: [][]byte{env}, 143 }, 144 } 145 _, err = protoutil.GetChannelIDFromBlock(badBlock) 146 assert.Error(t, err, "Expected error with malformed channel header") 147 148 // nil payload header 149 payload, _ = proto.Marshal(&cb.Payload{}) 150 env, _ = proto.Marshal(&cb.Envelope{ 151 Payload: payload, 152 }) 153 badBlock = &cb.Block{ 154 Data: &cb.BlockData{ 155 Data: [][]byte{env}, 156 }, 157 } 158 _, err = protoutil.GetChannelIDFromBlock(badBlock) 159 assert.Error(t, err, "Expected error when payload header is nil") 160 } 161 162 func TestGetBlockFromBlockBytes(t *testing.T) { 163 testChainID := "myuniquetestchainid" 164 gb, err := configtxtest.MakeGenesisBlock(testChainID) 165 assert.NoError(t, err, "Failed to create test configuration block") 166 blockBytes, err := protoutil.Marshal(gb) 167 assert.NoError(t, err, "Failed to marshal block") 168 _, err = protoutil.UnmarshalBlock(blockBytes) 169 assert.NoError(t, err, "to get block from block bytes") 170 171 // bad block bytes 172 _, err = protoutil.UnmarshalBlock([]byte("bad block")) 173 assert.Error(t, err, "Expected error for malformed block bytes") 174 } 175 176 func TestGetMetadataFromBlock(t *testing.T) { 177 t.Run("new block", func(t *testing.T) { 178 block := protoutil.NewBlock(0, nil) 179 md, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_ORDERER) 180 assert.NoError(t, err, "Unexpected error extracting metadata from new block") 181 assert.Nil(t, md.Value, "Expected metadata field value to be nil") 182 assert.Equal(t, 0, len(md.Value), "Expected length of metadata field value to be 0") 183 md = protoutil.GetMetadataFromBlockOrPanic(block, cb.BlockMetadataIndex_ORDERER) 184 assert.NotNil(t, md, "Expected to get metadata from block") 185 }) 186 t.Run("no metadata", func(t *testing.T) { 187 block := protoutil.NewBlock(0, nil) 188 block.Metadata = nil 189 _, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_ORDERER) 190 assert.Error(t, err, "Expected error with nil metadata") 191 assert.Contains(t, err.Error(), "no metadata in block") 192 }) 193 t.Run("no metadata at index", func(t *testing.T) { 194 block := protoutil.NewBlock(0, nil) 195 block.Metadata.Metadata = [][]byte{{1, 2, 3}} 196 _, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_LAST_CONFIG) 197 assert.Error(t, err, "Expected error with nil metadata") 198 assert.Contains(t, err.Error(), "no metadata at index") 199 }) 200 t.Run("malformed metadata", func(t *testing.T) { 201 block := protoutil.NewBlock(0, nil) 202 block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = []byte("bad metadata") 203 _, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_ORDERER) 204 assert.Error(t, err, "Expected error with malformed metadata") 205 assert.Contains(t, err.Error(), "error unmarshaling metadata at index [ORDERER]") 206 assert.Panics(t, func() { 207 _ = protoutil.GetMetadataFromBlockOrPanic(block, cb.BlockMetadataIndex_ORDERER) 208 }, "Expected panic with malformed metadata") 209 }) 210 } 211 212 func TestGetConsenterMetadataFromBlock(t *testing.T) { 213 var cases = []struct { 214 name string 215 value []byte 216 signatures []byte 217 orderer []byte 218 pass bool 219 }{ 220 { 221 name: "empty", 222 value: nil, 223 signatures: nil, 224 orderer: nil, 225 pass: true, 226 }, 227 { 228 name: "signature only", 229 value: []byte("hello"), 230 signatures: protoutil.MarshalOrPanic(&cb.Metadata{ 231 Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{ 232 ConsenterMetadata: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("hello")}), 233 }), 234 }), 235 orderer: nil, 236 pass: true, 237 }, 238 { 239 name: "orderer only", 240 value: []byte("hello"), 241 signatures: nil, 242 orderer: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("hello")}), 243 pass: true, 244 }, 245 { 246 name: "both signatures and orderer", 247 value: []byte("hello"), 248 signatures: protoutil.MarshalOrPanic(&cb.Metadata{ 249 Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{ 250 ConsenterMetadata: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("hello")}), 251 }), 252 }), 253 orderer: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("hello")}), 254 pass: true, 255 }, 256 { 257 name: "malformed OrdererBlockMetadata", 258 signatures: protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("malformed")}), 259 orderer: nil, 260 pass: false, 261 }, 262 } 263 264 for _, test := range cases { 265 block := protoutil.NewBlock(0, nil) 266 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = test.signatures 267 block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = test.orderer 268 result, err := protoutil.GetConsenterMetadataFromBlock(block) 269 270 if test.pass { 271 require.NoError(t, err) 272 require.Equal(t, result.Value, test.value) 273 } else { 274 require.Error(t, err) 275 } 276 } 277 } 278 279 func TestInitBlockMeta(t *testing.T) { 280 // block with no metadata 281 block := &cb.Block{} 282 protoutil.InitBlockMetadata(block) 283 // should have 3 entries 284 assert.Equal(t, 5, len(block.Metadata.Metadata), "Expected block to have 5 metadata entries") 285 286 // block with a single entry 287 block = &cb.Block{ 288 Metadata: &cb.BlockMetadata{}, 289 } 290 block.Metadata.Metadata = append(block.Metadata.Metadata, []byte{}) 291 protoutil.InitBlockMetadata(block) 292 // should have 3 entries 293 assert.Equal(t, 5, len(block.Metadata.Metadata), "Expected block to have 5 metadata entries") 294 } 295 296 func TestCopyBlockMetadata(t *testing.T) { 297 srcBlock := protoutil.NewBlock(0, nil) 298 dstBlock := &cb.Block{} 299 300 metadata, _ := proto.Marshal(&cb.Metadata{ 301 Value: []byte("orderer metadata"), 302 }) 303 srcBlock.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = metadata 304 protoutil.CopyBlockMetadata(srcBlock, dstBlock) 305 306 // check that the copy worked 307 assert.Equal(t, len(srcBlock.Metadata.Metadata), len(dstBlock.Metadata.Metadata), 308 "Expected target block to have same number of metadata entries after copy") 309 assert.Equal(t, metadata, dstBlock.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER], 310 "Unexpected metadata from target block") 311 } 312 313 func TestGetLastConfigIndexFromBlock(t *testing.T) { 314 index := uint64(2) 315 block := protoutil.NewBlock(0, nil) 316 317 t.Run("block with last config metadata in signatures field", func(t *testing.T) { 318 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{ 319 Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{ 320 LastConfig: &cb.LastConfig{Index: 2}, 321 }), 322 }) 323 result, err := protoutil.GetLastConfigIndexFromBlock(block) 324 assert.NoError(t, err, "Unexpected error returning last config index") 325 assert.Equal(t, index, result, "Unexpected last config index returned from block") 326 result = protoutil.GetLastConfigIndexFromBlockOrPanic(block) 327 assert.Equal(t, index, result, "Unexpected last config index returned from block") 328 }) 329 330 t.Run("block with malformed signatures", func(t *testing.T) { 331 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = []byte("apple") 332 _, err := protoutil.GetLastConfigIndexFromBlock(block) 333 assert.Error(t, err) 334 assert.Contains(t, err.Error(), "failed to retrieve metadata: error unmarshaling metadata at index [SIGNATURES]") 335 }) 336 337 t.Run("block with malformed orderer block metadata", func(t *testing.T) { 338 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{Value: []byte("banana")}) 339 _, err := protoutil.GetLastConfigIndexFromBlock(block) 340 assert.Error(t, err) 341 assert.Contains(t, err.Error(), "failed to unmarshal orderer block metadata") 342 }) 343 344 // TODO: FAB-15864 remove the tests below when we stop supporting upgrade from 345 // pre-1.4.1 orderer 346 t.Run("block with deprecated (pre-1.4.1) last config", func(t *testing.T) { 347 block = protoutil.NewBlock(0, nil) 348 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&cb.Metadata{ 349 Value: protoutil.MarshalOrPanic(&cb.LastConfig{ 350 Index: index, 351 }), 352 }) 353 result, err := protoutil.GetLastConfigIndexFromBlock(block) 354 assert.NoError(t, err, "Unexpected error returning last config index") 355 assert.Equal(t, index, result, "Unexpected last config index returned from block") 356 result = protoutil.GetLastConfigIndexFromBlockOrPanic(block) 357 assert.Equal(t, index, result, "Unexpected last config index returned from block") 358 }) 359 360 t.Run("malformed metadata", func(t *testing.T) { 361 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = []byte("bad metadata") 362 _, err := protoutil.GetLastConfigIndexFromBlock(block) 363 assert.Error(t, err) 364 assert.Contains(t, err.Error(), "failed to retrieve metadata: error unmarshaling metadata at index [LAST_CONFIG]") 365 }) 366 367 t.Run("malformed last config", func(t *testing.T) { 368 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&cb.Metadata{ 369 Value: []byte("bad last config"), 370 }) 371 _, err := protoutil.GetLastConfigIndexFromBlock(block) 372 assert.Error(t, err, "Expected error with malformed last config metadata") 373 assert.Contains(t, err.Error(), "error unmarshaling LastConfig") 374 assert.Panics(t, func() { 375 _ = protoutil.GetLastConfigIndexFromBlockOrPanic(block) 376 }, "Expected panic with malformed last config metadata") 377 }) 378 }