github.com/true-sqn/fabric@v2.1.1+incompatible/gossip/privdata/coordinator_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package privdata
     8  
     9  import (
    10  	"encoding/asn1"
    11  	"encoding/hex"
    12  	"errors"
    13  	"fmt"
    14  	"io/ioutil"
    15  	"os"
    16  	"reflect"
    17  	"testing"
    18  	"time"
    19  
    20  	pb "github.com/golang/protobuf/proto"
    21  	"github.com/hyperledger/fabric-protos-go/common"
    22  	proto "github.com/hyperledger/fabric-protos-go/gossip"
    23  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    24  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    25  	mspproto "github.com/hyperledger/fabric-protos-go/msp"
    26  	"github.com/hyperledger/fabric-protos-go/peer"
    27  	tspb "github.com/hyperledger/fabric-protos-go/transientstore"
    28  	"github.com/hyperledger/fabric/bccsp/factory"
    29  	"github.com/hyperledger/fabric/common/metrics/disabled"
    30  	util2 "github.com/hyperledger/fabric/common/util"
    31  	"github.com/hyperledger/fabric/core/common/privdata"
    32  	"github.com/hyperledger/fabric/core/ledger"
    33  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    34  	"github.com/hyperledger/fabric/core/transientstore"
    35  	"github.com/hyperledger/fabric/gossip/metrics"
    36  	gmetricsmocks "github.com/hyperledger/fabric/gossip/metrics/mocks"
    37  	privdatacommon "github.com/hyperledger/fabric/gossip/privdata/common"
    38  	"github.com/hyperledger/fabric/gossip/privdata/mocks"
    39  	capabilitymock "github.com/hyperledger/fabric/gossip/privdata/mocks"
    40  	"github.com/hyperledger/fabric/gossip/util"
    41  	"github.com/hyperledger/fabric/msp"
    42  	"github.com/hyperledger/fabric/msp/mgmt"
    43  	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
    44  	msptesttools "github.com/hyperledger/fabric/msp/mgmt/testtools"
    45  	"github.com/hyperledger/fabric/protoutil"
    46  	"github.com/stretchr/testify/assert"
    47  	"github.com/stretchr/testify/mock"
    48  	"github.com/stretchr/testify/require"
    49  )
    50  
    51  var testConfig = CoordinatorConfig{
    52  	PullRetryThreshold:             time.Second * 3,
    53  	TransientBlockRetention:        1000,
    54  	SkipPullingInvalidTransactions: false,
    55  }
    56  
    57  // CollectionCriteria aggregates criteria of
    58  // a collection
    59  type CollectionCriteria struct {
    60  	Channel    string
    61  	Collection string
    62  	Namespace  string
    63  }
    64  
    65  func fromCollectionCriteria(criteria privdata.CollectionCriteria) CollectionCriteria {
    66  	return CollectionCriteria{
    67  		Collection: criteria.Collection,
    68  		Namespace:  criteria.Namespace,
    69  		Channel:    criteria.Channel,
    70  	}
    71  }
    72  
    73  type validatorMock struct {
    74  	err error
    75  }
    76  
    77  func (v *validatorMock) Validate(block *common.Block) error {
    78  	if v.err != nil {
    79  		return v.err
    80  	}
    81  	return nil
    82  }
    83  
    84  type digests []privdatacommon.DigKey
    85  
    86  func (d digests) Equal(other digests) bool {
    87  	flatten := func(d digests) map[privdatacommon.DigKey]struct{} {
    88  		m := map[privdatacommon.DigKey]struct{}{}
    89  		for _, dig := range d {
    90  			m[dig] = struct{}{}
    91  		}
    92  		return m
    93  	}
    94  	return reflect.DeepEqual(flatten(d), flatten(other))
    95  }
    96  
    97  type fetchCall struct {
    98  	fetcher *fetcherMock
    99  	*mock.Call
   100  }
   101  
   102  func (fc *fetchCall) expectingEndorsers(orgs ...string) *fetchCall {
   103  	if fc.fetcher.expectedEndorsers == nil {
   104  		fc.fetcher.expectedEndorsers = make(map[string]struct{})
   105  	}
   106  	for _, org := range orgs {
   107  		sID := &mspproto.SerializedIdentity{Mspid: org, IdBytes: []byte(fmt.Sprintf("p0%s", org))}
   108  		b, _ := pb.Marshal(sID)
   109  		fc.fetcher.expectedEndorsers[string(b)] = struct{}{}
   110  	}
   111  
   112  	return fc
   113  }
   114  
   115  func (fc *fetchCall) expectingDigests(digests []privdatacommon.DigKey) *fetchCall {
   116  	fc.fetcher.expectedDigests = digests
   117  	return fc
   118  }
   119  
   120  func (fc *fetchCall) Return(returnArguments ...interface{}) *mock.Call {
   121  
   122  	return fc.Call.Return(returnArguments...)
   123  }
   124  
   125  type fetcherMock struct {
   126  	t *testing.T
   127  	mock.Mock
   128  	expectedDigests   []privdatacommon.DigKey
   129  	expectedEndorsers map[string]struct{}
   130  }
   131  
   132  func (f *fetcherMock) On(methodName string, arguments ...interface{}) *fetchCall {
   133  	return &fetchCall{
   134  		fetcher: f,
   135  		Call:    f.Mock.On(methodName, arguments...),
   136  	}
   137  }
   138  
   139  func (f *fetcherMock) fetch(dig2src dig2sources) (*privdatacommon.FetchedPvtDataContainer, error) {
   140  	uniqueEndorsements := make(map[string]interface{})
   141  	for _, endorsements := range dig2src {
   142  		for _, endorsement := range endorsements {
   143  			_, exists := f.expectedEndorsers[string(endorsement.Endorser)]
   144  			if !exists {
   145  				f.t.Fatalf("Encountered a non-expected endorser: %s", string(endorsement.Endorser))
   146  			}
   147  			uniqueEndorsements[string(endorsement.Endorser)] = struct{}{}
   148  		}
   149  	}
   150  	assert.True(f.t, digests(f.expectedDigests).Equal(digests(dig2src.keys())))
   151  	assert.Equal(f.t, len(f.expectedEndorsers), len(uniqueEndorsements))
   152  	args := f.Called(dig2src)
   153  	if args.Get(1) == nil {
   154  		return args.Get(0).(*privdatacommon.FetchedPvtDataContainer), nil
   155  	}
   156  	return nil, args.Get(1).(error)
   157  }
   158  
   159  type testTransientStore struct {
   160  	storeProvider transientstore.StoreProvider
   161  	store         *transientstore.Store
   162  	tempdir       string
   163  }
   164  
   165  func newTransientStore(t *testing.T) *testTransientStore {
   166  	s := &testTransientStore{}
   167  	var err error
   168  	s.tempdir, err = ioutil.TempDir("", "ts")
   169  	if err != nil {
   170  		t.Fatalf("Failed to create test directory, got err %s", err)
   171  		return s
   172  	}
   173  	s.storeProvider, err = transientstore.NewStoreProvider(s.tempdir)
   174  	if err != nil {
   175  		t.Fatalf("Failed to open store, got err %s", err)
   176  		return s
   177  	}
   178  	s.store, err = s.storeProvider.OpenStore("testchannelid")
   179  	if err != nil {
   180  		t.Fatalf("Failed to open store, got err %s", err)
   181  		return s
   182  	}
   183  	return s
   184  }
   185  
   186  func (s *testTransientStore) tearDown() {
   187  	s.storeProvider.Close()
   188  	os.RemoveAll(s.tempdir)
   189  }
   190  
   191  func (s *testTransientStore) Persist(txid string, blockHeight uint64,
   192  	privateSimulationResultsWithConfig *tspb.TxPvtReadWriteSetWithConfigInfo) error {
   193  	return s.store.Persist(txid, blockHeight, privateSimulationResultsWithConfig)
   194  }
   195  
   196  func (s *testTransientStore) GetTxPvtRWSetByTxid(txid string, filter ledger.PvtNsCollFilter) (RWSetScanner, error) {
   197  	return s.store.GetTxPvtRWSetByTxid(txid, filter)
   198  }
   199  
   200  func createcollectionStore(expectedSignedData protoutil.SignedData) *collectionStore {
   201  	return &collectionStore{
   202  		expectedSignedData: expectedSignedData,
   203  		policies:           make(map[collectionAccessPolicy]CollectionCriteria),
   204  		store:              make(map[CollectionCriteria]collectionAccessPolicy),
   205  	}
   206  }
   207  
   208  type collectionStore struct {
   209  	expectedSignedData protoutil.SignedData
   210  	acceptsAll         bool
   211  	acceptsNone        bool
   212  	lenient            bool
   213  	mspIdentifier      string
   214  	store              map[CollectionCriteria]collectionAccessPolicy
   215  	policies           map[collectionAccessPolicy]CollectionCriteria
   216  }
   217  
   218  func (cs *collectionStore) thatAcceptsAll() *collectionStore {
   219  	cs.acceptsAll = true
   220  	return cs
   221  }
   222  
   223  func (cs *collectionStore) thatAcceptsNone() *collectionStore {
   224  	cs.acceptsNone = true
   225  	return cs
   226  }
   227  
   228  func (cs *collectionStore) thatAccepts(cc CollectionCriteria) *collectionStore {
   229  	sp := collectionAccessPolicy{
   230  		cs: cs,
   231  		n:  util.RandomUInt64(),
   232  	}
   233  	cs.store[cc] = sp
   234  	cs.policies[sp] = cc
   235  	return cs
   236  }
   237  
   238  func (cs *collectionStore) withMSPIdentity(identifier string) *collectionStore {
   239  	cs.mspIdentifier = identifier
   240  	return cs
   241  }
   242  
   243  func (cs *collectionStore) RetrieveCollectionAccessPolicy(cc privdata.CollectionCriteria) (privdata.CollectionAccessPolicy, error) {
   244  	if sp, exists := cs.store[fromCollectionCriteria(cc)]; exists {
   245  		return &sp, nil
   246  	}
   247  	if cs.acceptsAll || cs.acceptsNone || cs.lenient {
   248  		return &collectionAccessPolicy{
   249  			cs: cs,
   250  			n:  util.RandomUInt64(),
   251  		}, nil
   252  	}
   253  	return nil, privdata.NoSuchCollectionError{}
   254  }
   255  
   256  func (cs *collectionStore) RetrieveCollection(privdata.CollectionCriteria) (privdata.Collection, error) {
   257  	panic("implement me")
   258  }
   259  
   260  func (cs *collectionStore) RetrieveCollectionConfig(cc privdata.CollectionCriteria) (*peer.StaticCollectionConfig, error) {
   261  	mspIdentifier := "different-org"
   262  	if _, exists := cs.store[fromCollectionCriteria(cc)]; exists || cs.acceptsAll {
   263  		mspIdentifier = cs.mspIdentifier
   264  	}
   265  	return &peer.StaticCollectionConfig{
   266  		Name:           cc.Collection,
   267  		MemberOnlyRead: true,
   268  		MemberOrgsPolicy: &peer.CollectionPolicyConfig{
   269  			Payload: &peer.CollectionPolicyConfig_SignaturePolicy{
   270  				SignaturePolicy: &common.SignaturePolicyEnvelope{
   271  					Rule: &common.SignaturePolicy{
   272  						Type: &common.SignaturePolicy_SignedBy{
   273  							SignedBy: 0,
   274  						},
   275  					},
   276  					Identities: []*mspproto.MSPPrincipal{
   277  						{
   278  							PrincipalClassification: mspproto.MSPPrincipal_ROLE,
   279  							Principal: protoutil.MarshalOrPanic(&mspproto.MSPRole{
   280  								MspIdentifier: mspIdentifier,
   281  								Role:          mspproto.MSPRole_MEMBER,
   282  							}),
   283  						},
   284  					},
   285  				},
   286  			},
   287  		},
   288  	}, nil
   289  }
   290  
   291  func (cs *collectionStore) RetrieveReadWritePermission(cc privdata.CollectionCriteria, sp *peer.SignedProposal, qe ledger.QueryExecutor) (bool, bool, error) {
   292  	panic("implement me")
   293  }
   294  
   295  func (cs *collectionStore) RetrieveCollectionConfigPackage(cc privdata.CollectionCriteria) (*peer.CollectionConfigPackage, error) {
   296  	return &peer.CollectionConfigPackage{
   297  		Config: []*peer.CollectionConfig{
   298  			{
   299  				Payload: &peer.CollectionConfig_StaticCollectionConfig{
   300  					StaticCollectionConfig: &peer.StaticCollectionConfig{
   301  						Name:              cc.Collection,
   302  						MaximumPeerCount:  1,
   303  						RequiredPeerCount: 1,
   304  					},
   305  				},
   306  			},
   307  		},
   308  	}, nil
   309  }
   310  
   311  func (cs *collectionStore) RetrieveCollectionPersistenceConfigs(cc privdata.CollectionCriteria) (privdata.CollectionPersistenceConfigs, error) {
   312  	panic("implement me")
   313  }
   314  
   315  func (cs *collectionStore) AccessFilter(channelName string, collectionPolicyConfig *peer.CollectionPolicyConfig) (privdata.Filter, error) {
   316  	panic("implement me")
   317  }
   318  
   319  type collectionAccessPolicy struct {
   320  	cs *collectionStore
   321  	n  uint64
   322  }
   323  
   324  func (cap *collectionAccessPolicy) MemberOrgs() map[string]struct{} {
   325  	return map[string]struct{}{
   326  		"org0": {},
   327  		"org1": {},
   328  	}
   329  }
   330  
   331  func (cap *collectionAccessPolicy) RequiredPeerCount() int {
   332  	return 1
   333  }
   334  
   335  func (cap *collectionAccessPolicy) MaximumPeerCount() int {
   336  	return 2
   337  }
   338  
   339  func (cap *collectionAccessPolicy) IsMemberOnlyRead() bool {
   340  	return false
   341  }
   342  
   343  func (cap *collectionAccessPolicy) IsMemberOnlyWrite() bool {
   344  	return false
   345  }
   346  
   347  func (cap *collectionAccessPolicy) AccessFilter() privdata.Filter {
   348  	return func(sd protoutil.SignedData) bool {
   349  		that, _ := asn1.Marshal(sd)
   350  		this, _ := asn1.Marshal(cap.cs.expectedSignedData)
   351  		if hex.EncodeToString(that) != hex.EncodeToString(this) {
   352  			panic(fmt.Errorf("self signed data passed isn't equal to expected:%v, %v", sd, cap.cs.expectedSignedData))
   353  		}
   354  
   355  		if cap.cs.acceptsNone {
   356  			return false
   357  		} else if cap.cs.acceptsAll {
   358  			return true
   359  		}
   360  
   361  		_, exists := cap.cs.policies[*cap]
   362  		return exists
   363  	}
   364  }
   365  
   366  func TestPvtDataCollections_FailOnEmptyPayload(t *testing.T) {
   367  	collection := &util.PvtDataCollections{
   368  		&ledger.TxPvtData{
   369  			SeqInBlock: uint64(1),
   370  			WriteSet: &rwset.TxPvtReadWriteSet{
   371  				DataModel: rwset.TxReadWriteSet_KV,
   372  				NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   373  					{
   374  						Namespace: "ns1",
   375  						CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   376  							{
   377  								CollectionName: "secretCollection",
   378  								Rwset:          []byte{1, 2, 3, 4, 5, 6, 7},
   379  							},
   380  						},
   381  					},
   382  				},
   383  			},
   384  		},
   385  
   386  		nil,
   387  	}
   388  
   389  	_, err := collection.Marshal()
   390  	assertion := assert.New(t)
   391  	assertion.Error(err, "Expected to fail since second item has nil payload")
   392  	assertion.Equal("Mallformed private data payload, rwset index 1 is nil", fmt.Sprintf("%s", err))
   393  }
   394  
   395  func TestPvtDataCollections_FailMarshalingWriteSet(t *testing.T) {
   396  	collection := &util.PvtDataCollections{
   397  		&ledger.TxPvtData{
   398  			SeqInBlock: uint64(1),
   399  			WriteSet:   nil,
   400  		},
   401  	}
   402  
   403  	_, err := collection.Marshal()
   404  	assertion := assert.New(t)
   405  	assertion.Error(err, "Expected to fail since first item has nil writeset")
   406  	assertion.Contains(fmt.Sprintf("%s", err), "Could not marshal private rwset index 0")
   407  }
   408  
   409  func TestPvtDataCollections_Marshal(t *testing.T) {
   410  	collection := &util.PvtDataCollections{
   411  		&ledger.TxPvtData{
   412  			SeqInBlock: uint64(1),
   413  			WriteSet: &rwset.TxPvtReadWriteSet{
   414  				DataModel: rwset.TxReadWriteSet_KV,
   415  				NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   416  					{
   417  						Namespace: "ns1",
   418  						CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   419  							{
   420  								CollectionName: "secretCollection",
   421  								Rwset:          []byte{1, 2, 3, 4, 5, 6, 7},
   422  							},
   423  						},
   424  					},
   425  				},
   426  			},
   427  		},
   428  
   429  		&ledger.TxPvtData{
   430  			SeqInBlock: uint64(2),
   431  			WriteSet: &rwset.TxPvtReadWriteSet{
   432  				DataModel: rwset.TxReadWriteSet_KV,
   433  				NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   434  					{
   435  						Namespace: "ns1",
   436  						CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   437  							{
   438  								CollectionName: "secretCollection",
   439  								Rwset:          []byte{42, 42, 42, 42, 42, 42, 42},
   440  							},
   441  						},
   442  					},
   443  					{
   444  						Namespace: "ns2",
   445  						CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   446  							{
   447  								CollectionName: "otherCollection",
   448  								Rwset:          []byte{10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
   449  							},
   450  						},
   451  					},
   452  				},
   453  			},
   454  		},
   455  	}
   456  
   457  	bytes, err := collection.Marshal()
   458  
   459  	assertion := assert.New(t)
   460  	assertion.NoError(err)
   461  	assertion.NotNil(bytes)
   462  	assertion.Equal(2, len(bytes))
   463  }
   464  
   465  func TestPvtDataCollections_Unmarshal(t *testing.T) {
   466  	collection := util.PvtDataCollections{
   467  		&ledger.TxPvtData{
   468  			SeqInBlock: uint64(1),
   469  			WriteSet: &rwset.TxPvtReadWriteSet{
   470  				DataModel: rwset.TxReadWriteSet_KV,
   471  				NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   472  					{
   473  						Namespace: "ns1",
   474  						CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   475  							{
   476  								CollectionName: "secretCollection",
   477  								Rwset:          []byte{1, 2, 3, 4, 5, 6, 7},
   478  							},
   479  						},
   480  					},
   481  				},
   482  			},
   483  		},
   484  	}
   485  
   486  	bytes, err := collection.Marshal()
   487  
   488  	assertion := assert.New(t)
   489  	assertion.NoError(err)
   490  	assertion.NotNil(bytes)
   491  	assertion.Equal(1, len(bytes))
   492  
   493  	var newCol util.PvtDataCollections
   494  
   495  	err = newCol.Unmarshal(bytes)
   496  	assertion.NoError(err)
   497  	assertion.Equal(1, len(newCol))
   498  	assertion.Equal(newCol[0].SeqInBlock, collection[0].SeqInBlock)
   499  	assertion.True(pb.Equal(newCol[0].WriteSet, collection[0].WriteSet))
   500  }
   501  
   502  type rwsTriplet struct {
   503  	namespace  string
   504  	collection string
   505  	rwset      string
   506  }
   507  
   508  func flattenTxPvtDataMap(pd ledger.TxPvtDataMap) map[uint64]map[rwsTriplet]struct{} {
   509  	m := make(map[uint64]map[rwsTriplet]struct{})
   510  	for seqInBlock, namespaces := range pd {
   511  		triplets := make(map[rwsTriplet]struct{})
   512  		for _, namespace := range namespaces.WriteSet.NsPvtRwset {
   513  			for _, col := range namespace.CollectionPvtRwset {
   514  				triplets[rwsTriplet{
   515  					namespace:  namespace.Namespace,
   516  					collection: col.CollectionName,
   517  					rwset:      hex.EncodeToString(col.Rwset),
   518  				}] = struct{}{}
   519  			}
   520  		}
   521  		m[seqInBlock] = triplets
   522  	}
   523  	return m
   524  }
   525  
   526  var expectedCommittedPrivateData1 = map[uint64]*ledger.TxPvtData{
   527  	0: {SeqInBlock: 0, WriteSet: &rwset.TxPvtReadWriteSet{
   528  		DataModel: rwset.TxReadWriteSet_KV,
   529  		NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   530  			{
   531  				Namespace: "ns1",
   532  				CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   533  					{
   534  						CollectionName: "c1",
   535  						Rwset:          []byte("rws-pre-image"),
   536  					},
   537  					{
   538  						CollectionName: "c2",
   539  						Rwset:          []byte("rws-pre-image"),
   540  					},
   541  				},
   542  			},
   543  		},
   544  	}},
   545  	1: {SeqInBlock: 1, WriteSet: &rwset.TxPvtReadWriteSet{
   546  		DataModel: rwset.TxReadWriteSet_KV,
   547  		NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   548  			{
   549  				Namespace: "ns2",
   550  				CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   551  					{
   552  						CollectionName: "c1",
   553  						Rwset:          []byte("rws-pre-image"),
   554  					},
   555  				},
   556  			},
   557  		},
   558  	}},
   559  }
   560  
   561  var expectedCommittedPrivateData2 = map[uint64]*ledger.TxPvtData{
   562  	0: {SeqInBlock: 0, WriteSet: &rwset.TxPvtReadWriteSet{
   563  		DataModel: rwset.TxReadWriteSet_KV,
   564  		NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   565  			{
   566  				Namespace: "ns3",
   567  				CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   568  					{
   569  						CollectionName: "c3",
   570  						Rwset:          []byte("rws-pre-image"),
   571  					},
   572  				},
   573  			},
   574  		},
   575  	}},
   576  }
   577  
   578  var expectedCommittedPrivateData3 = map[uint64]*ledger.TxPvtData{}
   579  
   580  func TestCoordinatorStoreInvalidBlock(t *testing.T) {
   581  	err := msptesttools.LoadMSPSetupForTesting()
   582  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
   583  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
   584  	serializedID, err := identity.Serialize()
   585  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
   586  	data := []byte{1, 2, 3}
   587  	signature, err := identity.Sign(data)
   588  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
   589  	mspID := "Org1MSP"
   590  	peerSelfSignedData := protoutil.SignedData{
   591  		Identity:  serializedID,
   592  		Signature: signature,
   593  		Data:      data,
   594  	}
   595  
   596  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
   597  
   598  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
   599  	committer := &mocks.Committer{}
   600  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
   601  		t.Fatal("Shouldn't have committed")
   602  	}).Return(nil)
   603  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsAll().withMSPIdentity(identity.GetMSPIdentifier())
   604  
   605  	store := newTransientStore(t)
   606  	defer store.tearDown()
   607  
   608  	assertPurged := func(txns ...string) {
   609  		for _, txn := range txns {
   610  			iterator, err := store.GetTxPvtRWSetByTxid(txn, nil)
   611  			if err != nil {
   612  				t.Fatalf("Failed iterating, got err %s", err)
   613  				iterator.Close()
   614  				return
   615  			}
   616  			res, err := iterator.Next()
   617  			if err != nil {
   618  				t.Fatalf("Failed iterating, got err %s", err)
   619  				iterator.Close()
   620  				return
   621  			}
   622  			assert.Nil(t, res)
   623  			iterator.Close()
   624  		}
   625  	}
   626  	fetcher := &fetcherMock{t: t}
   627  	pdFactory := &pvtDataFactory{}
   628  	bf := &blockFactory{
   629  		channelID: "testchannelid",
   630  	}
   631  
   632  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
   633  		return mgmt.GetManagerForChain("testchannelid")
   634  	})
   635  	block := bf.withoutMetadata().create()
   636  	// Scenario I: Block we got doesn't have any metadata with it
   637  	pvtData := pdFactory.create()
   638  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
   639  	capabilityProvider := &capabilitymock.CapabilityProvider{}
   640  	appCapability := &capabilitymock.AppCapabilities{}
   641  	capabilityProvider.On("Capabilities").Return(appCapability)
   642  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
   643  	coordinator := NewCoordinator(mspID, Support{
   644  		ChainID:            "testchannelid",
   645  		CollectionStore:    cs,
   646  		Committer:          committer,
   647  		Fetcher:            fetcher,
   648  		Validator:          &validatorMock{},
   649  		CapabilityProvider: capabilityProvider,
   650  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
   651  	err = coordinator.StoreBlock(block, pvtData)
   652  	assert.Error(t, err)
   653  	assert.Contains(t, err.Error(), "Block.Metadata is nil or Block.Metadata lacks a Tx filter bitmap")
   654  
   655  	// Scenario II: Validator has an error while validating the block
   656  	block = bf.create()
   657  	pvtData = pdFactory.create()
   658  	coordinator = NewCoordinator(mspID, Support{
   659  		ChainID:            "testchannelid",
   660  		CollectionStore:    cs,
   661  		Committer:          committer,
   662  		Fetcher:            fetcher,
   663  		Validator:          &validatorMock{fmt.Errorf("failed validating block")},
   664  		CapabilityProvider: capabilityProvider,
   665  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
   666  	err = coordinator.StoreBlock(block, pvtData)
   667  	assert.Error(t, err)
   668  	assert.Contains(t, err.Error(), "failed validating block")
   669  
   670  	// Scenario III: Block we got contains an inadequate length of Tx filter in the metadata
   671  	block = bf.withMetadataSize(100).create()
   672  	pvtData = pdFactory.create()
   673  	coordinator = NewCoordinator(mspID, Support{
   674  		ChainID:            "testchannelid",
   675  		CollectionStore:    cs,
   676  		Committer:          committer,
   677  		Fetcher:            fetcher,
   678  		Validator:          &validatorMock{},
   679  		CapabilityProvider: capabilityProvider,
   680  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
   681  	err = coordinator.StoreBlock(block, pvtData)
   682  	assert.Error(t, err)
   683  	assert.Contains(t, err.Error(), "block data size")
   684  	assert.Contains(t, err.Error(), "is different from Tx filter size")
   685  
   686  	// Scenario IV: The second transaction in the block we got is invalid, and we have no private data for that.
   687  	// As the StorePvtDataOfInvalidTx is set of false, if the coordinator would try to fetch private data, the
   688  	// test would fall because we haven't defined the mock operations for the transientstore (or for gossip)
   689  	// in this test.
   690  	var commitHappened bool
   691  	assertCommitHappened := func() {
   692  		assert.True(t, commitHappened)
   693  		commitHappened = false
   694  	}
   695  	digKeys := []privdatacommon.DigKey{
   696  		{
   697  			TxId:       "tx2",
   698  			Namespace:  "ns2",
   699  			Collection: "c1",
   700  			BlockSeq:   1,
   701  			SeqInBlock: 1,
   702  		},
   703  	}
   704  	fetcher = &fetcherMock{t: t}
   705  	fetcher.On("fetch", mock.Anything).expectingDigests(digKeys).expectingEndorsers(identity.GetMSPIdentifier()).Return(&privdatacommon.FetchedPvtDataContainer{
   706  		AvailableElements: nil,
   707  	}, nil)
   708  	committer = &mocks.Committer{}
   709  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
   710  		privateDataPassed2Ledger := args.Get(0).(*ledger.BlockAndPvtData).PvtData
   711  		commitHappened = true
   712  		// Only the first transaction's private data is passed to the ledger
   713  		assert.Len(t, privateDataPassed2Ledger, 1)
   714  		assert.Equal(t, 0, int(privateDataPassed2Ledger[0].SeqInBlock))
   715  		// The private data passed to the ledger contains "ns1" and has 2 collections in it
   716  		assert.Len(t, privateDataPassed2Ledger[0].WriteSet.NsPvtRwset, 1)
   717  		assert.Equal(t, "ns1", privateDataPassed2Ledger[0].WriteSet.NsPvtRwset[0].Namespace)
   718  		assert.Len(t, privateDataPassed2Ledger[0].WriteSet.NsPvtRwset[0].CollectionPvtRwset, 2)
   719  	}).Return(nil)
   720  	block = bf.withInvalidTxns(1).AddTxn("tx1", "ns1", hash, "c1", "c2").AddTxn("tx2", "ns2", hash, "c1").create()
   721  	pvtData = pdFactory.addRWSet().addNSRWSet("ns1", "c1", "c2").create()
   722  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
   723  
   724  	capabilityProvider = &capabilitymock.CapabilityProvider{}
   725  	appCapability = &capabilitymock.AppCapabilities{}
   726  	capabilityProvider.On("Capabilities").Return(appCapability)
   727  	appCapability.On("StorePvtDataOfInvalidTx").Return(false)
   728  	coordinator = NewCoordinator(mspID, Support{
   729  		ChainID:            "testchannelid",
   730  		CollectionStore:    cs,
   731  		Committer:          committer,
   732  		Fetcher:            fetcher,
   733  		Validator:          &validatorMock{},
   734  		CapabilityProvider: capabilityProvider,
   735  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
   736  	err = coordinator.StoreBlock(block, pvtData)
   737  	assert.NoError(t, err)
   738  	assertCommitHappened()
   739  	// Ensure the 2nd transaction which is invalid and wasn't committed - is still purged.
   740  	// This is so that if we get a transaction via dissemination from an endorser, we purge it
   741  	// when its block comes.
   742  	assertPurged("tx1", "tx2")
   743  
   744  	// Scenario V: The second transaction in the block we got is invalid, and we have no private
   745  	// data for that in the transient store. As we have set StorePvtDataOfInvalidTx to true and
   746  	// configured the coordinator to skip pulling pvtData of invalid transactions from other peers,
   747  	// it should not store the pvtData of invalid transaction in the ledger instead a missing entry.
   748  	testConfig.SkipPullingInvalidTransactions = true
   749  	assertCommitHappened = func() {
   750  		assert.True(t, commitHappened)
   751  		commitHappened = false
   752  	}
   753  	committer = &mocks.Committer{}
   754  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
   755  		blockAndPvtData := args.Get(0).(*ledger.BlockAndPvtData)
   756  		commitHappened = true
   757  		// Only the first transaction's private data is passed to the ledger
   758  		privateDataPassed2Ledger := blockAndPvtData.PvtData
   759  		assert.Len(t, privateDataPassed2Ledger, 1)
   760  		assert.Equal(t, 0, int(privateDataPassed2Ledger[0].SeqInBlock))
   761  		// The private data passed to the ledger contains "ns1" and has 2 collections in it
   762  		assert.Len(t, privateDataPassed2Ledger[0].WriteSet.NsPvtRwset, 1)
   763  		assert.Equal(t, "ns1", privateDataPassed2Ledger[0].WriteSet.NsPvtRwset[0].Namespace)
   764  		assert.Len(t, privateDataPassed2Ledger[0].WriteSet.NsPvtRwset[0].CollectionPvtRwset, 2)
   765  
   766  		missingPrivateDataPassed2Ledger := blockAndPvtData.MissingPvtData
   767  		assert.Len(t, missingPrivateDataPassed2Ledger, 1)
   768  		assert.Len(t, missingPrivateDataPassed2Ledger[1], 1)
   769  		assert.Equal(t, missingPrivateDataPassed2Ledger[1][0].Namespace, "ns2")
   770  		assert.Equal(t, missingPrivateDataPassed2Ledger[1][0].Collection, "c1")
   771  		assert.Equal(t, missingPrivateDataPassed2Ledger[1][0].IsEligible, true)
   772  
   773  		commitOpts := args.Get(1).(*ledger.CommitOptions)
   774  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
   775  		assert.Equal(t, expectedCommitOpts, commitOpts)
   776  	}).Return(nil)
   777  
   778  	block = bf.withInvalidTxns(1).AddTxn("tx1", "ns1", hash, "c1", "c2").AddTxn("tx2", "ns2", hash, "c1").create()
   779  	pvtData = pdFactory.addRWSet().addNSRWSet("ns1", "c1", "c2").create()
   780  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
   781  	capabilityProvider = &capabilitymock.CapabilityProvider{}
   782  	appCapability = &capabilitymock.AppCapabilities{}
   783  	capabilityProvider.On("Capabilities").Return(appCapability)
   784  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
   785  	digKeys = []privdatacommon.DigKey{}
   786  	fetcher = &fetcherMock{t: t}
   787  	fetcher.On("fetch", mock.Anything).expectingDigests(digKeys).Return(&privdatacommon.FetchedPvtDataContainer{
   788  		AvailableElements: nil,
   789  	}, nil)
   790  	coordinator = NewCoordinator(mspID, Support{
   791  		ChainID:            "testchannelid",
   792  		CollectionStore:    cs,
   793  		Committer:          committer,
   794  		Fetcher:            fetcher,
   795  		Validator:          &validatorMock{},
   796  		CapabilityProvider: capabilityProvider,
   797  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
   798  	err = coordinator.StoreBlock(block, pvtData)
   799  	assert.NoError(t, err)
   800  	assertCommitHappened()
   801  	assertPurged("tx1", "tx2")
   802  
   803  	// Scenario VI: The second transaction in the block we got is invalid. As we have set the
   804  	// StorePvtDataOfInvalidTx to true and configured the coordinator to pull pvtData of invalid
   805  	// transactions, it should store the pvtData of invalid transactions in the ledger.
   806  	testConfig.SkipPullingInvalidTransactions = false
   807  	committer = &mocks.Committer{}
   808  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
   809  		blockAndPvtData := args.Get(0).(*ledger.BlockAndPvtData)
   810  		commitHappened = true
   811  		// pvtData of both transactions must be present though the second transaction
   812  		// is invalid.
   813  		privateDataPassed2Ledger := blockAndPvtData.PvtData
   814  		assert.Len(t, privateDataPassed2Ledger, 2)
   815  		assert.Equal(t, 0, int(privateDataPassed2Ledger[0].SeqInBlock))
   816  		assert.Equal(t, 1, int(privateDataPassed2Ledger[1].SeqInBlock))
   817  		// The private data passed to the ledger for tx1 contains "ns1" and has 2 collections in it
   818  		assert.Len(t, privateDataPassed2Ledger[0].WriteSet.NsPvtRwset, 1)
   819  		assert.Equal(t, "ns1", privateDataPassed2Ledger[0].WriteSet.NsPvtRwset[0].Namespace)
   820  		assert.Len(t, privateDataPassed2Ledger[0].WriteSet.NsPvtRwset[0].CollectionPvtRwset, 2)
   821  		// The private data passed to the ledger for tx2 contains "ns2" and has 1 collection in it
   822  		assert.Len(t, privateDataPassed2Ledger[1].WriteSet.NsPvtRwset, 1)
   823  		assert.Equal(t, "ns2", privateDataPassed2Ledger[1].WriteSet.NsPvtRwset[0].Namespace)
   824  		assert.Len(t, privateDataPassed2Ledger[1].WriteSet.NsPvtRwset[0].CollectionPvtRwset, 1)
   825  
   826  		missingPrivateDataPassed2Ledger := blockAndPvtData.MissingPvtData
   827  		assert.Len(t, missingPrivateDataPassed2Ledger, 0)
   828  
   829  		commitOpts := args.Get(1).(*ledger.CommitOptions)
   830  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
   831  		assert.Equal(t, expectedCommitOpts, commitOpts)
   832  	}).Return(nil)
   833  
   834  	fetcher = &fetcherMock{t: t}
   835  	fetcher.On("fetch", mock.Anything).expectingDigests([]privdatacommon.DigKey{
   836  		{
   837  			TxId: "tx2", Namespace: "ns2", Collection: "c1", BlockSeq: 1, SeqInBlock: 1,
   838  		},
   839  	}).Return(&privdatacommon.FetchedPvtDataContainer{
   840  		AvailableElements: []*proto.PvtDataElement{
   841  			{
   842  				Digest: &proto.PvtDataDigest{
   843  					SeqInBlock: 1,
   844  					BlockSeq:   1,
   845  					Collection: "c1",
   846  					Namespace:  "ns2",
   847  					TxId:       "tx2",
   848  				},
   849  				Payload: [][]byte{[]byte("rws-pre-image")},
   850  			},
   851  		},
   852  	}, nil)
   853  
   854  	block = bf.withInvalidTxns(1).AddTxnWithEndorsement("tx1", "ns1", hash, "org1", true, "c1", "c2").
   855  		AddTxnWithEndorsement("tx2", "ns2", hash, "org2", true, "c1").create()
   856  	pvtData = pdFactory.addRWSet().addNSRWSet("ns1", "c1", "c2").create()
   857  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
   858  	coordinator = NewCoordinator(mspID, Support{
   859  		ChainID:            "testchannelid",
   860  		CollectionStore:    cs,
   861  		Committer:          committer,
   862  		Fetcher:            fetcher,
   863  		Validator:          &validatorMock{},
   864  		CapabilityProvider: capabilityProvider,
   865  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
   866  	err = coordinator.StoreBlock(block, pvtData)
   867  	assert.NoError(t, err)
   868  	assertCommitHappened()
   869  	assertPurged("tx1", "tx2")
   870  
   871  	// Scenario VII: Block doesn't contain a header
   872  	block.Header = nil
   873  	err = coordinator.StoreBlock(block, pvtData)
   874  	assert.Error(t, err)
   875  	assert.Contains(t, err.Error(), "Block header is nil")
   876  
   877  	// Scenario VIII: Block doesn't contain Data
   878  	block.Data = nil
   879  	err = coordinator.StoreBlock(block, pvtData)
   880  	assert.Error(t, err)
   881  	assert.Contains(t, err.Error(), "Block data is empty")
   882  }
   883  
   884  func TestCoordinatorToFilterOutPvtRWSetsWithWrongHash(t *testing.T) {
   885  	/*
   886  		Test case, where peer receives new block for commit
   887  		it has ns1:c1 in transient store, while it has wrong
   888  		hash, hence it will fetch ns1:c1 from other peers
   889  	*/
   890  	err := msptesttools.LoadMSPSetupForTesting()
   891  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
   892  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
   893  	serializedID, err := identity.Serialize()
   894  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
   895  	data := []byte{1, 2, 3}
   896  	signature, err := identity.Sign(data)
   897  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
   898  	mspID := "Org1MSP"
   899  	peerSelfSignedData := protoutil.SignedData{
   900  		Identity:  serializedID,
   901  		Signature: signature,
   902  		Data:      data,
   903  	}
   904  
   905  	expectedPvtData := map[uint64]*ledger.TxPvtData{
   906  		0: {SeqInBlock: 0, WriteSet: &rwset.TxPvtReadWriteSet{
   907  			DataModel: rwset.TxReadWriteSet_KV,
   908  			NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   909  				{
   910  					Namespace: "ns1",
   911  					CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   912  						{
   913  							CollectionName: "c1",
   914  							Rwset:          []byte("rws-original"),
   915  						},
   916  					},
   917  				},
   918  			},
   919  		}},
   920  	}
   921  
   922  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsAll().withMSPIdentity(identity.GetMSPIdentifier())
   923  	committer := &mocks.Committer{}
   924  
   925  	store := newTransientStore(t)
   926  	defer store.tearDown()
   927  
   928  	assertPurged := func(txns ...string) {
   929  		for _, txn := range txns {
   930  			iterator, err := store.GetTxPvtRWSetByTxid(txn, nil)
   931  			if err != nil {
   932  				t.Fatalf("Failed iterating, got err %s", err)
   933  				iterator.Close()
   934  				return
   935  			}
   936  			res, err := iterator.Next()
   937  			if err != nil {
   938  				t.Fatalf("Failed iterating, got err %s", err)
   939  				iterator.Close()
   940  				return
   941  			}
   942  			assert.Nil(t, res)
   943  			iterator.Close()
   944  		}
   945  	}
   946  
   947  	fetcher := &fetcherMock{t: t}
   948  
   949  	var commitHappened bool
   950  
   951  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
   952  		privateDataPassed2Ledger := args.Get(0).(*ledger.BlockAndPvtData).PvtData
   953  		assert.True(t, reflect.DeepEqual(flattenTxPvtDataMap(privateDataPassed2Ledger),
   954  			flattenTxPvtDataMap(expectedPvtData)))
   955  		commitHappened = true
   956  
   957  		commitOpts := args.Get(1).(*ledger.CommitOptions)
   958  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
   959  		assert.Equal(t, expectedCommitOpts, commitOpts)
   960  	}).Return(nil)
   961  
   962  	hash := util2.ComputeSHA256([]byte("rws-original"))
   963  	bf := &blockFactory{
   964  		channelID: "testchannelid",
   965  	}
   966  
   967  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
   968  		return mgmt.GetManagerForChain("testchannelid")
   969  	})
   970  
   971  	block := bf.AddTxnWithEndorsement("tx1", "ns1", hash, "org1", true, "c1").create()
   972  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
   973  
   974  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
   975  
   976  	capabilityProvider := &capabilitymock.CapabilityProvider{}
   977  	appCapability := &capabilitymock.AppCapabilities{}
   978  	capabilityProvider.On("Capabilities").Return(appCapability)
   979  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
   980  	coordinator := NewCoordinator(mspID, Support{
   981  		ChainID:            "testchannelid",
   982  		CollectionStore:    cs,
   983  		Committer:          committer,
   984  		Fetcher:            fetcher,
   985  		Validator:          &validatorMock{},
   986  		CapabilityProvider: capabilityProvider,
   987  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
   988  
   989  	fetcher.On("fetch", mock.Anything).expectingDigests([]privdatacommon.DigKey{
   990  		{
   991  			TxId: "tx1", Namespace: "ns1", Collection: "c1", BlockSeq: 1,
   992  		},
   993  	}).Return(&privdatacommon.FetchedPvtDataContainer{
   994  		AvailableElements: []*proto.PvtDataElement{
   995  			{
   996  				Digest: &proto.PvtDataDigest{
   997  					BlockSeq:   1,
   998  					Collection: "c1",
   999  					Namespace:  "ns1",
  1000  					TxId:       "tx1",
  1001  				},
  1002  				Payload: [][]byte{[]byte("rws-original")},
  1003  			},
  1004  		},
  1005  	}, nil)
  1006  
  1007  	coordinator.StoreBlock(block, nil)
  1008  	// Assert blocks was eventually committed
  1009  	assert.True(t, commitHappened)
  1010  
  1011  	// Assert transaction has been purged
  1012  	assertPurged("tx1")
  1013  }
  1014  
  1015  func TestCoordinatorStoreBlock(t *testing.T) {
  1016  	err := msptesttools.LoadMSPSetupForTesting()
  1017  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
  1018  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
  1019  	serializedID, err := identity.Serialize()
  1020  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
  1021  	data := []byte{1, 2, 3}
  1022  	signature, err := identity.Sign(data)
  1023  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
  1024  	mspID := "Org1MSP"
  1025  	peerSelfSignedData := protoutil.SignedData{
  1026  		Identity:  serializedID,
  1027  		Signature: signature,
  1028  		Data:      data,
  1029  	}
  1030  	// Green path test, all private data should be obtained successfully
  1031  
  1032  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsAll().withMSPIdentity(identity.GetMSPIdentifier())
  1033  
  1034  	var commitHappened bool
  1035  	assertCommitHappened := func() {
  1036  		assert.True(t, commitHappened)
  1037  		commitHappened = false
  1038  	}
  1039  	committer := &mocks.Committer{}
  1040  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
  1041  		privateDataPassed2Ledger := args.Get(0).(*ledger.BlockAndPvtData).PvtData
  1042  		assert.True(t, reflect.DeepEqual(flattenTxPvtDataMap(privateDataPassed2Ledger),
  1043  			flattenTxPvtDataMap(expectedCommittedPrivateData1)))
  1044  		commitHappened = true
  1045  
  1046  		commitOpts := args.Get(1).(*ledger.CommitOptions)
  1047  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
  1048  		assert.Equal(t, expectedCommitOpts, commitOpts)
  1049  	}).Return(nil)
  1050  
  1051  	store := newTransientStore(t)
  1052  	defer store.tearDown()
  1053  
  1054  	assertPurged := func(txns ...string) {
  1055  		for _, txn := range txns {
  1056  			iterator, err := store.GetTxPvtRWSetByTxid(txn, nil)
  1057  			if err != nil {
  1058  				t.Fatalf("Failed iterating, got err %s", err)
  1059  				iterator.Close()
  1060  				return
  1061  			}
  1062  			res, err := iterator.Next()
  1063  			if err != nil {
  1064  				t.Fatalf("Failed iterating, got err %s", err)
  1065  				iterator.Close()
  1066  				return
  1067  			}
  1068  			assert.Nil(t, res)
  1069  			iterator.Close()
  1070  		}
  1071  	}
  1072  
  1073  	fetcher := &fetcherMock{t: t}
  1074  
  1075  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
  1076  	pdFactory := &pvtDataFactory{}
  1077  	bf := &blockFactory{
  1078  		channelID: "testchannelid",
  1079  	}
  1080  
  1081  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1082  		return mgmt.GetManagerForChain("testchannelid")
  1083  	})
  1084  
  1085  	block := bf.AddTxnWithEndorsement("tx1", "ns1", hash, "org1", true, "c1", "c2").
  1086  		AddTxnWithEndorsement("tx2", "ns2", hash, "org2", true, "c1").create()
  1087  
  1088  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
  1089  
  1090  	fmt.Println("Scenario I")
  1091  	// Scenario I: Block we got has sufficient private data alongside it.
  1092  	// If the coordinator tries fetching from the transientstore, or peers it would result in panic,
  1093  	// because we didn't define yet the "On(...)" invocation of the transient store or other peers.
  1094  	pvtData := pdFactory.addRWSet().addNSRWSet("ns1", "c1", "c2").addRWSet().addNSRWSet("ns2", "c1").create()
  1095  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1096  
  1097  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1098  	appCapability := &capabilitymock.AppCapabilities{}
  1099  	capabilityProvider.On("Capabilities").Return(appCapability)
  1100  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1101  	coordinator := NewCoordinator(mspID, Support{
  1102  		ChainID:            "testchannelid",
  1103  		CollectionStore:    cs,
  1104  		Committer:          committer,
  1105  		Fetcher:            fetcher,
  1106  		Validator:          &validatorMock{},
  1107  		CapabilityProvider: capabilityProvider,
  1108  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1109  	err = coordinator.StoreBlock(block, pvtData)
  1110  	assert.NoError(t, err)
  1111  	assertCommitHappened()
  1112  	assertPurged("tx1", "tx2")
  1113  
  1114  	fmt.Println("Scenario II")
  1115  	// Scenario II: Block we got doesn't have sufficient private data alongside it,
  1116  	// it is missing ns1: c2, but the data exists in the transient store
  1117  	store.Persist("tx1", 1, &tspb.TxPvtReadWriteSetWithConfigInfo{
  1118  		PvtRwset: &rwset.TxPvtReadWriteSet{
  1119  			NsPvtRwset: []*rwset.NsPvtReadWriteSet{
  1120  				{
  1121  					Namespace: "ns1",
  1122  					CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
  1123  						{
  1124  							CollectionName: "c2",
  1125  							Rwset:          []byte("rws-pre-image"),
  1126  						},
  1127  					},
  1128  				},
  1129  			},
  1130  		},
  1131  		CollectionConfigs: make(map[string]*peer.CollectionConfigPackage),
  1132  	})
  1133  	pvtData = pdFactory.addRWSet().addNSRWSet("ns1", "c1").addRWSet().addNSRWSet("ns2", "c1").create()
  1134  	err = coordinator.StoreBlock(block, pvtData)
  1135  	assert.NoError(t, err)
  1136  	assertCommitHappened()
  1137  	assertPurged("tx1", "tx2")
  1138  
  1139  	fmt.Println("Scenario III")
  1140  	// Scenario III: Block doesn't have sufficient private data alongside it,
  1141  	// it is missing ns1: c2, and the data exists in the transient store,
  1142  	// but it is also missing ns2: c1, and that data doesn't exist in the transient store - but in a peer.
  1143  	// Additionally, the coordinator should pass an endorser identity of org1, but not of org2, since
  1144  	// the MemberOrgs() call doesn't return org2 but only org0 and org1.
  1145  	fetcher.On("fetch", mock.Anything).expectingDigests([]privdatacommon.DigKey{
  1146  		{
  1147  			TxId: "tx1", Namespace: "ns1", Collection: "c2", BlockSeq: 1,
  1148  		},
  1149  		{
  1150  			TxId: "tx2", Namespace: "ns2", Collection: "c1", BlockSeq: 1, SeqInBlock: 1,
  1151  		},
  1152  	}).Return(&privdatacommon.FetchedPvtDataContainer{
  1153  		AvailableElements: []*proto.PvtDataElement{
  1154  			{
  1155  				Digest: &proto.PvtDataDigest{
  1156  					BlockSeq:   1,
  1157  					Collection: "c2",
  1158  					Namespace:  "ns1",
  1159  					TxId:       "tx1",
  1160  				},
  1161  				Payload: [][]byte{[]byte("rws-pre-image")},
  1162  			},
  1163  			{
  1164  				Digest: &proto.PvtDataDigest{
  1165  					SeqInBlock: 1,
  1166  					BlockSeq:   1,
  1167  					Collection: "c1",
  1168  					Namespace:  "ns2",
  1169  					TxId:       "tx2",
  1170  				},
  1171  				Payload: [][]byte{[]byte("rws-pre-image")},
  1172  			},
  1173  		},
  1174  	}, nil)
  1175  	pvtData = pdFactory.addRWSet().addNSRWSet("ns1", "c1").create()
  1176  	err = coordinator.StoreBlock(block, pvtData)
  1177  	assertPurged("tx1", "tx2")
  1178  	assert.NoError(t, err)
  1179  	assertCommitHappened()
  1180  
  1181  	fmt.Println("Scenario IV")
  1182  	// Scenario IV: Block came with more than sufficient private data alongside it, some of it is redundant.
  1183  	pvtData = pdFactory.addRWSet().addNSRWSet("ns1", "c1", "c2", "c3").
  1184  		addRWSet().addNSRWSet("ns2", "c1", "c3").addRWSet().addNSRWSet("ns1", "c4").create()
  1185  	err = coordinator.StoreBlock(block, pvtData)
  1186  	assertPurged("tx1", "tx2")
  1187  	assert.NoError(t, err)
  1188  	assertCommitHappened()
  1189  
  1190  	fmt.Println("Scenario V")
  1191  	// Scenario V: Block we got has private data alongside it but coordinator cannot retrieve collection access
  1192  	// policy of collections due to databse unavailability error.
  1193  	// we verify that the error propagates properly.
  1194  	mockCs := &mocks.CollectionStore{}
  1195  	mockCs.On("RetrieveCollectionConfig", mock.Anything).Return(nil, errors.New("test error"))
  1196  	coordinator = NewCoordinator(mspID, Support{
  1197  		ChainID:            "testchannelid",
  1198  		CollectionStore:    mockCs,
  1199  		Committer:          committer,
  1200  		Fetcher:            fetcher,
  1201  		Validator:          &validatorMock{},
  1202  		CapabilityProvider: capabilityProvider,
  1203  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1204  	err = coordinator.StoreBlock(block, nil)
  1205  	assert.Error(t, err)
  1206  	assert.Equal(t, "test error", err.Error())
  1207  
  1208  	fmt.Println("Scenario VI")
  1209  	// Scenario VI: Block didn't get with any private data alongside it, and the transient store
  1210  	// has some problem.
  1211  	// In this case, we should try to fetch data from peers.
  1212  	block = bf.AddTxn("tx3", "ns3", hash, "c3").create()
  1213  	fetcher = &fetcherMock{t: t}
  1214  	fetcher.On("fetch", mock.Anything).expectingDigests([]privdatacommon.DigKey{
  1215  		{
  1216  			TxId: "tx3", Namespace: "ns3", Collection: "c3", BlockSeq: 1,
  1217  		},
  1218  	}).Return(&privdatacommon.FetchedPvtDataContainer{
  1219  		AvailableElements: []*proto.PvtDataElement{
  1220  			{
  1221  				Digest: &proto.PvtDataDigest{
  1222  					BlockSeq:   1,
  1223  					Collection: "c3",
  1224  					Namespace:  "ns3",
  1225  					TxId:       "tx3",
  1226  				},
  1227  				Payload: [][]byte{[]byte("rws-pre-image")},
  1228  			},
  1229  		},
  1230  	}, nil)
  1231  	committer = &mocks.Committer{}
  1232  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
  1233  		privateDataPassed2Ledger := args.Get(0).(*ledger.BlockAndPvtData).PvtData
  1234  		assert.True(t, reflect.DeepEqual(flattenTxPvtDataMap(privateDataPassed2Ledger),
  1235  			flattenTxPvtDataMap(expectedCommittedPrivateData2)))
  1236  		commitHappened = true
  1237  
  1238  		commitOpts := args.Get(1).(*ledger.CommitOptions)
  1239  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
  1240  		assert.Equal(t, expectedCommitOpts, commitOpts)
  1241  	}).Return(nil)
  1242  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1243  	coordinator = NewCoordinator(mspID, Support{
  1244  		ChainID:            "testchannelid",
  1245  		CollectionStore:    cs,
  1246  		Committer:          committer,
  1247  		Fetcher:            fetcher,
  1248  		Validator:          &validatorMock{},
  1249  		CapabilityProvider: capabilityProvider,
  1250  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1251  	err = coordinator.StoreBlock(block, nil)
  1252  	assertPurged("tx3")
  1253  	assert.NoError(t, err)
  1254  	assertCommitHappened()
  1255  
  1256  	fmt.Println("Scenario VII")
  1257  	// Scenario VII: Block contains 2 transactions, and the peer is eligible for only tx3-ns3-c3.
  1258  	// Also, the blocks comes with a private data for tx3-ns3-c3 so that the peer won't have to fetch the
  1259  	// private data from the transient store or peers, and in fact- if it attempts to fetch the data it's not eligible
  1260  	// for from the transient store or from peers - the test would fail because the Mock wasn't initialized.
  1261  	block = bf.AddTxn("tx3", "ns3", hash, "c3", "c2", "c1").AddTxn("tx1", "ns1", hash, "c1").create()
  1262  	cs = createcollectionStore(peerSelfSignedData).thatAccepts(CollectionCriteria{
  1263  		Collection: "c3",
  1264  		Namespace:  "ns3",
  1265  		Channel:    "testchannelid",
  1266  	}).withMSPIdentity(identity.GetMSPIdentifier())
  1267  	fetcher = &fetcherMock{t: t}
  1268  	committer = &mocks.Committer{}
  1269  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
  1270  		privateDataPassed2Ledger := args.Get(0).(*ledger.BlockAndPvtData).PvtData
  1271  		assert.True(t, reflect.DeepEqual(flattenTxPvtDataMap(privateDataPassed2Ledger),
  1272  			flattenTxPvtDataMap(expectedCommittedPrivateData2)))
  1273  		commitHappened = true
  1274  
  1275  		commitOpts := args.Get(1).(*ledger.CommitOptions)
  1276  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
  1277  		assert.Equal(t, expectedCommitOpts, commitOpts)
  1278  	}).Return(nil)
  1279  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1280  	coordinator = NewCoordinator(mspID, Support{
  1281  		ChainID:            "testchannelid",
  1282  		CollectionStore:    cs,
  1283  		Committer:          committer,
  1284  		Fetcher:            fetcher,
  1285  		Validator:          &validatorMock{},
  1286  		CapabilityProvider: capabilityProvider,
  1287  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1288  
  1289  	pvtData = pdFactory.addRWSet().addNSRWSet("ns3", "c3").create()
  1290  	err = coordinator.StoreBlock(block, pvtData)
  1291  	assert.NoError(t, err)
  1292  	assertCommitHappened()
  1293  	// In any case, all transactions in the block are purged from the transient store
  1294  	assertPurged("tx3", "tx1")
  1295  }
  1296  
  1297  func TestCoordinatorStoreBlockWhenPvtDataExistInLedger(t *testing.T) {
  1298  	err := msptesttools.LoadMSPSetupForTesting()
  1299  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
  1300  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
  1301  	serializedID, err := identity.Serialize()
  1302  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
  1303  	data := []byte{1, 2, 3}
  1304  	signature, err := identity.Sign(data)
  1305  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
  1306  	mspID := "Org1MSP"
  1307  	peerSelfSignedData := protoutil.SignedData{
  1308  		Identity:  serializedID,
  1309  		Signature: signature,
  1310  		Data:      data,
  1311  	}
  1312  
  1313  	var commitHappened bool
  1314  	assertCommitHappened := func() {
  1315  		assert.True(t, commitHappened)
  1316  		commitHappened = false
  1317  	}
  1318  	committer := &mocks.Committer{}
  1319  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
  1320  		privateDataPassed2Ledger := args.Get(0).(*ledger.BlockAndPvtData).PvtData
  1321  		assert.Equal(t, ledger.TxPvtDataMap{}, privateDataPassed2Ledger)
  1322  		commitOpts := args.Get(1).(*ledger.CommitOptions)
  1323  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: true}
  1324  		assert.Equal(t, expectedCommitOpts, commitOpts)
  1325  		commitHappened = true
  1326  	}).Return(nil)
  1327  
  1328  	fetcher := &fetcherMock{t: t}
  1329  
  1330  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
  1331  	pdFactory := &pvtDataFactory{}
  1332  	bf := &blockFactory{
  1333  		channelID: "testchannelid",
  1334  	}
  1335  
  1336  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1337  		return mgmt.GetManagerForChain("testchannelid")
  1338  	})
  1339  
  1340  	block := bf.AddTxnWithEndorsement("tx1", "ns1", hash, "org1", true, "c1", "c2").
  1341  		AddTxnWithEndorsement("tx2", "ns2", hash, "org2", true, "c1").create()
  1342  
  1343  	// Scenario: Block we got has been reprocessed and hence the sufficient pvtData is present
  1344  	// in the local pvtdataStore itself. The pvtData would be fetched from the local pvtdataStore.
  1345  	// If the coordinator tries fetching from the transientstore, or peers it would result in panic,
  1346  	// because we didn't define yet the "On(...)" invocation of the transient store or other peers.
  1347  	pvtData := pdFactory.addRWSet().addNSRWSet("ns1", "c1", "c2").addRWSet().addNSRWSet("ns2", "c1").create()
  1348  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(true, nil)
  1349  
  1350  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
  1351  
  1352  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1353  	appCapability := &capabilitymock.AppCapabilities{}
  1354  	capabilityProvider.On("Capabilities").Return(appCapability)
  1355  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1356  	coordinator := NewCoordinator(mspID, Support{
  1357  		ChainID:            "testchannelid",
  1358  		CollectionStore:    nil,
  1359  		Committer:          committer,
  1360  		Fetcher:            fetcher,
  1361  		Validator:          &validatorMock{},
  1362  		CapabilityProvider: capabilityProvider,
  1363  	}, nil, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1364  	err = coordinator.StoreBlock(block, pvtData)
  1365  	assert.NoError(t, err)
  1366  	assertCommitHappened()
  1367  }
  1368  
  1369  func TestProceedWithoutPrivateData(t *testing.T) {
  1370  	// Scenario: we are missing private data (c2 in ns3) and it cannot be obtained from any peer.
  1371  	// Block needs to be committed with missing private data.
  1372  	err := msptesttools.LoadMSPSetupForTesting()
  1373  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
  1374  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
  1375  	serializedID, err := identity.Serialize()
  1376  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
  1377  	data := []byte{1, 2, 3}
  1378  	signature, err := identity.Sign(data)
  1379  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
  1380  	mspID := "Org1MSP"
  1381  	peerSelfSignedData := protoutil.SignedData{
  1382  		Identity:  serializedID,
  1383  		Signature: signature,
  1384  		Data:      data,
  1385  	}
  1386  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsAll().withMSPIdentity(identity.GetMSPIdentifier())
  1387  	var commitHappened bool
  1388  	assertCommitHappened := func() {
  1389  		assert.True(t, commitHappened)
  1390  		commitHappened = false
  1391  	}
  1392  	committer := &mocks.Committer{}
  1393  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
  1394  		blockAndPrivateData := args.Get(0).(*ledger.BlockAndPvtData)
  1395  		privateDataPassed2Ledger := blockAndPrivateData.PvtData
  1396  		assert.True(t, reflect.DeepEqual(flattenTxPvtDataMap(privateDataPassed2Ledger),
  1397  			flattenTxPvtDataMap(expectedCommittedPrivateData2)))
  1398  		missingPrivateData := blockAndPrivateData.MissingPvtData
  1399  		expectedMissingPvtData := make(ledger.TxMissingPvtDataMap)
  1400  		expectedMissingPvtData.Add(0, "ns3", "c2", true)
  1401  		assert.Equal(t, expectedMissingPvtData, missingPrivateData)
  1402  		commitHappened = true
  1403  
  1404  		commitOpts := args.Get(1).(*ledger.CommitOptions)
  1405  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
  1406  		assert.Equal(t, expectedCommitOpts, commitOpts)
  1407  	}).Return(nil)
  1408  
  1409  	store := newTransientStore(t)
  1410  	defer store.tearDown()
  1411  
  1412  	assertPurged := func(txns ...string) {
  1413  		for _, txn := range txns {
  1414  			iterator, err := store.GetTxPvtRWSetByTxid(txn, nil)
  1415  			if err != nil {
  1416  				t.Fatalf("Failed iterating, got err %s", err)
  1417  				iterator.Close()
  1418  				return
  1419  			}
  1420  			res, err := iterator.Next()
  1421  			if err != nil {
  1422  				t.Fatalf("Failed iterating, got err %s", err)
  1423  				iterator.Close()
  1424  				return
  1425  			}
  1426  			assert.Nil(t, res)
  1427  			iterator.Close()
  1428  		}
  1429  	}
  1430  
  1431  	fetcher := &fetcherMock{t: t}
  1432  	// Have the peer return in response to the pull, a private data with a non matching hash
  1433  	fetcher.On("fetch", mock.Anything).expectingDigests([]privdatacommon.DigKey{
  1434  		{
  1435  			TxId: "tx1", Namespace: "ns3", Collection: "c2", BlockSeq: 1,
  1436  		},
  1437  	}).Return(&privdatacommon.FetchedPvtDataContainer{
  1438  		AvailableElements: []*proto.PvtDataElement{
  1439  			{
  1440  				Digest: &proto.PvtDataDigest{
  1441  					BlockSeq:   1,
  1442  					Collection: "c2",
  1443  					Namespace:  "ns3",
  1444  					TxId:       "tx1",
  1445  				},
  1446  				Payload: [][]byte{[]byte("wrong pre-image")},
  1447  			},
  1448  		},
  1449  	}, nil)
  1450  
  1451  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
  1452  	pdFactory := &pvtDataFactory{}
  1453  	bf := &blockFactory{
  1454  		channelID: "testchannelid",
  1455  	}
  1456  
  1457  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1458  		return mgmt.GetManagerForChain("testchannelid")
  1459  	})
  1460  
  1461  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
  1462  
  1463  	block := bf.AddTxn("tx1", "ns3", hash, "c3", "c2").create()
  1464  	pvtData := pdFactory.addRWSet().addNSRWSet("ns3", "c3").create()
  1465  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1466  
  1467  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1468  	appCapability := &capabilitymock.AppCapabilities{}
  1469  	capabilityProvider.On("Capabilities").Return(appCapability)
  1470  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1471  	coordinator := NewCoordinator(mspID, Support{
  1472  		ChainID:            "testchannelid",
  1473  		CollectionStore:    cs,
  1474  		Committer:          committer,
  1475  		Fetcher:            fetcher,
  1476  		Validator:          &validatorMock{},
  1477  		CapabilityProvider: capabilityProvider,
  1478  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1479  	err = coordinator.StoreBlock(block, pvtData)
  1480  	assert.NoError(t, err)
  1481  	assertCommitHappened()
  1482  	assertPurged("tx1")
  1483  }
  1484  
  1485  func TestProceedWithInEligiblePrivateData(t *testing.T) {
  1486  	// Scenario: we are missing private data (c2 in ns3) and it cannot be obtained from any peer.
  1487  	// Block needs to be committed with missing private data.
  1488  	err := msptesttools.LoadMSPSetupForTesting()
  1489  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
  1490  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
  1491  	serializedID, err := identity.Serialize()
  1492  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
  1493  	data := []byte{1, 2, 3}
  1494  	signature, err := identity.Sign(data)
  1495  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
  1496  	mspID := "Org1MSP"
  1497  	peerSelfSignedData := protoutil.SignedData{
  1498  		Identity:  serializedID,
  1499  		Signature: signature,
  1500  		Data:      data,
  1501  	}
  1502  
  1503  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsNone().withMSPIdentity(identity.GetMSPIdentifier())
  1504  
  1505  	var commitHappened bool
  1506  	assertCommitHappened := func() {
  1507  		assert.True(t, commitHappened)
  1508  		commitHappened = false
  1509  	}
  1510  	committer := &mocks.Committer{}
  1511  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
  1512  		blockAndPrivateData := args.Get(0).(*ledger.BlockAndPvtData)
  1513  		privateDataPassed2Ledger := blockAndPrivateData.PvtData
  1514  		assert.True(t, reflect.DeepEqual(flattenTxPvtDataMap(privateDataPassed2Ledger),
  1515  			flattenTxPvtDataMap(expectedCommittedPrivateData3)))
  1516  		missingPrivateData := blockAndPrivateData.MissingPvtData
  1517  		expectedMissingPvtData := make(ledger.TxMissingPvtDataMap)
  1518  		expectedMissingPvtData.Add(0, "ns3", "c2", false)
  1519  		assert.Equal(t, expectedMissingPvtData, missingPrivateData)
  1520  		commitHappened = true
  1521  
  1522  		commitOpts := args.Get(1).(*ledger.CommitOptions)
  1523  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
  1524  		assert.Equal(t, expectedCommitOpts, commitOpts)
  1525  	}).Return(nil)
  1526  
  1527  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
  1528  	bf := &blockFactory{
  1529  		channelID: "testchannelid",
  1530  	}
  1531  
  1532  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1533  		return mgmt.GetManagerForChain("testchannelid")
  1534  	})
  1535  
  1536  	block := bf.AddTxn("tx1", "ns3", hash, "c2").create()
  1537  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1538  
  1539  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
  1540  
  1541  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1542  	appCapability := &capabilitymock.AppCapabilities{}
  1543  	capabilityProvider.On("Capabilities").Return(appCapability)
  1544  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1545  	coordinator := NewCoordinator(mspID, Support{
  1546  		ChainID:            "testchannelid",
  1547  		CollectionStore:    cs,
  1548  		Committer:          committer,
  1549  		Fetcher:            nil,
  1550  		Validator:          &validatorMock{},
  1551  		CapabilityProvider: capabilityProvider,
  1552  	}, nil, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1553  	err = coordinator.StoreBlock(block, nil)
  1554  	assert.NoError(t, err)
  1555  	assertCommitHappened()
  1556  }
  1557  
  1558  func TestCoordinatorGetBlocks(t *testing.T) {
  1559  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
  1560  	err := msptesttools.LoadMSPSetupForTesting()
  1561  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
  1562  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
  1563  	serializedID, err := identity.Serialize()
  1564  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
  1565  	data := []byte{1, 2, 3}
  1566  	signature, err := identity.Sign(data)
  1567  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
  1568  	mspID := "Org1MSP"
  1569  	peerSelfSignedData := protoutil.SignedData{
  1570  		Identity:  serializedID,
  1571  		Signature: signature,
  1572  		Data:      data,
  1573  	}
  1574  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsAll().withMSPIdentity(identity.GetMSPIdentifier())
  1575  	committer := &mocks.Committer{}
  1576  
  1577  	store := newTransientStore(t)
  1578  	defer store.tearDown()
  1579  
  1580  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1581  		return mgmt.GetManagerForChain("testchannelid")
  1582  	})
  1583  
  1584  	fetcher := &fetcherMock{t: t}
  1585  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1586  
  1587  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1588  	appCapability := &capabilitymock.AppCapabilities{}
  1589  	capabilityProvider.On("Capabilities").Return(appCapability)
  1590  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1591  	coordinator := NewCoordinator(mspID, Support{
  1592  		ChainID:            "testchannelid",
  1593  		CollectionStore:    cs,
  1594  		Committer:          committer,
  1595  		Fetcher:            fetcher,
  1596  		Validator:          &validatorMock{},
  1597  		CapabilityProvider: capabilityProvider,
  1598  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1599  
  1600  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
  1601  	bf := &blockFactory{
  1602  		channelID: "testchannelid",
  1603  	}
  1604  	block := bf.AddTxn("tx1", "ns1", hash, "c1", "c2").AddTxn("tx2", "ns2", hash, "c1").create()
  1605  
  1606  	// Green path - block and private data is returned, but the requester isn't eligible for all the private data,
  1607  	// but only to a subset of it.
  1608  	cs = createcollectionStore(peerSelfSignedData).thatAccepts(CollectionCriteria{
  1609  		Namespace:  "ns1",
  1610  		Collection: "c2",
  1611  		Channel:    "testchannelid",
  1612  	}).withMSPIdentity(identity.GetMSPIdentifier())
  1613  	committer.Mock = mock.Mock{}
  1614  	committer.On("GetPvtDataAndBlockByNum", mock.Anything).Return(&ledger.BlockAndPvtData{
  1615  		Block:   block,
  1616  		PvtData: expectedCommittedPrivateData1,
  1617  	}, nil)
  1618  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1619  	coordinator = NewCoordinator(mspID, Support{
  1620  		ChainID:            "testchannelid",
  1621  		CollectionStore:    cs,
  1622  		Committer:          committer,
  1623  		Fetcher:            fetcher,
  1624  		Validator:          &validatorMock{},
  1625  		CapabilityProvider: capabilityProvider,
  1626  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1627  	expectedPrivData := (&pvtDataFactory{}).addRWSet().addNSRWSet("ns1", "c2").create()
  1628  	block2, returnedPrivateData, err := coordinator.GetPvtDataAndBlockByNum(1, peerSelfSignedData)
  1629  	assert.NoError(t, err)
  1630  	assert.Equal(t, block, block2)
  1631  	assert.Equal(t, expectedPrivData, []*ledger.TxPvtData(returnedPrivateData))
  1632  
  1633  	// Bad path - error occurs when trying to retrieve the block and private data
  1634  	committer.Mock = mock.Mock{}
  1635  	committer.On("GetPvtDataAndBlockByNum", mock.Anything).Return(nil, errors.New("uh oh"))
  1636  	block2, returnedPrivateData, err = coordinator.GetPvtDataAndBlockByNum(1, peerSelfSignedData)
  1637  	assert.Nil(t, block2)
  1638  	assert.Empty(t, returnedPrivateData)
  1639  	assert.Error(t, err)
  1640  }
  1641  
  1642  func TestPurgeBelowHeight(t *testing.T) {
  1643  	conf := testConfig
  1644  	conf.TransientBlockRetention = 5
  1645  	mspID := "Org1MSP"
  1646  	peerSelfSignedData := protoutil.SignedData{}
  1647  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsAll()
  1648  
  1649  	committer := &mocks.Committer{}
  1650  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Return(nil)
  1651  
  1652  	store := newTransientStore(t)
  1653  	defer store.tearDown()
  1654  
  1655  	// store 9 data sets initially
  1656  	for i := 0; i < 9; i++ {
  1657  		txID := fmt.Sprintf("tx%d", i+1)
  1658  		store.Persist(txID, uint64(i), &tspb.TxPvtReadWriteSetWithConfigInfo{
  1659  			PvtRwset: &rwset.TxPvtReadWriteSet{
  1660  				NsPvtRwset: []*rwset.NsPvtReadWriteSet{
  1661  					{
  1662  						Namespace: "ns1",
  1663  						CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
  1664  							{
  1665  								CollectionName: "c1",
  1666  								Rwset:          []byte("rws-pre-image"),
  1667  							},
  1668  						},
  1669  					},
  1670  				},
  1671  			},
  1672  			CollectionConfigs: make(map[string]*peer.CollectionConfigPackage),
  1673  		})
  1674  	}
  1675  	assertPurged := func(purged bool) {
  1676  		numTx := 9
  1677  		if purged {
  1678  			numTx = 10
  1679  		}
  1680  		for i := 1; i <= numTx; i++ {
  1681  			txID := fmt.Sprintf("tx%d", i)
  1682  			iterator, err := store.GetTxPvtRWSetByTxid(txID, nil)
  1683  			if err != nil {
  1684  				t.Fatalf("Failed iterating, got err %s", err)
  1685  				iterator.Close()
  1686  				return
  1687  			}
  1688  			res, err := iterator.Next()
  1689  			if err != nil {
  1690  				t.Fatalf("Failed iterating, got err %s", err)
  1691  				iterator.Close()
  1692  				return
  1693  			}
  1694  			if (i < 6 || i == numTx) && purged {
  1695  				assert.Nil(t, res)
  1696  			} else {
  1697  				assert.NotNil(t, res)
  1698  			}
  1699  			iterator.Close()
  1700  		}
  1701  	}
  1702  
  1703  	fetcher := &fetcherMock{t: t}
  1704  
  1705  	bf := &blockFactory{
  1706  		channelID: "testchannelid",
  1707  	}
  1708  
  1709  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1710  		return mgmt.GetManagerForChain("testchannelid")
  1711  	})
  1712  
  1713  	pdFactory := &pvtDataFactory{}
  1714  
  1715  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1716  
  1717  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
  1718  
  1719  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1720  	appCapability := &capabilitymock.AppCapabilities{}
  1721  	capabilityProvider.On("Capabilities").Return(appCapability)
  1722  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1723  	coordinator := NewCoordinator(mspID, Support{
  1724  		ChainID:            "testchannelid",
  1725  		CollectionStore:    cs,
  1726  		Committer:          committer,
  1727  		Fetcher:            fetcher,
  1728  		Validator:          &validatorMock{},
  1729  		CapabilityProvider: capabilityProvider,
  1730  	}, store.store, peerSelfSignedData, metrics, conf, idDeserializerFactory)
  1731  
  1732  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
  1733  	block := bf.AddTxn("tx10", "ns1", hash, "c1").create()
  1734  	block.Header.Number = 10
  1735  	pvtData := pdFactory.addRWSet().addNSRWSet("ns1", "c1").create()
  1736  	// test no blocks purged yet
  1737  	assertPurged(false)
  1738  	err := coordinator.StoreBlock(block, pvtData)
  1739  	assert.NoError(t, err)
  1740  	// test first 6 blocks were purged
  1741  	assertPurged(true)
  1742  }
  1743  
  1744  func TestCoordinatorStorePvtData(t *testing.T) {
  1745  	mspID := "Org1MSP"
  1746  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
  1747  	cs := createcollectionStore(protoutil.SignedData{}).thatAcceptsAll()
  1748  	committer := &mocks.Committer{}
  1749  
  1750  	store := newTransientStore(t)
  1751  	defer store.tearDown()
  1752  
  1753  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1754  		return mgmt.GetManagerForChain("testchannelid")
  1755  	})
  1756  
  1757  	fetcher := &fetcherMock{t: t}
  1758  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1759  
  1760  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1761  	appCapability := &capabilitymock.AppCapabilities{}
  1762  	capabilityProvider.On("Capabilities").Return(appCapability)
  1763  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1764  	coordinator := NewCoordinator(mspID, Support{
  1765  		ChainID:            "testchannelid",
  1766  		CollectionStore:    cs,
  1767  		Committer:          committer,
  1768  		Fetcher:            fetcher,
  1769  		Validator:          &validatorMock{},
  1770  		CapabilityProvider: capabilityProvider,
  1771  	}, store.store, protoutil.SignedData{}, metrics, testConfig, idDeserializerFactory)
  1772  	pvtData := (&pvtDataFactory{}).addRWSet().addNSRWSet("ns1", "c1").create()
  1773  	// Green path: ledger height can be retrieved from ledger/committer
  1774  	err := coordinator.StorePvtData("tx1", &tspb.TxPvtReadWriteSetWithConfigInfo{
  1775  		PvtRwset:          pvtData[0].WriteSet,
  1776  		CollectionConfigs: make(map[string]*peer.CollectionConfigPackage),
  1777  	}, uint64(5))
  1778  	assert.NoError(t, err)
  1779  }
  1780  
  1781  func TestContainsWrites(t *testing.T) {
  1782  	// Scenario I: Nil HashedRwSet in collection
  1783  	col := &rwsetutil.CollHashedRwSet{
  1784  		CollectionName: "col1",
  1785  	}
  1786  	assert.False(t, containsWrites("tx", "ns", col))
  1787  
  1788  	// Scenario II: No writes in collection
  1789  	col.HashedRwSet = &kvrwset.HashedRWSet{}
  1790  	assert.False(t, containsWrites("tx", "ns", col))
  1791  
  1792  	// Scenario III: Some writes in collection
  1793  	col.HashedRwSet.HashedWrites = append(col.HashedRwSet.HashedWrites, &kvrwset.KVWriteHash{})
  1794  	assert.True(t, containsWrites("tx", "ns", col))
  1795  }
  1796  
  1797  func TestIgnoreReadOnlyColRWSets(t *testing.T) {
  1798  	// Scenario: The transaction has some ColRWSets that have only reads and no writes,
  1799  	// These should be ignored and not considered as missing private data that needs to be retrieved
  1800  	// from the transient store or other peers.
  1801  	// The gossip and transient store mocks in this test aren't initialized with
  1802  	// actions, so if the coordinator attempts to fetch private data from the
  1803  	// transient store or other peers, the test would fail.
  1804  	// Also - we check that at commit time - the coordinator concluded that
  1805  	// no missing private data was found.
  1806  	err := msptesttools.LoadMSPSetupForTesting()
  1807  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
  1808  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
  1809  	serializedID, err := identity.Serialize()
  1810  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
  1811  	data := []byte{1, 2, 3}
  1812  	signature, err := identity.Sign(data)
  1813  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
  1814  	mspID := "Org1MSP"
  1815  	peerSelfSignedData := protoutil.SignedData{
  1816  		Identity:  serializedID,
  1817  		Signature: signature,
  1818  		Data:      data,
  1819  	}
  1820  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsAll().withMSPIdentity(identity.GetMSPIdentifier())
  1821  	var commitHappened bool
  1822  	assertCommitHappened := func() {
  1823  		assert.True(t, commitHappened)
  1824  		commitHappened = false
  1825  	}
  1826  	committer := &mocks.Committer{}
  1827  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
  1828  		blockAndPrivateData := args.Get(0).(*ledger.BlockAndPvtData)
  1829  		// Ensure there is no private data to commit
  1830  		assert.Empty(t, blockAndPrivateData.PvtData)
  1831  		// Ensure there is no missing private data
  1832  		assert.Empty(t, blockAndPrivateData.MissingPvtData)
  1833  		commitHappened = true
  1834  
  1835  		commitOpts := args.Get(1).(*ledger.CommitOptions)
  1836  		expectedCommitOpts := &ledger.CommitOptions{FetchPvtDataFromLedger: false}
  1837  		assert.Equal(t, expectedCommitOpts, commitOpts)
  1838  	}).Return(nil)
  1839  
  1840  	store := newTransientStore(t)
  1841  	defer store.tearDown()
  1842  
  1843  	fetcher := &fetcherMock{t: t}
  1844  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
  1845  	bf := &blockFactory{
  1846  		channelID: "testchannelid",
  1847  	}
  1848  
  1849  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1850  		return mgmt.GetManagerForChain("testchannelid")
  1851  	})
  1852  
  1853  	// The block contains a read only private data transaction
  1854  	block := bf.AddReadOnlyTxn("tx1", "ns3", hash, "c3", "c2").create()
  1855  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1856  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
  1857  
  1858  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1859  	appCapability := &capabilitymock.AppCapabilities{}
  1860  	capabilityProvider.On("Capabilities").Return(appCapability)
  1861  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1862  	coordinator := NewCoordinator(mspID, Support{
  1863  		ChainID:            "testchannelid",
  1864  		CollectionStore:    cs,
  1865  		Committer:          committer,
  1866  		Fetcher:            fetcher,
  1867  		Validator:          &validatorMock{},
  1868  		CapabilityProvider: capabilityProvider,
  1869  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1870  	// We pass a nil private data slice to indicate no pre-images though the block contains
  1871  	// private data reads.
  1872  	err = coordinator.StoreBlock(block, nil)
  1873  	assert.NoError(t, err)
  1874  	assertCommitHappened()
  1875  }
  1876  
  1877  func TestCoordinatorMetrics(t *testing.T) {
  1878  	err := msptesttools.LoadMSPSetupForTesting()
  1879  	require.NoError(t, err, fmt.Sprintf("Failed to setup local msp for testing, got err %s", err))
  1880  	identity := mspmgmt.GetLocalSigningIdentityOrPanic(factory.GetDefault())
  1881  	serializedID, err := identity.Serialize()
  1882  	require.NoError(t, err, fmt.Sprintf("Serialize should have succeeded, got err %s", err))
  1883  	data := []byte{1, 2, 3}
  1884  	signature, err := identity.Sign(data)
  1885  	require.NoError(t, err, fmt.Sprintf("Could not sign identity, got err %s", err))
  1886  	mspID := "Org1MSP"
  1887  	peerSelfSignedData := protoutil.SignedData{
  1888  		Identity:  serializedID,
  1889  		Signature: signature,
  1890  		Data:      data,
  1891  	}
  1892  
  1893  	cs := createcollectionStore(peerSelfSignedData).thatAcceptsAll().withMSPIdentity(identity.GetMSPIdentifier())
  1894  
  1895  	committer := &mocks.Committer{}
  1896  	committer.On("CommitLegacy", mock.Anything, mock.Anything).Return(nil)
  1897  
  1898  	store := newTransientStore(t)
  1899  	defer store.tearDown()
  1900  
  1901  	hash := util2.ComputeSHA256([]byte("rws-pre-image"))
  1902  	pdFactory := &pvtDataFactory{}
  1903  	bf := &blockFactory{
  1904  		channelID: "testchannelid",
  1905  	}
  1906  
  1907  	idDeserializerFactory := IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer {
  1908  		return mgmt.GetManagerForChain("testchannelid")
  1909  	})
  1910  
  1911  	block := bf.AddTxnWithEndorsement("tx1", "ns1", hash, "org1", true, "c1", "c2").
  1912  		AddTxnWithEndorsement("tx2", "ns2", hash, "org2", true, "c1").
  1913  		AddTxnWithEndorsement("tx3", "ns3", hash, "org3", true, "c1").create()
  1914  
  1915  	pvtData := pdFactory.addRWSet().addNSRWSet("ns1", "c1", "c2").addRWSet().addNSRWSet("ns2", "c1").create()
  1916  	// fetch duration metric only reported when fetching from remote peer
  1917  	fetcher := &fetcherMock{t: t}
  1918  	fetcher.On("fetch", mock.Anything).expectingDigests([]privdatacommon.DigKey{
  1919  		{
  1920  			TxId: "tx3", Namespace: "ns3", Collection: "c1", BlockSeq: 1, SeqInBlock: 2,
  1921  		},
  1922  	}).Return(&privdatacommon.FetchedPvtDataContainer{
  1923  		AvailableElements: []*proto.PvtDataElement{
  1924  			{
  1925  				Digest: &proto.PvtDataDigest{
  1926  					SeqInBlock: 2,
  1927  					BlockSeq:   1,
  1928  					Collection: "c1",
  1929  					Namespace:  "ns3",
  1930  					TxId:       "tx3",
  1931  				},
  1932  				Payload: [][]byte{[]byte("rws-pre-image")},
  1933  			},
  1934  		},
  1935  	}, nil)
  1936  
  1937  	testMetricProvider := gmetricsmocks.TestUtilConstructMetricProvider()
  1938  	metrics := metrics.NewGossipMetrics(testMetricProvider.FakeProvider).PrivdataMetrics
  1939  
  1940  	committer.On("DoesPvtDataInfoExistInLedger", mock.Anything).Return(false, nil)
  1941  
  1942  	capabilityProvider := &capabilitymock.CapabilityProvider{}
  1943  	appCapability := &capabilitymock.AppCapabilities{}
  1944  	capabilityProvider.On("Capabilities").Return(appCapability)
  1945  	appCapability.On("StorePvtDataOfInvalidTx").Return(true)
  1946  	coordinator := NewCoordinator(mspID, Support{
  1947  		ChainID:            "testchannelid",
  1948  		CollectionStore:    cs,
  1949  		Committer:          committer,
  1950  		Fetcher:            fetcher,
  1951  		Validator:          &validatorMock{},
  1952  		CapabilityProvider: capabilityProvider,
  1953  	}, store.store, peerSelfSignedData, metrics, testConfig, idDeserializerFactory)
  1954  	err = coordinator.StoreBlock(block, pvtData)
  1955  	assert.NoError(t, err)
  1956  
  1957  	// make sure all coordinator metrics were reported
  1958  
  1959  	assert.Equal(t,
  1960  		[]string{"channel", "testchannelid"},
  1961  		testMetricProvider.FakeValidationDuration.WithArgsForCall(0),
  1962  	)
  1963  	assert.True(t, testMetricProvider.FakeValidationDuration.ObserveArgsForCall(0) > 0)
  1964  	assert.Equal(t,
  1965  		[]string{"channel", "testchannelid"},
  1966  		testMetricProvider.FakeListMissingPrivateDataDuration.WithArgsForCall(0),
  1967  	)
  1968  	assert.True(t, testMetricProvider.FakeListMissingPrivateDataDuration.ObserveArgsForCall(0) > 0)
  1969  	assert.Equal(t,
  1970  		[]string{"channel", "testchannelid"},
  1971  		testMetricProvider.FakeFetchDuration.WithArgsForCall(0),
  1972  	)
  1973  	// fetch duration metric only reported when fetching from remote peer
  1974  	assert.True(t, testMetricProvider.FakeFetchDuration.ObserveArgsForCall(0) > 0)
  1975  	assert.Equal(t,
  1976  		[]string{"channel", "testchannelid"},
  1977  		testMetricProvider.FakeCommitPrivateDataDuration.WithArgsForCall(0),
  1978  	)
  1979  	assert.True(t, testMetricProvider.FakeCommitPrivateDataDuration.ObserveArgsForCall(0) > 0)
  1980  	assert.Equal(t,
  1981  		[]string{"channel", "testchannelid"},
  1982  		testMetricProvider.FakePurgeDuration.WithArgsForCall(0),
  1983  	)
  1984  	assert.True(t, testMetricProvider.FakePurgeDuration.ObserveArgsForCall(0) > 0)
  1985  }