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