github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/discovery/endorsement/endorsement_test.go (about) 1 /* 2 Copyright IBM Corp. 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/golang/protobuf/proto" 14 discoveryprotos "github.com/hyperledger/fabric-protos-go/discovery" 15 "github.com/hyperledger/fabric-protos-go/gossip" 16 "github.com/hyperledger/fabric-protos-go/msp" 17 "github.com/hyperledger/fabric-protos-go/peer" 18 "github.com/hyperledger/fabric/common/chaincode" 19 "github.com/hyperledger/fabric/common/policies" 20 "github.com/hyperledger/fabric/common/policies/inquire" 21 "github.com/hyperledger/fabric/gossip/api" 22 "github.com/hyperledger/fabric/gossip/common" 23 "github.com/hyperledger/fabric/gossip/discovery" 24 "github.com/hyperledger/fabric/protoutil" 25 "github.com/pkg/errors" 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/mock" 28 ) 29 30 var pkiID2MSPID = map[string]string{ 31 "p0": "Org0MSP", 32 "p1": "Org1MSP", 33 "p2": "Org2MSP", 34 "p3": "Org3MSP", 35 "p4": "Org4MSP", 36 "p5": "Org5MSP", 37 "p6": "Org6MSP", 38 "p7": "Org7MSP", 39 "p8": "Org8MSP", 40 "p9": "Org9MSP", 41 "p10": "Org10MSP", 42 "p11": "Org11MSP", 43 "p12": "Org12MSP", 44 "p13": "Org13MSP", 45 "p14": "Org14MSP", 46 "p15": "Org15MSP", 47 } 48 49 func TestPeersForEndorsement(t *testing.T) { 50 extractPeers := func(desc *discoveryprotos.EndorsementDescriptor) map[string]struct{} { 51 res := map[string]struct{}{} 52 for _, endorsers := range desc.EndorsersByGroups { 53 for _, p := range endorsers.Peers { 54 res[string(p.Identity)] = struct{}{} 55 assert.Equal(t, string(p.Identity), string(p.MembershipInfo.Payload)) 56 assert.Equal(t, string(p.Identity), string(p.StateInfo.Payload)) 57 } 58 } 59 return res 60 } 61 cc := "chaincode" 62 mf := &metadataFetcher{} 63 g := &gossipMock{} 64 pf := &policyFetcherMock{} 65 ccWithMissingPolicy := "chaincodeWithMissingPolicy" 66 channel := common.ChannelID("test") 67 alivePeers := peerSet{ 68 newPeer(0), 69 newPeer(2), 70 newPeer(4), 71 newPeer(6), 72 newPeer(8), 73 newPeer(10), 74 newPeer(11), 75 newPeer(12), 76 } 77 78 identities := identitySet(pkiID2MSPID) 79 80 chanPeers := peerSet{ 81 newPeer(0).withChaincode(cc, "1.0"), 82 newPeer(3).withChaincode(cc, "1.0"), 83 newPeer(6).withChaincode(cc, "1.0"), 84 newPeer(9).withChaincode(cc, "1.0"), 85 newPeer(11).withChaincode(cc, "1.0"), 86 newPeer(12).withChaincode(cc, "1.0"), 87 } 88 g.On("Peers").Return(alivePeers.toMembers()) 89 g.On("IdentityInfo").Return(identities) 90 91 // Scenario I: Policy isn't found 92 t.Run("PolicyNotFound", func(t *testing.T) { 93 pf.On("PolicyByChaincode", ccWithMissingPolicy).Return(nil).Once() 94 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 95 mf.On("Metadata").Return(&chaincode.Metadata{ 96 Name: cc, 97 Version: "1.0", 98 }).Once() 99 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 100 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 101 Chaincodes: []*discoveryprotos.ChaincodeCall{ 102 { 103 Name: ccWithMissingPolicy, 104 }, 105 }, 106 }) 107 assert.Nil(t, desc) 108 assert.Equal(t, "policy not found", err.Error()) 109 }) 110 111 t.Run("NotEnoughPeers", func(t *testing.T) { 112 // Scenario II: Policy is found but not enough peers to satisfy the policy. 113 // The policy requires a signature from: 114 // p1 and p6, or 115 // p11 x2 (twice), but we only have a single peer in the alive view for p11 116 pb := principalBuilder{} 117 policy := pb.newSet().addPrincipal(peerRole("p1")).addPrincipal(peerRole("p6")). 118 newSet().addPrincipal(peerRole("p11")).addPrincipal(peerRole("p11")).buildPolicy() 119 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 120 mf.On("Metadata").Return(&chaincode.Metadata{Name: cc, Version: "1.0"}).Once() 121 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 122 pf.On("PolicyByChaincode", cc).Return(policy).Once() 123 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 124 Chaincodes: []*discoveryprotos.ChaincodeCall{ 125 { 126 Name: cc, 127 }, 128 }, 129 }) 130 assert.Nil(t, desc) 131 assert.Equal(t, err.Error(), "cannot satisfy any principal combination") 132 }) 133 134 t.Run("DisjointViews", func(t *testing.T) { 135 pb := principalBuilder{} 136 // Scenario III: Policy is found and there are enough peers to satisfy 137 // only 1 type of principal combination: p0 and p6. 138 // However, the combination of a signature from p10 and p12 139 // cannot be satisfied because p10 is not in the channel view but only in the alive view 140 policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p6")). 141 newSet().addPrincipal(peerRole("p10")).addPrincipal(peerRole("p12")).buildPolicy() 142 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 143 mf.On("Metadata").Return(&chaincode.Metadata{ 144 Name: cc, 145 Version: "1.0", 146 }).Once() 147 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 148 pf.On("PolicyByChaincode", cc).Return(policy).Once() 149 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 150 Chaincodes: []*discoveryprotos.ChaincodeCall{ 151 { 152 Name: cc, 153 }, 154 }, 155 }) 156 assert.NoError(t, err) 157 assert.NotNil(t, desc) 158 assert.Len(t, desc.Layouts, 1) 159 assert.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 160 assert.Equal(t, map[string]struct{}{ 161 peerIdentityString("p0"): {}, 162 peerIdentityString("p6"): {}, 163 }, extractPeers(desc)) 164 }) 165 166 t.Run("MultipleCombinations", func(t *testing.T) { 167 // Scenario IV: Policy is found and there are enough peers to satisfy 168 // 2 principal combinations: 169 // p0 and p6, or 170 // p12 alone 171 pb := principalBuilder{} 172 policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p6")). 173 newSet().addPrincipal(peerRole("p12")).buildPolicy() 174 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 175 mf.On("Metadata").Return(&chaincode.Metadata{ 176 Name: cc, 177 Version: "1.0", 178 }).Once() 179 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 180 pf.On("PolicyByChaincode", cc).Return(policy).Once() 181 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 182 Chaincodes: []*discoveryprotos.ChaincodeCall{ 183 { 184 Name: cc, 185 }, 186 }, 187 }) 188 assert.NoError(t, err) 189 assert.NotNil(t, desc) 190 assert.Len(t, desc.Layouts, 2) 191 assert.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 192 assert.Len(t, desc.Layouts[1].QuantitiesByGroup, 1) 193 assert.Equal(t, map[string]struct{}{ 194 peerIdentityString("p0"): {}, 195 peerIdentityString("p6"): {}, 196 peerIdentityString("p12"): {}, 197 }, extractPeers(desc)) 198 }) 199 200 t.Run("WrongVersionInstalled", func(t *testing.T) { 201 // Scenario V: Policy is found, and there are enough peers to satisfy policy combinations, 202 // but all peers have the wrong version installed on them. 203 mf.On("Metadata").Return(&chaincode.Metadata{ 204 Name: cc, 205 Version: "1.1", 206 }).Once() 207 pb := principalBuilder{} 208 policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p6")). 209 newSet().addPrincipal(peerRole("p12")).buildPolicy() 210 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 211 pf.On("PolicyByChaincode", cc).Return(policy).Once() 212 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 213 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 214 Chaincodes: []*discoveryprotos.ChaincodeCall{ 215 { 216 Name: cc, 217 }, 218 }, 219 }) 220 assert.Nil(t, desc) 221 assert.Equal(t, "cannot satisfy any principal combination", err.Error()) 222 223 // Scenario VI: Policy is found, there are enough peers to satisfy policy combinations, 224 // but some peers have the wrong chaincode version, and some don't even have it installed. 225 chanPeers := peerSet{ 226 newPeer(0).withChaincode(cc, "0.6"), 227 newPeer(3).withChaincode(cc, "1.0"), 228 newPeer(6).withChaincode(cc, "1.0"), 229 newPeer(9).withChaincode(cc, "1.0"), 230 newPeer(12), 231 } 232 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 233 pf.On("PolicyByChaincode", cc).Return(policy).Once() 234 mf.On("Metadata").Return(&chaincode.Metadata{ 235 Name: cc, 236 Version: "1.0", 237 }).Once() 238 desc, err = analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 239 Chaincodes: []*discoveryprotos.ChaincodeCall{ 240 { 241 Name: cc, 242 }, 243 }, 244 }) 245 assert.Nil(t, desc) 246 assert.Equal(t, "cannot satisfy any principal combination", err.Error()) 247 }) 248 249 t.Run("NoChaincodeMetadataFromLedger", func(t *testing.T) { 250 // Scenario VII: Policy is found, there are enough peers to satisfy the policy, 251 // but the chaincode metadata cannot be fetched from the ledger. 252 pb := principalBuilder{} 253 policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p6")). 254 newSet().addPrincipal(peerRole("p12")).buildPolicy() 255 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 256 pf.On("PolicyByChaincode", cc).Return(policy).Once() 257 mf.On("Metadata").Return(nil).Once() 258 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 259 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 260 Chaincodes: []*discoveryprotos.ChaincodeCall{ 261 { 262 Name: cc, 263 }, 264 }, 265 }) 266 assert.Nil(t, desc) 267 assert.Equal(t, "No metadata was found for chaincode chaincode in channel test", err.Error()) 268 }) 269 270 t.Run("Collections", func(t *testing.T) { 271 // Scenario VIII: Policy is found and there are enough peers to satisfy 272 // 2 principal combinations: p0 and p6, or p12 alone. 273 // However, the query contains a collection which has a policy that permits only p0 and p12, 274 // and thus - the combination of p0 and p6 is filtered out and we're left with p12 only. 275 collectionOrgs := []*msp.MSPPrincipal{ 276 peerRole("p0"), 277 peerRole("p12"), 278 } 279 col2principals := map[string][]*msp.MSPPrincipal{ 280 "collection": collectionOrgs, 281 } 282 mf.On("Metadata").Return(&chaincode.Metadata{ 283 Name: cc, 284 Version: "1.0", 285 CollectionsConfig: buildCollectionConfig(col2principals), 286 }).Once() 287 pb := principalBuilder{} 288 policy := pb.newSet().addPrincipal(peerRole("p0")). 289 addPrincipal(peerRole("p6")).newSet(). 290 addPrincipal(peerRole("p12")).buildPolicy() 291 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 292 pf.On("PolicyByChaincode", cc).Return(policy).Once() 293 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 294 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 295 Chaincodes: []*discoveryprotos.ChaincodeCall{ 296 { 297 Name: cc, 298 CollectionNames: []string{"collection"}, 299 }, 300 }, 301 }) 302 assert.NoError(t, err) 303 assert.NotNil(t, desc) 304 assert.Len(t, desc.Layouts, 1) 305 assert.Len(t, desc.Layouts[0].QuantitiesByGroup, 1) 306 assert.Equal(t, map[string]struct{}{ 307 peerIdentityString("p12"): {}, 308 }, extractPeers(desc)) 309 }) 310 311 t.Run("Chaincode2Chaincode I", func(t *testing.T) { 312 // Scenario IX: A chaincode-to-chaincode query is made. 313 // Total organizations are 0, 2, 4, 6, 10, 12 314 // and the endorsement policies of the chaincodes are as follows: 315 // cc1: OR(AND(0, 2), AND(6, 10)) 316 // cc2: AND(6, 10, 12) 317 // cc3: AND(4, 12) 318 // Therefore, the result should be: 4, 6, 10, 12 319 320 chanPeers := peerSet{} 321 for _, id := range []int{0, 2, 4, 6, 10, 12} { 322 peer := newPeer(id).withChaincode("cc1", "1.0").withChaincode("cc2", "1.0").withChaincode("cc3", "1.0") 323 chanPeers = append(chanPeers, peer) 324 } 325 326 g.On("PeersOfChannel").Return(chanPeers.toMembers()).Once() 327 328 mf.On("Metadata").Return(&chaincode.Metadata{ 329 Name: "cc1", 330 Version: "1.0", 331 }).Once() 332 mf.On("Metadata").Return(&chaincode.Metadata{ 333 Name: "cc2", 334 Version: "1.0", 335 }).Once() 336 mf.On("Metadata").Return(&chaincode.Metadata{ 337 Name: "cc3", 338 Version: "1.0", 339 }).Once() 340 341 pb := principalBuilder{} 342 cc1policy := pb.newSet().addPrincipal(peerRole("p0")).addPrincipal(peerRole("p2")). 343 newSet().addPrincipal(peerRole("p6")).addPrincipal(peerRole("p10")).buildPolicy() 344 345 pf.On("PolicyByChaincode", "cc1").Return(cc1policy).Once() 346 347 cc2policy := pb.newSet().addPrincipal(peerRole("p6")). 348 addPrincipal(peerRole("p10")).addPrincipal(peerRole("p12")).buildPolicy() 349 pf.On("PolicyByChaincode", "cc2").Return(cc2policy).Once() 350 351 cc3policy := pb.newSet().addPrincipal(peerRole("p4")). 352 addPrincipal(peerRole("p12")).buildPolicy() 353 pf.On("PolicyByChaincode", "cc3").Return(cc3policy).Once() 354 355 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 356 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 357 Chaincodes: []*discoveryprotos.ChaincodeCall{ 358 { 359 Name: "cc1", 360 }, 361 { 362 Name: "cc2", 363 }, 364 { 365 Name: "cc3", 366 }, 367 }, 368 }) 369 assert.NoError(t, err) 370 assert.NotNil(t, desc) 371 assert.Len(t, desc.Layouts, 1) 372 assert.Len(t, desc.Layouts[0].QuantitiesByGroup, 4) 373 assert.Equal(t, map[string]struct{}{ 374 peerIdentityString("p4"): {}, 375 peerIdentityString("p6"): {}, 376 peerIdentityString("p10"): {}, 377 peerIdentityString("p12"): {}, 378 }, extractPeers(desc)) 379 }) 380 381 t.Run("Chaincode2Chaincode II", func(t *testing.T) { 382 // Scenario X: A chaincode-to-chaincode query is made. 383 // and the endorsement policies of the chaincodes are as follows: 384 // cc1: OR(0, 1) 385 // cc2: AND(0, 1) 386 // Therefore, the result should be: (0, 1) 387 388 cc1 := "cc1" 389 cc2 := "cc2" 390 chanPeers := peerSet{ 391 newPeer(0).withChaincode(cc1, "1.0").withChaincode(cc2, "1.0"), 392 newPeer(1).withChaincode(cc1, "1.0").withChaincode(cc2, "1.0"), 393 }.toMembers() 394 395 alivePeers := peerSet{ 396 newPeer(0), 397 newPeer(1), 398 }.toMembers() 399 400 g := &gossipMock{} 401 g.On("Peers").Return(alivePeers) 402 g.On("IdentityInfo").Return(identities) 403 g.On("PeersOfChannel").Return(chanPeers).Once() 404 405 mf.On("Metadata").Return(&chaincode.Metadata{ 406 Name: "cc1", 407 Version: "1.0", 408 }) 409 mf.On("Metadata").Return(&chaincode.Metadata{ 410 Name: "cc2", 411 Version: "1.0", 412 }) 413 414 pb := principalBuilder{} 415 cc1policy := pb.newSet().addPrincipal(peerRole("p0")). 416 newSet().addPrincipal(peerRole("p1")).buildPolicy() 417 pf.On("PolicyByChaincode", "cc1").Return(cc1policy).Once() 418 419 cc2policy := pb.newSet().addPrincipal(peerRole("p0")). 420 addPrincipal(peerRole("p1")).buildPolicy() 421 pf.On("PolicyByChaincode", "cc2").Return(cc2policy).Once() 422 423 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 424 desc, err := analyzer.PeersForEndorsement(channel, &discoveryprotos.ChaincodeInterest{ 425 Chaincodes: []*discoveryprotos.ChaincodeCall{ 426 { 427 Name: "cc1", 428 }, 429 { 430 Name: "cc2", 431 }, 432 }, 433 }) 434 assert.NoError(t, err) 435 assert.NotNil(t, desc) 436 assert.Len(t, desc.Layouts, 1) 437 assert.Len(t, desc.Layouts[0].QuantitiesByGroup, 2) 438 assert.Equal(t, map[string]struct{}{ 439 peerIdentityString("p0"): {}, 440 peerIdentityString("p1"): {}, 441 }, extractPeers(desc)) 442 }) 443 } 444 445 func TestPeersAuthorizedByCriteria(t *testing.T) { 446 cc1 := "cc1" 447 cc2 := "cc2" 448 members := peerSet{ 449 newPeer(0).withChaincode(cc1, "1.0"), 450 newPeer(3).withChaincode(cc1, "1.0"), 451 newPeer(6).withChaincode(cc1, "1.0"), 452 newPeer(9).withChaincode(cc1, "1.0"), 453 newPeer(12).withChaincode(cc1, "1.0"), 454 }.toMembers() 455 456 members2 := append(discovery.Members{}, members...) 457 members2 = append(members2, peerSet{newPeer(13).withChaincode(cc1, "1.1").withChaincode(cc2, "1.0")}.toMembers()...) 458 members2 = append(members2, peerSet{newPeer(14).withChaincode(cc1, "1.1")}.toMembers()...) 459 members2 = append(members2, peerSet{newPeer(15).withChaincode(cc2, "1.0")}.toMembers()...) 460 461 alivePeers := peerSet{ 462 newPeer(0), 463 newPeer(2), 464 newPeer(4), 465 newPeer(6), 466 newPeer(8), 467 newPeer(10), 468 newPeer(11), 469 newPeer(12), 470 newPeer(13), 471 newPeer(14), 472 newPeer(15), 473 }.toMembers() 474 475 identities := identitySet(pkiID2MSPID) 476 477 for _, tst := range []struct { 478 name string 479 arguments *discoveryprotos.ChaincodeInterest 480 totalExistingMembers discovery.Members 481 metadata []*chaincode.Metadata 482 expected discovery.Members 483 }{ 484 { 485 name: "Nil interest", 486 arguments: nil, 487 totalExistingMembers: members, 488 expected: members, 489 }, 490 { 491 name: "Empty interest invocation chain", 492 arguments: &discoveryprotos.ChaincodeInterest{}, 493 totalExistingMembers: members, 494 expected: members, 495 }, 496 { 497 name: "Chaincodes only installed on some peers", 498 arguments: &discoveryprotos.ChaincodeInterest{ 499 Chaincodes: []*discoveryprotos.ChaincodeCall{ 500 {Name: cc1}, 501 {Name: cc2}, 502 }, 503 }, 504 totalExistingMembers: members2, 505 metadata: []*chaincode.Metadata{ 506 { 507 Name: "cc1", 508 Version: "1.1", 509 }, 510 { 511 Name: "cc2", 512 Version: "1.0", 513 }, 514 }, 515 expected: peerSet{newPeer(13).withChaincode(cc1, "1.1").withChaincode(cc2, "1.0")}.toMembers(), 516 }, 517 { 518 name: "Only some peers authorized by collection", 519 arguments: &discoveryprotos.ChaincodeInterest{ 520 Chaincodes: []*discoveryprotos.ChaincodeCall{ 521 {Name: cc1, CollectionNames: []string{"collection"}}, 522 }, 523 }, 524 totalExistingMembers: members, 525 metadata: []*chaincode.Metadata{ 526 { 527 Name: cc1, 528 Version: "1.0", 529 CollectionsConfig: buildCollectionConfig(map[string][]*msp.MSPPrincipal{ 530 "collection": { 531 peerRole("p0"), 532 peerRole("p12"), 533 }, 534 }), 535 }, 536 { 537 Name: cc1, 538 Version: "1.0", 539 CollectionsConfig: buildCollectionConfig(map[string][]*msp.MSPPrincipal{ 540 "collection": { 541 peerRole("p3"), 542 peerRole("p9"), 543 }, 544 }), 545 }, 546 }, 547 expected: peerSet{ 548 newPeer(0).withChaincode(cc1, "1.0"), 549 newPeer(12).withChaincode(cc1, "1.0")}.toMembers(), 550 }, 551 } { 552 t.Run(tst.name, func(t *testing.T) { 553 g := &gossipMock{} 554 pf := &policyFetcherMock{} 555 mf := &metadataFetcher{} 556 g.On("Peers").Return(alivePeers) 557 g.On("IdentityInfo").Return(identities) 558 g.On("PeersOfChannel").Return(tst.totalExistingMembers).Once() 559 for _, md := range tst.metadata { 560 mf.On("Metadata").Return(md).Once() 561 } 562 563 analyzer := NewEndorsementAnalyzer(g, pf, &principalEvaluatorMock{}, mf) 564 actualMembers, err := analyzer.PeersAuthorizedByCriteria(common.ChannelID("mychannel"), tst.arguments) 565 assert.NoError(t, err) 566 assert.Equal(t, tst.expected, actualMembers) 567 }) 568 } 569 } 570 571 func TestPop(t *testing.T) { 572 slice := []inquire.ComparablePrincipalSets{{}, {}} 573 assert.Len(t, slice, 2) 574 _, slice, err := popComparablePrincipalSets(slice) 575 assert.NoError(t, err) 576 assert.Len(t, slice, 1) 577 _, slice, err = popComparablePrincipalSets(slice) 578 assert.Len(t, slice, 0) 579 _, slice, err = popComparablePrincipalSets(slice) 580 assert.Error(t, err) 581 assert.Equal(t, "no principal sets remained after filtering", err.Error()) 582 } 583 584 func TestMergePrincipalSetsNilInput(t *testing.T) { 585 _, err := mergePrincipalSets(nil) 586 assert.Error(t, err) 587 assert.Equal(t, "no principal sets remained after filtering", err.Error()) 588 } 589 590 func TestComputePrincipalSetsNoPolicies(t *testing.T) { 591 // Tests a hypothetical case where no chaincodes populate the chaincode interest. 592 593 interest := &discoveryprotos.ChaincodeInterest{ 594 Chaincodes: []*discoveryprotos.ChaincodeCall{}, 595 } 596 ea := &endorsementAnalyzer{} 597 _, err := ea.computePrincipalSets(common.ChannelID("mychannel"), interest) 598 assert.Error(t, err) 599 assert.Contains(t, err.Error(), "no principal sets remained after filtering") 600 } 601 602 func TestLoadMetadataAndFiltersCollectionNotPresentInConfig(t *testing.T) { 603 interest := &discoveryprotos.ChaincodeInterest{ 604 Chaincodes: []*discoveryprotos.ChaincodeCall{ 605 { 606 Name: "mycc", 607 CollectionNames: []string{"bar"}, 608 }, 609 }, 610 } 611 612 org1AndOrg2 := []*msp.MSPPrincipal{ 613 orgPrincipal("Org1MSP"), 614 orgPrincipal("Org2MSP"), 615 } 616 col2principals := map[string][]*msp.MSPPrincipal{ 617 "foo": org1AndOrg2, 618 } 619 config := buildCollectionConfig(col2principals) 620 621 mdf := &metadataFetcher{} 622 mdf.On("Metadata").Return(&chaincode.Metadata{ 623 Name: "mycc", 624 CollectionsConfig: config, 625 Policy: []byte{1, 2, 3}, 626 }) 627 628 _, err := loadMetadataAndFilters(metadataAndFilterContext{ 629 identityInfoByID: nil, 630 evaluator: nil, 631 chainID: common.ChannelID("mychannel"), 632 fetch: mdf, 633 interest: interest, 634 }) 635 636 assert.Equal(t, "collection bar doesn't exist in collection config for chaincode mycc", err.Error()) 637 } 638 639 func TestLoadMetadataAndFiltersInvalidCollectionData(t *testing.T) { 640 interest := &discoveryprotos.ChaincodeInterest{ 641 Chaincodes: []*discoveryprotos.ChaincodeCall{ 642 { 643 Name: "mycc", 644 CollectionNames: []string{"col1"}, 645 }, 646 }, 647 } 648 mdf := &metadataFetcher{} 649 mdf.On("Metadata").Return(&chaincode.Metadata{ 650 Name: "mycc", 651 CollectionsConfig: &peer.CollectionConfigPackage{}, 652 Policy: []byte{1, 2, 3}, 653 }) 654 655 _, err := loadMetadataAndFilters(metadataAndFilterContext{ 656 identityInfoByID: nil, 657 evaluator: nil, 658 chainID: common.ChannelID("mychannel"), 659 fetch: mdf, 660 interest: interest, 661 }) 662 assert.Error(t, err) 663 assert.Contains(t, err.Error(), "collection col1 doesn't exist in collection config for chaincode mycc") 664 } 665 666 type peerSet []*peerInfo 667 668 func (p peerSet) toMembers() discovery.Members { 669 var members discovery.Members 670 for _, peer := range p { 671 members = append(members, peer.NetworkMember) 672 } 673 return members 674 } 675 676 func identitySet(pkiID2MSPID map[string]string) api.PeerIdentitySet { 677 var res api.PeerIdentitySet 678 for pkiID, mspID := range pkiID2MSPID { 679 sID := &msp.SerializedIdentity{ 680 Mspid: pkiID2MSPID[pkiID], 681 IdBytes: []byte(pkiID), 682 } 683 res = append(res, api.PeerIdentityInfo{ 684 Identity: api.PeerIdentityType(protoutil.MarshalOrPanic(sID)), 685 PKIId: common.PKIidType(pkiID), 686 Organization: api.OrgIdentityType(mspID), 687 }) 688 } 689 return res 690 } 691 692 type peerInfo struct { 693 identity api.PeerIdentityType 694 pkiID common.PKIidType 695 discovery.NetworkMember 696 } 697 698 func peerIdentityString(id string) string { 699 return string(protoutil.MarshalOrPanic(&msp.SerializedIdentity{ 700 Mspid: pkiID2MSPID[id], 701 IdBytes: []byte(id), 702 })) 703 } 704 705 func newPeer(i int) *peerInfo { 706 p := fmt.Sprintf("p%d", i) 707 identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{ 708 Mspid: pkiID2MSPID[p], 709 IdBytes: []byte(p), 710 }) 711 return &peerInfo{ 712 pkiID: common.PKIidType(p), 713 identity: api.PeerIdentityType(identity), 714 NetworkMember: discovery.NetworkMember{ 715 PKIid: common.PKIidType(p), 716 Endpoint: p, 717 InternalEndpoint: p, 718 Envelope: &gossip.Envelope{ 719 Payload: []byte(identity), 720 }, 721 }, 722 } 723 } 724 725 func peerRole(pkiID string) *msp.MSPPrincipal { 726 return &msp.MSPPrincipal{ 727 PrincipalClassification: msp.MSPPrincipal_ROLE, 728 Principal: protoutil.MarshalOrPanic(&msp.MSPRole{ 729 MspIdentifier: pkiID2MSPID[pkiID], 730 Role: msp.MSPRole_PEER, 731 }), 732 } 733 } 734 735 func (pi *peerInfo) withChaincode(name, version string) *peerInfo { 736 if pi.Properties == nil { 737 pi.Properties = &gossip.Properties{} 738 } 739 pi.Properties.Chaincodes = append(pi.Properties.Chaincodes, &gossip.Chaincode{ 740 Name: name, 741 Version: version, 742 }) 743 return pi 744 } 745 746 type gossipMock struct { 747 mock.Mock 748 } 749 750 func (g *gossipMock) IdentityInfo() api.PeerIdentitySet { 751 return g.Called().Get(0).(api.PeerIdentitySet) 752 } 753 754 func (g *gossipMock) PeersOfChannel(_ common.ChannelID) discovery.Members { 755 members := g.Called().Get(0) 756 return members.(discovery.Members) 757 } 758 759 func (g *gossipMock) Peers() discovery.Members { 760 members := g.Called().Get(0) 761 return members.(discovery.Members) 762 } 763 764 type policyFetcherMock struct { 765 mock.Mock 766 } 767 768 func (pf *policyFetcherMock) PolicyByChaincode(channel string, chaincode string) policies.InquireablePolicy { 769 arg := pf.Called(chaincode) 770 if arg.Get(0) == nil { 771 return nil 772 } 773 return arg.Get(0).(policies.InquireablePolicy) 774 } 775 776 type principalBuilder struct { 777 ip inquireablePolicy 778 } 779 780 func (pb *principalBuilder) buildPolicy() inquireablePolicy { 781 defer func() { 782 pb.ip = nil 783 }() 784 return pb.ip 785 } 786 787 func (pb *principalBuilder) newSet() *principalBuilder { 788 pb.ip = append(pb.ip, make(policies.PrincipalSet, 0)) 789 return pb 790 } 791 792 func (pb *principalBuilder) addPrincipal(principal *msp.MSPPrincipal) *principalBuilder { 793 pb.ip[len(pb.ip)-1] = append(pb.ip[len(pb.ip)-1], principal) 794 return pb 795 } 796 797 type inquireablePolicy []policies.PrincipalSet 798 799 func (ip inquireablePolicy) SatisfiedBy() []policies.PrincipalSet { 800 return ip 801 } 802 803 type principalEvaluatorMock struct { 804 } 805 806 func (pe *principalEvaluatorMock) SatisfiesPrincipal(channel string, identity []byte, principal *msp.MSPPrincipal) error { 807 peerRole := &msp.MSPRole{} 808 if err := proto.Unmarshal(principal.Principal, peerRole); err != nil { 809 return err 810 } 811 sId := &msp.SerializedIdentity{} 812 if err := proto.Unmarshal(identity, sId); err != nil { 813 return err 814 } 815 if peerRole.MspIdentifier == sId.Mspid { 816 return nil 817 } 818 return errors.New("bingo") 819 } 820 821 type metadataFetcher struct { 822 mock.Mock 823 } 824 825 func (mf *metadataFetcher) Metadata(channel string, cc string, _ bool) *chaincode.Metadata { 826 arg := mf.Called().Get(0) 827 if arg == nil { 828 return nil 829 } 830 return arg.(*chaincode.Metadata) 831 }