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  }