github.com/kaituanwang/hyperledger@v2.0.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  }