github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/discovery/endorsement/endorsement_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package endorsement 8 9 import ( 10 "fmt" 11 "testing" 12 13 "github.com/hechain20/hechain/common/policydsl" 14 common2 "github.com/hyperledger/fabric-protos-go/common" 15 16 "github.com/golang/protobuf/proto" 17 "github.com/hechain20/hechain/common/chaincode" 18 "github.com/hechain20/hechain/common/policies" 19 "github.com/hechain20/hechain/common/policies/inquire" 20 "github.com/hechain20/hechain/gossip/api" 21 "github.com/hechain20/hechain/gossip/common" 22 "github.com/hechain20/hechain/gossip/discovery" 23 "github.com/hechain20/hechain/protoutil" 24 discoveryprotos "github.com/hyperledger/fabric-protos-go/discovery" 25 "github.com/hyperledger/fabric-protos-go/gossip" 26 "github.com/hyperledger/fabric-protos-go/msp" 27 "github.com/hyperledger/fabric-protos-go/peer" 28 "github.com/pkg/errors" 29 "github.com/stretchr/testify/mock" 30 "github.com/stretchr/testify/require" 31 ) 32 33 var pkiID2MSPID = map[string]string{ 34 "p0": "Org0MSP", 35 "p1": "Org1MSP", 36 "p2": "Org2MSP", 37 "p3": "Org3MSP", 38 "p4": "Org4MSP", 39 "p5": "Org5MSP", 40 "p6": "Org6MSP", 41 "p7": "Org7MSP", 42 "p8": "Org8MSP", 43 "p9": "Org9MSP", 44 "p10": "Org10MSP", 45 "p11": "Org11MSP", 46 "p12": "Org12MSP", 47 "p13": "Org13MSP", 48 "p14": "Org14MSP", 49 "p15": "Org15MSP", 50 } 51 52 func TestPeersForEndorsement(t *testing.T) { 53 extractPeers := func(desc *discoveryprotos.EndorsementDescriptor) map[string]struct{} { 54 res := map[string]struct{}{} 55 for _, endorsers := range desc.EndorsersByGroups { 56 for _, p := range endorsers.Peers { 57 res[string(p.Identity)] = struct{}{} 58 require.Equal(t, string(p.Identity), string(p.MembershipInfo.Payload)) 59 require.Equal(t, string(p.Identity), string(p.StateInfo.Payload)) 60 } 61 } 62 return res 63 } 64 cc := "chaincode" 65 g := &gossipMock{} 66 pf := &policyFetcherMock{} 67 ccWithMissingPolicy := "chaincodeWithMissingPolicy" 68 channel := common.ChannelID("test") 69 alivePeers := peerSet{ 70 newPeer(0), 71 newPeer(2), 72 newPeer(4), 73 newPeer(6), 74 newPeer(8), 75 newPeer(10), 76 newPeer(11), 77 newPeer(12), 78 } 79 80 identities := identitySet(pkiID2MSPID) 81 82 chanPeers := peerSet{ 83 newPeer(0).withChaincode(cc, "1.0"), 84 newPeer(3).withChaincode(cc, "1.0"), 85 newPeer(6).withChaincode(cc, "1.0"), 86 newPeer(9).withChaincode(cc, "1.0"), 87 newPeer(11).withChaincode(cc, "1.0"), 88 newPeer(12).withChaincode(cc, "1.0"), 89 } 90 g.On("Peers").Return(alivePeers.toMembers()) 91 g.On("IdentityInfo").Return(identities) 92 93 // Scenario I: Policy isn't found 94 t.Run("PolicyNotFound", func(t *testing.T) { 95 pf.On("PoliciesByChaincode", ccWithMissingPolicy).Return(nil).Once() 96 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 97 mf := &metadataFetcher{} 98 mf.On("Metadata").Return(&chaincode.Metadata{ 99 Name: cc, 100 Version: "1.0", 101 }).Once() 102 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 103 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 104 Chaincodes: []*peer.ChaincodeCall{ 105 { 106 Name: ccWithMissingPolicy, 107 }, 108 }, 109 }) 110 require.Nil(t, desc) 111 require.Equal(t, "policy not found", err.Error()) 112 }) 113 114 t.Run("NotEnoughPeers", func(t *testing.T) { 115 // Scenario II: Policy is found but not enough peers to satisfy the policy. 116 // The policy requires a signature from: 117 // p1 and p6, or 118 // p11 x2 (twice), but we only have a single peer in the alive view for p11 119 pb := principalBuilder{} 120 policy := pb.newSet().addPrincipal(peerRole("p1")).addPrincipal(peerRole("p6")). 121 newSet().addPrincipal(peerRole("p11")).addPrincipal(peerRole("p11")).buildPolicy() 122 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 123 mf := &metadataFetcher{} 124 mf.On("Metadata").Return(&chaincode.Metadata{Name: cc, Version: "1.0"}).Once() 125 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 126 pf.On("PoliciesByChaincode", cc).Return(policy).Once() 127 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 128 Chaincodes: []*peer.ChaincodeCall{ 129 { 130 Name: cc, 131 }, 132 }, 133 }) 134 require.Nil(t, desc) 135 require.Equal(t, err.Error(), "no peer combination can satisfy the endorsement policy") 136 }) 137 138 t.Run("DisjointViews", func(t *testing.T) { 139 pb := principalBuilder{} 140 // Scenario III: Policy is found and there are enough peers to satisfy 141 // only 1 type of principal combination: p0 and p6. 142 // However, the combination of a signature from p10 and p12 143 // cannot be satisfied because p10 is not in the channel view but only in the alive view 144 policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p6")). 145 newSet().addPrincipal(peerRole("p10")).addPrincipal(peerRole("p12")).buildPolicy() 146 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 147 mf := &metadataFetcher{} 148 mf.On("Metadata").Return(&chaincode.Metadata{ 149 Name: cc, 150 Version: "1.0", 151 }).Once() 152 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 153 pf.On("PoliciesByChaincode", cc).Return(policy).Once() 154 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 155 Chaincodes: []*peer.ChaincodeCall{ 156 { 157 Name: cc, 158 }, 159 }, 160 }) 161 require.NoError(t, err) 162 require.NotNil(t, desc) 163 require.Len(t, desc.Layouts, 1) 164 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 165 require.Equal(t, map[string]struct{}{ 166 peerIdentityString("p0"): {}, 167 peerIdentityString("p6"): {}, 168 }, extractPeers(desc)) 169 }) 170 171 t.Run("MultipleCombinations", func(t *testing.T) { 172 // Scenario IV: Policy is found and there are enough peers to satisfy 173 // 2 principal combinations: 174 // p0 and p6, or 175 // p12 alone 176 pb := principalBuilder{} 177 policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p6")). 178 newSet().addPrincipal(peerRole("p12")).buildPolicy() 179 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 180 mf := &metadataFetcher{} 181 mf.On("Metadata").Return(&chaincode.Metadata{ 182 Name: cc, 183 Version: "1.0", 184 }).Once() 185 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 186 pf.On("PoliciesByChaincode", cc).Return(policy).Once() 187 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 188 Chaincodes: []*peer.ChaincodeCall{ 189 { 190 Name: cc, 191 }, 192 }, 193 }) 194 require.NoError(t, err) 195 require.NotNil(t, desc) 196 require.Len(t, desc.Layouts, 2) 197 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 198 require.Len(t, desc.Layouts[1].QuantitiesByGroup, 1) 199 require.Equal(t, map[string]struct{}{ 200 peerIdentityString("p0"): {}, 201 peerIdentityString("p6"): {}, 202 peerIdentityString("p12"): {}, 203 }, extractPeers(desc)) 204 }) 205 206 t.Run("WrongVersionInstalled", func(t *testing.T) { 207 // Scenario V: Policy is found, and there are enough peers to satisfy policy combinations, 208 // but all peers have the wrong version installed on them. 209 mf := &metadataFetcher{} 210 mf.On("Metadata").Return(&chaincode.Metadata{ 211 Name: cc, 212 Version: "1.1", 213 }).Once() 214 pb := principalBuilder{} 215 policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p6")). 216 newSet().addPrincipal(peerRole("p12")).buildPolicy() 217 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 218 pf.On("PoliciesByChaincode", cc).Return(policy).Once() 219 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 220 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 221 Chaincodes: []*peer.ChaincodeCall{ 222 { 223 Name: cc, 224 }, 225 }, 226 }) 227 require.Nil(t, desc) 228 require.Equal(t, "required chaincodes are not installed on sufficient peers", err.Error()) 229 230 // Scenario VI: Policy is found, there are enough peers to satisfy policy combinations, 231 // but some peers have the wrong chaincode version, and some don't even have it installed. 232 chanPeers := peerSet{ 233 newPeer(0).withChaincode(cc, "0.6"), 234 newPeer(3).withChaincode(cc, "1.0"), 235 newPeer(6).withChaincode(cc, "1.0"), 236 newPeer(9).withChaincode(cc, "1.0"), 237 newPeer(12), 238 } 239 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 240 pf.On("PoliciesByChaincode", cc).Return(policy).Once() 241 mf.On("Metadata").Return(&chaincode.Metadata{ 242 Name: cc, 243 Version: "1.0", 244 }).Once() 245 desc, err = analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 246 Chaincodes: []*peer.ChaincodeCall{ 247 { 248 Name: cc, 249 }, 250 }, 251 }) 252 require.Nil(t, desc) 253 require.Equal(t, "required chaincodes are not installed on sufficient peers", err.Error()) 254 }) 255 256 t.Run("NoChaincodeMetadataFromLedger", func(t *testing.T) { 257 // Scenario VII: Policy is found, there are enough peers to satisfy the policy, 258 // but the chaincode metadata cannot be fetched from the ledger. 259 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 260 mf := &metadataFetcher{} 261 mf.On("Metadata").Return(nil).Once() 262 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 263 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 264 Chaincodes: []*peer.ChaincodeCall{ 265 { 266 Name: cc, 267 }, 268 }, 269 }) 270 require.Nil(t, desc) 271 require.Equal(t, "No metadata was found for chaincode chaincode in channel test", err.Error()) 272 }) 273 274 t.Run("Collections", func(t *testing.T) { 275 // Scenario VIII: Policy is found and there are enough peers to satisfy 276 // 2 principal combinations: p0 and p6, or p12 alone. 277 // However, the query contains a collection which has a policy that permits only p0 and p12, 278 // and thus - the combination of p0 and p6 is filtered out and we're left with p12 only. 279 collectionOrgs := []*msp.MSPPrincipal{ 280 peerRole("p0"), 281 peerRole("p12"), 282 } 283 col2principals := map[string][]*msp.MSPPrincipal{ 284 "collection": collectionOrgs, 285 } 286 mf := &metadataFetcher{} 287 mf.On("Metadata").Return(&chaincode.Metadata{ 288 Name: cc, 289 Version: "1.0", 290 CollectionsConfig: buildCollectionConfig(col2principals), 291 }).Once() 292 pb := principalBuilder{} 293 policy := pb.newSet().addPrincipal(peerRole("p0")). 294 addPrincipal(peerRole("p6")).newSet(). 295 addPrincipal(peerRole("p12")).buildPolicy() 296 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 297 pf.On("PoliciesByChaincode", cc).Return(policy).Once() 298 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 299 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 300 Chaincodes: []*peer.ChaincodeCall{ 301 { 302 Name: cc, 303 CollectionNames: []string{"collection"}, 304 }, 305 }, 306 }) 307 require.NoError(t, err) 308 require.NotNil(t, desc) 309 require.Len(t, desc.Layouts, 1) 310 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 1) 311 require.Equal(t, map[string]struct{}{ 312 peerIdentityString("p12"): {}, 313 }, extractPeers(desc)) 314 }) 315 316 t.Run("Chaincode2Chaincode I", func(t *testing.T) { 317 // Scenario IX: A chaincode-to-chaincode query is made. 318 // Total organizations are 0, 2, 4, 6, 10, 12 319 // and the endorsement policies of the chaincodes are as follows: 320 // cc1: OR(AND(0, 2), AND(6, 10)) 321 // cc2: AND(6, 10, 12) 322 // cc3: AND(4, 12) 323 // Therefore, the result should be: 4, 6, 10, 12 324 325 chanPeers := peerSet{} 326 for _, id := range []int{0, 2, 4, 6, 10, 12} { 327 peer := newPeer(id).withChaincode("cc1", "1.0").withChaincode("cc2", "1.0").withChaincode("cc3", "1.0") 328 chanPeers = append(chanPeers, peer) 329 } 330 331 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 332 333 mf := &metadataFetcher{} 334 mf.On("Metadata").Return(&chaincode.Metadata{ 335 Name: "cc1", 336 Version: "1.0", 337 }).Once() 338 mf.On("Metadata").Return(&chaincode.Metadata{ 339 Name: "cc2", 340 Version: "1.0", 341 }).Once() 342 mf.On("Metadata").Return(&chaincode.Metadata{ 343 Name: "cc3", 344 Version: "1.0", 345 }).Once() 346 347 pb := principalBuilder{} 348 cc1policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p2")). 349 newSet().addPrincipal(peerRole("p6")).addPrincipal(peerRole("p10")).buildPolicy() 350 351 pf.On("PoliciesByChaincode", "cc1").Return(cc1policy).Once() 352 353 cc2policy := pb.newSet().addPrincipal(peerRole("p6")). 354 addPrincipal(peerRole("p10")).addPrincipal(peerRole("p12")).buildPolicy() 355 pf.On("PoliciesByChaincode", "cc2").Return(cc2policy).Once() 356 357 cc3policy := pb.newSet().addPrincipal(peerRole("p4")). 358 addPrincipal(peerRole("p12")).buildPolicy() 359 pf.On("PoliciesByChaincode", "cc3").Return(cc3policy).Once() 360 361 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 362 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 363 Chaincodes: []*peer.ChaincodeCall{ 364 { 365 Name: "cc1", 366 }, 367 { 368 Name: "cc2", 369 }, 370 { 371 Name: "cc3", 372 }, 373 }, 374 }) 375 require.NoError(t, err) 376 require.NotNil(t, desc) 377 require.Len(t, desc.Layouts, 1) 378 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 4) 379 require.Equal(t, map[string]struct{}{ 380 peerIdentityString("p4"): {}, 381 peerIdentityString("p6"): {}, 382 peerIdentityString("p10"): {}, 383 peerIdentityString("p12"): {}, 384 }, extractPeers(desc)) 385 }) 386 387 t.Run("Chaincode2Chaincode II", func(t *testing.T) { 388 // Scenario X: A chaincode-to-chaincode query is made. 389 // and the endorsement policies of the chaincodes are as follows: 390 // cc1: OR(0, 1) 391 // cc2: AND(0, 1) 392 // Therefore, the result should be: (0, 1) 393 394 cc1 := "cc1" 395 cc2 := "cc2" 396 chanPeers := peerSet{ 397 newPeer(0).withChaincode(cc1, "1.0").withChaincode(cc2, "1.0"), 398 newPeer(1).withChaincode(cc1, "1.0").withChaincode(cc2, "1.0"), 399 }.toMembers() 400 401 alivePeers := peerSet{ 402 newPeer(0), 403 newPeer(1), 404 }.toMembers() 405 406 g := &gossipMock{} 407 g.On("Peers").Return(alivePeers) 408 g.On("IdentityInfo").Return(identities) 409 g.On("PeersOfChannel").Return(chanPeers).Once() 410 411 mf := &metadataFetcher{} 412 mf.On("Metadata").Return(&chaincode.Metadata{ 413 Name: "cc1", 414 Version: "1.0", 415 }) 416 mf.On("Metadata").Return(&chaincode.Metadata{ 417 Name: "cc2", 418 Version: "1.0", 419 }) 420 421 pb := principalBuilder{} 422 cc1policy := pb.newSet().addPrincipal(peerRole("p0")). 423 newSet().addPrincipal(peerRole("p1")).buildPolicy() 424 pf.On("PoliciesByChaincode", "cc1").Return(cc1policy).Once() 425 426 cc2policy := pb.newSet().addPrincipal(peerRole("p0")). 427 addPrincipal(peerRole("p1")).buildPolicy() 428 pf.On("PoliciesByChaincode", "cc2").Return(cc2policy).Once() 429 430 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 431 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 432 Chaincodes: []*peer.ChaincodeCall{ 433 { 434 Name: "cc1", 435 }, 436 { 437 Name: "cc2", 438 }, 439 }, 440 }) 441 require.NoError(t, err) 442 require.NotNil(t, desc) 443 require.Len(t, desc.Layouts, 1) 444 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 445 require.Equal(t, map[string]struct{}{ 446 peerIdentityString("p0"): {}, 447 peerIdentityString("p1"): {}, 448 }, extractPeers(desc)) 449 }) 450 451 t.Run("Collection specific EP", func(t *testing.T) { 452 // Scenario XI: Policy is found and there are enough peers to satisfy 453 // 2 principal combinations: p0 and p6, or p12 alone. 454 // The collection has p0, p6, and p12 in it. 455 // The chaincode EP is (p0 and p6) or p12. 456 // However, the the chaincode has a collection level EP that requires p6 and p12. 457 // Thus, the only combination that can satisfy would be p6 and p12. 458 collectionOrgs := []*msp.MSPPrincipal{ 459 peerRole("p0"), 460 peerRole("p6"), 461 peerRole("p12"), 462 } 463 col2principals := map[string][]*msp.MSPPrincipal{ 464 "collection": collectionOrgs, 465 } 466 467 mf := &metadataFetcher{} 468 mf.On("Metadata").Return(&chaincode.Metadata{ 469 Name: cc, 470 Version: "1.0", 471 CollectionsConfig: buildCollectionConfig(col2principals), 472 }).Once() 473 pb := principalBuilder{} 474 chaincodeEP := pb.newSet().addPrincipal(peerRole("p0")). 475 addPrincipal(peerRole("p6")).newSet(). 476 addPrincipal(peerRole("p12")).buildPolicy() 477 collectionEP := pb.newSet().addPrincipal(peerRole("p6")). 478 addPrincipal(peerRole("p12")).buildPolicy() 479 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 480 pf := &policyFetcherMock{} 481 pf.On("PoliciesByChaincode", cc).Return([]policies.InquireablePolicy{chaincodeEP, collectionEP}).Once() 482 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 483 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 484 Chaincodes: []*peer.ChaincodeCall{ 485 { 486 Name: cc, 487 CollectionNames: []string{"collection"}, 488 }, 489 }, 490 }) 491 require.NoError(t, err) 492 require.NotNil(t, desc) 493 require.Len(t, desc.Layouts, 1) 494 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 495 require.Equal(t, map[string]struct{}{ 496 peerIdentityString("p6"): {}, 497 peerIdentityString("p12"): {}, 498 }, extractPeers(desc)) 499 }) 500 501 t.Run("Private data blind write", func(t *testing.T) { 502 // Scenario XII: The collection has only p0 in it 503 // The chaincode EP is p6 or p0. 504 // The collection endorsement policy is p0 and p6. 505 // However p6 is not in the collection at all (only p0), 506 // so it doesn't have the pre-images. 507 // To that end, the client indicates that it's a blind write 508 // by turning on the "noPrivateRead" field in the request. 509 // This might seem like a pathological case, but it's 510 // effective because it is in the intersection of 511 // several use cases. 512 513 collectionOrgs := []*msp.MSPPrincipal{ 514 peerRole("p0"), 515 } 516 col2principals := map[string][]*msp.MSPPrincipal{ 517 "collection": collectionOrgs, 518 } 519 520 mf := &metadataFetcher{} 521 mf.On("Metadata").Return(&chaincode.Metadata{ 522 Name: cc, 523 Version: "1.0", 524 CollectionsConfig: buildCollectionConfig(col2principals), 525 }).Once() 526 pb := principalBuilder{} 527 chaincodeEP := pb.newSet().addPrincipal(peerRole("p0")).newSet(). // p0 or p6 528 addPrincipal(peerRole("p6")).buildPolicy() 529 collectionEP := pb.newSet().addPrincipal(peerRole("p0")). // p0 and p6 530 addPrincipal(peerRole("p6")).buildPolicy() 531 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 532 pf := &policyFetcherMock{} 533 pf.On("PoliciesByChaincode", cc).Return([]policies.InquireablePolicy{chaincodeEP, collectionEP}).Once() 534 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 535 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 536 Chaincodes: []*peer.ChaincodeCall{ 537 { 538 Name: cc, 539 CollectionNames: []string{"collection"}, 540 NoPrivateReads: true, // This means a blind write 541 }, 542 }, 543 }) 544 require.NoError(t, err) 545 require.NotNil(t, desc) 546 require.Len(t, desc.Layouts, 1) 547 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 548 require.Equal(t, map[string]struct{}{ 549 peerIdentityString("p0"): {}, 550 peerIdentityString("p6"): {}, 551 }, extractPeers(desc)) 552 }) 553 554 t.Run("Chaincode call with state based endorsement policy I", func(t *testing.T) { 555 // Scenario XIII: A chaincode call with a state based endorsement policy 556 // Total organizations are 0, 2, 4, 6, 10, 12 557 // and the endorsement policies of the chaincode is: 558 // cc1: OR(AND(0, 2), AND(6, 10)) 559 // However the chaincode call is accompanied with a hint 560 // for a state based endorsement policy for organization 10 561 // Therefore, the result should be: 6, 10 562 563 chanPeers := peerSet{} 564 for _, id := range []int{0, 2, 4, 6, 10, 12} { 565 peer := newPeer(id).withChaincode("cc1", "1.0") 566 chanPeers = append(chanPeers, peer) 567 } 568 569 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 570 571 mf := &metadataFetcher{} 572 mf.On("Metadata").Return(&chaincode.Metadata{ 573 Name: "cc1", 574 Version: "1.0", 575 }).Once() 576 577 pb := principalBuilder{} 578 cc1policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p2")). 579 newSet().addPrincipal(peerRole("p6")).addPrincipal(peerRole("p10")).buildPolicy() 580 581 pf.On("PoliciesByChaincode", "cc1").Return(cc1policy).Once() 582 583 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 584 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 585 Chaincodes: []*peer.ChaincodeCall{ 586 { 587 Name: "cc1", 588 KeyPolicies: []*common2.SignaturePolicyEnvelope{ 589 { 590 Identities: []*msp.MSPPrincipal{peerRole("p10")}, 591 Rule: policydsl.SignedBy(0), 592 }, 593 }, 594 }, 595 }, 596 }) 597 require.NoError(t, err) 598 require.NotNil(t, desc) 599 require.Len(t, desc.Layouts, 1) 600 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 601 require.Equal(t, map[string]struct{}{ 602 peerIdentityString("p6"): {}, 603 peerIdentityString("p10"): {}, 604 }, extractPeers(desc)) 605 }) 606 607 t.Run("Chaincode call with state based endorsement policy II", func(t *testing.T) { 608 // Scenario XIV: A chaincode call with a state based endorsement policy 609 // Total organizations are 0, 2, 4, 6, 10, 12 610 // and the endorsement policies of the chaincode is: 611 // cc1: OR(AND(0, 2), AND(6, 10)) 612 // However the chaincode call is accompanied with a hint 613 // for a state based endorsement policy for organization 12 614 // Therefore, the result should be: {0, 2, 12} or {6, 10, 12} 615 616 chanPeers := peerSet{} 617 for _, id := range []int{0, 2, 4, 6, 10, 12} { 618 peer := newPeer(id).withChaincode("cc1", "1.0") 619 chanPeers = append(chanPeers, peer) 620 } 621 622 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 623 624 mf := &metadataFetcher{} 625 mf.On("Metadata").Return(&chaincode.Metadata{ 626 Name: "cc1", 627 Version: "1.0", 628 }).Once() 629 630 pb := principalBuilder{} 631 cc1policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p2")). 632 newSet().addPrincipal(peerRole("p6")).addPrincipal(peerRole("p10")).buildPolicy() 633 634 pf.On("PoliciesByChaincode", "cc1").Return(cc1policy).Once() 635 636 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 637 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 638 Chaincodes: []*peer.ChaincodeCall{ 639 { 640 Name: "cc1", 641 KeyPolicies: []*common2.SignaturePolicyEnvelope{ 642 { 643 Identities: []*msp.MSPPrincipal{peerRole("p12")}, 644 Rule: policydsl.SignedBy(0), 645 }, 646 }, 647 }, 648 }, 649 }) 650 require.NoError(t, err) 651 require.NotNil(t, desc) 652 require.Len(t, desc.Layouts, 2) 653 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 3) 654 require.Len(t, desc.Layouts[1].QuantitiesByGroup, 3) 655 require.Equal(t, map[string]struct{}{ 656 peerIdentityString("p0"): {}, 657 peerIdentityString("p2"): {}, 658 peerIdentityString("p6"): {}, 659 peerIdentityString("p10"): {}, 660 peerIdentityString("p12"): {}, 661 }, extractPeers(desc)) 662 // Find ID of org 12 663 664 // Ensure org 12 (and no other org) is found in both layouts 665 var intersectionSize int 666 for g1 := range desc.Layouts[0].QuantitiesByGroup { 667 for g2 := range desc.Layouts[1].QuantitiesByGroup { 668 if g1 == g2 { 669 require.Equal(t, intersectionSize, 0) 670 intersectionSize++ 671 require.Equal(t, peerIdentityString("p12"), string(desc.EndorsersByGroups[g1].Peers[0].Identity)) 672 } 673 } 674 } 675 }) 676 677 t.Run("Chaincode call with state based endorsement policy III", func(t *testing.T) { 678 // Scenario XV: A chaincode call with a state based endorsement policy 679 // Total organizations are 0, 2, 4, 6, 10, 12 680 // and the endorsement policies of the chaincode is: 681 // cc1: OR(AND(0, 2), AND(6, 10)) 682 // However the chaincode call is accompanied with a hint 683 // for a state based endorsement policy for both organizations 2 and 6 684 // Therefore, the result should be: {0, 2, 6} or {2, 6, 10} 685 686 chanPeers := peerSet{} 687 for _, id := range []int{0, 2, 4, 6, 10, 12} { 688 peer := newPeer(id).withChaincode("cc1", "1.0") 689 chanPeers = append(chanPeers, peer) 690 } 691 692 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 693 694 mf := &metadataFetcher{} 695 mf.On("Metadata").Return(&chaincode.Metadata{ 696 Name: "cc1", 697 Version: "1.0", 698 }).Once() 699 700 pb := principalBuilder{} 701 cc1policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p2")). 702 newSet().addPrincipal(peerRole("p6")).addPrincipal(peerRole("p10")).buildPolicy() 703 704 pf.On("PoliciesByChaincode", "cc1").Return(cc1policy).Once() 705 706 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 707 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 708 Chaincodes: []*peer.ChaincodeCall{ 709 { 710 Name: "cc1", 711 KeyPolicies: []*common2.SignaturePolicyEnvelope{ 712 { 713 Identities: []*msp.MSPPrincipal{peerRole("p2")}, 714 Rule: policydsl.SignedBy(0), 715 }, 716 { 717 Identities: []*msp.MSPPrincipal{peerRole("p6")}, 718 Rule: policydsl.SignedBy(0), 719 }, 720 }, 721 }, 722 }, 723 }) 724 require.NoError(t, err) 725 require.NotNil(t, desc) 726 require.Len(t, desc.Layouts, 2) 727 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 3) 728 require.Equal(t, map[string]struct{}{ 729 peerIdentityString("p0"): {}, 730 peerIdentityString("p2"): {}, 731 peerIdentityString("p6"): {}, 732 peerIdentityString("p10"): {}, 733 }, extractPeers(desc)) 734 735 // Ensure orgs 2, 6 are found in both layouts 736 intersection := make(map[string]struct{}) 737 for g1 := range desc.Layouts[0].QuantitiesByGroup { 738 for g2 := range desc.Layouts[1].QuantitiesByGroup { 739 if g1 == g2 { 740 intersection[string(desc.EndorsersByGroups[g1].Peers[0].Identity)] = struct{}{} 741 } 742 } 743 } 744 745 require.Equal(t, map[string]struct{}{ 746 peerIdentityString("p2"): {}, 747 peerIdentityString("p6"): {}, 748 }, intersection) 749 }) 750 751 t.Run("Chaincode call with DisregardNamespacePolicy set but no key policies or collection policies present", func(t *testing.T) { 752 // Scenario XVI: A chaincode call with DisregardNamespacePolicy set 753 // Total organizations are 0, 2, 4, 6, 10, 12 754 // and there is a collection specified by the client but no collection policies exist 755 // We expect an error because since DisregardNamespacePolicy is specified, and no collection policies are defined, 756 // there is not a single endorsement policy to compute. 757 758 chanPeers := peerSet{} 759 for _, id := range []int{0, 2, 4, 6, 10, 12} { 760 peer := newPeer(id).withChaincode("cc1", "1.0") 761 chanPeers = append(chanPeers, peer) 762 } 763 764 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 765 766 mf := &metadataFetcher{} 767 mf.On("Metadata").Return(&chaincode.Metadata{ 768 Name: "cc1", 769 Version: "1.0", 770 }).Once() 771 772 pb := principalBuilder{} 773 cc1policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p2")). 774 newSet().addPrincipal(peerRole("p6")).addPrincipal(peerRole("p10")).buildPolicy() 775 776 pf.On("PoliciesByChaincode", "cc1").Return(cc1policy).Once() 777 778 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 779 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 780 Chaincodes: []*peer.ChaincodeCall{ 781 { 782 Name: "cc1", 783 DisregardNamespacePolicy: true, 784 }, 785 }, 786 }) 787 require.EqualError(t, err, "requested to disregard chaincode cc1's policy but key and collection policies are missing,"+ 788 " either disable DisregardNamespacePolicy or specify at least one key policy or at least one collection policy") 789 require.Nil(t, desc) 790 }) 791 792 t.Run("Chaincode call with state based endorsement policy and no chaincode namespace policy", func(t *testing.T) { 793 // Scenario XVII: A chaincode call with a state based endorsement policy and DisregardNamespacePolicy set 794 // Total organizations are 0, 2, 4, 6, 10, 12 795 // and the endorsement policies of the chaincode is: 796 // cc1: OR(AND(0, 2), AND(6, 10)) 797 // However the chaincode call is accompanied with a hint 798 // for a state based endorsement policy for both organizations 2 and 6 799 // Therefore, the result should be: {2, 6} 800 801 chanPeers := peerSet{} 802 for _, id := range []int{0, 2, 4, 6, 10, 12} { 803 peer := newPeer(id).withChaincode("cc1", "1.0") 804 chanPeers = append(chanPeers, peer) 805 } 806 807 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 808 809 mf := &metadataFetcher{} 810 mf.On("Metadata").Return(&chaincode.Metadata{ 811 Name: "cc1", 812 Version: "1.0", 813 }).Once() 814 815 pb := principalBuilder{} 816 cc1policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p2")). 817 newSet().addPrincipal(peerRole("p6")).addPrincipal(peerRole("p10")).buildPolicy() 818 819 pf.On("PoliciesByChaincode", "cc1").Return(cc1policy).Once() 820 821 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 822 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 823 Chaincodes: []*peer.ChaincodeCall{ 824 { 825 Name: "cc1", 826 DisregardNamespacePolicy: true, 827 KeyPolicies: []*common2.SignaturePolicyEnvelope{ 828 { 829 Identities: []*msp.MSPPrincipal{peerRole("p2")}, 830 Rule: policydsl.SignedBy(0), 831 }, 832 { 833 Identities: []*msp.MSPPrincipal{peerRole("p6")}, 834 Rule: policydsl.SignedBy(0), 835 }, 836 }, 837 }, 838 }, 839 }) 840 require.NoError(t, err) 841 require.NotNil(t, desc) 842 require.Len(t, desc.Layouts, 1) 843 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 844 require.Equal(t, map[string]struct{}{ 845 peerIdentityString("p2"): {}, 846 peerIdentityString("p6"): {}, 847 }, extractPeers(desc)) 848 }) 849 850 t.Run("Chaincode call with collection endorsement policy and no namespace endorsement policy", func(t *testing.T) { 851 // Scenario XVIII: A chaincode call with collection endorsement policy and DisregardNamespacePolicy set 852 // The chaincode EP is OR(AND(0, 2), AND(6, 10)) 853 // The collection endorsement policy is p0 and p2. 854 // Additionally, the client sets DisregardNamespacePolicy which makes 855 // discovery only use the collection policy and not the namespace policy. 856 857 chanPeers := peerSet{} 858 for _, id := range []int{0, 2, 4, 6, 10, 12} { 859 peer := newPeer(id).withChaincode("cc1", "1.0") 860 chanPeers = append(chanPeers, peer) 861 } 862 863 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 864 865 collectionOrgs := []*msp.MSPPrincipal{ 866 peerRole("p0"), 867 peerRole("p2"), 868 } 869 col2principals := map[string][]*msp.MSPPrincipal{ 870 "collection": collectionOrgs, 871 } 872 mf := &metadataFetcher{} 873 mf.On("Metadata").Return(&chaincode.Metadata{ 874 Name: "cc1", 875 Version: "1.0", 876 CollectionsConfig: buildCollectionConfig(col2principals), 877 }).Once() 878 879 pb := principalBuilder{} 880 cc1policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p2")). 881 newSet().addPrincipal(peerRole("p6")).addPrincipal(peerRole("p10")).buildPolicy() 882 883 collectionEP := pb.newSet().addPrincipal(peerRole("p0")). // p0 and p6 884 addPrincipal(peerRole("p2")).buildPolicy() 885 886 pf.On("PoliciesByChaincode", "cc1").Return([]policies.InquireablePolicy{cc1policy, collectionEP}).Once() 887 888 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 889 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 890 Chaincodes: []*peer.ChaincodeCall{ 891 { 892 Name: "cc1", 893 DisregardNamespacePolicy: true, 894 CollectionNames: []string{"collection"}, 895 }, 896 }, 897 }) 898 require.NoError(t, err) 899 require.NotNil(t, desc) 900 require.Len(t, desc.Layouts, 1) 901 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 902 require.Equal(t, map[string]struct{}{ 903 peerIdentityString("p0"): {}, 904 peerIdentityString("p2"): {}, 905 }, extractPeers(desc)) 906 }) 907 908 t.Run("Identity based endorsement policy doesn't interfere with discovery", func(t *testing.T) { 909 // Scenario XIX: Policy is based on either identities or on organizations 910 // 2 principal combinations: 911 // p0 and p6 (organizations), or p7 (identity) 912 913 pb := principalBuilder{} 914 policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p6")). 915 newSet().addPrincipal(identity("p7")).buildPolicy() 916 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 917 mf := &metadataFetcher{} 918 mf.On("Metadata").Return(&chaincode.Metadata{ 919 Name: cc, 920 Version: "1.0", 921 }).Once() 922 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 923 924 pf.On("PoliciesByChaincode", cc).Return(policy).Once() 925 desc, err := analyzer.PeersForEndorsement(channel, &peer.ChaincodeInterest{ 926 Chaincodes: []*peer.ChaincodeCall{ 927 { 928 Name: cc, 929 }, 930 }, 931 }) 932 require.NoError(t, err) 933 require.NotNil(t, desc) 934 require.Len(t, desc.Layouts, 1) 935 require.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 936 require.Equal(t, map[string]struct{}{ 937 peerIdentityString("p0"): {}, 938 peerIdentityString("p6"): {}, 939 }, extractPeers(desc)) 940 }) 941 } 942 943 func TestPeersAuthorizedByCriteria(t *testing.T) { 944 cc1 := "cc1" 945 cc2 := "cc2" 946 members := peerSet{ 947 newPeer(0).withChaincode(cc1, "1.0"), 948 newPeer(3).withChaincode(cc1, "1.0"), 949 newPeer(6).withChaincode(cc1, "1.0"), 950 newPeer(9).withChaincode(cc1, "1.0"), 951 newPeer(12).withChaincode(cc1, "1.0"), 952 }.toMembers() 953 954 members2 := append(discovery.Members{}, members...) 955 members2 = append(members2, peerSet{newPeer(13).withChaincode(cc1, "1.1").withChaincode(cc2, "1.0")}.toMembers()...) 956 members2 = append(members2, peerSet{newPeer(14).withChaincode(cc1, "1.1")}.toMembers()...) 957 members2 = append(members2, peerSet{newPeer(15).withChaincode(cc2, "1.0")}.toMembers()...) 958 959 alivePeers := peerSet{ 960 newPeer(0), 961 newPeer(2), 962 newPeer(4), 963 newPeer(6), 964 newPeer(8), 965 newPeer(10), 966 newPeer(11), 967 newPeer(12), 968 newPeer(13), 969 newPeer(14), 970 newPeer(15), 971 }.toMembers() 972 973 identities := identitySet(pkiID2MSPID) 974 975 for _, tst := range []struct { 976 name string 977 arguments *peer.ChaincodeInterest 978 totalExistingMembers discovery.Members 979 metadata []*chaincode.Metadata 980 expected discovery.Members 981 }{ 982 { 983 name: "Nil interest", 984 arguments: nil, 985 totalExistingMembers: members, 986 expected: members, 987 }, 988 { 989 name: "Empty interest invocation chain", 990 arguments: &peer.ChaincodeInterest{}, 991 totalExistingMembers: members, 992 expected: members, 993 }, 994 { 995 name: "Chaincodes only installed on some peers", 996 arguments: &peer.ChaincodeInterest{ 997 Chaincodes: []*peer.ChaincodeCall{ 998 {Name: cc1}, 999 {Name: cc2}, 1000 }, 1001 }, 1002 totalExistingMembers: members2, 1003 metadata: []*chaincode.Metadata{ 1004 { 1005 Name: "cc1", 1006 Version: "1.1", 1007 }, 1008 { 1009 Name: "cc2", 1010 Version: "1.0", 1011 }, 1012 }, 1013 expected: peerSet{newPeer(13).withChaincode(cc1, "1.1").withChaincode(cc2, "1.0")}.toMembers(), 1014 }, 1015 { 1016 name: "Only some peers authorized by collection", 1017 arguments: &peer.ChaincodeInterest{ 1018 Chaincodes: []*peer.ChaincodeCall{ 1019 {Name: cc1, CollectionNames: []string{"collection"}}, 1020 }, 1021 }, 1022 totalExistingMembers: members, 1023 metadata: []*chaincode.Metadata{ 1024 { 1025 Name: cc1, 1026 Version: "1.0", 1027 CollectionsConfig: buildCollectionConfig(map[string][]*msp.MSPPrincipal{ 1028 "collection": { 1029 peerRole("p0"), 1030 peerRole("p12"), 1031 }, 1032 }), 1033 }, 1034 { 1035 Name: cc1, 1036 Version: "1.0", 1037 CollectionsConfig: buildCollectionConfig(map[string][]*msp.MSPPrincipal{ 1038 "collection": { 1039 peerRole("p3"), 1040 peerRole("p9"), 1041 }, 1042 }), 1043 }, 1044 }, 1045 expected: peerSet{ 1046 newPeer(0).withChaincode(cc1, "1.0"), 1047 newPeer(12).withChaincode(cc1, "1.0"), 1048 }.toMembers(), 1049 }, 1050 } { 1051 t.Run(tst.name, func(t *testing.T) { 1052 g := &gossipMock{} 1053 pf := &policyFetcherMock{} 1054 mf := &metadataFetcher{} 1055 g.On("Peers").Return(alivePeers) 1056 g.On("IdentityInfo").Return(identities) 1057 g.On("PeersOfChannel").Return(tst.totalExistingMembers).Once() 1058 for _, md := range tst.metadata { 1059 mf.On("Metadata").Return(md).Once() 1060 } 1061 1062 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 1063 actualMembers, err := analyzer.PeersAuthorizedByCriteria(common.ChannelID("mychannel"), tst.arguments) 1064 require.NoError(t, err) 1065 require.Equal(t, tst.expected, actualMembers) 1066 }) 1067 } 1068 } 1069 1070 func TestPop(t *testing.T) { 1071 slice := []inquire.ComparablePrincipalSets{{}, {}} 1072 require.Len(t, slice, 2) 1073 _, slice, err := popComparablePrincipalSets(slice) 1074 require.NoError(t, err) 1075 require.Len(t, slice, 1) 1076 _, slice, err = popComparablePrincipalSets(slice) 1077 require.NoError(t, err) 1078 require.Len(t, slice, 0) 1079 _, _, err = popComparablePrincipalSets(slice) 1080 require.Error(t, err) 1081 require.Equal(t, "no principal sets remained after filtering", err.Error()) 1082 } 1083 1084 func TestMergePrincipalSetsNilInput(t *testing.T) { 1085 _, err := mergePrincipalSets(nil) 1086 require.Error(t, err) 1087 require.Equal(t, "no principal sets remained after filtering", err.Error()) 1088 } 1089 1090 func TestComputePrincipalSetsNoPolicies(t *testing.T) { 1091 // Tests a hypothetical case where no chaincodes populate the chaincode interest. 1092 1093 interest := &peer.ChaincodeInterest{ 1094 Chaincodes: []*peer.ChaincodeCall{}, 1095 } 1096 ea := &endorsementAnalyzer{} 1097 _, err := ea.computePrincipalSets(common.ChannelID("mychannel"), interest) 1098 require.Error(t, err) 1099 require.Contains(t, err.Error(), "no principal sets remained after filtering") 1100 } 1101 1102 func TestLoadMetadataAndFiltersCollectionNotPresentInConfig(t *testing.T) { 1103 interest := &peer.ChaincodeInterest{ 1104 Chaincodes: []*peer.ChaincodeCall{ 1105 { 1106 Name: "mycc", 1107 CollectionNames: []string{"bar"}, 1108 }, 1109 }, 1110 } 1111 1112 org1AndOrg2 := []*msp.MSPPrincipal{ 1113 orgPrincipal("Org1MSP"), 1114 orgPrincipal("Org2MSP"), 1115 } 1116 col2principals := map[string][]*msp.MSPPrincipal{ 1117 "foo": org1AndOrg2, 1118 } 1119 config := buildCollectionConfig(col2principals) 1120 1121 mdf := &metadataFetcher{} 1122 mdf.On("Metadata").Return(&chaincode.Metadata{ 1123 Name: "mycc", 1124 CollectionsConfig: config, 1125 Policy: []byte{1, 2, 3}, 1126 }) 1127 1128 _, err := loadMetadataAndFilters(metadataAndFilterContext{ 1129 identityInfoByID: nil, 1130 evaluator: nil, 1131 chainID: common.ChannelID("mychannel"), 1132 fetch: mdf, 1133 interest: interest, 1134 }) 1135 1136 require.Equal(t, "collection bar doesn't exist in collection config for chaincode mycc", err.Error()) 1137 } 1138 1139 func TestLoadMetadataAndFiltersInvalidCollectionData(t *testing.T) { 1140 interest := &peer.ChaincodeInterest{ 1141 Chaincodes: []*peer.ChaincodeCall{ 1142 { 1143 Name: "mycc", 1144 CollectionNames: []string{"col1"}, 1145 }, 1146 }, 1147 } 1148 mdf := &metadataFetcher{} 1149 mdf.On("Metadata").Return(&chaincode.Metadata{ 1150 Name: "mycc", 1151 CollectionsConfig: &peer.CollectionConfigPackage{}, 1152 Policy: []byte{1, 2, 3}, 1153 }) 1154 1155 _, err := loadMetadataAndFilters(metadataAndFilterContext{ 1156 identityInfoByID: nil, 1157 evaluator: nil, 1158 chainID: common.ChannelID("mychannel"), 1159 fetch: mdf, 1160 interest: interest, 1161 }) 1162 require.Error(t, err) 1163 require.Contains(t, err.Error(), "collection col1 doesn't exist in collection config for chaincode mycc") 1164 } 1165 1166 type peerSet []*peerInfo 1167 1168 func (p peerSet) toMembers() discovery.Members { 1169 var members discovery.Members 1170 for _, peer := range p { 1171 members = append(members, peer.NetworkMember) 1172 } 1173 return members 1174 } 1175 1176 func identitySet(pkiID2MSPID map[string]string) api.PeerIdentitySet { 1177 var res api.PeerIdentitySet 1178 for pkiID, mspID := range pkiID2MSPID { 1179 sID := &msp.SerializedIdentity{ 1180 Mspid: pkiID2MSPID[pkiID], 1181 IdBytes: []byte(pkiID), 1182 } 1183 res = append(res, api.PeerIdentityInfo{ 1184 Identity: api.PeerIdentityType(protoutil.MarshalOrPanic(sID)), 1185 PKIId: common.PKIidType(pkiID), 1186 Organization: api.OrgIdentityType(mspID), 1187 }) 1188 } 1189 return res 1190 } 1191 1192 type peerInfo struct { 1193 identity api.PeerIdentityType 1194 pkiID common.PKIidType 1195 discovery.NetworkMember 1196 } 1197 1198 func peerIdentityString(id string) string { 1199 return string(protoutil.MarshalOrPanic(&msp.SerializedIdentity{ 1200 Mspid: pkiID2MSPID[id], 1201 IdBytes: []byte(id), 1202 })) 1203 } 1204 1205 func newPeer(i int) *peerInfo { 1206 p := fmt.Sprintf("p%d", i) 1207 identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{ 1208 Mspid: pkiID2MSPID[p], 1209 IdBytes: []byte(p), 1210 }) 1211 return &peerInfo{ 1212 pkiID: common.PKIidType(p), 1213 identity: api.PeerIdentityType(identity), 1214 NetworkMember: discovery.NetworkMember{ 1215 PKIid: common.PKIidType(p), 1216 Endpoint: p, 1217 InternalEndpoint: p, 1218 Envelope: &gossip.Envelope{ 1219 Payload: []byte(identity), 1220 }, 1221 }, 1222 } 1223 } 1224 1225 func peerRole(pkiID string) *msp.MSPPrincipal { 1226 return &msp.MSPPrincipal{ 1227 PrincipalClassification: msp.MSPPrincipal_ROLE, 1228 Principal: protoutil.MarshalOrPanic(&msp.MSPRole{ 1229 MspIdentifier: pkiID2MSPID[pkiID], 1230 Role: msp.MSPRole_PEER, 1231 }), 1232 } 1233 } 1234 1235 func identity(pkiID string) *msp.MSPPrincipal { 1236 return &msp.MSPPrincipal{ 1237 PrincipalClassification: msp.MSPPrincipal_IDENTITY, 1238 Principal: protoutil.MarshalOrPanic(&msp.SerializedIdentity{ 1239 Mspid: pkiID2MSPID[pkiID], 1240 IdBytes: []byte(pkiID), 1241 }), 1242 } 1243 } 1244 1245 func (pi *peerInfo) withChaincode(name, version string) *peerInfo { 1246 if pi.Properties == nil { 1247 pi.Properties = &gossip.Properties{} 1248 } 1249 pi.Properties.Chaincodes = append(pi.Properties.Chaincodes, &gossip.Chaincode{ 1250 Name: name, 1251 Version: version, 1252 }) 1253 return pi 1254 } 1255 1256 type gossipMock struct { 1257 mock.Mock 1258 } 1259 1260 func (g *gossipMock) IdentityInfo() api.PeerIdentitySet { 1261 return g.Called().Get(0).(api.PeerIdentitySet) 1262 } 1263 1264 func (g *gossipMock) PeersOfChannel(_ common.ChannelID) discovery.Members { 1265 members := g.Called().Get(0) 1266 return members.(discovery.Members) 1267 } 1268 1269 func (g *gossipMock) Peers() discovery.Members { 1270 members := g.Called().Get(0) 1271 return members.(discovery.Members) 1272 } 1273 1274 type policyFetcherMock struct { 1275 mock.Mock 1276 } 1277 1278 func (pf *policyFetcherMock) PoliciesByChaincode(channel string, chaincode string, collections ...string) []policies.InquireablePolicy { 1279 arg := pf.Called(chaincode) 1280 if arg.Get(0) == nil { 1281 return nil 1282 } 1283 1284 singlePolicy, isSinglePolicy := arg.Get(0).(policies.InquireablePolicy) 1285 if isSinglePolicy { 1286 return []policies.InquireablePolicy{singlePolicy} 1287 } 1288 1289 return arg.Get(0).([]policies.InquireablePolicy) 1290 } 1291 1292 type principalBuilder struct { 1293 ip inquireablePolicy 1294 } 1295 1296 func (pb *principalBuilder) buildPolicy() inquireablePolicy { 1297 defer func() { 1298 pb.ip = nil 1299 }() 1300 return pb.ip 1301 } 1302 1303 func (pb *principalBuilder) newSet() *principalBuilder { 1304 pb.ip = append(pb.ip, make(policies.PrincipalSet, 0)) 1305 return pb 1306 } 1307 1308 func (pb *principalBuilder) addPrincipal(principal *msp.MSPPrincipal) *principalBuilder { 1309 pb.ip[len(pb.ip)-1] = append(pb.ip[len(pb.ip)-1], principal) 1310 return pb 1311 } 1312 1313 type inquireablePolicy []policies.PrincipalSet 1314 1315 func (ip inquireablePolicy) SatisfiedBy() []policies.PrincipalSet { 1316 return ip 1317 } 1318 1319 type principalEvaluatorMock struct{} 1320 1321 func (pe *principalEvaluatorMock) SatisfiesPrincipal(_ string, identity []byte, principal *msp.MSPPrincipal) error { 1322 sId := &msp.SerializedIdentity{} 1323 if err := proto.Unmarshal(identity, sId); err != nil { 1324 return err 1325 } 1326 if principal.PrincipalClassification == msp.MSPPrincipal_IDENTITY { 1327 identityPrincipal := &msp.SerializedIdentity{} 1328 if err := proto.Unmarshal(principal.Principal, identityPrincipal); err != nil { 1329 return err 1330 } 1331 if proto.Equal(sId, identityPrincipal) { 1332 return nil 1333 } 1334 return fmt.Errorf("identities do not match") 1335 } 1336 // Else, it's either an OU type or a role type, so we only classify by MSP ID 1337 peerRole := &msp.MSPRole{} 1338 if err := proto.Unmarshal(principal.Principal, peerRole); err != nil { 1339 return err 1340 } 1341 if peerRole.MspIdentifier == sId.Mspid { 1342 return nil 1343 } 1344 return errors.New("bingo") 1345 } 1346 1347 type metadataFetcher struct { 1348 mock.Mock 1349 } 1350 1351 func (mf *metadataFetcher) Metadata(channel string, cc string, _ ...string) *chaincode.Metadata { 1352 arg := mf.Called().Get(0) 1353 if arg == nil { 1354 return nil 1355 } 1356 return arg.(*chaincode.Metadata) 1357 }