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 }