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