github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/pvtdatastorage/reconcile_missing_pvtdata_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package pvtdatastorage 8 9 import ( 10 "fmt" 11 "testing" 12 13 "github.com/osdi23p228/fabric/core/ledger" 14 btltestutil "github.com/osdi23p228/fabric/core/ledger/pvtdatapolicy/testutil" 15 "github.com/stretchr/testify/require" 16 "github.com/willf/bitset" 17 ) 18 19 type blockTxPvtDataInfoForTest struct { 20 blkNum uint64 21 txNum uint64 22 pvtDataPresent map[string][]string 23 pvtDataMissing map[string][]string 24 } 25 26 type pvtDataForTest struct { 27 blockNum uint64 28 pvtData []*ledger.TxPvtData 29 dataKeys []*dataKey 30 missingDataInfo ledger.TxMissingPvtDataMap 31 } 32 33 func TestCommitPvtDataOfOldBlocks(t *testing.T) { 34 btlPolicy := btltestutil.SampleBTLPolicy( 35 map[[2]string]uint64{ 36 {"ns-1", "coll-1"}: 0, 37 {"ns-1", "coll-2"}: 0, 38 {"ns-2", "coll-1"}: 0, 39 {"ns-2", "coll-2"}: 0, 40 }, 41 ) 42 env := NewTestStoreEnv(t, "TestCommitPvtDataOfOldBlocks", btlPolicy, pvtDataConf()) 43 defer env.Cleanup() 44 store := env.TestStore 45 46 blockTxPvtDataInfo := []*blockTxPvtDataInfoForTest{ 47 { 48 blkNum: 1, 49 txNum: 1, 50 pvtDataMissing: map[string][]string{ 51 "ns-1": {"coll-1", "coll-2"}, 52 "ns-2": {"coll-1", "coll-2"}, 53 }, 54 }, 55 { 56 blkNum: 1, 57 txNum: 2, 58 pvtDataPresent: map[string][]string{ 59 "ns-2": {"coll-1", "coll-2"}, 60 }, 61 pvtDataMissing: map[string][]string{ 62 "ns-1": {"coll-1", "coll-2"}, 63 }, 64 }, 65 { 66 blkNum: 1, 67 txNum: 4, 68 pvtDataPresent: map[string][]string{ 69 "ns-1": {"coll-1", "coll-2"}, 70 "ns-2": {"coll-1", "coll-2"}, 71 }, 72 }, 73 { 74 blkNum: 2, 75 txNum: 1, 76 pvtDataMissing: map[string][]string{ 77 "ns-1": {"coll-1", "coll-2"}, 78 }, 79 }, 80 { 81 blkNum: 2, 82 txNum: 3, 83 pvtDataMissing: map[string][]string{ 84 "ns-1": {"coll-1"}, 85 }, 86 }, 87 } 88 89 blocksPvtData, missingDataSummary := constructPvtDataForTest(t, blockTxPvtDataInfo) 90 91 require.NoError(t, store.Commit(0, nil, nil)) 92 require.NoError(t, store.Commit(1, blocksPvtData[1].pvtData, blocksPvtData[1].missingDataInfo)) 93 require.NoError(t, store.Commit(2, blocksPvtData[2].pvtData, blocksPvtData[2].missingDataInfo)) 94 95 assertMissingDataInfo(t, store, missingDataSummary, 2) 96 97 // COMMIT some of the missing data in the block 1 and block 2 98 oldBlockTxPvtDataInfo := []*blockTxPvtDataInfoForTest{ 99 { 100 blkNum: 1, 101 txNum: 1, 102 pvtDataPresent: map[string][]string{ 103 "ns-1": {"coll-1"}, 104 "ns-2": {"coll-1"}, 105 }, 106 pvtDataMissing: map[string][]string{ 107 "ns-1": {"coll-2"}, 108 "ns-2": {"coll-2"}, 109 }, 110 }, 111 { 112 blkNum: 1, 113 txNum: 2, 114 pvtDataPresent: map[string][]string{ 115 "ns-1": {"coll-1"}, 116 }, 117 pvtDataMissing: map[string][]string{ 118 "ns-1": {"coll-2"}, 119 }, 120 }, 121 { 122 blkNum: 2, 123 txNum: 1, 124 pvtDataMissing: map[string][]string{ 125 "ns-1": {"coll-1", "coll-2"}, 126 }, 127 }, 128 { 129 blkNum: 2, 130 txNum: 3, 131 pvtDataPresent: map[string][]string{ 132 "ns-1": {"coll-1"}, 133 }, 134 }, 135 } 136 137 blocksPvtData, missingDataSummary = constructPvtDataForTest(t, oldBlockTxPvtDataInfo) 138 oldBlocksPvtData := map[uint64][]*ledger.TxPvtData{ 139 1: blocksPvtData[1].pvtData, 140 2: blocksPvtData[2].pvtData, 141 } 142 require.NoError(t, store.CommitPvtDataOfOldBlocks(oldBlocksPvtData, nil)) 143 144 for _, b := range blocksPvtData { 145 for _, dkey := range b.dataKeys { 146 require.True(t, testDataKeyExists(t, store, dkey)) 147 } 148 } 149 assertMissingDataInfo(t, store, missingDataSummary, 2) 150 } 151 152 func TestCommitPvtDataOfOldBlocksWithBTL(t *testing.T) { 153 setup := func(store *Store) { 154 blockTxPvtDataInfo := []*blockTxPvtDataInfoForTest{ 155 { 156 blkNum: 1, 157 txNum: 1, 158 pvtDataMissing: map[string][]string{ 159 "ns-1": {"coll-1"}, 160 "ns-2": {"coll-1"}, 161 }, 162 }, 163 { 164 blkNum: 1, 165 txNum: 2, 166 pvtDataMissing: map[string][]string{ 167 "ns-1": {"coll-1"}, 168 "ns-2": {"coll-1"}, 169 }, 170 }, 171 { 172 blkNum: 1, 173 txNum: 3, 174 pvtDataMissing: map[string][]string{ 175 "ns-1": {"coll-1"}, 176 "ns-2": {"coll-1"}, 177 }, 178 }, 179 } 180 181 blocksPvtData, missingDataSummary := constructPvtDataForTest(t, blockTxPvtDataInfo) 182 183 require.NoError(t, store.Commit(0, nil, nil)) 184 require.NoError(t, store.Commit(1, blocksPvtData[1].pvtData, blocksPvtData[1].missingDataInfo)) 185 186 assertMissingDataInfo(t, store, missingDataSummary, 1) 187 188 // COMMIT BLOCK 2 & 3 WITH NO PVTDATA 189 require.NoError(t, store.Commit(2, nil, nil)) 190 require.NoError(t, store.Commit(3, nil, nil)) 191 } 192 193 t.Run("expired but not purged", func(t *testing.T) { 194 btlPolicy := btltestutil.SampleBTLPolicy( 195 map[[2]string]uint64{ 196 {"ns-1", "coll-1"}: 1, 197 {"ns-2", "coll-1"}: 1, 198 }, 199 ) 200 env := NewTestStoreEnv(t, "TestCommitPvtDataOfOldBlocksWithBTL", btlPolicy, pvtDataConf()) 201 defer env.Cleanup() 202 store := env.TestStore 203 204 setup(store) 205 // in block 1, ns-1:coll-1 and ns-2:coll-2 should have expired but not purged. 206 // hence, the commit of pvtdata of block 1 transaction 1 should create entries 207 // in the store 208 oldBlockTxPvtDataInfo := []*blockTxPvtDataInfoForTest{ 209 { 210 blkNum: 1, 211 txNum: 1, 212 pvtDataPresent: map[string][]string{ 213 "ns-1": {"coll-1"}, 214 "ns-2": {"coll-1"}, 215 }, 216 }, 217 } 218 219 blocksPvtData, _ := constructPvtDataForTest(t, oldBlockTxPvtDataInfo) 220 oldBlocksPvtData := map[uint64][]*ledger.TxPvtData{ 221 1: blocksPvtData[1].pvtData, 222 } 223 deprioritizedList := ledger.MissingPvtDataInfo{ 224 1: ledger.MissingBlockPvtdataInfo{ 225 2: { 226 { 227 Namespace: "ns-1", 228 Collection: "coll-1", 229 }, 230 { 231 Namespace: "ns-2", 232 Collection: "coll-1", 233 }, 234 }, 235 }, 236 } 237 require.NoError(t, store.CommitPvtDataOfOldBlocks(oldBlocksPvtData, deprioritizedList)) 238 239 for _, b := range blocksPvtData { 240 for _, dkey := range b.dataKeys { 241 require.True(t, testDataKeyExists(t, store, dkey)) 242 } 243 } 244 // as all missing data are expired, get missing info would return nil though 245 // it is not purged yet 246 assertMissingDataInfo(t, store, make(ledger.MissingPvtDataInfo), 1) 247 248 // deprioritized list should be present 249 tests := []struct { 250 key nsCollBlk 251 expectedBitmap *bitset.BitSet 252 }{ 253 { 254 key: nsCollBlk{ 255 ns: "ns-1", 256 coll: "coll-1", 257 blkNum: 1, 258 }, 259 expectedBitmap: constructBitSetForTest(2), 260 }, 261 { 262 key: nsCollBlk{ 263 ns: "ns-2", 264 coll: "coll-1", 265 blkNum: 1, 266 }, 267 expectedBitmap: constructBitSetForTest(2), 268 }, 269 } 270 271 for _, tt := range tests { 272 encKey := encodeElgDeprioMissingDataKey(&missingDataKey{tt.key}) 273 missingData, err := store.db.Get(encKey) 274 require.NoError(t, err) 275 276 expectedMissingData, err := encodeMissingDataValue(tt.expectedBitmap) 277 require.NoError(t, err) 278 require.Equal(t, expectedMissingData, missingData) 279 } 280 }) 281 282 t.Run("expired and purged", func(t *testing.T) { 283 btlPolicy := btltestutil.SampleBTLPolicy( 284 map[[2]string]uint64{ 285 {"ns-1", "coll-1"}: 1, 286 {"ns-2", "coll-1"}: 1, 287 }, 288 ) 289 env := NewTestStoreEnv(t, "TestCommitPvtDataOfOldBlocksWithBTL", btlPolicy, pvtDataConf()) 290 defer env.Cleanup() 291 store := env.TestStore 292 293 setup(store) 294 require.NoError(t, store.Commit(4, nil, nil)) 295 296 testWaitForPurgerRoutineToFinish(store) 297 298 // in block 1, ns-1:coll-1 and ns-2:coll-2 should have expired and purged. 299 // hence, the commit of pvtdata of block 1 transaction 2 should not create 300 // entries in the store 301 oldBlockTxPvtDataInfo := []*blockTxPvtDataInfoForTest{ 302 { 303 blkNum: 1, 304 txNum: 2, 305 pvtDataPresent: map[string][]string{ 306 "ns-1": {"coll-1"}, 307 "ns-2": {"coll-1"}, 308 }, 309 }, 310 } 311 blocksPvtData, _ := constructPvtDataForTest(t, oldBlockTxPvtDataInfo) 312 oldBlocksPvtData := map[uint64][]*ledger.TxPvtData{ 313 1: blocksPvtData[1].pvtData, 314 } 315 deprioritizedList := ledger.MissingPvtDataInfo{ 316 1: ledger.MissingBlockPvtdataInfo{ 317 3: { 318 { 319 Namespace: "ns-1", 320 Collection: "coll-1", 321 }, 322 { 323 Namespace: "ns-2", 324 Collection: "coll-1", 325 }, 326 }, 327 }, 328 } 329 require.NoError(t, store.CommitPvtDataOfOldBlocks(oldBlocksPvtData, deprioritizedList)) 330 331 for _, b := range blocksPvtData { 332 for _, dkey := range b.dataKeys { 333 require.False(t, testDataKeyExists(t, store, dkey)) 334 } 335 } 336 337 // deprioritized list should not be present 338 keys := []nsCollBlk{ 339 { 340 ns: "ns-1", 341 coll: "coll-1", 342 blkNum: 1, 343 }, 344 { 345 ns: "ns-2", 346 coll: "coll-1", 347 blkNum: 1, 348 }, 349 } 350 351 for _, k := range keys { 352 encKey := encodeElgDeprioMissingDataKey(&missingDataKey{k}) 353 missingData, err := store.db.Get(encKey) 354 require.NoError(t, err) 355 require.Nil(t, missingData) 356 } 357 }) 358 } 359 360 func TestCommitPvtDataOfOldBlocksWithDeprioritization(t *testing.T) { 361 blockTxPvtDataInfo := []*blockTxPvtDataInfoForTest{ 362 { 363 blkNum: 1, 364 txNum: 1, 365 pvtDataMissing: map[string][]string{ 366 "ns-1": {"coll-1"}, 367 "ns-2": {"coll-1"}, 368 }, 369 }, 370 { 371 blkNum: 1, 372 txNum: 2, 373 pvtDataMissing: map[string][]string{ 374 "ns-1": {"coll-1"}, 375 "ns-2": {"coll-1"}, 376 }, 377 }, 378 { 379 blkNum: 2, 380 txNum: 1, 381 pvtDataMissing: map[string][]string{ 382 "ns-1": {"coll-1"}, 383 "ns-2": {"coll-1"}, 384 }, 385 }, 386 { 387 blkNum: 2, 388 txNum: 2, 389 pvtDataMissing: map[string][]string{ 390 "ns-1": {"coll-1"}, 391 "ns-2": {"coll-1"}, 392 }, 393 }, 394 } 395 396 blocksPvtData, missingDataSummary := constructPvtDataForTest(t, blockTxPvtDataInfo) 397 398 tests := []struct { 399 name string 400 deprioritizedList ledger.MissingPvtDataInfo 401 expectedPrioMissingDataKeys ledger.MissingPvtDataInfo 402 }{ 403 { 404 name: "all keys deprioritized", 405 deprioritizedList: missingDataSummary, 406 expectedPrioMissingDataKeys: make(ledger.MissingPvtDataInfo), 407 }, 408 { 409 name: "some keys deprioritized", 410 deprioritizedList: ledger.MissingPvtDataInfo{ 411 1: ledger.MissingBlockPvtdataInfo{ 412 2: { 413 { 414 Namespace: "ns-1", 415 Collection: "coll-1", 416 }, 417 }, 418 }, 419 2: ledger.MissingBlockPvtdataInfo{ 420 2: { 421 { 422 Namespace: "ns-1", 423 Collection: "coll-1", 424 }, 425 }, 426 }, 427 }, 428 expectedPrioMissingDataKeys: ledger.MissingPvtDataInfo{ 429 1: ledger.MissingBlockPvtdataInfo{ 430 1: { 431 { 432 Namespace: "ns-1", 433 Collection: "coll-1", 434 }, 435 { 436 Namespace: "ns-2", 437 Collection: "coll-1", 438 }, 439 }, 440 2: { 441 { 442 Namespace: "ns-2", 443 Collection: "coll-1", 444 }, 445 }, 446 }, 447 2: ledger.MissingBlockPvtdataInfo{ 448 1: { 449 { 450 Namespace: "ns-1", 451 Collection: "coll-1", 452 }, 453 { 454 Namespace: "ns-2", 455 Collection: "coll-1", 456 }, 457 }, 458 2: { 459 { 460 Namespace: "ns-2", 461 Collection: "coll-1", 462 }, 463 }, 464 }, 465 }, 466 }, 467 } 468 469 for _, tt := range tests { 470 t.Run(tt.name, func(t *testing.T) { 471 btlPolicy := btltestutil.SampleBTLPolicy( 472 map[[2]string]uint64{ 473 {"ns-1", "coll-1"}: 0, 474 {"ns-2", "coll-1"}: 0, 475 }, 476 ) 477 env := NewTestStoreEnv(t, "TestCommitPvtDataOfOldBlocksWithDeprio", btlPolicy, pvtDataConf()) 478 defer env.Cleanup() 479 store := env.TestStore 480 481 // COMMIT BLOCK 0 WITH NO DATA 482 require.NoError(t, store.Commit(0, nil, nil)) 483 require.NoError(t, store.Commit(1, blocksPvtData[1].pvtData, blocksPvtData[1].missingDataInfo)) 484 require.NoError(t, store.Commit(2, blocksPvtData[2].pvtData, blocksPvtData[2].missingDataInfo)) 485 486 assertMissingDataInfo(t, store, missingDataSummary, 2) 487 488 require.NoError(t, store.CommitPvtDataOfOldBlocks(nil, tt.deprioritizedList)) 489 490 prioMissingData, err := store.getMissingData(elgPrioritizedMissingDataGroup, 3) 491 require.NoError(t, err) 492 require.Equal(t, len(tt.expectedPrioMissingDataKeys), len(prioMissingData)) 493 for blkNum, txsMissingData := range tt.expectedPrioMissingDataKeys { 494 for txNum, expectedMissingData := range txsMissingData { 495 require.ElementsMatch(t, expectedMissingData, prioMissingData[blkNum][txNum]) 496 } 497 } 498 499 deprioMissingData, err := store.getMissingData(elgDeprioritizedMissingDataGroup, 3) 500 require.NoError(t, err) 501 require.Equal(t, len(tt.deprioritizedList), len(deprioMissingData)) 502 for blkNum, txsMissingData := range tt.deprioritizedList { 503 for txNum, expectedMissingData := range txsMissingData { 504 require.ElementsMatch(t, expectedMissingData, deprioMissingData[blkNum][txNum]) 505 } 506 } 507 508 oldBlockTxPvtDataInfo := []*blockTxPvtDataInfoForTest{ 509 { 510 blkNum: 1, 511 txNum: 1, 512 pvtDataPresent: map[string][]string{ 513 "ns-1": {"coll-1"}, 514 "ns-2": {"coll-1"}, 515 }, 516 }, 517 { 518 blkNum: 1, 519 txNum: 2, 520 pvtDataPresent: map[string][]string{ 521 "ns-1": {"coll-1"}, 522 "ns-2": {"coll-1"}, 523 }, 524 }, 525 { 526 blkNum: 2, 527 txNum: 1, 528 pvtDataPresent: map[string][]string{ 529 "ns-1": {"coll-1"}, 530 "ns-2": {"coll-1"}, 531 }, 532 }, 533 { 534 blkNum: 2, 535 txNum: 2, 536 pvtDataPresent: map[string][]string{ 537 "ns-1": {"coll-1"}, 538 "ns-2": {"coll-1"}, 539 }, 540 }, 541 } 542 543 pvtDataOfOldBlocks, _ := constructPvtDataForTest(t, oldBlockTxPvtDataInfo) 544 oldBlocksPvtData := map[uint64][]*ledger.TxPvtData{ 545 1: pvtDataOfOldBlocks[1].pvtData, 546 2: pvtDataOfOldBlocks[2].pvtData, 547 } 548 require.NoError(t, store.CommitPvtDataOfOldBlocks(oldBlocksPvtData, nil)) 549 550 prioMissingData, err = store.getMissingData(elgPrioritizedMissingDataGroup, 3) 551 require.NoError(t, err) 552 require.Equal(t, make(ledger.MissingPvtDataInfo), prioMissingData) 553 554 deprioMissingData, err = store.getMissingData(elgDeprioritizedMissingDataGroup, 3) 555 require.NoError(t, err) 556 require.Equal(t, make(ledger.MissingPvtDataInfo), deprioMissingData) 557 }) 558 } 559 } 560 561 func constructPvtDataForTest(t *testing.T, blockInfo []*blockTxPvtDataInfoForTest) (map[uint64]*pvtDataForTest, ledger.MissingPvtDataInfo) { 562 blocksPvtData := make(map[uint64]*pvtDataForTest) 563 missingPvtDataInfoSummary := make(ledger.MissingPvtDataInfo) 564 565 for _, b := range blockInfo { 566 p, ok := blocksPvtData[b.blkNum] 567 if !ok { 568 p = &pvtDataForTest{ 569 missingDataInfo: make(ledger.TxMissingPvtDataMap), 570 } 571 blocksPvtData[b.blkNum] = p 572 } 573 574 for ns, colls := range b.pvtDataMissing { 575 for _, coll := range colls { 576 p.missingDataInfo.Add(b.txNum, ns, coll, true) 577 missingPvtDataInfoSummary.Add(b.blkNum, b.txNum, ns, coll) 578 } 579 } 580 581 var nsColls []string 582 for ns, colls := range b.pvtDataPresent { 583 for _, coll := range colls { 584 nsColls = append(nsColls, fmt.Sprintf("%s:%s", ns, coll)) 585 p.dataKeys = append(p.dataKeys, &dataKey{ 586 nsCollBlk: nsCollBlk{ 587 ns: ns, 588 coll: coll, 589 blkNum: b.blkNum, 590 }, 591 txNum: b.txNum, 592 }) 593 } 594 } 595 596 if len(nsColls) == 0 { 597 continue 598 } 599 p.pvtData = append( 600 p.pvtData, 601 produceSamplePvtdata(t, b.txNum, nsColls), 602 ) 603 } 604 605 return blocksPvtData, missingPvtDataInfoSummary 606 } 607 608 func assertMissingDataInfo(t *testing.T, store *Store, expected ledger.MissingPvtDataInfo, numRecentBlocks int) { 609 missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(numRecentBlocks) 610 require.NoError(t, err) 611 require.Equal(t, len(expected), len(missingPvtDataInfo)) 612 for blkNum, txsMissingData := range expected { 613 for txNum, expectedMissingData := range txsMissingData { 614 require.ElementsMatch(t, expectedMissingData, missingPvtDataInfo[blkNum][txNum]) 615 } 616 } 617 } 618 619 func constructBitSetForTest(txNums ...uint) *bitset.BitSet { 620 bitmap := &bitset.BitSet{} 621 for _, txNum := range txNums { 622 bitmap.Set(txNum) 623 } 624 return bitmap 625 }