github.com/true-sqn/fabric@v2.1.1+incompatible/internal/peer/chaincode/common_test.go (about)

     1  /*
     2  Copyright Digital Asset Holdings, LLC. All Rights Reserved.
     3  Copyright IBM Corp. All Rights Reserved.
     4  
     5  SPDX-License-Identifier: Apache-2.0
     6  */
     7  
     8  package chaincode
     9  
    10  import (
    11  	"context"
    12  	"crypto/tls"
    13  	"encoding/json"
    14  	"errors"
    15  	"fmt"
    16  	"sort"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/golang/protobuf/proto"
    21  	cb "github.com/hyperledger/fabric-protos-go/common"
    22  	pb "github.com/hyperledger/fabric-protos-go/peer"
    23  	"github.com/hyperledger/fabric/bccsp/factory"
    24  	"github.com/hyperledger/fabric/bccsp/sw"
    25  	"github.com/hyperledger/fabric/common/policydsl"
    26  	"github.com/hyperledger/fabric/core/config/configtest"
    27  	"github.com/hyperledger/fabric/internal/configtxgen/encoder"
    28  	"github.com/hyperledger/fabric/internal/configtxgen/genesisconfig"
    29  	"github.com/hyperledger/fabric/internal/peer/chaincode/mock"
    30  	"github.com/hyperledger/fabric/internal/peer/common"
    31  	"github.com/hyperledger/fabric/internal/pkg/identity"
    32  	"github.com/hyperledger/fabric/protoutil"
    33  	. "github.com/onsi/gomega"
    34  	"github.com/spf13/cobra"
    35  	"github.com/spf13/viper"
    36  	"github.com/stretchr/testify/assert"
    37  	"github.com/stretchr/testify/require"
    38  )
    39  
    40  //go:generate counterfeiter -o mock/signer_serializer.go --fake-name SignerSerializer . signerSerializer
    41  
    42  type signerSerializer interface {
    43  	identity.SignerSerializer
    44  }
    45  
    46  //go:generate counterfeiter -o mock/deliver.go --fake-name Deliver . deliver
    47  
    48  type deliver interface {
    49  	pb.Deliver_DeliverClient
    50  }
    51  
    52  //go:generate counterfeiter -o mock/deliver_client.go --fake-name PeerDeliverClient . peerDeliverClient
    53  
    54  type peerDeliverClient interface {
    55  	pb.DeliverClient
    56  }
    57  
    58  func TestCheckChaincodeCmdParamsWithNewCallingSchema(t *testing.T) {
    59  	chaincodeCtorJSON = `{ "Args":["func", "param"] }`
    60  	chaincodePath = "some/path"
    61  	chaincodeName = "somename"
    62  	require := require.New(t)
    63  	result := checkChaincodeCmdParams(&cobra.Command{})
    64  
    65  	require.Nil(result)
    66  }
    67  
    68  func TestCheckChaincodeCmdParamsWithOldCallingSchema(t *testing.T) {
    69  	chaincodeCtorJSON = `{ "Function":"func", "Args":["param"] }`
    70  	chaincodePath = "some/path"
    71  	chaincodeName = "somename"
    72  	require := require.New(t)
    73  	result := checkChaincodeCmdParams(&cobra.Command{})
    74  
    75  	require.Nil(result)
    76  }
    77  
    78  func TestCheckChaincodeCmdParamsWithoutName(t *testing.T) {
    79  	chaincodeCtorJSON = `{ "Function":"func", "Args":["param"] }`
    80  	chaincodePath = "some/path"
    81  	chaincodeName = ""
    82  	require := require.New(t)
    83  	result := checkChaincodeCmdParams(&cobra.Command{})
    84  
    85  	require.Error(result)
    86  }
    87  
    88  func TestCheckChaincodeCmdParamsWithFunctionOnly(t *testing.T) {
    89  	chaincodeCtorJSON = `{ "Function":"func" }`
    90  	chaincodePath = "some/path"
    91  	chaincodeName = "somename"
    92  	require := require.New(t)
    93  	result := checkChaincodeCmdParams(&cobra.Command{})
    94  
    95  	require.Error(result)
    96  }
    97  
    98  func TestCheckChaincodeCmdParamsEmptyCtor(t *testing.T) {
    99  	chaincodeCtorJSON = `{}`
   100  	chaincodePath = "some/path"
   101  	chaincodeName = "somename"
   102  	require := require.New(t)
   103  	result := checkChaincodeCmdParams(&cobra.Command{})
   104  
   105  	require.Error(result)
   106  }
   107  
   108  func TestCheckValidJSON(t *testing.T) {
   109  	validJSON := `{"Args":["a","b","c"]}`
   110  	input := &chaincodeInput{}
   111  	if err := json.Unmarshal([]byte(validJSON), &input); err != nil {
   112  		t.Fail()
   113  		t.Logf("Chaincode argument error: %s", err)
   114  		return
   115  	}
   116  
   117  	validJSON = `{"Function":"f", "Args":["a","b","c"]}`
   118  	if err := json.Unmarshal([]byte(validJSON), &input); err != nil {
   119  		t.Fail()
   120  		t.Logf("Chaincode argument error: %s", err)
   121  		return
   122  	}
   123  
   124  	validJSON = `{"Function":"f", "Args":[]}`
   125  	if err := json.Unmarshal([]byte(validJSON), &input); err != nil {
   126  		t.Fail()
   127  		t.Logf("Chaincode argument error: %s", err)
   128  		return
   129  	}
   130  
   131  	validJSON = `{"Function":"f"}`
   132  	if err := json.Unmarshal([]byte(validJSON), &input); err != nil {
   133  		t.Fail()
   134  		t.Logf("Chaincode argument error: %s", err)
   135  		return
   136  	}
   137  }
   138  
   139  func TestCheckInvalidJSON(t *testing.T) {
   140  	invalidJSON := `{["a","b","c"]}`
   141  	input := &chaincodeInput{}
   142  	if err := json.Unmarshal([]byte(invalidJSON), &input); err == nil {
   143  		t.Fail()
   144  		t.Logf("Bar argument error should have been caught: %s", invalidJSON)
   145  		return
   146  	}
   147  
   148  	invalidJSON = `{"Function":}`
   149  	if err := json.Unmarshal([]byte(invalidJSON), &input); err == nil {
   150  		t.Fail()
   151  		t.Logf("Chaincode argument error: %s", err)
   152  		t.Logf("Bar argument error should have been caught: %s", invalidJSON)
   153  		return
   154  	}
   155  }
   156  
   157  func TestGetOrdererEndpointFromConfigTx(t *testing.T) {
   158  	signer, err := common.GetDefaultSigner()
   159  	assert.NoError(t, err)
   160  
   161  	mockchain := "mockchain"
   162  	factory.InitFactories(nil)
   163  	config := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir())
   164  	pgen := encoder.New(config)
   165  	genesisBlock := pgen.GenesisBlockForChannel(mockchain)
   166  
   167  	mockResponse := &pb.ProposalResponse{
   168  		Response:    &pb.Response{Status: 200, Payload: protoutil.MarshalOrPanic(genesisBlock)},
   169  		Endorsement: &pb.Endorsement{},
   170  	}
   171  	mockEndorserClient := common.GetMockEndorserClient(mockResponse, nil)
   172  
   173  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   174  	assert.NoError(t, err)
   175  	ordererEndpoints, err := common.GetOrdererEndpointOfChain(mockchain, signer, mockEndorserClient, cryptoProvider)
   176  	assert.NoError(t, err, "GetOrdererEndpointOfChain from genesis block")
   177  
   178  	assert.Equal(t, len(ordererEndpoints), 1)
   179  	assert.Equal(t, ordererEndpoints[0], "127.0.0.1:7050")
   180  }
   181  
   182  func TestGetOrdererEndpointFail(t *testing.T) {
   183  	signer, err := common.GetDefaultSigner()
   184  	assert.NoError(t, err)
   185  
   186  	mockchain := "mockchain"
   187  	factory.InitFactories(nil)
   188  
   189  	mockResponse := &pb.ProposalResponse{
   190  		Response:    &pb.Response{Status: 404, Payload: []byte{}},
   191  		Endorsement: &pb.Endorsement{},
   192  	}
   193  	mockEndorserClient := common.GetMockEndorserClient(mockResponse, nil)
   194  
   195  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   196  	assert.NoError(t, err)
   197  	_, err = common.GetOrdererEndpointOfChain(mockchain, signer, mockEndorserClient, cryptoProvider)
   198  	assert.Error(t, err, "GetOrdererEndpointOfChain from invalid response")
   199  }
   200  
   201  const sampleCollectionConfigGood = `[
   202  	{
   203  		"name": "foo",
   204  		"policy": "OR('A.member', 'B.member')",
   205  		"requiredPeerCount": 3,
   206  		"maxPeerCount": 483279847,
   207  		"blockToLive":10,
   208  		"memberOnlyRead": true,
   209  		"memberOnlyWrite": true
   210  	}
   211  ]`
   212  
   213  const sampleCollectionConfigGoodNoMaxPeerCountOrRequiredPeerCount = `[
   214  	{
   215  		"name": "foo",
   216  		"policy": "OR('A.member', 'B.member')",
   217  		"blockToLive":10,
   218  		"memberOnlyRead": true,
   219  		"memberOnlyWrite": true
   220  	}
   221  ]`
   222  
   223  const sampleCollectionConfigGoodWithSignaturePolicy = `[
   224  	{
   225  		"name": "foo",
   226  		"policy": "OR('A.member', 'B.member')",
   227  		"requiredPeerCount": 3,
   228  		"maxPeerCount": 483279847,
   229  		"blockToLive":10,
   230  		"memberOnlyRead": true,
   231  		"memberOnlyWrite": true,
   232  		"endorsementPolicy": {
   233  			"signaturePolicy": "OR('A.member', 'B.member')"
   234  		}
   235  	}
   236  ]`
   237  
   238  const sampleCollectionConfigGoodWithChannelConfigPolicy = `[
   239  	{
   240  		"name": "foo",
   241  		"policy": "OR('A.member', 'B.member')",
   242  		"requiredPeerCount": 3,
   243  		"maxPeerCount": 483279847,
   244  		"blockToLive":10,
   245  		"memberOnlyRead": true,
   246  		"memberOnlyWrite": true,
   247  		"endorsementPolicy": {
   248  			"channelConfigPolicy": "/Channel/Application/Endorsement"
   249  		}
   250  	}
   251  ]`
   252  
   253  const sampleCollectionConfigBad = `[
   254  	{
   255  		"name": "foo",
   256  		"policy": "barf",
   257  		"requiredPeerCount": 3,
   258  		"maxPeerCount": 483279847
   259  	}
   260  ]`
   261  
   262  const sampleCollectionConfigBadInvalidSignaturePolicy = `[
   263  	{
   264  		"name": "foo",
   265  		"policy": "OR('A.member', 'B.member')",
   266  		"requiredPeerCount": 3,
   267  		"maxPeerCount": 483279847,
   268  		"blockToLive":10,
   269  		"memberOnlyRead": true,
   270  		"memberOnlyWrite": true,
   271  		"endorsementPolicy": {
   272  			"signaturePolicy": "invalid"
   273  		}
   274  	}
   275  ]`
   276  
   277  const sampleCollectionConfigBadSignaturePolicyAndChannelConfigPolicy = `[
   278  	{
   279  		"name": "foo",
   280  		"policy": "OR('A.member', 'B.member')",
   281  		"requiredPeerCount": 3,
   282  		"maxPeerCount": 483279847,
   283  		"blockToLive":10,
   284  		"memberOnlyRead": true,
   285  		"memberOnlyWrite": true,
   286  		"endorsementPolicy": {
   287  			"signaturePolicy": "OR('A.member', 'B.member')",
   288  			"channelConfigPolicy": "/Channel/Application/Endorsement"
   289  		}
   290  	}
   291  ]`
   292  
   293  func TestCollectionParsing(t *testing.T) {
   294  	ccp, ccpBytes, err := getCollectionConfigFromBytes([]byte(sampleCollectionConfigGood))
   295  	assert.NoError(t, err)
   296  	assert.NotNil(t, ccp)
   297  	assert.NotNil(t, ccpBytes)
   298  	conf := ccp.Config[0].GetStaticCollectionConfig()
   299  	pol, _ := policydsl.FromString("OR('A.member', 'B.member')")
   300  	assert.Equal(t, 3, int(conf.RequiredPeerCount))
   301  	assert.Equal(t, 483279847, int(conf.MaximumPeerCount))
   302  	assert.Equal(t, "foo", conf.Name)
   303  	assert.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy()))
   304  	assert.Equal(t, 10, int(conf.BlockToLive))
   305  	assert.Equal(t, true, conf.MemberOnlyRead)
   306  	assert.Nil(t, conf.EndorsementPolicy)
   307  	t.Logf("conf=%s", conf)
   308  
   309  	// Test default values for RequiredPeerCount and MaxPeerCount
   310  	ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodNoMaxPeerCountOrRequiredPeerCount))
   311  	assert.NoError(t, err)
   312  	assert.NotNil(t, ccp)
   313  	assert.NotNil(t, ccpBytes)
   314  	conf = ccp.Config[0].GetStaticCollectionConfig()
   315  	pol, _ = policydsl.FromString("OR('A.member', 'B.member')")
   316  	assert.Equal(t, 0, int(conf.RequiredPeerCount))
   317  	assert.Equal(t, 1, int(conf.MaximumPeerCount))
   318  	assert.Equal(t, "foo", conf.Name)
   319  	assert.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy()))
   320  	assert.Equal(t, 10, int(conf.BlockToLive))
   321  	assert.Equal(t, true, conf.MemberOnlyRead)
   322  	assert.Nil(t, conf.EndorsementPolicy)
   323  	t.Logf("conf=%s", conf)
   324  
   325  	ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodWithSignaturePolicy))
   326  	assert.NoError(t, err)
   327  	assert.NotNil(t, ccp)
   328  	assert.NotNil(t, ccpBytes)
   329  	conf = ccp.Config[0].GetStaticCollectionConfig()
   330  	pol, _ = policydsl.FromString("OR('A.member', 'B.member')")
   331  	assert.Equal(t, 3, int(conf.RequiredPeerCount))
   332  	assert.Equal(t, 483279847, int(conf.MaximumPeerCount))
   333  	assert.Equal(t, "foo", conf.Name)
   334  	assert.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy()))
   335  	assert.Equal(t, 10, int(conf.BlockToLive))
   336  	assert.Equal(t, true, conf.MemberOnlyRead)
   337  	assert.True(t, proto.Equal(pol, conf.EndorsementPolicy.GetSignaturePolicy()))
   338  	t.Logf("conf=%s", conf)
   339  
   340  	ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodWithChannelConfigPolicy))
   341  	assert.NoError(t, err)
   342  	assert.NotNil(t, ccp)
   343  	assert.NotNil(t, ccpBytes)
   344  	conf = ccp.Config[0].GetStaticCollectionConfig()
   345  	pol, _ = policydsl.FromString("OR('A.member', 'B.member')")
   346  	assert.Equal(t, 3, int(conf.RequiredPeerCount))
   347  	assert.Equal(t, 483279847, int(conf.MaximumPeerCount))
   348  	assert.Equal(t, "foo", conf.Name)
   349  	assert.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy()))
   350  	assert.Equal(t, 10, int(conf.BlockToLive))
   351  	assert.Equal(t, true, conf.MemberOnlyRead)
   352  	assert.Equal(t, "/Channel/Application/Endorsement", conf.EndorsementPolicy.GetChannelConfigPolicyReference())
   353  	t.Logf("conf=%s", conf)
   354  
   355  	failureTests := []struct {
   356  		name             string
   357  		collectionConfig string
   358  		expectedErr      string
   359  	}{
   360  		{
   361  			name:             "Invalid member orgs policy",
   362  			collectionConfig: sampleCollectionConfigBad,
   363  			expectedErr:      "invalid policy barf: unrecognized token 'barf' in policy string",
   364  		},
   365  		{
   366  			name:             "Invalid collection config",
   367  			collectionConfig: "barf",
   368  			expectedErr:      "could not parse the collection configuration: invalid character 'b' looking for beginning of value",
   369  		},
   370  		{
   371  			name:             "Invalid signature policy",
   372  			collectionConfig: sampleCollectionConfigBadInvalidSignaturePolicy,
   373  			expectedErr:      `invalid endorsement policy [&chaincode.endorsementPolicy{ChannelConfigPolicy:"", SignaturePolicy:"invalid"}]: invalid signature policy: invalid`,
   374  		},
   375  		{
   376  			name:             "Signature policy and channel config policy both specified",
   377  			collectionConfig: sampleCollectionConfigBadSignaturePolicyAndChannelConfigPolicy,
   378  			expectedErr:      `invalid endorsement policy [&chaincode.endorsementPolicy{ChannelConfigPolicy:"/Channel/Application/Endorsement", SignaturePolicy:"OR('A.member', 'B.member')"}]: cannot specify both "--signature-policy" and "--channel-config-policy"`,
   379  		},
   380  	}
   381  
   382  	for _, test := range failureTests {
   383  		t.Run(test.name, func(t *testing.T) {
   384  			ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(test.collectionConfig))
   385  			assert.EqualError(t, err, test.expectedErr)
   386  			assert.Nil(t, ccp)
   387  			assert.Nil(t, ccpBytes)
   388  		})
   389  	}
   390  }
   391  
   392  func TestValidatePeerConnectionParams(t *testing.T) {
   393  	defer resetFlags()
   394  	defer viper.Reset()
   395  	assert := assert.New(t)
   396  	cleanup := configtest.SetDevFabricConfigPath(t)
   397  	defer cleanup()
   398  
   399  	// TLS disabled
   400  	viper.Set("peer.tls.enabled", false)
   401  
   402  	// failure - more than one peer and TLS root cert - not invoke
   403  	resetFlags()
   404  	peerAddresses = []string{"peer0", "peer1"}
   405  	tlsRootCertFiles = []string{"cert0", "cert1"}
   406  	err := validatePeerConnectionParameters("query")
   407  	assert.Error(err)
   408  	assert.Contains(err.Error(), "command can only be executed against one peer")
   409  
   410  	// success - peer provided and no TLS root certs
   411  	// TLS disabled
   412  	resetFlags()
   413  	peerAddresses = []string{"peer0"}
   414  	err = validatePeerConnectionParameters("query")
   415  	assert.NoError(err)
   416  	assert.Nil(tlsRootCertFiles)
   417  
   418  	// success - more TLS root certs than peers
   419  	// TLS disabled
   420  	resetFlags()
   421  	peerAddresses = []string{"peer0"}
   422  	tlsRootCertFiles = []string{"cert0", "cert1"}
   423  	err = validatePeerConnectionParameters("invoke")
   424  	assert.NoError(err)
   425  	assert.Nil(tlsRootCertFiles)
   426  
   427  	// success - multiple peers and no TLS root certs - invoke
   428  	// TLS disabled
   429  	resetFlags()
   430  	peerAddresses = []string{"peer0", "peer1"}
   431  	err = validatePeerConnectionParameters("invoke")
   432  	assert.NoError(err)
   433  	assert.Nil(tlsRootCertFiles)
   434  
   435  	// TLS enabled
   436  	viper.Set("peer.tls.enabled", true)
   437  
   438  	// failure - uneven number of peers and TLS root certs - invoke
   439  	// TLS enabled
   440  	resetFlags()
   441  	peerAddresses = []string{"peer0", "peer1"}
   442  	tlsRootCertFiles = []string{"cert0"}
   443  	err = validatePeerConnectionParameters("invoke")
   444  	assert.Error(err)
   445  	assert.Contains(err.Error(), fmt.Sprintf("number of peer addresses (%d) does not match the number of TLS root cert files (%d)", len(peerAddresses), len(tlsRootCertFiles)))
   446  
   447  	// success - more than one peer and TLS root certs - invoke
   448  	// TLS enabled
   449  	resetFlags()
   450  	peerAddresses = []string{"peer0", "peer1"}
   451  	tlsRootCertFiles = []string{"cert0", "cert1"}
   452  	err = validatePeerConnectionParameters("invoke")
   453  	assert.NoError(err)
   454  
   455  	// failure - connection profile doesn't exist
   456  	resetFlags()
   457  	connectionProfile = "blah"
   458  	err = validatePeerConnectionParameters("invoke")
   459  	assert.Error(err)
   460  	assert.Contains(err.Error(), "error reading connection profile")
   461  
   462  	// failure - connection profile has peer defined in channel config but
   463  	// not in peer config
   464  	resetFlags()
   465  	channelID = "mychannel"
   466  	connectionProfile = "testdata/connectionprofile-uneven.yaml"
   467  	err = validatePeerConnectionParameters("invoke")
   468  	assert.Error(err)
   469  	assert.Contains(err.Error(), "defined in the channel config but doesn't have associated peer config")
   470  
   471  	// success - connection profile exists
   472  	resetFlags()
   473  	channelID = "mychannel"
   474  	connectionProfile = "testdata/connectionprofile.yaml"
   475  	err = validatePeerConnectionParameters("invoke")
   476  	assert.NoError(err)
   477  }
   478  
   479  func TestInitCmdFactoryFailures(t *testing.T) {
   480  	defer resetFlags()
   481  	assert := assert.New(t)
   482  
   483  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   484  	assert.Nil(err)
   485  
   486  	// failure validating peer connection parameters
   487  	resetFlags()
   488  	peerAddresses = []string{"peer0", "peer1"}
   489  	tlsRootCertFiles = []string{"cert0", "cert1"}
   490  	cf, err := InitCmdFactory("query", true, false, cryptoProvider)
   491  	assert.Error(err)
   492  	assert.Contains(err.Error(), "error validating peer connection parameters: 'query' command can only be executed against one peer")
   493  	assert.Nil(cf)
   494  
   495  	// failure - no peers supplied and endorser client is needed
   496  	resetFlags()
   497  	peerAddresses = []string{}
   498  	cf, err = InitCmdFactory("query", true, false, cryptoProvider)
   499  	assert.Error(err)
   500  	assert.Contains(err.Error(), "no endorser clients retrieved")
   501  	assert.Nil(cf)
   502  
   503  	// failure - orderer client is needed, ordering endpoint is empty and no
   504  	// endorser client supplied
   505  	resetFlags()
   506  	peerAddresses = nil
   507  	cf, err = InitCmdFactory("invoke", false, true, cryptoProvider)
   508  	assert.Error(err)
   509  	assert.Contains(err.Error(), "no ordering endpoint or endorser client supplied")
   510  	assert.Nil(cf)
   511  }
   512  
   513  func TestDeliverGroupConnect(t *testing.T) {
   514  	defer resetFlags()
   515  	g := NewGomegaWithT(t)
   516  
   517  	// success
   518  	mockDeliverClients := []*DeliverClient{
   519  		{
   520  			Client:  getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0"),
   521  			Address: "peer0",
   522  		},
   523  		{
   524  			Client:  getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0"),
   525  			Address: "peer1",
   526  		},
   527  	}
   528  	dg := DeliverGroup{
   529  		Clients:   mockDeliverClients,
   530  		ChannelID: "testchannel",
   531  		Signer:    &mock.SignerSerializer{},
   532  		Certificate: tls.Certificate{
   533  			Certificate: [][]byte{[]byte("test")},
   534  		},
   535  		TxID: "txid0",
   536  	}
   537  	err := dg.Connect(context.Background())
   538  	g.Expect(err).To(BeNil())
   539  
   540  	// failure - DeliverFiltered returns error
   541  	mockDC := &mock.PeerDeliverClient{}
   542  	mockDC.DeliverFilteredReturns(nil, errors.New("icecream"))
   543  	mockDeliverClients = []*DeliverClient{
   544  		{
   545  			Client:  mockDC,
   546  			Address: "peer0",
   547  		},
   548  	}
   549  	dg = DeliverGroup{
   550  		Clients:   mockDeliverClients,
   551  		ChannelID: "testchannel",
   552  		Signer:    &mock.SignerSerializer{},
   553  		Certificate: tls.Certificate{
   554  			Certificate: [][]byte{[]byte("test")},
   555  		},
   556  		TxID: "txid0",
   557  	}
   558  	err = dg.Connect(context.Background())
   559  	g.Expect(err.Error()).To(ContainSubstring("error connecting to deliver filtered"))
   560  	g.Expect(err.Error()).To(ContainSubstring("icecream"))
   561  
   562  	// failure - Send returns error
   563  	mockD := &mock.Deliver{}
   564  	mockD.SendReturns(errors.New("blah"))
   565  	mockDC.DeliverFilteredReturns(mockD, nil)
   566  	mockDeliverClients = []*DeliverClient{
   567  		{
   568  			Client:  mockDC,
   569  			Address: "peer0",
   570  		},
   571  	}
   572  	dg = DeliverGroup{
   573  		Clients:   mockDeliverClients,
   574  		ChannelID: "testchannel",
   575  		Signer:    &mock.SignerSerializer{},
   576  		Certificate: tls.Certificate{
   577  			Certificate: [][]byte{[]byte("test")},
   578  		},
   579  		TxID: "txid0",
   580  	}
   581  	err = dg.Connect(context.Background())
   582  	g.Expect(err.Error()).To(ContainSubstring("error sending deliver seek info"))
   583  	g.Expect(err.Error()).To(ContainSubstring("blah"))
   584  
   585  	// failure - deliver registration timeout
   586  	delayChan := make(chan struct{})
   587  	mockDCDelay := getMockDeliverClientRegisterAfterDelay(delayChan)
   588  	mockDeliverClients = []*DeliverClient{
   589  		{
   590  			Client:  mockDCDelay,
   591  			Address: "peer0",
   592  		},
   593  	}
   594  	ctx, cancelFunc := context.WithTimeout(context.Background(), 10*time.Millisecond)
   595  	defer cancelFunc()
   596  	dg = DeliverGroup{
   597  		Clients:   mockDeliverClients,
   598  		ChannelID: "testchannel",
   599  		Signer:    &mock.SignerSerializer{},
   600  		Certificate: tls.Certificate{
   601  			Certificate: [][]byte{[]byte("test")},
   602  		},
   603  		TxID: "txid0",
   604  	}
   605  	err = dg.Connect(ctx)
   606  	g.Expect(err.Error()).To(ContainSubstring("timed out waiting for connection to deliver on all peers"))
   607  	close(delayChan)
   608  }
   609  
   610  func TestDeliverGroupWait(t *testing.T) {
   611  	defer resetFlags()
   612  	g := NewGomegaWithT(t)
   613  
   614  	// success
   615  	mockConn := &mock.Deliver{}
   616  	filteredResp := &pb.DeliverResponse{
   617  		Type: &pb.DeliverResponse_FilteredBlock{FilteredBlock: createFilteredBlock(pb.TxValidationCode_VALID, "txid0")},
   618  	}
   619  	mockConn.RecvReturns(filteredResp, nil)
   620  	mockDeliverClients := []*DeliverClient{
   621  		{
   622  			Connection: mockConn,
   623  			Address:    "peer0",
   624  		},
   625  	}
   626  	dg := DeliverGroup{
   627  		Clients:   mockDeliverClients,
   628  		ChannelID: "testchannel",
   629  		Signer:    &mock.SignerSerializer{},
   630  		Certificate: tls.Certificate{
   631  			Certificate: [][]byte{[]byte("test")},
   632  		},
   633  		TxID: "txid0",
   634  	}
   635  	err := dg.Wait(context.Background())
   636  	g.Expect(err).To(BeNil())
   637  
   638  	// failure - Recv returns error
   639  	mockConn = &mock.Deliver{}
   640  	mockConn.RecvReturns(nil, errors.New("avocado"))
   641  	mockDeliverClients = []*DeliverClient{
   642  		{
   643  			Connection: mockConn,
   644  			Address:    "peer0",
   645  		},
   646  	}
   647  	dg = DeliverGroup{
   648  		Clients:   mockDeliverClients,
   649  		ChannelID: "testchannel",
   650  		Signer:    &mock.SignerSerializer{},
   651  		Certificate: tls.Certificate{
   652  			Certificate: [][]byte{[]byte("test")},
   653  		},
   654  		TxID: "txid0",
   655  	}
   656  	err = dg.Wait(context.Background())
   657  	g.Expect(err.Error()).To(ContainSubstring("error receiving from deliver filtered"))
   658  	g.Expect(err.Error()).To(ContainSubstring("avocado"))
   659  
   660  	// failure - Recv returns unexpected type
   661  	mockConn = &mock.Deliver{}
   662  	resp := &pb.DeliverResponse{
   663  		Type: &pb.DeliverResponse_Block{},
   664  	}
   665  	mockConn.RecvReturns(resp, nil)
   666  	mockDeliverClients = []*DeliverClient{
   667  		{
   668  			Connection: mockConn,
   669  			Address:    "peer0",
   670  		},
   671  	}
   672  	dg = DeliverGroup{
   673  		Clients:   mockDeliverClients,
   674  		ChannelID: "testchannel",
   675  		Signer:    &mock.SignerSerializer{},
   676  		Certificate: tls.Certificate{
   677  			Certificate: [][]byte{[]byte("test")},
   678  		},
   679  		TxID: "txid0",
   680  	}
   681  	err = dg.Wait(context.Background())
   682  	g.Expect(err.Error()).To(ContainSubstring("unexpected response type"))
   683  
   684  	// failure - both connections return error
   685  	mockConn = &mock.Deliver{}
   686  	mockConn.RecvReturns(nil, errors.New("barbeque"))
   687  	mockConn2 := &mock.Deliver{}
   688  	mockConn2.RecvReturns(nil, errors.New("tofu"))
   689  	mockDeliverClients = []*DeliverClient{
   690  		{
   691  			Connection: mockConn,
   692  			Address:    "peerBBQ",
   693  		},
   694  		{
   695  			Connection: mockConn2,
   696  			Address:    "peerTOFU",
   697  		},
   698  	}
   699  	dg = DeliverGroup{
   700  		Clients:   mockDeliverClients,
   701  		ChannelID: "testchannel",
   702  		Signer:    &mock.SignerSerializer{},
   703  		Certificate: tls.Certificate{
   704  			Certificate: [][]byte{[]byte("test")},
   705  		},
   706  		TxID: "txid0",
   707  	}
   708  	err = dg.Wait(context.Background())
   709  	g.Expect(err.Error()).To(SatisfyAny(
   710  		ContainSubstring("barbeque"),
   711  		ContainSubstring("tofu")))
   712  }
   713  
   714  func TestChaincodeInvokeOrQuery_waitForEvent(t *testing.T) {
   715  	defer resetFlags()
   716  
   717  	waitForEvent = true
   718  	mockCF, err := getMockChaincodeCmdFactory()
   719  	assert.NoError(t, err)
   720  	peerAddresses = []string{"peer0", "peer1"}
   721  	channelID := "testchannel"
   722  	txID := "txid0"
   723  
   724  	t.Run("success - deliver clients returns event with expected txid", func(t *testing.T) {
   725  		_, err = ChaincodeInvokeOrQuery(
   726  			&pb.ChaincodeSpec{},
   727  			channelID,
   728  			txID,
   729  			true,
   730  			mockCF.Signer,
   731  			mockCF.Certificate,
   732  			mockCF.EndorserClients,
   733  			mockCF.DeliverClients,
   734  			mockCF.BroadcastClient,
   735  		)
   736  		assert.NoError(t, err)
   737  	})
   738  
   739  	t.Run("success - one deliver client first receives block without txid and then one with txid", func(t *testing.T) {
   740  		filteredBlocks := []*pb.FilteredBlock{
   741  			createFilteredBlock(pb.TxValidationCode_VALID, "theseare", "notthetxidsyouarelookingfor"),
   742  			createFilteredBlock(pb.TxValidationCode_VALID, "txid0"),
   743  		}
   744  		mockDCTwoBlocks := getMockDeliverClientRespondsWithFilteredBlocks(filteredBlocks)
   745  		mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0")
   746  		mockDeliverClients := []pb.DeliverClient{mockDCTwoBlocks, mockDC}
   747  
   748  		_, err = ChaincodeInvokeOrQuery(
   749  			&pb.ChaincodeSpec{},
   750  			channelID,
   751  			txID,
   752  			true,
   753  			mockCF.Signer,
   754  			mockCF.Certificate,
   755  			mockCF.EndorserClients,
   756  			mockDeliverClients,
   757  			mockCF.BroadcastClient,
   758  		)
   759  		assert.NoError(t, err)
   760  	})
   761  
   762  	t.Run("failure - one of the deliver clients returns error", func(t *testing.T) {
   763  		mockDCErr := getMockDeliverClientWithErr("moist")
   764  		mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0")
   765  		mockDeliverClients := []pb.DeliverClient{mockDCErr, mockDC}
   766  
   767  		_, err = ChaincodeInvokeOrQuery(
   768  			&pb.ChaincodeSpec{},
   769  			channelID,
   770  			txID,
   771  			true,
   772  			mockCF.Signer,
   773  			mockCF.Certificate,
   774  			mockCF.EndorserClients,
   775  			mockDeliverClients,
   776  			mockCF.BroadcastClient,
   777  		)
   778  		assert.Error(t, err)
   779  		assert.Contains(t, err.Error(), "moist")
   780  	})
   781  
   782  	t.Run("failure - transaction committed with non-success validation code", func(t *testing.T) {
   783  		mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0")
   784  		mockDCFail := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_ENDORSEMENT_POLICY_FAILURE, "txid0")
   785  		mockDeliverClients := []pb.DeliverClient{mockDCFail, mockDC}
   786  
   787  		_, err = ChaincodeInvokeOrQuery(
   788  			&pb.ChaincodeSpec{},
   789  			channelID,
   790  			txID,
   791  			true,
   792  			mockCF.Signer,
   793  			mockCF.Certificate,
   794  			mockCF.EndorserClients,
   795  			mockDeliverClients,
   796  			mockCF.BroadcastClient,
   797  		)
   798  		assert.Error(t, err)
   799  		assert.Equal(t, err.Error(), "transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE)")
   800  	})
   801  
   802  	t.Run("failure - deliver returns response status instead of block", func(t *testing.T) {
   803  		mockDC := &mock.PeerDeliverClient{}
   804  		mockDF := &mock.Deliver{}
   805  		resp := &pb.DeliverResponse{
   806  			Type: &pb.DeliverResponse_Status{
   807  				Status: cb.Status_FORBIDDEN,
   808  			},
   809  		}
   810  		mockDF.RecvReturns(resp, nil)
   811  		mockDC.DeliverFilteredReturns(mockDF, nil)
   812  		mockDeliverClients := []pb.DeliverClient{mockDC}
   813  		_, err = ChaincodeInvokeOrQuery(
   814  			&pb.ChaincodeSpec{},
   815  			channelID,
   816  			txID,
   817  			true,
   818  			mockCF.Signer,
   819  			mockCF.Certificate,
   820  			mockCF.EndorserClients,
   821  			mockDeliverClients,
   822  			mockCF.BroadcastClient,
   823  		)
   824  		assert.Error(t, err)
   825  		assert.Equal(t, err.Error(), "deliver completed with status (FORBIDDEN) before txid received")
   826  	})
   827  
   828  	t.Run(" failure - timeout occurs - both deliver clients don't return an event with the expected txid before timeout", func(t *testing.T) {
   829  		delayChan := make(chan struct{})
   830  		mockDCDelay := getMockDeliverClientRespondAfterDelay(delayChan, pb.TxValidationCode_VALID, "txid0")
   831  		mockDeliverClients := []pb.DeliverClient{mockDCDelay, mockDCDelay}
   832  		waitForEventTimeout = 10 * time.Millisecond
   833  
   834  		_, err = ChaincodeInvokeOrQuery(
   835  			&pb.ChaincodeSpec{},
   836  			channelID,
   837  			txID,
   838  			true,
   839  			mockCF.Signer,
   840  			mockCF.Certificate,
   841  			mockCF.EndorserClients,
   842  			mockDeliverClients,
   843  			mockCF.BroadcastClient,
   844  		)
   845  		assert.Error(t, err)
   846  		assert.Contains(t, err.Error(), "timed out")
   847  		close(delayChan)
   848  	})
   849  }
   850  
   851  func TestProcessProposals(t *testing.T) {
   852  	// Build clients that return a range of status codes (for verifying each client is called).
   853  	mockClients := []pb.EndorserClient{}
   854  	for i := 2; i <= 5; i++ {
   855  		response := &pb.ProposalResponse{
   856  			Response:    &pb.Response{Status: int32(i * 100)},
   857  			Endorsement: &pb.Endorsement{},
   858  		}
   859  		mockClients = append(mockClients, common.GetMockEndorserClient(response, nil))
   860  	}
   861  	mockErrorClient := common.GetMockEndorserClient(nil, errors.New("failed to call endorser"))
   862  	signedProposal := &pb.SignedProposal{}
   863  	t.Run("should process a proposal for a single peer", func(t *testing.T) {
   864  		responses, err := processProposals([]pb.EndorserClient{mockClients[0]}, signedProposal)
   865  		assert.NoError(t, err)
   866  		assert.Len(t, responses, 1)
   867  		assert.Equal(t, responses[0].Response.Status, int32(200))
   868  	})
   869  	t.Run("should process a proposal for multiple peers", func(t *testing.T) {
   870  		responses, err := processProposals(mockClients, signedProposal)
   871  		assert.NoError(t, err)
   872  		assert.Len(t, responses, 4)
   873  		// Sort the statuses (as they may turn up in different order) before comparing.
   874  		statuses := []int32{}
   875  		for _, response := range responses {
   876  			statuses = append(statuses, response.Response.Status)
   877  		}
   878  		sort.Slice(statuses, func(i, j int) bool { return statuses[i] < statuses[j] })
   879  		assert.EqualValues(t, []int32{200, 300, 400, 500}, statuses)
   880  	})
   881  	t.Run("should return an error from processing a proposal for a single peer", func(t *testing.T) {
   882  		responses, err := processProposals([]pb.EndorserClient{mockErrorClient}, signedProposal)
   883  		assert.EqualError(t, err, "failed to call endorser")
   884  		assert.Nil(t, responses)
   885  	})
   886  	t.Run("should return an error from processing a proposal for a single peer within multiple peers", func(t *testing.T) {
   887  		responses, err := processProposals([]pb.EndorserClient{mockClients[0], mockErrorClient, mockClients[1]}, signedProposal)
   888  		assert.EqualError(t, err, "failed to call endorser")
   889  		assert.Nil(t, responses)
   890  	})
   891  }