github.com/hyperledger-labs/bdls@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  }