github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/channelinfo_provider_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kvledger
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  	"testing"
    15  
    16  	"github.com/golang/protobuf/proto"
    17  	"github.com/hechain20/hechain/common/channelconfig"
    18  	"github.com/hechain20/hechain/common/configtx/test"
    19  	"github.com/hechain20/hechain/common/ledger/blkstorage"
    20  	"github.com/hechain20/hechain/common/ledger/testutil"
    21  	"github.com/hechain20/hechain/common/metrics/disabled"
    22  	"github.com/hechain20/hechain/core/ledger"
    23  	"github.com/hechain20/hechain/core/ledger/mock"
    24  	"github.com/hechain20/hechain/protoutil"
    25  	"github.com/hyperledger/fabric-config/protolator"
    26  	cb "github.com/hyperledger/fabric-protos-go/common"
    27  	pb "github.com/hyperledger/fabric-protos-go/peer"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestNamespacesAndCollections(t *testing.T) {
    32  	channelName := "testnamespacesandcollections"
    33  	basePath, err := ioutil.TempDir("", "testchannelinfoprovider")
    34  	require.NoError(t, err)
    35  	defer os.RemoveAll(basePath)
    36  	blkStoreProvider, blkStore := openBlockStorage(t, channelName, basePath)
    37  	defer blkStoreProvider.Close()
    38  
    39  	// add genesis block and another config block so that we can retrieve MSPIDs
    40  	// 3 orgs/MSPIDs are added: SampleOrg/SampleOrg, org1/Org1MSP, org2/Org2MSP
    41  	genesisBlock, err := test.MakeGenesisBlock(channelName)
    42  	require.NoError(t, err)
    43  	require.NoError(t, blkStore.AddBlock(genesisBlock))
    44  	orgGroups := createTestOrgGroups(t)
    45  	config := getConfigFromBlock(genesisBlock)
    46  	config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups["org1"] = orgGroups["org1"]
    47  	config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups["org2"] = orgGroups["org2"]
    48  	configEnv := getEnvelopeFromConfig(channelName, config)
    49  	configBlock := newBlock([]*cb.Envelope{configEnv}, 1, 1, protoutil.BlockHeaderHash(genesisBlock.Header))
    50  	require.NoError(t, blkStore.AddBlock(configBlock))
    51  
    52  	// prepare fakeDeployedCCInfoProvider to create mocked test data
    53  	deployedccInfo := map[string]*ledger.DeployedChaincodeInfo{
    54  		"cc1": {
    55  			Name:                        "cc1",
    56  			Version:                     "version",
    57  			Hash:                        []byte("cc1-hash"),
    58  			ExplicitCollectionConfigPkg: prepareCollectionConfigPackage([]string{"collectionA", "collectionB"}),
    59  		},
    60  		"cc2": {
    61  			Name:    "cc2",
    62  			Version: "version",
    63  			Hash:    []byte("cc2-hash"),
    64  		},
    65  	}
    66  	fakeDeployedCCInfoProvider := &mock.DeployedChaincodeInfoProvider{}
    67  	fakeDeployedCCInfoProvider.NamespacesReturns([]string{"_lifecycle", "lscc"})
    68  	fakeDeployedCCInfoProvider.AllChaincodesInfoReturns(deployedccInfo, nil)
    69  	fakeDeployedCCInfoProvider.GenerateImplicitCollectionForOrgStub = func(mspID string) *pb.StaticCollectionConfig {
    70  		return &pb.StaticCollectionConfig{
    71  			Name: fmt.Sprintf("_implicit_org_%s", mspID),
    72  		}
    73  	}
    74  
    75  	// verify NamespacesAndCollections
    76  	channelInfoProvider := &channelInfoProvider{channelName, blkStore, fakeDeployedCCInfoProvider}
    77  	expectedNamespacesAndColls := map[string][]string{
    78  		"cc1":        {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP", "_implicit_org_SampleOrg", "collectionA", "collectionB"},
    79  		"cc2":        {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP", "_implicit_org_SampleOrg"},
    80  		"_lifecycle": {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP", "_implicit_org_SampleOrg"},
    81  		"lscc":       {},
    82  		"":           {},
    83  	}
    84  	namespacesAndColls, err := channelInfoProvider.NamespacesAndCollections(nil)
    85  	require.NoError(t, err)
    86  	require.Equal(t, len(expectedNamespacesAndColls), len(namespacesAndColls))
    87  	for ns, colls := range expectedNamespacesAndColls {
    88  		require.ElementsMatch(t, colls, namespacesAndColls[ns])
    89  	}
    90  }
    91  
    92  // TestGetAllMSPIDs verifies getAllMSPIDs by adding and removing organizations to the channel config.
    93  func TestGetAllMSPIDs(t *testing.T) {
    94  	channelName := "testgetallmspids"
    95  	basePath, err := ioutil.TempDir("", "testchannelinfoprovider")
    96  	require.NoError(t, err)
    97  	defer os.RemoveAll(basePath)
    98  
    99  	blkStoreProvider, blkStore := openBlockStorage(t, channelName, basePath)
   100  	defer blkStoreProvider.Close()
   101  	channelInfoProvider := &channelInfoProvider{channelName, blkStore, nil}
   102  
   103  	var block *cb.Block
   104  	var configBlock *cb.Block
   105  	lastBlockNum := uint64(0)
   106  	lastConfigBlockNum := uint64(0)
   107  
   108  	// verify GetAllMSPIDs in a corner case where the channel has no block
   109  	verifyGetAllMSPIDs(t, channelInfoProvider, nil)
   110  
   111  	// add genesis block and verify GetAllMSPIDs when the channel has only genesis block
   112  	// the genesis block is created for org "SampleOrg" with MSPID "SampleOrg"
   113  	configBlock, err = test.MakeGenesisBlock(channelName)
   114  	require.NoError(t, err)
   115  	require.NoError(t, blkStore.AddBlock(configBlock))
   116  	verifyGetAllMSPIDs(t, channelInfoProvider, []string{"SampleOrg"})
   117  
   118  	// add some blocks and verify GetAllMSPIDs
   119  	block = configBlock
   120  	for i := 0; i < 3; i++ {
   121  		lastBlockNum++
   122  		block = newBlock([]*cb.Envelope{}, lastBlockNum, lastConfigBlockNum, protoutil.BlockHeaderHash(block.Header))
   123  		require.NoError(t, blkStore.AddBlock(block))
   124  	}
   125  	verifyGetAllMSPIDs(t, channelInfoProvider, []string{"SampleOrg"})
   126  
   127  	// create test org groups, update the config by adding org1 (Org1MSP) and org2 (Org2MSP)
   128  	orgGroups := createTestOrgGroups(t)
   129  	config := getConfigFromBlock(configBlock)
   130  	config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups["org1"] = orgGroups["org1"]
   131  	config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups["org2"] = orgGroups["org2"]
   132  
   133  	// add the config block and verify GetAllMSPIDs
   134  	lastBlockNum++
   135  	lastConfigBlockNum = lastBlockNum
   136  	configEnv := getEnvelopeFromConfig(channelName, config)
   137  	configBlock = newBlock([]*cb.Envelope{configEnv}, lastBlockNum, lastConfigBlockNum, protoutil.BlockHeaderHash(block.Header))
   138  	require.NoError(t, blkStore.AddBlock(configBlock))
   139  	verifyGetAllMSPIDs(t, channelInfoProvider, []string{"Org1MSP", "Org2MSP", "SampleOrg"})
   140  
   141  	// update the config by removing "org1"
   142  	config = getConfigFromBlock(configBlock)
   143  	delete(config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups, "org1")
   144  
   145  	// add the config block and verify GetAllMSPIDs
   146  	lastBlockNum++
   147  	lastConfigBlockNum = lastBlockNum
   148  	configEnv = getEnvelopeFromConfig(channelName, config)
   149  	configBlock = newBlock([]*cb.Envelope{configEnv}, lastBlockNum, lastConfigBlockNum, protoutil.BlockHeaderHash(configBlock.Header))
   150  	require.NoError(t, blkStore.AddBlock(configBlock))
   151  	verifyGetAllMSPIDs(t, channelInfoProvider, []string{"Org1MSP", "Org2MSP", "SampleOrg"})
   152  
   153  	// add some blocks and verify GetAllMSPIDs
   154  	block = configBlock
   155  	for i := 0; i < 2; i++ {
   156  		lastBlockNum++
   157  		block = newBlock([]*cb.Envelope{}, lastBlockNum, lastConfigBlockNum, protoutil.BlockHeaderHash(block.Header))
   158  		require.NoError(t, blkStore.AddBlock(block))
   159  	}
   160  	verifyGetAllMSPIDs(t, channelInfoProvider, []string{"Org1MSP", "Org2MSP", "SampleOrg"})
   161  
   162  	// verify the orgs in most recent config block
   163  	lastConfigBlock, err := channelInfoProvider.mostRecentConfigBlockAsOf(lastBlockNum)
   164  	require.NoError(t, err)
   165  	config = getConfigFromBlock(lastConfigBlock)
   166  	require.Equal(t, 2, len(config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups))
   167  	require.Contains(t, config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups, "SampleOrg")
   168  	require.Contains(t, config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups, "org2")
   169  }
   170  
   171  func TestGetAllMSPIDs_NegativeTests(t *testing.T) {
   172  	channelName := "testgetallmspidsnegativetests"
   173  	basePath, err := ioutil.TempDir("", "testchannelinfoprovider_negativetests")
   174  	require.NoError(t, err)
   175  	defer os.RemoveAll(basePath)
   176  
   177  	blkStoreProvider, blkStore := openBlockStorage(t, channelName, basePath)
   178  	defer blkStoreProvider.Close()
   179  	channelInfoProvider := &channelInfoProvider{channelName, blkStore, nil}
   180  
   181  	var configBlock *cb.Block
   182  	lastBlockNum := uint64(0)
   183  	lastConfigBlockNum := uint64(0)
   184  
   185  	// add genesis block
   186  	configBlock, err = test.MakeGenesisBlock(channelName)
   187  	require.NoError(t, err)
   188  	require.NoError(t, blkStore.AddBlock(configBlock))
   189  
   190  	// test ExtractMSPIDsForApplicationOrgs error by having a malformed config block
   191  	lastBlockNum++
   192  	lastConfigBlockNum++
   193  	configBlock = newBlock([]*cb.Envelope{}, lastBlockNum, lastConfigBlockNum, protoutil.BlockHeaderHash(configBlock.Header))
   194  	require.NoError(t, blkStore.AddBlock(configBlock))
   195  	_, err = channelInfoProvider.getAllMSPIDs()
   196  	require.EqualError(t, err, "malformed configuration block: envelope index out of bounds")
   197  
   198  	// test RetrieveBlockByNumber error by using a non-existent block num for config block index
   199  	lastBlockNum++
   200  	lastConfigBlockNum++
   201  	configBlock = newBlock(nil, lastBlockNum, lastBlockNum+1, protoutil.BlockHeaderHash(configBlock.Header))
   202  	require.NoError(t, blkStore.AddBlock(configBlock))
   203  	_, err = channelInfoProvider.getAllMSPIDs()
   204  	require.EqualError(t, err, "no such block number [3] in index")
   205  
   206  	// test GetLastConfigIndexFromBlock error by using invalid bytes for LastConfig metadata value
   207  	lastBlockNum++
   208  	lastConfigBlockNum++
   209  	configBlock = newBlock(nil, lastBlockNum, lastConfigBlockNum, protoutil.BlockHeaderHash(configBlock.Header))
   210  	configBlock.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = []byte("invalid_bytes")
   211  	require.NoError(t, blkStore.AddBlock(configBlock))
   212  	_, err = channelInfoProvider.getAllMSPIDs()
   213  	require.EqualError(t, err, "failed to retrieve metadata: error unmarshalling metadata at index [SIGNATURES]: unexpected EOF")
   214  
   215  	// test RetrieveBlockByNumber error (before calling GetLastConfigIndexFromBlock) by closing block store provider
   216  	blkStoreProvider.Close()
   217  	_, err = channelInfoProvider.getAllMSPIDs()
   218  	require.Contains(t, err.Error(), "leveldb: closed")
   219  }
   220  
   221  func openBlockStorage(t *testing.T, channelName string, basePath string) (*blkstorage.BlockStoreProvider, *blkstorage.BlockStore) {
   222  	blkStoreProvider, err := blkstorage.NewProvider(
   223  		blkstorage.NewConf(basePath, maxBlockFileSize),
   224  		&blkstorage.IndexConfig{AttrsToIndex: attrsToIndex},
   225  		&disabled.Provider{},
   226  	)
   227  	require.NoError(t, err)
   228  	blkStore, err := blkStoreProvider.Open(channelName)
   229  	require.NoError(t, err)
   230  	return blkStoreProvider, blkStore
   231  }
   232  
   233  func verifyGetAllMSPIDs(t *testing.T, channelInfoProvider *channelInfoProvider, expectedMSPIDs []string) {
   234  	mspids, err := channelInfoProvider.getAllMSPIDs()
   235  	require.NoError(t, err)
   236  	require.ElementsMatch(t, expectedMSPIDs, mspids)
   237  }
   238  
   239  func newBlock(env []*cb.Envelope, blockNum uint64, lastConfigBlockNum uint64, previousHash []byte) *cb.Block {
   240  	block := testutil.NewBlock(env, blockNum, previousHash)
   241  	block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{
   242  		Value: protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{
   243  			LastConfig: &cb.LastConfig{Index: lastConfigBlockNum},
   244  		}),
   245  	})
   246  	return block
   247  }
   248  
   249  func getConfigFromBlock(block *cb.Block) *cb.Config {
   250  	blockDataEnvelope := &cb.Envelope{}
   251  	err := proto.Unmarshal(block.Data.Data[0], blockDataEnvelope)
   252  	if err != nil {
   253  		panic(err)
   254  	}
   255  
   256  	blockDataPayload := &cb.Payload{}
   257  	err = proto.Unmarshal(blockDataEnvelope.Payload, blockDataPayload)
   258  	if err != nil {
   259  		panic(err)
   260  	}
   261  
   262  	config := &cb.ConfigEnvelope{}
   263  	err = proto.Unmarshal(blockDataPayload.Data, config)
   264  	if err != nil {
   265  		panic(err)
   266  	}
   267  
   268  	return config.Config
   269  }
   270  
   271  func getEnvelopeFromConfig(channelName string, config *cb.Config) *cb.Envelope {
   272  	return &cb.Envelope{
   273  		Payload: protoutil.MarshalOrPanic(&cb.Payload{
   274  			Header: &cb.Header{
   275  				ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{
   276  					ChannelId: channelName,
   277  					Type:      int32(cb.HeaderType_CONFIG),
   278  				}),
   279  			},
   280  			Data: protoutil.MarshalOrPanic(&cb.ConfigEnvelope{
   281  				Config: config,
   282  			}),
   283  		}),
   284  	}
   285  }
   286  
   287  // createTestOrgGroups returns application org ConfigGroups based on test_configblock.json.
   288  // The config block contains the following organizations(MSPIDs): org1(Org1MSP) and org2(Org2MSP)
   289  func createTestOrgGroups(t *testing.T) map[string]*cb.ConfigGroup {
   290  	blockData, err := ioutil.ReadFile("testdata/test_configblock.json")
   291  	require.NoError(t, err)
   292  	block := &cb.Block{}
   293  	require.NoError(t, protolator.DeepUnmarshalJSON(bytes.NewBuffer(blockData), block))
   294  	config := getConfigFromBlock(block)
   295  	return config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups
   296  }
   297  
   298  func prepareCollectionConfigPackage(collNames []string) *pb.CollectionConfigPackage {
   299  	collConfigs := make([]*pb.CollectionConfig, len(collNames))
   300  	for i, name := range collNames {
   301  		collConfigs[i] = &pb.CollectionConfig{
   302  			Payload: &pb.CollectionConfig_StaticCollectionConfig{
   303  				StaticCollectionConfig: &pb.StaticCollectionConfig{
   304  					Name: name,
   305  				},
   306  			},
   307  		}
   308  	}
   309  	return &pb.CollectionConfigPackage{Config: collConfigs}
   310  }