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