github.com/defanghe/fabric@v2.1.1+incompatible/discovery/test/integration_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package test 8 9 import ( 10 "bytes" 11 "context" 12 "crypto/ecdsa" 13 "crypto/rand" 14 "crypto/x509" 15 "encoding/hex" 16 "encoding/pem" 17 "fmt" 18 "io/ioutil" 19 "os" 20 "os/exec" 21 "path/filepath" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/golang/protobuf/proto" 27 "github.com/hyperledger/fabric-protos-go/common" 28 . "github.com/hyperledger/fabric-protos-go/discovery" 29 "github.com/hyperledger/fabric-protos-go/gossip" 30 msprotos "github.com/hyperledger/fabric-protos-go/msp" 31 "github.com/hyperledger/fabric-protos-go/peer" 32 "github.com/hyperledger/fabric/bccsp/sw" 33 bccsp "github.com/hyperledger/fabric/bccsp/utils" 34 "github.com/hyperledger/fabric/common/cauthdsl" 35 "github.com/hyperledger/fabric/common/configtx" 36 "github.com/hyperledger/fabric/common/crypto/tlsgen" 37 "github.com/hyperledger/fabric/common/policies" 38 "github.com/hyperledger/fabric/common/policydsl" 39 "github.com/hyperledger/fabric/common/util" 40 "github.com/hyperledger/fabric/core/cclifecycle" 41 lifecyclemocks "github.com/hyperledger/fabric/core/cclifecycle/mocks" 42 "github.com/hyperledger/fabric/core/common/ccprovider" 43 "github.com/hyperledger/fabric/discovery" 44 disc "github.com/hyperledger/fabric/discovery/client" 45 "github.com/hyperledger/fabric/discovery/endorsement" 46 discsupport "github.com/hyperledger/fabric/discovery/support" 47 discacl "github.com/hyperledger/fabric/discovery/support/acl" 48 ccsupport "github.com/hyperledger/fabric/discovery/support/chaincode" 49 "github.com/hyperledger/fabric/discovery/support/config" 50 "github.com/hyperledger/fabric/discovery/support/mocks" 51 "github.com/hyperledger/fabric/gossip/api" 52 gcommon "github.com/hyperledger/fabric/gossip/common" 53 gdisc "github.com/hyperledger/fabric/gossip/discovery" 54 "github.com/hyperledger/fabric/gossip/protoext" 55 "github.com/hyperledger/fabric/internal/configtxgen/encoder" 56 "github.com/hyperledger/fabric/internal/configtxgen/genesisconfig" 57 "github.com/hyperledger/fabric/internal/pkg/comm" 58 "github.com/hyperledger/fabric/msp" 59 "github.com/hyperledger/fabric/protoutil" 60 "github.com/onsi/gomega/gexec" 61 "github.com/pkg/errors" 62 "github.com/stretchr/testify/assert" 63 "google.golang.org/grpc" 64 ) 65 66 var ( 67 testPeers testPeerSet 68 69 cryptogen, idemixgen, testdir string 70 71 collectionConfigBytes = buildCollectionConfig(map[string][]*msprotos.MSPPrincipal{ 72 "col1": {orgPrincipal("Org1MSP")}, 73 "col12": {orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}, 74 }) 75 76 cc1Bytes = protoutil.MarshalOrPanic(&ccprovider.ChaincodeData{ 77 Name: "cc1", 78 Version: "1.0", 79 Id: []byte{42}, 80 Policy: protoutil.MarshalOrPanic(policyFromString("AND('Org1MSP.member', 'Org1MSP.member')")), 81 }) 82 83 cc2Bytes = protoutil.MarshalOrPanic(&ccprovider.ChaincodeData{ 84 Name: "cc2", 85 Version: "1.0", 86 Id: []byte{43}, 87 Policy: protoutil.MarshalOrPanic(policyFromString("AND('Org1MSP.member', 'Org2MSP.member')")), 88 }) 89 ) 90 91 func TestMain(m *testing.M) { 92 if err := buildBinaries(); err != nil { 93 fmt.Printf("failed to build binaries: +%v", err) 94 gexec.CleanupBuildArtifacts() 95 os.Exit(1) 96 } 97 98 var err error 99 testdir, err = generateChannelArtifacts() 100 if err != nil { 101 fmt.Printf("failed to generate channel artifacts: +%v", err) 102 os.RemoveAll(testdir) 103 gexec.CleanupBuildArtifacts() 104 os.Exit(1) 105 } 106 107 peerDirPrefix := filepath.Join(testdir, "crypto-config", "peerOrganizations") 108 testPeers = testPeerSet{ 109 newPeer(peerDirPrefix, "Org1MSP", 1, 0), 110 newPeer(peerDirPrefix, "Org1MSP", 1, 1), 111 newPeer(peerDirPrefix, "Org2MSP", 2, 0), 112 newPeer(peerDirPrefix, "Org2MSP", 2, 1), 113 } 114 115 rc := m.Run() 116 os.RemoveAll(testdir) 117 gexec.CleanupBuildArtifacts() 118 os.Exit(rc) 119 } 120 121 func TestGreenPath(t *testing.T) { 122 t.Parallel() 123 client, admin, service := createClientAndService(t, testdir) 124 defer service.Stop() 125 defer client.conn.Close() 126 127 service.lsccMetadataManager.query.On("GetState", "lscc", "cc1").Return(cc1Bytes, nil) 128 service.lsccMetadataManager.query.On("GetState", "lscc", "cc2").Return(cc2Bytes, nil) 129 service.lsccMetadataManager.query.On("GetState", "lscc", "cc2~collection").Return(collectionConfigBytes, nil) 130 131 ccWithCollection := &ChaincodeInterest{ 132 Chaincodes: []*ChaincodeCall{ 133 {Name: "cc2", CollectionNames: []string{"col12"}}, 134 }, 135 } 136 cc2cc := &ChaincodeInterest{ 137 Chaincodes: []*ChaincodeCall{ 138 {Name: "cc1"}, {Name: "cc2"}, 139 }, 140 } 141 142 // Send all queries 143 req := disc.NewRequest().AddLocalPeersQuery().OfChannel("mychannel") 144 col1 := &ChaincodeCall{Name: "cc2", CollectionNames: []string{"col1"}} 145 nonExistentCollection := &ChaincodeCall{Name: "cc2", CollectionNames: []string{"col3"}} 146 _ = nonExistentCollection 147 req, err := req.AddPeersQuery().AddPeersQuery(col1).AddPeersQuery(nonExistentCollection).AddConfigQuery().AddEndorsersQuery(cc2cc, ccWithCollection) 148 149 t.Run("Local peer query", func(t *testing.T) { 150 assert.NoError(t, err) 151 res, err := admin.Send(context.Background(), req, admin.AuthInfo) 152 assert.NoError(t, err) 153 returnedPeers, err := res.ForLocal().Peers() 154 assert.NoError(t, err) 155 assert.True(t, peersToTestPeers(returnedPeers).Equal(testPeers.withoutStateInfo())) 156 }) 157 158 t.Run("Channel peer queries", func(t *testing.T) { 159 assert.NoError(t, err) 160 res, err := client.Send(context.Background(), req, client.AuthInfo) 161 assert.NoError(t, err) 162 returnedPeers, err := res.ForChannel("mychannel").Peers() 163 assert.NoError(t, err) 164 assert.True(t, peersToTestPeers(returnedPeers).Equal(testPeers)) 165 166 returnedPeers, err = res.ForChannel("mychannel").Peers(col1) 167 assert.NoError(t, err) 168 // Ensure only peers from Org1 are returned 169 for _, p := range returnedPeers { 170 assert.Equal(t, "Org1MSP", p.MSPID) 171 } 172 173 // Ensure that the client handles correctly errors returned from the server 174 // in case of a bad request 175 returnedPeers, err = res.ForChannel("mychannel").Peers(nonExistentCollection) 176 assert.Equal(t, "collection col3 doesn't exist in collection config for chaincode cc2", err.Error()) 177 }) 178 179 t.Run("Endorser chaincode to chaincode", func(t *testing.T) { 180 assert.NoError(t, err) 181 res, err := client.Send(context.Background(), req, client.AuthInfo) 182 assert.NoError(t, err) 183 endorsers, err := res.ForChannel("mychannel").Endorsers(cc2cc.Chaincodes, disc.NoFilter) 184 assert.NoError(t, err) 185 endorsersByMSP := map[string][]string{} 186 187 for _, endorser := range endorsers { 188 endorsersByMSP[endorser.MSPID] = append(endorsersByMSP[endorser.MSPID], string(endorser.Identity)) 189 } 190 // For cc2cc we expect 2 peers from Org1MSP and 1 from Org2MSP 191 assert.Equal(t, 2, len(endorsersByMSP["Org1MSP"])) 192 assert.Equal(t, 1, len(endorsersByMSP["Org2MSP"])) 193 }) 194 195 t.Run("Endorser chaincode with collection", func(t *testing.T) { 196 assert.NoError(t, err) 197 res, err := client.Send(context.Background(), req, client.AuthInfo) 198 assert.NoError(t, err) 199 endorsers, err := res.ForChannel("mychannel").Endorsers(ccWithCollection.Chaincodes, disc.NoFilter) 200 assert.NoError(t, err) 201 202 endorsersByMSP := map[string][]string{} 203 for _, endorser := range endorsers { 204 endorsersByMSP[endorser.MSPID] = append(endorsersByMSP[endorser.MSPID], string(endorser.Identity)) 205 } 206 assert.Equal(t, 1, len(endorsersByMSP["Org1MSP"])) 207 assert.Equal(t, 1, len(endorsersByMSP["Org2MSP"])) 208 }) 209 210 t.Run("Config query", func(t *testing.T) { 211 assert.NoError(t, err) 212 res, err := client.Send(context.Background(), req, client.AuthInfo) 213 assert.NoError(t, err) 214 conf, err := res.ForChannel("mychannel").Config() 215 assert.NoError(t, err) 216 // Ensure MSP Configs are exactly as they appear in the config block 217 for mspID, mspConfig := range conf.Msps { 218 expectedConfig := service.sup.mspConfigs[mspID] 219 assert.Equal(t, expectedConfig, mspConfig) 220 } 221 // Ensure orderer endpoints are as they appear in the config block 222 for mspID, endpoints := range conf.Orderers { 223 assert.Equal(t, "OrdererMSP", mspID) 224 endpoints := endpoints.Endpoint 225 assert.Len(t, endpoints, 1) 226 assert.Equal(t, "orderer.example.com", endpoints[0].Host) 227 assert.Equal(t, uint32(7050), endpoints[0].Port) 228 } 229 }) 230 } 231 232 func TestEndorsementComputationFailure(t *testing.T) { 233 t.Parallel() 234 client, _, service := createClientAndService(t, testdir) 235 defer service.Stop() 236 defer client.conn.Close() 237 238 service.lsccMetadataManager.query.On("GetState", "lscc", "cc1").Return(cc1Bytes, nil) 239 service.lsccMetadataManager.query.On("GetState", "lscc", "cc2").Return(cc2Bytes, nil) 240 service.lsccMetadataManager.query.On("GetState", "lscc", "cc2~collection").Return(collectionConfigBytes, nil) 241 242 // Now test a collection query that should fail because cc2's endorsement policy is Org1MSP AND org2MSP 243 // but the collection is configured only to have peers from Org1MSP 244 ccWithCollection := &ChaincodeInterest{ 245 Chaincodes: []*ChaincodeCall{ 246 {Name: "cc2", CollectionNames: []string{"col1"}}, 247 }, 248 } 249 req, err := disc.NewRequest().OfChannel("mychannel").AddEndorsersQuery(ccWithCollection) 250 assert.NoError(t, err) 251 res, err := client.Send(context.Background(), req, client.AuthInfo) 252 assert.NoError(t, err) 253 254 endorsers, err := res.ForChannel("mychannel").Endorsers(ccWithCollection.Chaincodes, disc.NoFilter) 255 assert.Empty(t, endorsers) 256 assert.Contains(t, err.Error(), "failed constructing descriptor") 257 } 258 259 func TestLedgerFailure(t *testing.T) { 260 t.Parallel() 261 client, _, service := createClientAndService(t, testdir) 262 defer service.Stop() 263 defer client.conn.Close() 264 265 service.lsccMetadataManager.query.On("GetState", "lscc", "cc1").Return(cc1Bytes, nil) 266 service.lsccMetadataManager.query.On("GetState", "lscc", "cc2").Return(nil, errors.New("IO error")) 267 service.lsccMetadataManager.query.On("GetState", "lscc", "cc12~collection").Return(collectionConfigBytes, nil) 268 269 ccWithCollection := &ChaincodeInterest{ 270 Chaincodes: []*ChaincodeCall{ 271 {Name: "cc1"}, 272 {Name: "cc2", CollectionNames: []string{"col1"}}, 273 }, 274 } 275 req, err := disc.NewRequest().OfChannel("mychannel").AddEndorsersQuery(ccWithCollection) 276 assert.NoError(t, err) 277 res, err := client.Send(context.Background(), req, client.AuthInfo) 278 assert.NoError(t, err) 279 280 endorsers, err := res.ForChannel("mychannel").Endorsers(ccWithCollection.Chaincodes, disc.NoFilter) 281 assert.Empty(t, endorsers) 282 assert.Contains(t, err.Error(), "failed constructing descriptor") 283 } 284 285 func TestRevocation(t *testing.T) { 286 t.Parallel() 287 client, _, service := createClientAndService(t, testdir) 288 defer service.Stop() 289 defer client.conn.Close() 290 291 req := disc.NewRequest().OfChannel("mychannel").AddPeersQuery() 292 res, err := client.Send(context.Background(), req, client.AuthInfo) 293 assert.NoError(t, err) 294 // Record number of times we deserialized the identity 295 firstCount := atomic.LoadUint32(&service.sup.deserializeIdentityCount) 296 297 // Do the same query again 298 peers, err := res.ForChannel("mychannel").Peers() 299 assert.NotEmpty(t, peers) 300 assert.NoError(t, err) 301 302 res, err = client.Send(context.Background(), req, client.AuthInfo) 303 assert.NoError(t, err) 304 // The amount of times deserializeIdentity was called should not have changed 305 // because requests should have hit the cache 306 secondCount := atomic.LoadUint32(&service.sup.deserializeIdentityCount) 307 assert.Equal(t, firstCount, secondCount) 308 309 // Now, increment the config sequence 310 oldSeq := service.sup.sequenceWrapper.Sequence() 311 v := &mocks.ConfigtxValidator{} 312 v.SequenceReturns(oldSeq + 1) 313 service.sup.sequenceWrapper.instance.Store(v) 314 315 // Revoke all identities inside the MSP manager 316 atomic.AddUint32(&service.sup.mspWrapper.blocks, uint32(1)) 317 318 // Send the query for the third time 319 res, err = client.Send(context.Background(), req, client.AuthInfo) 320 assert.NoError(t, err) 321 // The cache should have been purged, thus deserializeIdentity should have been 322 // called an additional time 323 thirdCount := atomic.LoadUint32(&service.sup.deserializeIdentityCount) 324 assert.NotEqual(t, thirdCount, secondCount) 325 326 // We should be denied access 327 peers, err = res.ForChannel("mychannel").Peers() 328 assert.Empty(t, peers) 329 assert.Contains(t, err.Error(), "access denied") 330 } 331 332 type client struct { 333 *disc.Client 334 *AuthInfo 335 conn *grpc.ClientConn 336 } 337 338 func (c *client) newConnection() (*grpc.ClientConn, error) { 339 return c.conn, nil 340 } 341 342 type mspWrapper struct { 343 deserializeIdentityCount uint32 344 msp.MSPManager 345 mspConfigs map[string]*msprotos.FabricMSPConfig 346 blocks uint32 347 } 348 349 func (w *mspWrapper) DeserializeIdentity(serializedIdentity []byte) (msp.Identity, error) { 350 atomic.AddUint32(&w.deserializeIdentityCount, 1) 351 if atomic.LoadUint32(&w.blocks) == uint32(1) { 352 return nil, errors.New("failed deserializing identity") 353 } 354 return w.MSPManager.DeserializeIdentity(serializedIdentity) 355 } 356 357 type lsccMetadataManager struct { 358 *cclifecycle.MetadataManager 359 query *lifecyclemocks.Query 360 } 361 362 func newLSCCMetadataManager() *lsccMetadataManager { 363 enumerator := &lifecyclemocks.Enumerator{} 364 enumerator.On("Enumerate").Return(nil, nil) 365 m, err := cclifecycle.NewMetadataManager(enumerator) 366 if err != nil { 367 panic(err) 368 } 369 qc := &lifecyclemocks.QueryCreator{} 370 query := &lifecyclemocks.Query{} 371 query.On("Done").Return() 372 qc.On("NewQuery").Return(query, nil) 373 _, err = m.NewChannelSubscription("mychannel", qc) 374 if err != nil { 375 panic(err) 376 } 377 return &lsccMetadataManager{ 378 MetadataManager: m, 379 query: query, 380 } 381 } 382 383 type principalEvaluator struct { 384 *discacl.DiscoverySupport 385 msp.MSPManager 386 } 387 388 type service struct { 389 *grpc.Server 390 lsccMetadataManager *lsccMetadataManager 391 sup *support 392 } 393 394 type support struct { 395 discovery.Support 396 *mspWrapper 397 *sequenceWrapper 398 } 399 400 type sequenceWrapper struct { 401 configtx.Validator 402 instance atomic.Value 403 } 404 405 func (s *sequenceWrapper) Sequence() uint64 { 406 return s.instance.Load().(*mocks.ConfigtxValidator).Sequence() 407 } 408 409 func createSupport(t *testing.T, dir string, lsccMetadataManager *lsccMetadataManager) *support { 410 configs := make(map[string]*msprotos.FabricMSPConfig) 411 mspMgr := createMSPManager(t, dir, configs) 412 mspManagerWrapper := &mspWrapper{ 413 MSPManager: mspMgr, 414 mspConfigs: configs, 415 } 416 mspMgr = mspManagerWrapper 417 msps, _ := mspMgr.GetMSPs() 418 org1MSP := msps["Org1MSP"] 419 s := &sequenceWrapper{} 420 v := &mocks.ConfigtxValidator{} 421 v.SequenceReturns(1) 422 s.instance.Store(v) 423 chConfig := createChannelConfigGetter(s, mspMgr) 424 polMgr := createPolicyManagerGetter(t, mspMgr) 425 426 channelVerifier := discacl.NewChannelVerifier(policies.ChannelApplicationWriters, polMgr) 427 428 org1Admin, err := policydsl.FromString("OR('Org1MSP.admin')") 429 assert.NoError(t, err) 430 org1AdminPolicy, _, err := cauthdsl.NewPolicyProvider(org1MSP).NewPolicy(protoutil.MarshalOrPanic(org1Admin)) 431 assert.NoError(t, err) 432 acl := discacl.NewDiscoverySupport(channelVerifier, org1AdminPolicy, chConfig) 433 434 gSup := &mocks.GossipSupport{} 435 gSup.On("ChannelExists", "mychannel").Return(true) 436 gSup.On("PeersOfChannel", gcommon.ChannelID("mychannel")).Return(testPeers.toStateInfoSet()) 437 gSup.On("Peers").Return(testPeers.toMembershipSet()) 438 gSup.On("IdentityInfo").Return(testPeers.toIdentitySet()) 439 440 pe := &principalEvaluator{ 441 MSPManager: mspMgr, 442 DiscoverySupport: &discacl.DiscoverySupport{ 443 ChannelConfigGetter: createChannelConfigGetter(s, mspMgr), 444 }, 445 } 446 447 ccSup := ccsupport.NewDiscoverySupport(lsccMetadataManager) 448 ea := endorsement.NewEndorsementAnalyzer(gSup, ccSup, pe, lsccMetadataManager) 449 450 fakeBlockGetter := &mocks.ConfigBlockGetter{} 451 fakeBlockGetter.GetCurrConfigBlockReturns(createGenesisBlock(filepath.Join(dir, "crypto-config"))) 452 confSup := config.NewDiscoverySupport(fakeBlockGetter) 453 return &support{ 454 Support: discsupport.NewDiscoverySupport(acl, gSup, ea, confSup, acl), 455 mspWrapper: mspManagerWrapper, 456 sequenceWrapper: s, 457 } 458 } 459 460 func createClientAndService(t *testing.T, testdir string) (*client, *client, *service) { 461 ca, err := tlsgen.NewCA() 462 assert.NoError(t, err) 463 464 serverKeyPair, err := ca.NewServerCertKeyPair("127.0.0.1") 465 assert.NoError(t, err) 466 467 // Create a server on an ephemeral port 468 gRPCServer, err := comm.NewGRPCServer("127.0.0.1:", comm.ServerConfig{ 469 SecOpts: comm.SecureOptions{ 470 Key: serverKeyPair.Key, 471 Certificate: serverKeyPair.Cert, 472 UseTLS: true, 473 }, 474 }) 475 476 l := newLSCCMetadataManager() 477 sup := createSupport(t, testdir, l) 478 svc := discovery.NewService(discovery.Config{ 479 TLS: gRPCServer.TLSEnabled(), 480 AuthCacheEnabled: true, 481 AuthCacheMaxSize: 10, 482 AuthCachePurgeRetentionRatio: 0.5, 483 }, sup) 484 485 RegisterDiscoveryServer(gRPCServer.Server(), svc) 486 487 assert.NoError(t, err) 488 go gRPCServer.Start() 489 490 clientKeyPair, err := ca.NewClientCertKeyPair() 491 assert.NoError(t, err) 492 493 dialer, err := comm.NewGRPCClient(comm.ClientConfig{ 494 Timeout: time.Second * 3, 495 SecOpts: comm.SecureOptions{ 496 UseTLS: true, 497 Certificate: clientKeyPair.Cert, 498 Key: clientKeyPair.Key, 499 ServerRootCAs: [][]byte{ca.CertBytes()}, 500 }, 501 }) 502 assert.NoError(t, err) 503 504 conn, err := dialer.NewConnection(gRPCServer.Address()) 505 assert.NoError(t, err) 506 507 userSigner := createUserSigner(t) 508 wrapperUserClient := &client{AuthInfo: &AuthInfo{ 509 ClientIdentity: userSigner.Creator, 510 ClientTlsCertHash: util.ComputeSHA256(clientKeyPair.TLSCert.Raw), 511 }, conn: conn} 512 var signerCacheSize uint = 10 513 wrapperUserClient.Client = disc.NewClient(wrapperUserClient.newConnection, userSigner.Sign, signerCacheSize) 514 515 adminSigner := createAdminSigner(t) 516 wrapperAdminClient := &client{AuthInfo: &AuthInfo{ 517 ClientIdentity: adminSigner.Creator, 518 ClientTlsCertHash: util.ComputeSHA256(clientKeyPair.TLSCert.Raw), 519 }, conn: conn} 520 wrapperAdminClient.Client = disc.NewClient(wrapperAdminClient.newConnection, adminSigner.Sign, signerCacheSize) 521 522 service := &service{Server: gRPCServer.Server(), lsccMetadataManager: l, sup: sup} 523 return wrapperUserClient, wrapperAdminClient, service 524 } 525 526 func createUserSigner(t *testing.T) *signer { 527 identityDir := filepath.Join(testdir, "crypto-config", "peerOrganizations", "org1.example.com", "users", "User1@org1.example.com", "msp") 528 certPath := filepath.Join(identityDir, "signcerts", "User1@org1.example.com-cert.pem") 529 keyPath := filepath.Join(identityDir, "keystore") 530 keys, err := ioutil.ReadDir(keyPath) 531 assert.NoError(t, err) 532 assert.Len(t, keys, 1) 533 keyPath = filepath.Join(keyPath, keys[0].Name()) 534 signer, err := newSigner("Org1MSP", certPath, keyPath) 535 assert.NoError(t, err) 536 return signer 537 } 538 539 func createAdminSigner(t *testing.T) *signer { 540 identityDir := filepath.Join(testdir, "crypto-config", "peerOrganizations", "org1.example.com", "users", "Admin@org1.example.com", "msp") 541 certPath := filepath.Join(identityDir, "signcerts", "Admin@org1.example.com-cert.pem") 542 keyPath := filepath.Join(identityDir, "keystore") 543 keys, err := ioutil.ReadDir(keyPath) 544 assert.NoError(t, err) 545 assert.Len(t, keys, 1) 546 keyPath = filepath.Join(keyPath, keys[0].Name()) 547 signer, err := newSigner("Org1MSP", certPath, keyPath) 548 assert.NoError(t, err) 549 return signer 550 } 551 552 func createMSP(t *testing.T, dir, mspID string) (msp.MSP, *msprotos.FabricMSPConfig) { 553 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 554 assert.NoError(t, err) 555 channelMSP, err := msp.New( 556 &msp.BCCSPNewOpts{NewBaseOpts: msp.NewBaseOpts{Version: msp.MSPv1_4_3}}, 557 cryptoProvider, 558 ) 559 assert.NoError(t, err) 560 561 mspConf, err := msp.GetVerifyingMspConfig(dir, mspID, "bccsp") 562 assert.NoError(t, err) 563 564 fabConf := &msprotos.FabricMSPConfig{} 565 proto.Unmarshal(mspConf.Config, fabConf) 566 567 channelMSP.Setup(mspConf) 568 return channelMSP, fabConf 569 } 570 571 func createMSPManager(t *testing.T, dir string, configs map[string]*msprotos.FabricMSPConfig) msp.MSPManager { 572 var mspsOfChannel []msp.MSP 573 for _, mspConf := range []struct { 574 mspID string 575 mspDir string 576 }{ 577 { 578 mspID: "Org1MSP", 579 mspDir: filepath.Join(dir, "crypto-config", "peerOrganizations", "org1.example.com", "msp"), 580 }, 581 { 582 mspID: "Org2MSP", 583 mspDir: filepath.Join(dir, "crypto-config", "peerOrganizations", "org2.example.com", "msp"), 584 }, 585 { 586 mspID: "OrdererMSP", 587 mspDir: filepath.Join(dir, "crypto-config", "ordererOrganizations", "example.com", "msp"), 588 }, 589 } { 590 mspInstance, conf := createMSP(t, mspConf.mspDir, mspConf.mspID) 591 configs[mspConf.mspID] = conf 592 mspsOfChannel = append(mspsOfChannel, mspInstance) 593 } 594 595 mspMgr := msp.NewMSPManager() 596 mspMgr.Setup(mspsOfChannel) 597 return mspMgr 598 } 599 600 func createChannelConfigGetter(s *sequenceWrapper, mspMgr msp.MSPManager) discacl.ChannelConfigGetter { 601 resources := &mocks.Resources{} 602 resources.ConfigtxValidatorReturns(s) 603 resources.MSPManagerReturns(mspMgr) 604 chConfig := &mocks.ChannelConfigGetter{} 605 chConfig.GetChannelConfigReturns(resources) 606 return chConfig 607 } 608 609 func createPolicyManagerGetter(t *testing.T, mspMgr msp.MSPManager) *mocks.ChannelPolicyManagerGetter { 610 org1Org2Members, err := policydsl.FromString("OR('Org1MSP.client', 'Org2MSP.client')") 611 assert.NoError(t, err) 612 org1Org2MembersPolicy, _, err := cauthdsl.NewPolicyProvider(mspMgr).NewPolicy(protoutil.MarshalOrPanic(org1Org2Members)) 613 assert.NoError(t, err) 614 615 polMgr := &mocks.ChannelPolicyManagerGetter{} 616 policyMgr := &mocks.PolicyManager{} 617 policyMgr.On("GetPolicy", policies.ChannelApplicationWriters).Return(org1Org2MembersPolicy, true) 618 polMgr.On("Manager", "mychannel").Return(policyMgr, false) 619 return polMgr 620 } 621 622 func buildBinaries() error { 623 var err error 624 cryptogen, err = gexec.Build("github.com/hyperledger/fabric/cmd/cryptogen") 625 if err != nil { 626 return errors.WithStack(err) 627 } 628 629 idemixgen, err = gexec.Build("github.com/hyperledger/fabric/cmd/idemixgen") 630 if err != nil { 631 return errors.WithStack(err) 632 } 633 return nil 634 } 635 636 func generateChannelArtifacts() (string, error) { 637 dir, err := ioutil.TempDir("", "TestMSPIDMapping") 638 if err != nil { 639 return "", errors.WithStack(err) 640 } 641 cryptoConfigDir := filepath.Join(dir, "crypto-config") 642 args := []string{ 643 "generate", 644 fmt.Sprintf("--output=%s", cryptoConfigDir), 645 fmt.Sprintf("--config=%s", filepath.Join("testdata", "crypto-config.yaml")), 646 } 647 b, err := exec.Command(cryptogen, args...).CombinedOutput() 648 if err != nil { 649 return "", errors.Wrap(err, string(b)) 650 } 651 652 idemixConfigDir := filepath.Join(dir, "crypto-config", "idemix") 653 b, err = exec.Command(idemixgen, "ca-keygen", fmt.Sprintf("--output=%s", idemixConfigDir)).CombinedOutput() 654 if err != nil { 655 return "", errors.Wrap(err, string(b)) 656 } 657 return dir, nil 658 } 659 660 func createGenesisBlock(cryptoConfigDir string) *common.Block { 661 appConfig := genesisconfig.Load("TwoOrgsChannel", "testdata") 662 ordererConfig := genesisconfig.Load("TwoOrgsOrdererGenesis", "testdata") 663 // Glue the two parts together, without loss of generality - to the application parts 664 appConfig.Orderer = ordererConfig.Orderer 665 channelConfig := appConfig 666 667 idemixConfigDir := filepath.Join(cryptoConfigDir, "idemix") 668 // Override the MSP directories 669 for _, org := range channelConfig.Orderer.Organizations { 670 org.MSPDir = filepath.Join(cryptoConfigDir, "ordererOrganizations", "example.com", "msp") 671 } 672 for i, org := range channelConfig.Application.Organizations { 673 if org.MSPType != "bccsp" { 674 org.MSPDir = filepath.Join(idemixConfigDir) 675 continue 676 } 677 org.MSPDir = filepath.Join(cryptoConfigDir, "peerOrganizations", fmt.Sprintf("org%d.example.com", i+1), "msp") 678 } 679 680 channelGenerator := encoder.New(channelConfig) 681 return channelGenerator.GenesisBlockForChannel("mychannel") 682 } 683 684 type testPeer struct { 685 mspID string 686 identity []byte 687 stateInfoMsg gdisc.NetworkMember 688 aliveMsg gdisc.NetworkMember 689 } 690 691 func (tp testPeer) Equal(other testPeer) bool { 692 if tp.mspID != other.mspID || !bytes.Equal(tp.identity, other.identity) { 693 return false 694 } 695 if tp.aliveMsg.Endpoint != other.aliveMsg.Endpoint || !bytes.Equal(tp.aliveMsg.PKIid, other.aliveMsg.PKIid) { 696 return false 697 } 698 if !proto.Equal(tp.aliveMsg.Envelope, other.aliveMsg.Envelope) { 699 return false 700 } 701 if !bytes.Equal(tp.stateInfoMsg.PKIid, other.stateInfoMsg.PKIid) { 702 return false 703 } 704 if !proto.Equal(tp.stateInfoMsg.Envelope, other.stateInfoMsg.Envelope) { 705 return false 706 } 707 if !proto.Equal(tp.stateInfoMsg.Properties, other.stateInfoMsg.Properties) { 708 return false 709 } 710 return true 711 } 712 713 type testPeerSet []*testPeer 714 715 func (ps testPeerSet) withoutStateInfo() testPeerSet { 716 var res testPeerSet 717 for _, p := range ps { 718 peer := *p 719 peer.stateInfoMsg = gdisc.NetworkMember{} 720 res = append(res, &peer) 721 } 722 return res 723 } 724 725 func (ps testPeerSet) toStateInfoSet() gdisc.Members { 726 var members gdisc.Members 727 for _, p := range ps { 728 members = append(members, p.stateInfoMsg) 729 } 730 return members 731 } 732 733 func (ps testPeerSet) toMembershipSet() gdisc.Members { 734 var members gdisc.Members 735 for _, p := range ps { 736 members = append(members, p.aliveMsg) 737 } 738 return members 739 } 740 741 func (ps testPeerSet) toIdentitySet() api.PeerIdentitySet { 742 var idSet api.PeerIdentitySet 743 for _, p := range ps { 744 idSet = append(idSet, api.PeerIdentityInfo{ 745 Identity: p.identity, 746 PKIId: p.aliveMsg.PKIid, 747 Organization: api.OrgIdentityType(p.mspID), 748 }) 749 } 750 return idSet 751 } 752 753 func (ps testPeerSet) Equal(that testPeerSet) bool { 754 this := ps 755 return this.SubsetEqual(that) && that.SubsetEqual(this) 756 } 757 758 func (ps testPeerSet) SubsetEqual(that testPeerSet) bool { 759 this := ps 760 for _, p := range this { 761 if !that.Contains(p) { 762 return false 763 } 764 } 765 return true 766 } 767 768 func (ps testPeerSet) Contains(peer *testPeer) bool { 769 for _, p := range ps { 770 if peer.Equal(*p) { 771 return true 772 } 773 } 774 return false 775 } 776 777 func peersToTestPeers(peers []*disc.Peer) testPeerSet { 778 var res testPeerSet 779 for _, p := range peers { 780 pkiID := gcommon.PKIidType(hex.EncodeToString(util.ComputeSHA256(p.Identity))) 781 var stateInfoMember gdisc.NetworkMember 782 if p.StateInfoMessage != nil { 783 stateInfo, _ := protoext.EnvelopeToGossipMessage(p.StateInfoMessage.Envelope) 784 stateInfoMember = gdisc.NetworkMember{ 785 PKIid: pkiID, 786 Envelope: p.StateInfoMessage.Envelope, 787 Properties: stateInfo.GetStateInfo().Properties, 788 } 789 } 790 791 tp := &testPeer{ 792 mspID: p.MSPID, 793 identity: p.Identity, 794 aliveMsg: gdisc.NetworkMember{ 795 PKIid: pkiID, 796 Endpoint: string(pkiID), 797 Envelope: p.AliveMessage.Envelope, 798 }, 799 stateInfoMsg: stateInfoMember, 800 } 801 res = append(res, tp) 802 } 803 return res 804 } 805 806 func newPeer(dir, mspID string, org, id int) *testPeer { 807 peerStr := fmt.Sprintf("peer%d.org%d.example.com", id, org) 808 certFile := filepath.Join(dir, fmt.Sprintf("org%d.example.com", org), 809 "peers", peerStr, "msp", "signcerts", fmt.Sprintf("%s-cert.pem", peerStr)) 810 certBytes, err := ioutil.ReadFile(certFile) 811 if err != nil { 812 panic(fmt.Sprintf("failed reading file %s: %v", certFile, err)) 813 } 814 sID := &msprotos.SerializedIdentity{ 815 Mspid: mspID, 816 IdBytes: certBytes, 817 } 818 identityBytes := protoutil.MarshalOrPanic(sID) 819 pkiID := gcommon.PKIidType(hex.EncodeToString(util.ComputeSHA256(identityBytes))) 820 return &testPeer{ 821 mspID: mspID, 822 identity: identityBytes, 823 aliveMsg: aliveMsg(pkiID), 824 stateInfoMsg: stateInfoMsg(pkiID), 825 } 826 } 827 828 func stateInfoMsg(pkiID gcommon.PKIidType) gdisc.NetworkMember { 829 si := &gossip.StateInfo{ 830 Properties: &gossip.Properties{ 831 LedgerHeight: 100, 832 Chaincodes: []*gossip.Chaincode{ 833 { 834 Name: "cc1", 835 Version: "1.0", 836 Metadata: []byte{42}, 837 }, 838 { 839 Name: "cc2", 840 Version: "1.0", 841 Metadata: []byte{43}, 842 }, 843 }, 844 }, 845 PkiId: pkiID, 846 Timestamp: &gossip.PeerTime{}, 847 } 848 gm := &gossip.GossipMessage{ 849 Content: &gossip.GossipMessage_StateInfo{ 850 StateInfo: si, 851 }, 852 } 853 sm, _ := protoext.NoopSign(gm) 854 return gdisc.NetworkMember{ 855 Properties: si.Properties, 856 PKIid: pkiID, 857 Envelope: sm.Envelope, 858 } 859 } 860 861 func aliveMsg(pkiID gcommon.PKIidType) gdisc.NetworkMember { 862 am := &gossip.AliveMessage{ 863 Membership: &gossip.Member{ 864 PkiId: pkiID, 865 Endpoint: string(pkiID), 866 }, 867 Timestamp: &gossip.PeerTime{}, 868 } 869 gm := &gossip.GossipMessage{ 870 Content: &gossip.GossipMessage_AliveMsg{ 871 AliveMsg: am, 872 }, 873 } 874 sm, _ := protoext.NoopSign(gm) 875 return gdisc.NetworkMember{ 876 PKIid: pkiID, 877 Endpoint: string(pkiID), 878 Envelope: sm.Envelope, 879 } 880 } 881 882 func buildCollectionConfig(col2principals map[string][]*msprotos.MSPPrincipal) []byte { 883 collections := &peer.CollectionConfigPackage{} 884 for col, principals := range col2principals { 885 collections.Config = append(collections.Config, &peer.CollectionConfig{ 886 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 887 StaticCollectionConfig: &peer.StaticCollectionConfig{ 888 Name: col, 889 MemberOrgsPolicy: &peer.CollectionPolicyConfig{ 890 Payload: &peer.CollectionPolicyConfig_SignaturePolicy{ 891 SignaturePolicy: &common.SignaturePolicyEnvelope{ 892 Identities: principals, 893 }, 894 }, 895 }, 896 }, 897 }, 898 }) 899 } 900 return protoutil.MarshalOrPanic(collections) 901 } 902 903 func orgPrincipal(mspID string) *msprotos.MSPPrincipal { 904 return &msprotos.MSPPrincipal{ 905 PrincipalClassification: msprotos.MSPPrincipal_ROLE, 906 Principal: protoutil.MarshalOrPanic(&msprotos.MSPRole{ 907 MspIdentifier: mspID, 908 Role: msprotos.MSPRole_MEMBER, 909 }), 910 } 911 } 912 913 func policyFromString(s string) *common.SignaturePolicyEnvelope { 914 p, err := policydsl.FromString(s) 915 if err != nil { 916 panic(err) 917 } 918 return p 919 } 920 921 type signer struct { 922 key *ecdsa.PrivateKey 923 Creator []byte 924 } 925 926 func newSigner(msp, certPath, keyPath string) (*signer, error) { 927 sId, err := serializeIdentity(certPath, msp) 928 if err != nil { 929 return nil, errors.WithStack(err) 930 } 931 key, err := loadPrivateKey(keyPath) 932 if err != nil { 933 return nil, errors.WithStack(err) 934 } 935 return &signer{ 936 Creator: sId, 937 key: key, 938 }, nil 939 } 940 941 func serializeIdentity(clientCert string, mspID string) ([]byte, error) { 942 b, err := ioutil.ReadFile(clientCert) 943 if err != nil { 944 return nil, errors.WithStack(err) 945 } 946 sId := &msprotos.SerializedIdentity{ 947 Mspid: mspID, 948 IdBytes: b, 949 } 950 return protoutil.MarshalOrPanic(sId), nil 951 } 952 953 func (si *signer) Sign(msg []byte) ([]byte, error) { 954 digest := util.ComputeSHA256(msg) 955 return signECDSA(si.key, digest) 956 } 957 958 func loadPrivateKey(file string) (*ecdsa.PrivateKey, error) { 959 b, err := ioutil.ReadFile(file) 960 if err != nil { 961 return nil, errors.WithStack(err) 962 } 963 bl, _ := pem.Decode(b) 964 key, err := x509.ParsePKCS8PrivateKey(bl.Bytes) 965 if err != nil { 966 return nil, errors.WithStack(err) 967 } 968 return key.(*ecdsa.PrivateKey), nil 969 } 970 971 func signECDSA(k *ecdsa.PrivateKey, digest []byte) (signature []byte, err error) { 972 r, s, err := ecdsa.Sign(rand.Reader, k, digest) 973 if err != nil { 974 return nil, err 975 } 976 977 s, err = bccsp.ToLowS(&k.PublicKey, s) 978 if err != nil { 979 return nil, err 980 } 981 return bccsp.MarshalECDSASignature(r, s) 982 }