github.com/yimialmonte/fabric@v2.1.1+incompatible/gossip/privdata/reconcile_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  	"errors"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  
    15  	gossip2 "github.com/hyperledger/fabric-protos-go/gossip"
    16  	"github.com/hyperledger/fabric-protos-go/peer"
    17  	"github.com/hyperledger/fabric/common/metrics/disabled"
    18  	util2 "github.com/hyperledger/fabric/common/util"
    19  	"github.com/hyperledger/fabric/core/ledger"
    20  	"github.com/hyperledger/fabric/gossip/metrics"
    21  	gmetricsmocks "github.com/hyperledger/fabric/gossip/metrics/mocks"
    22  	privdatacommon "github.com/hyperledger/fabric/gossip/privdata/common"
    23  	"github.com/hyperledger/fabric/gossip/privdata/mocks"
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/mock"
    26  )
    27  
    28  func TestNoItemsToReconcile(t *testing.T) {
    29  	// Scenario: there is no missing private data to reconcile.
    30  	// reconciler should identify that we don't have missing data and it doesn't need to call reconciliationFetcher to
    31  	// fetch missing items.
    32  	// reconciler shouldn't get an error.
    33  	committer := &mocks.Committer{}
    34  	fetcher := &mocks.ReconciliationFetcher{}
    35  	missingPvtDataTracker := &mocks.MissingPvtDataTracker{}
    36  	var missingInfo ledger.MissingPvtDataInfo
    37  	missingInfo = make(map[uint64]ledger.MissingBlockPvtdataInfo)
    38  
    39  	missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil)
    40  	committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil)
    41  	fetcher.On("FetchReconciledItems", mock.Anything).Return(nil, errors.New("this function shouldn't be called"))
    42  
    43  	r := &Reconciler{
    44  		channel:                "",
    45  		metrics:                metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics,
    46  		ReconcileSleepInterval: time.Minute,
    47  		ReconcileBatchSize:     1,
    48  		ReconciliationFetcher:  fetcher, Committer: committer,
    49  	}
    50  	err := r.reconcile()
    51  
    52  	assert.NoError(t, err)
    53  }
    54  
    55  func TestNotReconcilingWhenCollectionConfigNotAvailable(t *testing.T) {
    56  	// Scenario: reconciler gets an error when trying to read collection config for the missing private data.
    57  	// as a result it removes the digest slice, and there are no digests to pull.
    58  	// shouldn't get an error.
    59  	committer := &mocks.Committer{}
    60  	fetcher := &mocks.ReconciliationFetcher{}
    61  	configHistoryRetriever := &mocks.ConfigHistoryRetriever{}
    62  	missingPvtDataTracker := &mocks.MissingPvtDataTracker{}
    63  	var missingInfo ledger.MissingPvtDataInfo
    64  
    65  	missingInfo = map[uint64]ledger.MissingBlockPvtdataInfo{
    66  		1: map[uint64][]*ledger.MissingCollectionPvtDataInfo{
    67  			1: {{Collection: "col1", Namespace: "chain1"}},
    68  		},
    69  	}
    70  
    71  	var collectionConfigInfo ledger.CollectionConfigInfo
    72  
    73  	missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil)
    74  	configHistoryRetriever.On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).Return(&collectionConfigInfo, errors.New("fail to get collection config"))
    75  	committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil)
    76  	committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil)
    77  
    78  	var fetchCalled bool
    79  	fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) {
    80  		var dig2CollectionConfig = args.Get(0).(privdatacommon.Dig2CollectionConfig)
    81  		assert.Equal(t, 0, len(dig2CollectionConfig))
    82  		fetchCalled = true
    83  	}).Return(nil, errors.New("called with no digests"))
    84  
    85  	r := &Reconciler{
    86  		channel:                "",
    87  		metrics:                metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics,
    88  		ReconcileSleepInterval: time.Minute,
    89  		ReconcileBatchSize:     1,
    90  		ReconciliationFetcher:  fetcher, Committer: committer,
    91  	}
    92  	err := r.reconcile()
    93  
    94  	assert.Error(t, err)
    95  	assert.Equal(t, "called with no digests", err.Error())
    96  	assert.True(t, fetchCalled)
    97  }
    98  
    99  func TestReconciliationHappyPathWithoutScheduler(t *testing.T) {
   100  	// Scenario: happy path when trying to reconcile missing private data.
   101  	committer := &mocks.Committer{}
   102  	fetcher := &mocks.ReconciliationFetcher{}
   103  	configHistoryRetriever := &mocks.ConfigHistoryRetriever{}
   104  	missingPvtDataTracker := &mocks.MissingPvtDataTracker{}
   105  	var missingInfo ledger.MissingPvtDataInfo
   106  
   107  	missingInfo = map[uint64]ledger.MissingBlockPvtdataInfo{
   108  		3: map[uint64][]*ledger.MissingCollectionPvtDataInfo{
   109  			1: {{Collection: "col1", Namespace: "ns1"}},
   110  		},
   111  	}
   112  
   113  	collectionConfigInfo := ledger.CollectionConfigInfo{
   114  		CollectionConfig: &peer.CollectionConfigPackage{
   115  			Config: []*peer.CollectionConfig{
   116  				{Payload: &peer.CollectionConfig_StaticCollectionConfig{
   117  					StaticCollectionConfig: &peer.StaticCollectionConfig{
   118  						Name: "col1",
   119  					},
   120  				}},
   121  			},
   122  		},
   123  		CommittingBlockNum: 1,
   124  	}
   125  
   126  	missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil).Run(func(_ mock.Arguments) {
   127  		missingPvtDataTracker.Mock = mock.Mock{}
   128  		missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(nil, nil)
   129  	})
   130  	configHistoryRetriever.On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).Return(&collectionConfigInfo, nil)
   131  	committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil)
   132  	committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil)
   133  
   134  	result := &privdatacommon.FetchedPvtDataContainer{}
   135  	fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) {
   136  		var dig2CollectionConfig = args.Get(0).(privdatacommon.Dig2CollectionConfig)
   137  		assert.Equal(t, 1, len(dig2CollectionConfig))
   138  		for digest := range dig2CollectionConfig {
   139  			hash := util2.ComputeSHA256([]byte("rws-pre-image"))
   140  			element := &gossip2.PvtDataElement{
   141  				Digest: &gossip2.PvtDataDigest{
   142  					TxId:       digest.TxId,
   143  					BlockSeq:   digest.BlockSeq,
   144  					Collection: digest.Collection,
   145  					Namespace:  digest.Namespace,
   146  					SeqInBlock: digest.SeqInBlock,
   147  				},
   148  				Payload: [][]byte{hash},
   149  			}
   150  			result.AvailableElements = append(result.AvailableElements, element)
   151  		}
   152  	}).Return(result, nil)
   153  
   154  	var commitPvtDataOfOldBlocksHappened bool
   155  	var blockNum, seqInBlock uint64
   156  	blockNum = 3
   157  	seqInBlock = 1
   158  	committer.On("CommitPvtDataOfOldBlocks", mock.Anything).Run(func(args mock.Arguments) {
   159  		var reconciledPvtdata = args.Get(0).([]*ledger.ReconciledPvtdata)
   160  		assert.Equal(t, 1, len(reconciledPvtdata))
   161  		assert.Equal(t, blockNum, reconciledPvtdata[0].BlockNum)
   162  		assert.Equal(t, seqInBlock, reconciledPvtdata[0].WriteSets[1].SeqInBlock)
   163  		assert.Equal(t, "ns1", reconciledPvtdata[0].WriteSets[1].WriteSet.NsPvtRwset[0].Namespace)
   164  		assert.Equal(t, "col1", reconciledPvtdata[0].WriteSets[1].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].CollectionName)
   165  		commitPvtDataOfOldBlocksHappened = true
   166  	}).Return([]*ledger.PvtdataHashMismatch{}, nil)
   167  
   168  	testMetricProvider := gmetricsmocks.TestUtilConstructMetricProvider()
   169  	metrics := metrics.NewGossipMetrics(testMetricProvider.FakeProvider).PrivdataMetrics
   170  
   171  	r := &Reconciler{
   172  		channel:                "mychannel",
   173  		metrics:                metrics,
   174  		ReconcileSleepInterval: time.Minute,
   175  		ReconcileBatchSize:     1,
   176  		ReconciliationFetcher:  fetcher, Committer: committer,
   177  	}
   178  	err := r.reconcile()
   179  
   180  	assert.NoError(t, err)
   181  	assert.True(t, commitPvtDataOfOldBlocksHappened)
   182  
   183  	assert.Equal(t,
   184  		[]string{"channel", "mychannel"},
   185  		testMetricProvider.FakeReconciliationDuration.WithArgsForCall(0),
   186  	)
   187  }
   188  
   189  func TestReconciliationHappyPathWithScheduler(t *testing.T) {
   190  	// Scenario: happy path when trying to reconcile missing private data.
   191  	committer := &mocks.Committer{}
   192  	fetcher := &mocks.ReconciliationFetcher{}
   193  	configHistoryRetriever := &mocks.ConfigHistoryRetriever{}
   194  	missingPvtDataTracker := &mocks.MissingPvtDataTracker{}
   195  	var missingInfo ledger.MissingPvtDataInfo
   196  
   197  	missingInfo = map[uint64]ledger.MissingBlockPvtdataInfo{
   198  		3: map[uint64][]*ledger.MissingCollectionPvtDataInfo{
   199  			1: {{Collection: "col1", Namespace: "ns1"}},
   200  		},
   201  	}
   202  
   203  	collectionConfigInfo := ledger.CollectionConfigInfo{
   204  		CollectionConfig: &peer.CollectionConfigPackage{
   205  			Config: []*peer.CollectionConfig{
   206  				{Payload: &peer.CollectionConfig_StaticCollectionConfig{
   207  					StaticCollectionConfig: &peer.StaticCollectionConfig{
   208  						Name: "col1",
   209  					},
   210  				}},
   211  			},
   212  		},
   213  		CommittingBlockNum: 1,
   214  	}
   215  
   216  	missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil).Run(func(_ mock.Arguments) {
   217  		missingPvtDataTracker.Mock = mock.Mock{}
   218  		missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(nil, nil)
   219  	})
   220  	configHistoryRetriever.On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).Return(&collectionConfigInfo, nil)
   221  	committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil)
   222  	committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil)
   223  
   224  	result := &privdatacommon.FetchedPvtDataContainer{}
   225  	fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) {
   226  		var dig2CollectionConfig = args.Get(0).(privdatacommon.Dig2CollectionConfig)
   227  		assert.Equal(t, 1, len(dig2CollectionConfig))
   228  		for digest := range dig2CollectionConfig {
   229  			hash := util2.ComputeSHA256([]byte("rws-pre-image"))
   230  			element := &gossip2.PvtDataElement{
   231  				Digest: &gossip2.PvtDataDigest{
   232  					TxId:       digest.TxId,
   233  					BlockSeq:   digest.BlockSeq,
   234  					Collection: digest.Collection,
   235  					Namespace:  digest.Namespace,
   236  					SeqInBlock: digest.SeqInBlock,
   237  				},
   238  				Payload: [][]byte{hash},
   239  			}
   240  			result.AvailableElements = append(result.AvailableElements, element)
   241  		}
   242  	}).Return(result, nil)
   243  
   244  	var wg sync.WaitGroup
   245  	wg.Add(1)
   246  
   247  	var commitPvtDataOfOldBlocksHappened bool
   248  	var blockNum, seqInBlock uint64
   249  	blockNum = 3
   250  	seqInBlock = 1
   251  	committer.On("CommitPvtDataOfOldBlocks", mock.Anything).Run(func(args mock.Arguments) {
   252  		var reconciledPvtdata = args.Get(0).([]*ledger.ReconciledPvtdata)
   253  		assert.Equal(t, 1, len(reconciledPvtdata))
   254  		assert.Equal(t, blockNum, reconciledPvtdata[0].BlockNum)
   255  		assert.Equal(t, seqInBlock, reconciledPvtdata[0].WriteSets[1].SeqInBlock)
   256  		assert.Equal(t, "ns1", reconciledPvtdata[0].WriteSets[1].WriteSet.NsPvtRwset[0].Namespace)
   257  		assert.Equal(t, "col1", reconciledPvtdata[0].WriteSets[1].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].CollectionName)
   258  		commitPvtDataOfOldBlocksHappened = true
   259  		wg.Done()
   260  	}).Return([]*ledger.PvtdataHashMismatch{}, nil)
   261  
   262  	r := NewReconciler(
   263  		"",
   264  		metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics,
   265  		committer,
   266  		fetcher,
   267  		&PrivdataConfig{
   268  			ReconcileSleepInterval: time.Millisecond * 100,
   269  			ReconcileBatchSize:     1,
   270  			ReconciliationEnabled:  true,
   271  		})
   272  	r.Start()
   273  	wg.Wait()
   274  	r.Stop()
   275  
   276  	assert.True(t, commitPvtDataOfOldBlocksHappened)
   277  }
   278  
   279  func TestReconciliationPullingMissingPrivateDataAtOnePass(t *testing.T) {
   280  	// Scenario: define batch size to retrieve missing private data to 1
   281  	// and make sure that even though there are missing data for two blocks
   282  	// they will be reconciled with one shot.
   283  	committer := &mocks.Committer{}
   284  	fetcher := &mocks.ReconciliationFetcher{}
   285  	configHistoryRetriever := &mocks.ConfigHistoryRetriever{}
   286  	missingPvtDataTracker := &mocks.MissingPvtDataTracker{}
   287  
   288  	missingInfo := ledger.MissingPvtDataInfo{
   289  		4: ledger.MissingBlockPvtdataInfo{
   290  			1: {{Collection: "col1", Namespace: "ns1"}},
   291  		},
   292  	}
   293  
   294  	collectionConfigInfo := &ledger.CollectionConfigInfo{
   295  		CollectionConfig: &peer.CollectionConfigPackage{
   296  			Config: []*peer.CollectionConfig{
   297  				{Payload: &peer.CollectionConfig_StaticCollectionConfig{
   298  					StaticCollectionConfig: &peer.StaticCollectionConfig{
   299  						Name: "col1",
   300  					},
   301  				}},
   302  				{Payload: &peer.CollectionConfig_StaticCollectionConfig{
   303  					StaticCollectionConfig: &peer.StaticCollectionConfig{
   304  						Name: "col2",
   305  					},
   306  				}},
   307  			},
   308  		},
   309  		CommittingBlockNum: 1,
   310  	}
   311  
   312  	stopC := make(chan struct{})
   313  	nextC := make(chan struct{})
   314  
   315  	missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).
   316  		Return(missingInfo, nil).Run(func(_ mock.Arguments) {
   317  		missingInfo := ledger.MissingPvtDataInfo{
   318  			3: ledger.MissingBlockPvtdataInfo{
   319  				2: {{Collection: "col2", Namespace: "ns2"}},
   320  			},
   321  		}
   322  		missingPvtDataTracker.Mock = mock.Mock{}
   323  		missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).
   324  			Return(missingInfo, nil).Run(func(_ mock.Arguments) {
   325  			// here we are making sure that we will first stop
   326  			// reconciliation so next call to GetMissingPvtDataInfoForMostRecentBlocks
   327  			// will go into same round
   328  			<-nextC
   329  			missingPvtDataTracker.Mock = mock.Mock{}
   330  			missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).
   331  				Return(nil, nil)
   332  		})
   333  		// make sure we calling stop reconciliation loop, so for sure
   334  		// in this test we won't get to second round though making sure
   335  		// we are retrieving on single pass
   336  		stopC <- struct{}{}
   337  	})
   338  
   339  	configHistoryRetriever.
   340  		On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).
   341  		Return(collectionConfigInfo, nil)
   342  
   343  	committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil)
   344  	committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil)
   345  
   346  	result := &privdatacommon.FetchedPvtDataContainer{}
   347  	fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) {
   348  		result.AvailableElements = make([]*gossip2.PvtDataElement, 0)
   349  		var dig2CollectionConfig = args.Get(0).(privdatacommon.Dig2CollectionConfig)
   350  		assert.Equal(t, 1, len(dig2CollectionConfig))
   351  		for digest := range dig2CollectionConfig {
   352  			hash := util2.ComputeSHA256([]byte("rws-pre-image"))
   353  			element := &gossip2.PvtDataElement{
   354  				Digest: &gossip2.PvtDataDigest{
   355  					TxId:       digest.TxId,
   356  					BlockSeq:   digest.BlockSeq,
   357  					Collection: digest.Collection,
   358  					Namespace:  digest.Namespace,
   359  					SeqInBlock: digest.SeqInBlock,
   360  				},
   361  				Payload: [][]byte{hash},
   362  			}
   363  			result.AvailableElements = append(result.AvailableElements, element)
   364  		}
   365  	}).Return(result, nil)
   366  
   367  	var wg sync.WaitGroup
   368  	wg.Add(2)
   369  
   370  	var commitPvtDataOfOldBlocksHappened bool
   371  	pvtDataStore := make([][]*ledger.ReconciledPvtdata, 0)
   372  	committer.On("CommitPvtDataOfOldBlocks", mock.Anything).Run(func(args mock.Arguments) {
   373  		var reconciledPvtdata = args.Get(0).([]*ledger.ReconciledPvtdata)
   374  		assert.Equal(t, 1, len(reconciledPvtdata))
   375  		pvtDataStore = append(pvtDataStore, reconciledPvtdata)
   376  		commitPvtDataOfOldBlocksHappened = true
   377  		wg.Done()
   378  	}).Return([]*ledger.PvtdataHashMismatch{}, nil)
   379  
   380  	r := NewReconciler(
   381  		"",
   382  		metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics,
   383  		committer,
   384  		fetcher,
   385  		&PrivdataConfig{
   386  			ReconcileSleepInterval: time.Millisecond * 100,
   387  			ReconcileBatchSize:     1,
   388  			ReconciliationEnabled:  true,
   389  		})
   390  	r.Start()
   391  	<-stopC
   392  	r.Stop()
   393  	nextC <- struct{}{}
   394  	wg.Wait()
   395  
   396  	assert.Equal(t, 2, len(pvtDataStore))
   397  	assert.Equal(t, uint64(4), pvtDataStore[0][0].BlockNum)
   398  	assert.Equal(t, uint64(3), pvtDataStore[1][0].BlockNum)
   399  
   400  	assert.Equal(t, uint64(1), pvtDataStore[0][0].WriteSets[1].SeqInBlock)
   401  	assert.Equal(t, uint64(2), pvtDataStore[1][0].WriteSets[2].SeqInBlock)
   402  
   403  	assert.Equal(t, "ns1", pvtDataStore[0][0].WriteSets[1].WriteSet.NsPvtRwset[0].Namespace)
   404  	assert.Equal(t, "ns2", pvtDataStore[1][0].WriteSets[2].WriteSet.NsPvtRwset[0].Namespace)
   405  
   406  	assert.Equal(t, "col1", pvtDataStore[0][0].WriteSets[1].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].CollectionName)
   407  	assert.Equal(t, "col2", pvtDataStore[1][0].WriteSets[2].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].CollectionName)
   408  
   409  	assert.True(t, commitPvtDataOfOldBlocksHappened)
   410  }
   411  
   412  func TestReconciliationFailedToCommit(t *testing.T) {
   413  	committer := &mocks.Committer{}
   414  	fetcher := &mocks.ReconciliationFetcher{}
   415  	configHistoryRetriever := &mocks.ConfigHistoryRetriever{}
   416  	missingPvtDataTracker := &mocks.MissingPvtDataTracker{}
   417  	var missingInfo ledger.MissingPvtDataInfo
   418  
   419  	missingInfo = map[uint64]ledger.MissingBlockPvtdataInfo{
   420  		3: map[uint64][]*ledger.MissingCollectionPvtDataInfo{
   421  			1: {{Collection: "col1", Namespace: "ns1"}},
   422  		},
   423  	}
   424  
   425  	collectionConfigInfo := ledger.CollectionConfigInfo{
   426  		CollectionConfig: &peer.CollectionConfigPackage{
   427  			Config: []*peer.CollectionConfig{
   428  				{Payload: &peer.CollectionConfig_StaticCollectionConfig{
   429  					StaticCollectionConfig: &peer.StaticCollectionConfig{
   430  						Name: "col1",
   431  					},
   432  				}},
   433  			},
   434  		},
   435  		CommittingBlockNum: 1,
   436  	}
   437  
   438  	missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil).Run(func(_ mock.Arguments) {
   439  		missingPvtDataTracker.Mock = mock.Mock{}
   440  		missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(nil, nil)
   441  	})
   442  	configHistoryRetriever.On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).Return(&collectionConfigInfo, nil)
   443  	committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil)
   444  	committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil)
   445  
   446  	result := &privdatacommon.FetchedPvtDataContainer{}
   447  	fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) {
   448  		var dig2CollectionConfig = args.Get(0).(privdatacommon.Dig2CollectionConfig)
   449  		assert.Equal(t, 1, len(dig2CollectionConfig))
   450  		for digest := range dig2CollectionConfig {
   451  			hash := util2.ComputeSHA256([]byte("rws-pre-image"))
   452  			element := &gossip2.PvtDataElement{
   453  				Digest: &gossip2.PvtDataDigest{
   454  					TxId:       digest.TxId,
   455  					BlockSeq:   digest.BlockSeq,
   456  					Collection: digest.Collection,
   457  					Namespace:  digest.Namespace,
   458  					SeqInBlock: digest.SeqInBlock,
   459  				},
   460  				Payload: [][]byte{hash},
   461  			}
   462  			result.AvailableElements = append(result.AvailableElements, element)
   463  		}
   464  	}).Return(result, nil)
   465  
   466  	committer.On("CommitPvtDataOfOldBlocks", mock.Anything).Return(nil, errors.New("failed to commit"))
   467  
   468  	r := &Reconciler{
   469  		channel:                "",
   470  		metrics:                metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics,
   471  		ReconcileSleepInterval: time.Minute,
   472  		ReconcileBatchSize:     1,
   473  		ReconciliationFetcher:  fetcher, Committer: committer,
   474  	}
   475  	err := r.reconcile()
   476  
   477  	assert.Error(t, err)
   478  	assert.Contains(t, err.Error(), "failed to commit")
   479  }
   480  
   481  func TestFailuresWhileReconcilingMissingPvtData(t *testing.T) {
   482  	metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics
   483  	committer := &mocks.Committer{}
   484  	fetcher := &mocks.ReconciliationFetcher{}
   485  	committer.On("GetMissingPvtDataTracker").Return(nil, errors.New("failed to obtain missing pvt data tracker"))
   486  
   487  	r := NewReconciler(
   488  		"",
   489  		metrics,
   490  		committer,
   491  		fetcher,
   492  		&PrivdataConfig{
   493  			ReconcileSleepInterval: time.Millisecond * 100,
   494  			ReconcileBatchSize:     1,
   495  			ReconciliationEnabled:  true,
   496  		})
   497  	err := r.reconcile()
   498  	assert.Error(t, err)
   499  	assert.Contains(t, "failed to obtain missing pvt data tracker", err.Error())
   500  
   501  	committer.Mock = mock.Mock{}
   502  	committer.On("GetMissingPvtDataTracker").Return(nil, nil)
   503  	r = NewReconciler("", metrics, committer, fetcher,
   504  		&PrivdataConfig{ReconcileSleepInterval: time.Millisecond * 100, ReconcileBatchSize: 1, ReconciliationEnabled: true})
   505  	err = r.reconcile()
   506  	assert.Error(t, err)
   507  	assert.Contains(t, "got nil as MissingPvtDataTracker, exiting...", err.Error())
   508  
   509  	missingPvtDataTracker := &mocks.MissingPvtDataTracker{}
   510  	missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(nil, errors.New("failed get missing pvt data for recent blocks"))
   511  
   512  	committer.Mock = mock.Mock{}
   513  	committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil)
   514  	r = NewReconciler("", metrics, committer, fetcher,
   515  		&PrivdataConfig{ReconcileSleepInterval: time.Millisecond * 100, ReconcileBatchSize: 1, ReconciliationEnabled: true})
   516  	err = r.reconcile()
   517  	assert.Error(t, err)
   518  	assert.Contains(t, "failed get missing pvt data for recent blocks", err.Error())
   519  }