github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/gossip/privdata/reconcile_test.go (about) 1 /* 2 Copyright hechain. 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 "github.com/hechain20/hechain/common/metrics/disabled" 16 util2 "github.com/hechain20/hechain/common/util" 17 "github.com/hechain20/hechain/core/ledger" 18 "github.com/hechain20/hechain/gossip/metrics" 19 gmetricsmocks "github.com/hechain20/hechain/gossip/metrics/mocks" 20 privdatacommon "github.com/hechain20/hechain/gossip/privdata/common" 21 "github.com/hechain20/hechain/gossip/privdata/mocks" 22 gossip2 "github.com/hyperledger/fabric-protos-go/gossip" 23 "github.com/hyperledger/fabric-protos-go/peer" 24 "github.com/stretchr/testify/mock" 25 "github.com/stretchr/testify/require" 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 missingInfo := ledger.MissingPvtDataInfo{} 37 38 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil) 39 committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil) 40 fetcher.On("FetchReconciledItems", mock.Anything).Return(nil, errors.New("this function shouldn't be called")) 41 42 r := &Reconciler{ 43 channel: "mychannel", 44 logger: logger.With("channel", "mychannel"), 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 require.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 64 missingInfo := ledger.MissingPvtDataInfo{ 65 1: map[uint64][]*ledger.MissingCollectionPvtDataInfo{ 66 1: {{Collection: "col1", Namespace: "chain1"}}, 67 }, 68 } 69 70 var collectionConfigInfo ledger.CollectionConfigInfo 71 72 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil) 73 configHistoryRetriever.On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).Return(&collectionConfigInfo, errors.New("fail to get collection config")) 74 committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil) 75 committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil) 76 77 var fetchCalled bool 78 fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) { 79 dig2CollectionConfig := args.Get(0).(privdatacommon.Dig2CollectionConfig) 80 require.Equal(t, 0, len(dig2CollectionConfig)) 81 fetchCalled = true 82 }).Return(nil, errors.New("called with no digests")) 83 84 r := &Reconciler{ 85 channel: "mychannel", 86 logger: logger.With("channel", "mychannel"), 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 require.Error(t, err) 95 require.Equal(t, "called with no digests", err.Error()) 96 require.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 106 missingInfo := ledger.MissingPvtDataInfo{ 107 3: map[uint64][]*ledger.MissingCollectionPvtDataInfo{ 108 1: {{Collection: "col1", Namespace: "ns1"}}, 109 }, 110 4: map[uint64][]*ledger.MissingCollectionPvtDataInfo{ 111 4: {{Collection: "col1", Namespace: "ns1"}}, 112 5: {{Collection: "col1", Namespace: "ns1"}}, 113 }, 114 } 115 116 collectionConfigInfo := ledger.CollectionConfigInfo{ 117 CollectionConfig: &peer.CollectionConfigPackage{ 118 Config: []*peer.CollectionConfig{ 119 {Payload: &peer.CollectionConfig_StaticCollectionConfig{ 120 StaticCollectionConfig: &peer.StaticCollectionConfig{ 121 Name: "col1", 122 }, 123 }}, 124 }, 125 }, 126 CommittingBlockNum: 1, 127 } 128 129 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil).Run(func(_ mock.Arguments) { 130 missingPvtDataTracker.Mock = mock.Mock{} 131 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(nil, nil) 132 }) 133 configHistoryRetriever.On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).Return(&collectionConfigInfo, nil) 134 committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil) 135 committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil) 136 137 result := &privdatacommon.FetchedPvtDataContainer{} 138 fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) { 139 dig2CollectionConfig := args.Get(0).(privdatacommon.Dig2CollectionConfig) 140 require.Equal(t, 3, len(dig2CollectionConfig)) 141 for digest := range dig2CollectionConfig { 142 if digest.BlockSeq != 3 { 143 // fetch private data only for block 3. Assume that the other 144 // block's private data could not be fetched 145 continue 146 } 147 hash := util2.ComputeSHA256([]byte("rws-pre-image")) 148 element := &gossip2.PvtDataElement{ 149 Digest: &gossip2.PvtDataDigest{ 150 TxId: digest.TxId, 151 BlockSeq: digest.BlockSeq, 152 Collection: digest.Collection, 153 Namespace: digest.Namespace, 154 SeqInBlock: digest.SeqInBlock, 155 }, 156 Payload: [][]byte{hash}, 157 } 158 result.AvailableElements = append(result.AvailableElements, element) 159 } 160 }).Return(result, nil) 161 162 expectedUnreconciledMissingData := ledger.MissingPvtDataInfo{ 163 4: map[uint64][]*ledger.MissingCollectionPvtDataInfo{ 164 4: {{Collection: "col1", Namespace: "ns1"}}, 165 5: {{Collection: "col1", Namespace: "ns1"}}, 166 }, 167 } 168 169 var commitPvtDataOfOldBlocksHappened bool 170 var blockNum, seqInBlock uint64 171 blockNum = 3 172 seqInBlock = 1 173 committer.On("CommitPvtDataOfOldBlocks", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { 174 require.Len(t, args, 2) 175 reconciledPvtdata := args.Get(0).([]*ledger.ReconciledPvtdata) 176 require.Equal(t, 1, len(reconciledPvtdata)) 177 require.Equal(t, blockNum, reconciledPvtdata[0].BlockNum) 178 require.Equal(t, seqInBlock, reconciledPvtdata[0].WriteSets[1].SeqInBlock) 179 require.Equal(t, "ns1", reconciledPvtdata[0].WriteSets[1].WriteSet.NsPvtRwset[0].Namespace) 180 require.Equal(t, "col1", reconciledPvtdata[0].WriteSets[1].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].CollectionName) 181 commitPvtDataOfOldBlocksHappened = true 182 183 unreconciledPvtdata := args.Get(1).(ledger.MissingPvtDataInfo) 184 require.Equal(t, expectedUnreconciledMissingData, unreconciledPvtdata) 185 }).Return([]*ledger.PvtdataHashMismatch{}, nil) 186 187 testMetricProvider := gmetricsmocks.TestUtilConstructMetricProvider() 188 metrics := metrics.NewGossipMetrics(testMetricProvider.FakeProvider).PrivdataMetrics 189 190 r := &Reconciler{ 191 channel: "mychannel", 192 logger: logger.With("channel", "mychannel"), 193 metrics: metrics, 194 ReconcileSleepInterval: time.Minute, 195 ReconcileBatchSize: 1, 196 ReconciliationFetcher: fetcher, Committer: committer, 197 } 198 err := r.reconcile() 199 200 require.NoError(t, err) 201 require.True(t, commitPvtDataOfOldBlocksHappened) 202 203 require.Equal(t, 204 []string{"channel", "mychannel"}, 205 testMetricProvider.FakeReconciliationDuration.WithArgsForCall(0), 206 ) 207 } 208 209 func TestReconciliationHappyPathWithScheduler(t *testing.T) { 210 // Scenario: happy path when trying to reconcile missing private data. 211 committer := &mocks.Committer{} 212 fetcher := &mocks.ReconciliationFetcher{} 213 configHistoryRetriever := &mocks.ConfigHistoryRetriever{} 214 missingPvtDataTracker := &mocks.MissingPvtDataTracker{} 215 216 missingInfo := ledger.MissingPvtDataInfo{ 217 3: map[uint64][]*ledger.MissingCollectionPvtDataInfo{ 218 1: {{Collection: "col1", Namespace: "ns1"}}, 219 }, 220 } 221 222 collectionConfigInfo := ledger.CollectionConfigInfo{ 223 CollectionConfig: &peer.CollectionConfigPackage{ 224 Config: []*peer.CollectionConfig{ 225 {Payload: &peer.CollectionConfig_StaticCollectionConfig{ 226 StaticCollectionConfig: &peer.StaticCollectionConfig{ 227 Name: "col1", 228 }, 229 }}, 230 }, 231 }, 232 CommittingBlockNum: 1, 233 } 234 235 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil).Run(func(_ mock.Arguments) { 236 missingPvtDataTracker.Mock = mock.Mock{} 237 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(nil, nil) 238 }) 239 configHistoryRetriever.On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).Return(&collectionConfigInfo, nil) 240 committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil) 241 committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil) 242 243 result := &privdatacommon.FetchedPvtDataContainer{} 244 fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) { 245 dig2CollectionConfig := args.Get(0).(privdatacommon.Dig2CollectionConfig) 246 require.Equal(t, 1, len(dig2CollectionConfig)) 247 for digest := range dig2CollectionConfig { 248 hash := util2.ComputeSHA256([]byte("rws-pre-image")) 249 element := &gossip2.PvtDataElement{ 250 Digest: &gossip2.PvtDataDigest{ 251 TxId: digest.TxId, 252 BlockSeq: digest.BlockSeq, 253 Collection: digest.Collection, 254 Namespace: digest.Namespace, 255 SeqInBlock: digest.SeqInBlock, 256 }, 257 Payload: [][]byte{hash}, 258 } 259 result.AvailableElements = append(result.AvailableElements, element) 260 } 261 }).Return(result, nil) 262 263 var wg sync.WaitGroup 264 wg.Add(1) 265 266 var commitPvtDataOfOldBlocksHappened bool 267 var blockNum, seqInBlock uint64 268 blockNum = 3 269 seqInBlock = 1 270 committer.On("CommitPvtDataOfOldBlocks", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { 271 reconciledPvtdata := args.Get(0).([]*ledger.ReconciledPvtdata) 272 require.Equal(t, 1, len(reconciledPvtdata)) 273 require.Equal(t, blockNum, reconciledPvtdata[0].BlockNum) 274 require.Equal(t, seqInBlock, reconciledPvtdata[0].WriteSets[1].SeqInBlock) 275 require.Equal(t, "ns1", reconciledPvtdata[0].WriteSets[1].WriteSet.NsPvtRwset[0].Namespace) 276 require.Equal(t, "col1", reconciledPvtdata[0].WriteSets[1].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].CollectionName) 277 commitPvtDataOfOldBlocksHappened = true 278 279 require.Nil(t, args.Get(1)) 280 wg.Done() 281 }).Return([]*ledger.PvtdataHashMismatch{}, nil) 282 283 r := NewReconciler( 284 "", 285 metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics, 286 committer, 287 fetcher, 288 &PrivdataConfig{ 289 ReconcileSleepInterval: time.Millisecond * 100, 290 ReconcileBatchSize: 1, 291 ReconciliationEnabled: true, 292 }) 293 r.Start() 294 wg.Wait() 295 r.Stop() 296 297 require.True(t, commitPvtDataOfOldBlocksHappened) 298 } 299 300 func TestReconciliationPullingMissingPrivateDataAtOnePass(t *testing.T) { 301 // Scenario: define batch size to retrieve missing private data to 1 302 // and make sure that even though there are missing data for two blocks 303 // they will be reconciled with one shot. 304 committer := &mocks.Committer{} 305 fetcher := &mocks.ReconciliationFetcher{} 306 configHistoryRetriever := &mocks.ConfigHistoryRetriever{} 307 missingPvtDataTracker := &mocks.MissingPvtDataTracker{} 308 309 missingInfo := ledger.MissingPvtDataInfo{ 310 4: ledger.MissingBlockPvtdataInfo{ 311 1: {{Collection: "col1", Namespace: "ns1"}}, 312 }, 313 } 314 315 collectionConfigInfo := &ledger.CollectionConfigInfo{ 316 CollectionConfig: &peer.CollectionConfigPackage{ 317 Config: []*peer.CollectionConfig{ 318 {Payload: &peer.CollectionConfig_StaticCollectionConfig{ 319 StaticCollectionConfig: &peer.StaticCollectionConfig{ 320 Name: "col1", 321 }, 322 }}, 323 {Payload: &peer.CollectionConfig_StaticCollectionConfig{ 324 StaticCollectionConfig: &peer.StaticCollectionConfig{ 325 Name: "col2", 326 }, 327 }}, 328 }, 329 }, 330 CommittingBlockNum: 1, 331 } 332 333 stopC := make(chan struct{}) 334 nextC := make(chan struct{}) 335 336 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything). 337 Return(missingInfo, nil).Run(func(_ mock.Arguments) { 338 missingInfo := ledger.MissingPvtDataInfo{ 339 3: ledger.MissingBlockPvtdataInfo{ 340 2: {{Collection: "col2", Namespace: "ns2"}}, 341 }, 342 } 343 missingPvtDataTracker.Mock = mock.Mock{} 344 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything). 345 Return(missingInfo, nil).Run(func(_ mock.Arguments) { 346 // here we are making sure that we will first stop 347 // reconciliation so next call to GetMissingPvtDataInfoForMostRecentBlocks 348 // will go into same round 349 <-nextC 350 missingPvtDataTracker.Mock = mock.Mock{} 351 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything). 352 Return(nil, nil) 353 }) 354 // make sure we calling stop reconciliation loop, so for sure 355 // in this test we won't get to second round though making sure 356 // we are retrieving on single pass 357 stopC <- struct{}{} 358 }) 359 360 configHistoryRetriever. 361 On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything). 362 Return(collectionConfigInfo, nil) 363 364 committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil) 365 committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil) 366 367 result := &privdatacommon.FetchedPvtDataContainer{} 368 fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) { 369 result.AvailableElements = make([]*gossip2.PvtDataElement, 0) 370 dig2CollectionConfig := args.Get(0).(privdatacommon.Dig2CollectionConfig) 371 require.Equal(t, 1, len(dig2CollectionConfig)) 372 for digest := range dig2CollectionConfig { 373 hash := util2.ComputeSHA256([]byte("rws-pre-image")) 374 element := &gossip2.PvtDataElement{ 375 Digest: &gossip2.PvtDataDigest{ 376 TxId: digest.TxId, 377 BlockSeq: digest.BlockSeq, 378 Collection: digest.Collection, 379 Namespace: digest.Namespace, 380 SeqInBlock: digest.SeqInBlock, 381 }, 382 Payload: [][]byte{hash}, 383 } 384 result.AvailableElements = append(result.AvailableElements, element) 385 } 386 }).Return(result, nil) 387 388 var wg sync.WaitGroup 389 wg.Add(2) 390 391 var commitPvtDataOfOldBlocksHappened bool 392 pvtDataStore := make([][]*ledger.ReconciledPvtdata, 0) 393 committer.On("CommitPvtDataOfOldBlocks", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { 394 reconciledPvtdata := args.Get(0).([]*ledger.ReconciledPvtdata) 395 require.Equal(t, 1, len(reconciledPvtdata)) 396 pvtDataStore = append(pvtDataStore, reconciledPvtdata) 397 commitPvtDataOfOldBlocksHappened = true 398 399 require.Nil(t, args.Get(1)) 400 wg.Done() 401 }).Return([]*ledger.PvtdataHashMismatch{}, nil) 402 403 r := NewReconciler( 404 "", 405 metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics, 406 committer, 407 fetcher, 408 &PrivdataConfig{ 409 ReconcileSleepInterval: time.Millisecond * 100, 410 ReconcileBatchSize: 1, 411 ReconciliationEnabled: true, 412 }) 413 r.Start() 414 <-stopC 415 r.Stop() 416 nextC <- struct{}{} 417 wg.Wait() 418 419 require.Equal(t, 2, len(pvtDataStore)) 420 require.Equal(t, uint64(4), pvtDataStore[0][0].BlockNum) 421 require.Equal(t, uint64(3), pvtDataStore[1][0].BlockNum) 422 423 require.Equal(t, uint64(1), pvtDataStore[0][0].WriteSets[1].SeqInBlock) 424 require.Equal(t, uint64(2), pvtDataStore[1][0].WriteSets[2].SeqInBlock) 425 426 require.Equal(t, "ns1", pvtDataStore[0][0].WriteSets[1].WriteSet.NsPvtRwset[0].Namespace) 427 require.Equal(t, "ns2", pvtDataStore[1][0].WriteSets[2].WriteSet.NsPvtRwset[0].Namespace) 428 429 require.Equal(t, "col1", pvtDataStore[0][0].WriteSets[1].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].CollectionName) 430 require.Equal(t, "col2", pvtDataStore[1][0].WriteSets[2].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].CollectionName) 431 432 require.True(t, commitPvtDataOfOldBlocksHappened) 433 } 434 435 func TestReconciliationFailedToCommit(t *testing.T) { 436 committer := &mocks.Committer{} 437 fetcher := &mocks.ReconciliationFetcher{} 438 configHistoryRetriever := &mocks.ConfigHistoryRetriever{} 439 missingPvtDataTracker := &mocks.MissingPvtDataTracker{} 440 441 missingInfo := ledger.MissingPvtDataInfo{ 442 3: map[uint64][]*ledger.MissingCollectionPvtDataInfo{ 443 1: {{Collection: "col1", Namespace: "ns1"}}, 444 }, 445 } 446 447 collectionConfigInfo := ledger.CollectionConfigInfo{ 448 CollectionConfig: &peer.CollectionConfigPackage{ 449 Config: []*peer.CollectionConfig{ 450 {Payload: &peer.CollectionConfig_StaticCollectionConfig{ 451 StaticCollectionConfig: &peer.StaticCollectionConfig{ 452 Name: "col1", 453 }, 454 }}, 455 }, 456 }, 457 CommittingBlockNum: 1, 458 } 459 460 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(missingInfo, nil).Run(func(_ mock.Arguments) { 461 missingPvtDataTracker.Mock = mock.Mock{} 462 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(nil, nil) 463 }) 464 configHistoryRetriever.On("MostRecentCollectionConfigBelow", mock.Anything, mock.Anything).Return(&collectionConfigInfo, nil) 465 committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil) 466 committer.On("GetConfigHistoryRetriever").Return(configHistoryRetriever, nil) 467 468 result := &privdatacommon.FetchedPvtDataContainer{} 469 fetcher.On("FetchReconciledItems", mock.Anything).Run(func(args mock.Arguments) { 470 dig2CollectionConfig := args.Get(0).(privdatacommon.Dig2CollectionConfig) 471 require.Equal(t, 1, len(dig2CollectionConfig)) 472 for digest := range dig2CollectionConfig { 473 hash := util2.ComputeSHA256([]byte("rws-pre-image")) 474 element := &gossip2.PvtDataElement{ 475 Digest: &gossip2.PvtDataDigest{ 476 TxId: digest.TxId, 477 BlockSeq: digest.BlockSeq, 478 Collection: digest.Collection, 479 Namespace: digest.Namespace, 480 SeqInBlock: digest.SeqInBlock, 481 }, 482 Payload: [][]byte{hash}, 483 } 484 result.AvailableElements = append(result.AvailableElements, element) 485 } 486 }).Return(result, nil) 487 488 committer.On("CommitPvtDataOfOldBlocks", mock.Anything, mock.Anything).Return(nil, errors.New("failed to commit")) 489 490 r := &Reconciler{ 491 channel: "mychannel", 492 logger: logger.With("channel", "mychannel"), 493 metrics: metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics, 494 ReconcileSleepInterval: time.Minute, 495 ReconcileBatchSize: 1, 496 ReconciliationFetcher: fetcher, Committer: committer, 497 } 498 err := r.reconcile() 499 500 require.Error(t, err) 501 require.Contains(t, err.Error(), "failed to commit") 502 } 503 504 func TestFailuresWhileReconcilingMissingPvtData(t *testing.T) { 505 metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics 506 committer := &mocks.Committer{} 507 fetcher := &mocks.ReconciliationFetcher{} 508 committer.On("GetMissingPvtDataTracker").Return(nil, errors.New("failed to obtain missing pvt data tracker")) 509 510 r := NewReconciler( 511 "", 512 metrics, 513 committer, 514 fetcher, 515 &PrivdataConfig{ 516 ReconcileSleepInterval: time.Millisecond * 100, 517 ReconcileBatchSize: 1, 518 ReconciliationEnabled: true, 519 }) 520 err := r.reconcile() 521 require.Error(t, err) 522 require.Contains(t, "failed to obtain missing pvt data tracker", err.Error()) 523 524 committer.Mock = mock.Mock{} 525 committer.On("GetMissingPvtDataTracker").Return(nil, nil) 526 r = NewReconciler("", metrics, committer, fetcher, 527 &PrivdataConfig{ReconcileSleepInterval: time.Millisecond * 100, ReconcileBatchSize: 1, ReconciliationEnabled: true}) 528 err = r.reconcile() 529 require.Error(t, err) 530 require.Contains(t, "got nil as MissingPvtDataTracker, exiting...", err.Error()) 531 532 missingPvtDataTracker := &mocks.MissingPvtDataTracker{} 533 missingPvtDataTracker.On("GetMissingPvtDataInfoForMostRecentBlocks", mock.Anything).Return(nil, errors.New("failed get missing pvt data for recent blocks")) 534 535 committer.Mock = mock.Mock{} 536 committer.On("GetMissingPvtDataTracker").Return(missingPvtDataTracker, nil) 537 r = NewReconciler("", metrics, committer, fetcher, 538 &PrivdataConfig{ReconcileSleepInterval: time.Millisecond * 100, ReconcileBatchSize: 1, ReconciliationEnabled: true}) 539 err = r.reconcile() 540 require.Error(t, err) 541 require.Contains(t, "failed get missing pvt data for recent blocks", err.Error()) 542 } 543 544 func TestConstructUnreconciledMissingData(t *testing.T) { 545 requestedMissingData := privdatacommon.Dig2CollectionConfig{ 546 privdatacommon.DigKey{ 547 TxId: "tx1", 548 Namespace: "ns1", 549 Collection: "coll1", 550 BlockSeq: 1, 551 SeqInBlock: 1, 552 }: nil, 553 privdatacommon.DigKey{ 554 TxId: "tx1", 555 Namespace: "ns2", 556 Collection: "coll2", 557 BlockSeq: 1, 558 SeqInBlock: 1, 559 }: nil, 560 privdatacommon.DigKey{ 561 TxId: "tx1", 562 Namespace: "ns3", 563 Collection: "coll3", 564 BlockSeq: 1, 565 SeqInBlock: 3, 566 }: nil, 567 privdatacommon.DigKey{ 568 TxId: "tx2", 569 Namespace: "ns4", 570 Collection: "coll4", 571 BlockSeq: 4, 572 SeqInBlock: 4, 573 }: nil, 574 } 575 576 testCases := []struct { 577 description string 578 fetchedData []*gossip2.PvtDataElement 579 expectedUnreconciledMissingData ledger.MissingPvtDataInfo 580 }{ 581 { 582 description: "none-reconciled", 583 fetchedData: nil, 584 expectedUnreconciledMissingData: ledger.MissingPvtDataInfo{ 585 1: ledger.MissingBlockPvtdataInfo{ 586 1: []*ledger.MissingCollectionPvtDataInfo{ 587 { 588 Namespace: "ns1", 589 Collection: "coll1", 590 }, 591 { 592 Namespace: "ns2", 593 Collection: "coll2", 594 }, 595 }, 596 3: []*ledger.MissingCollectionPvtDataInfo{ 597 { 598 Namespace: "ns3", 599 Collection: "coll3", 600 }, 601 }, 602 }, 603 4: ledger.MissingBlockPvtdataInfo{ 604 4: []*ledger.MissingCollectionPvtDataInfo{ 605 { 606 Namespace: "ns4", 607 Collection: "coll4", 608 }, 609 }, 610 }, 611 }, 612 }, 613 { 614 description: "all-reconciled", 615 fetchedData: []*gossip2.PvtDataElement{ 616 { 617 Digest: &gossip2.PvtDataDigest{ 618 TxId: "tx1", 619 Namespace: "ns1", 620 Collection: "coll1", 621 BlockSeq: 1, 622 SeqInBlock: 1, 623 }, 624 }, 625 { 626 Digest: &gossip2.PvtDataDigest{ 627 TxId: "tx1", 628 Namespace: "ns2", 629 Collection: "coll2", 630 BlockSeq: 1, 631 SeqInBlock: 1, 632 }, 633 }, 634 { 635 Digest: &gossip2.PvtDataDigest{ 636 TxId: "tx1", 637 Namespace: "ns3", 638 Collection: "coll3", 639 BlockSeq: 1, 640 SeqInBlock: 3, 641 }, 642 }, 643 { 644 Digest: &gossip2.PvtDataDigest{ 645 TxId: "tx2", 646 Namespace: "ns4", 647 Collection: "coll4", 648 BlockSeq: 4, 649 SeqInBlock: 4, 650 }, 651 }, 652 }, 653 expectedUnreconciledMissingData: nil, 654 }, 655 { 656 description: "some-unreconciled", 657 fetchedData: []*gossip2.PvtDataElement{ 658 { 659 Digest: &gossip2.PvtDataDigest{ 660 TxId: "tx1", 661 Namespace: "ns1", 662 Collection: "coll1", 663 BlockSeq: 1, 664 SeqInBlock: 1, 665 }, 666 }, 667 { 668 Digest: &gossip2.PvtDataDigest{ 669 TxId: "tx1", 670 Namespace: "ns3", 671 Collection: "coll3", 672 BlockSeq: 1, 673 SeqInBlock: 3, 674 }, 675 }, 676 { 677 Digest: &gossip2.PvtDataDigest{ 678 TxId: "tx2", 679 Namespace: "ns4", 680 Collection: "coll4", 681 BlockSeq: 4, 682 SeqInBlock: 4, 683 }, 684 }, 685 }, 686 expectedUnreconciledMissingData: ledger.MissingPvtDataInfo{ 687 1: ledger.MissingBlockPvtdataInfo{ 688 1: []*ledger.MissingCollectionPvtDataInfo{ 689 { 690 Namespace: "ns2", 691 Collection: "coll2", 692 }, 693 }, 694 }, 695 }, 696 }, 697 } 698 699 for _, testCase := range testCases { 700 t.Run(testCase.description, func(t *testing.T) { 701 unreconciledData := constructUnreconciledMissingData(requestedMissingData, testCase.fetchedData) 702 require.Equal(t, len(testCase.expectedUnreconciledMissingData), len(unreconciledData)) 703 for blkNum, txsMissingData := range testCase.expectedUnreconciledMissingData { 704 for txNum, expectedUnreconciledData := range txsMissingData { 705 require.ElementsMatch(t, expectedUnreconciledData, unreconciledData[blkNum][txNum]) 706 } 707 } 708 }) 709 } 710 }