github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/pvtdatastorage/store_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 "io/ioutil" 12 "os" 13 "strings" 14 "testing" 15 "time" 16 17 "github.com/golang/protobuf/proto" 18 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 19 "github.com/osdi23p228/fabric/common/ledger/util/leveldbhelper" 20 "github.com/osdi23p228/fabric/core/ledger" 21 "github.com/osdi23p228/fabric/core/ledger/kvledger/txmgmt/rwsetutil" 22 btltestutil "github.com/osdi23p228/fabric/core/ledger/pvtdatapolicy/testutil" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func TestMain(m *testing.M) { 27 os.Exit(m.Run()) 28 } 29 30 func TestEmptyStore(t *testing.T) { 31 env := NewTestStoreEnv(t, "TestEmptyStore", nil, pvtDataConf()) 32 defer env.Cleanup() 33 store := env.TestStore 34 require.True(t, store.isEmpty) 35 } 36 37 func TestStoreBasicCommitAndRetrieval(t *testing.T) { 38 btlPolicy := btltestutil.SampleBTLPolicy( 39 map[[2]string]uint64{ 40 {"ns-1", "coll-1"}: 0, 41 {"ns-1", "coll-2"}: 0, 42 {"ns-2", "coll-1"}: 0, 43 {"ns-2", "coll-2"}: 0, 44 {"ns-3", "coll-1"}: 0, 45 {"ns-4", "coll-1"}: 0, 46 {"ns-4", "coll-2"}: 0, 47 }, 48 ) 49 50 env := NewTestStoreEnv(t, "TestStoreBasicCommitAndRetrieval", btlPolicy, pvtDataConf()) 51 defer env.Cleanup() 52 store := env.TestStore 53 testData := []*ledger.TxPvtData{ 54 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 55 produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 56 } 57 58 // construct missing data for block 1 59 blk1MissingData := make(ledger.TxMissingPvtDataMap) 60 61 // eligible missing data in tx1 62 blk1MissingData.Add(1, "ns-1", "coll-1", true) 63 blk1MissingData.Add(1, "ns-1", "coll-2", true) 64 blk1MissingData.Add(1, "ns-2", "coll-1", true) 65 blk1MissingData.Add(1, "ns-2", "coll-2", true) 66 // eligible missing data in tx2 67 blk1MissingData.Add(2, "ns-3", "coll-1", true) 68 // ineligible missing data in tx4 69 blk1MissingData.Add(4, "ns-4", "coll-1", false) 70 blk1MissingData.Add(4, "ns-4", "coll-2", false) 71 72 // construct missing data for block 2 73 blk2MissingData := make(ledger.TxMissingPvtDataMap) 74 // eligible missing data in tx1 75 blk2MissingData.Add(1, "ns-1", "coll-1", true) 76 blk2MissingData.Add(1, "ns-1", "coll-2", true) 77 // eligible missing data in tx3 78 blk2MissingData.Add(3, "ns-1", "coll-1", true) 79 80 // no pvt data with block 0 81 require.NoError(t, store.Commit(0, nil, nil)) 82 83 // pvt data with block 1 - commit 84 require.NoError(t, store.Commit(1, testData, blk1MissingData)) 85 86 // pvt data retrieval for block 0 should return nil 87 var nilFilter ledger.PvtNsCollFilter 88 retrievedData, err := store.GetPvtDataByBlockNum(0, nilFilter) 89 require.NoError(t, err) 90 require.Nil(t, retrievedData) 91 92 // pvt data retrieval for block 1 should return full pvtdata 93 retrievedData, err = store.GetPvtDataByBlockNum(1, nilFilter) 94 require.NoError(t, err) 95 for i, data := range retrievedData { 96 require.Equal(t, data.SeqInBlock, testData[i].SeqInBlock) 97 require.True(t, proto.Equal(data.WriteSet, testData[i].WriteSet)) 98 } 99 100 // pvt data retrieval for block 1 with filter should return filtered pvtdata 101 filter := ledger.NewPvtNsCollFilter() 102 filter.Add("ns-1", "coll-1") 103 filter.Add("ns-2", "coll-2") 104 retrievedData, err = store.GetPvtDataByBlockNum(1, filter) 105 require.NoError(t, err) 106 expectedRetrievedData := []*ledger.TxPvtData{ 107 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-2:coll-2"}), 108 produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-2:coll-2"}), 109 } 110 for i, data := range retrievedData { 111 require.Equal(t, data.SeqInBlock, expectedRetrievedData[i].SeqInBlock) 112 require.True(t, proto.Equal(data.WriteSet, expectedRetrievedData[i].WriteSet)) 113 } 114 115 // pvt data retrieval for block 2 should return ErrOutOfRange 116 retrievedData, err = store.GetPvtDataByBlockNum(2, nilFilter) 117 _, ok := err.(*ErrOutOfRange) 118 require.True(t, ok) 119 require.Nil(t, retrievedData) 120 121 // pvt data with block 2 - commit 122 require.NoError(t, store.Commit(2, testData, blk2MissingData)) 123 124 // retrieve the stored missing entries using GetMissingPvtDataInfoForMostRecentBlocks 125 // Only the code path of eligible entries would be covered in this unit-test. For 126 // ineligible entries, the code path will be covered in FAB-11437 127 128 expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo) 129 // missing data in block2, tx1 130 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1") 131 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 132 expectedMissingPvtDataInfo.Add(2, 3, "ns-1", "coll-1") 133 134 missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(1) 135 require.NoError(t, err) 136 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 137 138 // missing data in block1, tx1 139 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1") 140 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2") 141 expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1") 142 expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-2") 143 144 // missing data in block1, tx2 145 expectedMissingPvtDataInfo.Add(1, 2, "ns-3", "coll-1") 146 147 missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(2) 148 require.NoError(t, err) 149 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 150 151 missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10) 152 require.NoError(t, err) 153 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 154 } 155 156 func TestStoreIteratorError(t *testing.T) { 157 env := NewTestStoreEnv(t, "TestStoreIteratorError", nil, pvtDataConf()) 158 defer env.Cleanup() 159 store := env.TestStore 160 require.NoError(t, store.Commit(0, nil, nil)) 161 env.TestStoreProvider.Close() 162 errStr := "internal leveldb error while obtaining db iterator: leveldb: closed" 163 164 t.Run("GetPvtDataByBlockNum", func(t *testing.T) { 165 block, err := store.GetPvtDataByBlockNum(0, nil) 166 require.EqualError(t, err, errStr) 167 require.Nil(t, block) 168 }) 169 170 t.Run("GetMissingPvtDataInfoForMostRecentBlocks", func(t *testing.T) { 171 missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(10) 172 require.EqualError(t, err, errStr) 173 require.Nil(t, missingPvtDataInfo) 174 }) 175 176 t.Run("retrieveExpiryEntries", func(t *testing.T) { 177 expiryEntries, err := store.retrieveExpiryEntries(0, 1) 178 require.EqualError(t, err, errStr) 179 require.Nil(t, expiryEntries) 180 }) 181 182 t.Run("processCollElgEvents", func(t *testing.T) { 183 storeDir, err := ioutil.TempDir("", "pdstore") 184 require.NoError(t, err) 185 s := &Store{} 186 dbProvider, err := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: storeDir}) 187 require.NoError(t, err) 188 s.db = dbProvider.GetDBHandle("test-ledger") 189 dbProvider.Close() 190 require.EqualError(t, s.processCollElgEvents(), errStr) 191 }) 192 } 193 194 func TestGetMissingDataInfo(t *testing.T) { 195 setup := func(ledgerid string, c *PrivateDataConfig) *Store { 196 btlPolicy := btltestutil.SampleBTLPolicy( 197 map[[2]string]uint64{ 198 {"ns-1", "coll-1"}: 0, 199 {"ns-1", "coll-2"}: 0, 200 }, 201 ) 202 203 env := NewTestStoreEnv(t, ledgerid, btlPolicy, c) 204 t.Cleanup( 205 func() { 206 defer env.Cleanup() 207 }, 208 ) 209 store := env.TestStore 210 211 // construct missing data for block 1 212 blk1MissingData := make(ledger.TxMissingPvtDataMap) 213 blk1MissingData.Add(1, "ns-1", "coll-1", true) 214 blk1MissingData.Add(1, "ns-1", "coll-2", true) 215 216 require.NoError(t, store.Commit(0, nil, nil)) 217 require.NoError(t, store.Commit(1, nil, blk1MissingData)) 218 219 deprioritizedList := ledger.MissingPvtDataInfo{ 220 1: ledger.MissingBlockPvtdataInfo{ 221 1: { 222 { 223 Namespace: "ns-1", 224 Collection: "coll-2", 225 }, 226 }, 227 }, 228 } 229 require.NoError(t, store.CommitPvtDataOfOldBlocks(nil, deprioritizedList)) 230 231 return env.TestStore 232 } 233 234 t.Run("always access deprioritized missing data", func(t *testing.T) { 235 conf := pvtDataConf() 236 conf.DeprioritizedDataReconcilerInterval = 0 237 store := setup("testGetMissingDataInfoFromDeprioList", conf) 238 239 expectedDeprioMissingDataInfo := ledger.MissingPvtDataInfo{ 240 1: ledger.MissingBlockPvtdataInfo{ 241 1: { 242 { 243 Namespace: "ns-1", 244 Collection: "coll-2", 245 }, 246 }, 247 }, 248 } 249 250 for i := 0; i < 2; i++ { 251 assertMissingDataInfo(t, store, expectedDeprioMissingDataInfo, 2) 252 } 253 }) 254 255 t.Run("change the deprioritized missing data access time", func(t *testing.T) { 256 conf := pvtDataConf() 257 conf.DeprioritizedDataReconcilerInterval = 300 * time.Minute 258 store := setup("testGetMissingDataInfoFromPrioAndDeprioList", conf) 259 260 expectedPrioMissingDataInfo := ledger.MissingPvtDataInfo{ 261 1: ledger.MissingBlockPvtdataInfo{ 262 1: { 263 { 264 Namespace: "ns-1", 265 Collection: "coll-1", 266 }, 267 }, 268 }, 269 } 270 271 expectedDeprioMissingDataInfo := ledger.MissingPvtDataInfo{ 272 1: ledger.MissingBlockPvtdataInfo{ 273 1: { 274 { 275 Namespace: "ns-1", 276 Collection: "coll-2", 277 }, 278 }, 279 }, 280 } 281 282 for i := 0; i < 3; i++ { 283 assertMissingDataInfo(t, store, expectedPrioMissingDataInfo, 2) 284 } 285 286 store.accessDeprioMissingDataAfter = time.Now().Add(-time.Second) 287 lesserThanNextAccessTime := time.Now().Add(store.deprioritizedDataReconcilerInterval).Add(-2 * time.Second) 288 greaterThanNextAccessTime := time.Now().Add(store.deprioritizedDataReconcilerInterval).Add(2 * time.Second) 289 assertMissingDataInfo(t, store, expectedDeprioMissingDataInfo, 2) 290 291 require.True(t, store.accessDeprioMissingDataAfter.After(lesserThanNextAccessTime)) 292 require.False(t, store.accessDeprioMissingDataAfter.After(greaterThanNextAccessTime)) 293 for i := 0; i < 3; i++ { 294 assertMissingDataInfo(t, store, expectedPrioMissingDataInfo, 2) 295 } 296 }) 297 298 } 299 300 func TestExpiryDataNotIncluded(t *testing.T) { 301 ledgerid := "TestExpiryDataNotIncluded" 302 btlPolicy := btltestutil.SampleBTLPolicy( 303 map[[2]string]uint64{ 304 {"ns-1", "coll-1"}: 1, 305 {"ns-1", "coll-2"}: 0, 306 {"ns-2", "coll-1"}: 0, 307 {"ns-2", "coll-2"}: 2, 308 {"ns-3", "coll-1"}: 1, 309 {"ns-3", "coll-2"}: 0, 310 }, 311 ) 312 env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf()) 313 defer env.Cleanup() 314 store := env.TestStore 315 316 // construct missing data for block 1 317 blk1MissingData := make(ledger.TxMissingPvtDataMap) 318 // eligible missing data in tx1 319 blk1MissingData.Add(1, "ns-1", "coll-1", true) 320 blk1MissingData.Add(1, "ns-1", "coll-2", true) 321 // ineligible missing data in tx4 322 blk1MissingData.Add(4, "ns-3", "coll-1", false) 323 blk1MissingData.Add(4, "ns-3", "coll-2", false) 324 325 // construct missing data for block 2 326 blk2MissingData := make(ledger.TxMissingPvtDataMap) 327 // eligible missing data in tx1 328 blk2MissingData.Add(1, "ns-1", "coll-1", true) 329 blk2MissingData.Add(1, "ns-1", "coll-2", true) 330 331 // no pvt data with block 0 332 require.NoError(t, store.Commit(0, nil, nil)) 333 334 // write pvt data for block 1 335 testDataForBlk1 := []*ledger.TxPvtData{ 336 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 337 produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 338 } 339 require.NoError(t, store.Commit(1, testDataForBlk1, blk1MissingData)) 340 341 // write pvt data for block 2 342 testDataForBlk2 := []*ledger.TxPvtData{ 343 produceSamplePvtdata(t, 3, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 344 produceSamplePvtdata(t, 5, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 345 } 346 require.NoError(t, store.Commit(2, testDataForBlk2, blk2MissingData)) 347 348 retrievedData, _ := store.GetPvtDataByBlockNum(1, nil) 349 // block 1 data should still be not expired 350 for i, data := range retrievedData { 351 require.Equal(t, data.SeqInBlock, testDataForBlk1[i].SeqInBlock) 352 require.True(t, proto.Equal(data.WriteSet, testDataForBlk1[i].WriteSet)) 353 } 354 355 // none of the missing data entries would have expired 356 expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo) 357 // missing data in block2, tx1 358 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1") 359 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 360 361 // missing data in block1, tx1 362 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1") 363 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2") 364 365 missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(10) 366 require.NoError(t, err) 367 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 368 369 // Commit block 3 with no pvtdata 370 require.NoError(t, store.Commit(3, nil, nil)) 371 372 // After committing block 3, the data for "ns-1:coll1" of block 1 should have expired and should not be returned by the store 373 expectedPvtdataFromBlock1 := []*ledger.TxPvtData{ 374 produceSamplePvtdata(t, 2, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 375 produceSamplePvtdata(t, 4, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 376 } 377 retrievedData, _ = store.GetPvtDataByBlockNum(1, nil) 378 require.Equal(t, expectedPvtdataFromBlock1, retrievedData) 379 380 // After committing block 3, the missing data of "ns1-coll1" in block1-tx1 should have expired 381 expectedMissingPvtDataInfo = make(ledger.MissingPvtDataInfo) 382 // missing data in block2, tx1 383 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1") 384 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 385 // missing data in block1, tx1 386 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2") 387 388 missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10) 389 require.NoError(t, err) 390 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 391 392 // Commit block 4 with no pvtdata 393 require.NoError(t, store.Commit(4, nil, nil)) 394 395 // After committing block 4, the data for "ns-2:coll2" of block 1 should also have expired and should not be returned by the store 396 expectedPvtdataFromBlock1 = []*ledger.TxPvtData{ 397 produceSamplePvtdata(t, 2, []string{"ns-1:coll-2", "ns-2:coll-1"}), 398 produceSamplePvtdata(t, 4, []string{"ns-1:coll-2", "ns-2:coll-1"}), 399 } 400 retrievedData, _ = store.GetPvtDataByBlockNum(1, nil) 401 require.Equal(t, expectedPvtdataFromBlock1, retrievedData) 402 403 // Now, for block 2, "ns-1:coll1" should also have expired 404 expectedPvtdataFromBlock2 := []*ledger.TxPvtData{ 405 produceSamplePvtdata(t, 3, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 406 produceSamplePvtdata(t, 5, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 407 } 408 retrievedData, _ = store.GetPvtDataByBlockNum(2, nil) 409 require.Equal(t, expectedPvtdataFromBlock2, retrievedData) 410 411 // After committing block 4, the missing data of "ns1-coll1" in block2-tx1 should have expired 412 expectedMissingPvtDataInfo = make(ledger.MissingPvtDataInfo) 413 // missing data in block2, tx1 414 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 415 416 // missing data in block1, tx1 417 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2") 418 419 missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10) 420 require.NoError(t, err) 421 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 422 } 423 424 func TestStorePurge(t *testing.T) { 425 ledgerid := "TestStorePurge" 426 btlPolicy := btltestutil.SampleBTLPolicy( 427 map[[2]string]uint64{ 428 {"ns-1", "coll-1"}: 1, 429 {"ns-1", "coll-2"}: 0, 430 {"ns-2", "coll-1"}: 0, 431 {"ns-2", "coll-2"}: 4, 432 {"ns-3", "coll-1"}: 1, 433 {"ns-3", "coll-2"}: 0, 434 }, 435 ) 436 env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf()) 437 defer env.Cleanup() 438 s := env.TestStore 439 440 // no pvt data with block 0 441 require.NoError(t, s.Commit(0, nil, nil)) 442 443 // construct missing data for block 1 444 blk1MissingData := make(ledger.TxMissingPvtDataMap) 445 // eligible missing data in tx1 446 blk1MissingData.Add(1, "ns-1", "coll-1", true) 447 blk1MissingData.Add(1, "ns-1", "coll-2", true) 448 // eligible missing data in tx3 449 blk1MissingData.Add(3, "ns-1", "coll-1", true) 450 blk1MissingData.Add(3, "ns-1", "coll-2", true) 451 // ineligible missing data in tx4 452 blk1MissingData.Add(4, "ns-3", "coll-1", false) 453 blk1MissingData.Add(4, "ns-3", "coll-2", false) 454 455 // write pvt data for block 1 456 testDataForBlk1 := []*ledger.TxPvtData{ 457 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 458 produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 459 } 460 require.NoError(t, s.Commit(1, testDataForBlk1, blk1MissingData)) 461 462 // write pvt data for block 2 463 require.NoError(t, s.Commit(2, nil, nil)) 464 // data for ns-1:coll-1 and ns-2:coll-2 should exist in store 465 ns1Coll1 := &dataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-1", blkNum: 1}, txNum: 2} 466 ns2Coll2 := &dataKey{nsCollBlk: nsCollBlk{ns: "ns-2", coll: "coll-2", blkNum: 1}, txNum: 2} 467 468 // eligible missingData entries for ns-1:coll-1, ns-1:coll-2 (neverExpires) should exist in store 469 ns1Coll1elgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-1", blkNum: 1}} 470 ns1Coll2elgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-2", blkNum: 1}} 471 472 // ineligible missingData entries for ns-3:col-1, ns-3:coll-2 (neverExpires) should exist in store 473 ns3Coll1inelgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-3", coll: "coll-1", blkNum: 1}} 474 ns3Coll2inelgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-3", coll: "coll-2", blkNum: 1}} 475 476 testWaitForPurgerRoutineToFinish(s) 477 require.True(t, testDataKeyExists(t, s, ns1Coll1)) 478 require.True(t, testDataKeyExists(t, s, ns2Coll2)) 479 480 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 481 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 482 483 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD)) 484 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD)) 485 486 deprioritizedList := ledger.MissingPvtDataInfo{ 487 1: ledger.MissingBlockPvtdataInfo{ 488 3: { 489 { 490 Namespace: "ns-1", 491 Collection: "coll-1", 492 }, 493 { 494 Namespace: "ns-1", 495 Collection: "coll-2", 496 }, 497 }, 498 }, 499 } 500 require.NoError(t, s.CommitPvtDataOfOldBlocks(nil, deprioritizedList)) 501 502 // write pvt data for block 3 503 require.NoError(t, s.Commit(3, nil, nil)) 504 // data for ns-1:coll-1 and ns-2:coll-2 should exist in store (because purger should not be launched at block 3) 505 testWaitForPurgerRoutineToFinish(s) 506 require.True(t, testDataKeyExists(t, s, ns1Coll1)) 507 require.True(t, testDataKeyExists(t, s, ns2Coll2)) 508 // eligible missingData entries for ns-1:coll-1, ns-1:coll-2 (neverExpires) should exist in store 509 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 510 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 511 // some transactions which miss ns-1:coll-1 and ns-1:coll-2 has be moved to deprioritizedList list 512 require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 513 require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 514 // ineligible missingData entries for ns-3:col-1, ns-3:coll-2 (neverExpires) should exist in store 515 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD)) 516 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD)) 517 518 // write pvt data for block 4 519 require.NoError(t, s.Commit(4, nil, nil)) 520 // data for ns-1:coll-1 should not exist in store (because purger should be launched at block 4) 521 // but ns-2:coll-2 should exist because it expires at block 5 522 testWaitForPurgerRoutineToFinish(s) 523 require.False(t, testDataKeyExists(t, s, ns1Coll1)) 524 require.True(t, testDataKeyExists(t, s, ns2Coll2)) 525 // eligible missingData entries for ns-1:coll-1 should have expired and ns-1:coll-2 (neverExpires) should exist in store 526 require.False(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 527 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 528 require.False(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 529 require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 530 // ineligible missingData entries for ns-3:col-1 should have expired and ns-3:coll-2 (neverExpires) should exist in store 531 require.False(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD)) 532 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD)) 533 534 // write pvt data for block 5 535 require.NoError(t, s.Commit(5, nil, nil)) 536 // ns-2:coll-2 should exist because though the data expires at block 5 but purger is launched every second block 537 testWaitForPurgerRoutineToFinish(s) 538 require.False(t, testDataKeyExists(t, s, ns1Coll1)) 539 require.True(t, testDataKeyExists(t, s, ns2Coll2)) 540 541 // write pvt data for block 6 542 require.NoError(t, s.Commit(6, nil, nil)) 543 // ns-2:coll-2 should not exists now (because purger should be launched at block 6) 544 testWaitForPurgerRoutineToFinish(s) 545 require.False(t, testDataKeyExists(t, s, ns1Coll1)) 546 require.False(t, testDataKeyExists(t, s, ns2Coll2)) 547 548 // "ns-2:coll-1" should never have been purged (because, it was no btl was declared for this) 549 require.True(t, testDataKeyExists(t, s, &dataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-2", blkNum: 1}, txNum: 2})) 550 } 551 552 func TestStoreState(t *testing.T) { 553 btlPolicy := btltestutil.SampleBTLPolicy( 554 map[[2]string]uint64{ 555 {"ns-1", "coll-1"}: 0, 556 {"ns-1", "coll-2"}: 0, 557 }, 558 ) 559 env := NewTestStoreEnv(t, "TestStoreState", btlPolicy, pvtDataConf()) 560 defer env.Cleanup() 561 store := env.TestStore 562 testData := []*ledger.TxPvtData{ 563 produceSamplePvtdata(t, 0, []string{"ns-1:coll-1", "ns-1:coll-2"}), 564 } 565 _, ok := store.Commit(1, testData, nil).(*ErrIllegalArgs) 566 require.True(t, ok) 567 } 568 569 func TestPendingBatch(t *testing.T) { 570 btlPolicy := btltestutil.SampleBTLPolicy( 571 map[[2]string]uint64{ 572 {"ns-1", "coll-1"}: 0, 573 {"ns-1", "coll-2"}: 0, 574 }, 575 ) 576 env := NewTestStoreEnv(t, "TestPendingBatch", btlPolicy, pvtDataConf()) 577 defer env.Cleanup() 578 s := env.TestStore 579 existingLastBlockNum := uint64(25) 580 batch := s.db.NewUpdateBatch() 581 batch.Put(lastCommittedBlkkey, encodeLastCommittedBlockVal(existingLastBlockNum)) 582 require.NoError(t, s.db.WriteBatch(batch, true)) 583 s.lastCommittedBlock = existingLastBlockNum 584 s.isEmpty = false 585 testLastCommittedBlockHeight(t, existingLastBlockNum+1, s) 586 587 // assume that a block has been prepared in v142 and the peer was 588 // killed for upgrade. When the pvtdataStore is opened again with 589 // v2.0 peer, the pendingBatch should be marked as committed. 590 batch = s.db.NewUpdateBatch() 591 592 // store pvtData entries 593 dataKey := &dataKey{nsCollBlk{"ns-1", "coll-1", 26}, 1} 594 dataValue := &rwset.CollectionPvtReadWriteSet{CollectionName: "coll-1", Rwset: []byte("pvtdata")} 595 keyBytes := encodeDataKey(dataKey) 596 valueBytes, err := encodeDataValue(dataValue) 597 require.NoError(t, err) 598 batch.Put(keyBytes, valueBytes) 599 600 // store pendingBatch marker 601 batch.Put(pendingCommitKey, emptyValue) 602 603 // write to the store 604 require.NoError(t, s.db.WriteBatch(batch, true)) 605 testLastCommittedBlockHeight(t, existingLastBlockNum+1, s) 606 607 // as the block commit is pending, we cannot read the pvtData 608 hasPendingBatch, err := s.hasPendingCommit() 609 require.NoError(t, err) 610 require.Equal(t, true, hasPendingBatch) 611 pvtData, err := s.GetPvtDataByBlockNum(26, nil) 612 _, ok := err.(*ErrOutOfRange) 613 require.True(t, ok) 614 require.Nil(t, pvtData) 615 616 // emulate a version upgrade 617 env.CloseAndReopen() 618 619 s = env.TestStore 620 testLastCommittedBlockHeight(t, existingLastBlockNum+2, s) 621 hasPendingBatch, err = s.hasPendingCommit() 622 require.NoError(t, err) 623 require.Equal(t, false, hasPendingBatch) 624 testDataKeyExists(t, s, dataKey) 625 626 expectedPvtData := &rwset.TxPvtReadWriteSet{ 627 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 628 { 629 Namespace: "ns-1", 630 CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{ 631 dataValue, 632 }, 633 }, 634 }, 635 } 636 pvtData, err = s.GetPvtDataByBlockNum(26, nil) 637 require.NoError(t, err) 638 require.Equal(t, 1, len(pvtData)) 639 require.Equal(t, uint64(1), pvtData[0].SeqInBlock) 640 require.True(t, proto.Equal(expectedPvtData, pvtData[0].WriteSet)) 641 } 642 643 func TestCollElgEnabled(t *testing.T) { 644 conf := pvtDataConf() 645 testCollElgEnabled(t, conf) 646 conf.BatchesInterval = 1 647 conf.MaxBatchSize = 1 648 testCollElgEnabled(t, conf) 649 } 650 651 func testCollElgEnabled(t *testing.T, conf *PrivateDataConfig) { 652 ledgerid := "TestCollElgEnabled" 653 btlPolicy := btltestutil.SampleBTLPolicy( 654 map[[2]string]uint64{ 655 {"ns-1", "coll-1"}: 0, 656 {"ns-1", "coll-2"}: 0, 657 {"ns-2", "coll-1"}: 0, 658 {"ns-2", "coll-2"}: 0, 659 }, 660 ) 661 env := NewTestStoreEnv(t, ledgerid, btlPolicy, conf) 662 defer env.Cleanup() 663 testStore := env.TestStore 664 665 // Initial state: eligible for {ns-1:coll-1 and ns-2:coll-1 } 666 667 // no pvt data with block 0 668 require.NoError(t, testStore.Commit(0, nil, nil)) 669 670 // construct and commit block 1 671 blk1MissingData := make(ledger.TxMissingPvtDataMap) 672 blk1MissingData.Add(1, "ns-1", "coll-1", true) 673 blk1MissingData.Add(1, "ns-2", "coll-1", true) 674 blk1MissingData.Add(4, "ns-1", "coll-2", false) 675 blk1MissingData.Add(4, "ns-2", "coll-2", false) 676 testDataForBlk1 := []*ledger.TxPvtData{ 677 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1"}), 678 } 679 require.NoError(t, testStore.Commit(1, testDataForBlk1, blk1MissingData)) 680 681 // construct and commit block 2 682 blk2MissingData := make(ledger.TxMissingPvtDataMap) 683 // ineligible missing data in tx1 684 blk2MissingData.Add(1, "ns-1", "coll-2", false) 685 blk2MissingData.Add(1, "ns-2", "coll-2", false) 686 testDataForBlk2 := []*ledger.TxPvtData{ 687 produceSamplePvtdata(t, 3, []string{"ns-1:coll-1"}), 688 } 689 require.NoError(t, testStore.Commit(2, testDataForBlk2, blk2MissingData)) 690 691 // Retrieve and verify missing data reported 692 // Expected missing data should be only blk1-tx1 (because, the other missing data is marked as ineliigible) 693 expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo) 694 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1") 695 expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1") 696 missingPvtDataInfo, err := testStore.GetMissingPvtDataInfoForMostRecentBlocks(10) 697 require.NoError(t, err) 698 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 699 700 // Enable eligibility for {ns-1:coll2} 701 require.NoError(t, 702 testStore.ProcessCollsEligibilityEnabled( 703 5, 704 map[string][]string{ 705 "ns-1": {"coll-2"}, 706 }, 707 )) 708 testutilWaitForCollElgProcToFinish(testStore) 709 710 // Retrieve and verify missing data reported 711 // Expected missing data should include newly eiligible collections 712 expectedMissingPvtDataInfo.Add(1, 4, "ns-1", "coll-2") 713 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 714 missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10) 715 require.NoError(t, err) 716 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 717 718 // Enable eligibility for {ns-2:coll2} 719 require.NoError(t, 720 testStore.ProcessCollsEligibilityEnabled(6, 721 map[string][]string{ 722 "ns-2": {"coll-2"}, 723 }, 724 )) 725 testutilWaitForCollElgProcToFinish(testStore) 726 727 // Retrieve and verify missing data reported 728 // Expected missing data should include newly eiligible collections 729 expectedMissingPvtDataInfo.Add(1, 4, "ns-2", "coll-2") 730 expectedMissingPvtDataInfo.Add(2, 1, "ns-2", "coll-2") 731 missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10) 732 require.NoError(t, err) 733 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 734 } 735 736 func testLastCommittedBlockHeight(t *testing.T, expectedBlockHt uint64, store *Store) { 737 blkHt, err := store.LastCommittedBlockHeight() 738 require.NoError(t, err) 739 require.Equal(t, expectedBlockHt, blkHt) 740 } 741 742 func testDataKeyExists(t *testing.T, s *Store, dataKey *dataKey) bool { 743 dataKeyBytes := encodeDataKey(dataKey) 744 val, err := s.db.Get(dataKeyBytes) 745 require.NoError(t, err) 746 return len(val) != 0 747 } 748 749 func testElgPrioMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool { 750 key := encodeElgPrioMissingDataKey(missingDataKey) 751 752 val, err := s.db.Get(key) 753 require.NoError(t, err) 754 return len(val) != 0 755 } 756 757 func testElgDeprioMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool { 758 key := encodeElgDeprioMissingDataKey(missingDataKey) 759 760 val, err := s.db.Get(key) 761 require.NoError(t, err) 762 return len(val) != 0 763 } 764 func testInelgMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool { 765 key := encodeInelgMissingDataKey(missingDataKey) 766 767 val, err := s.db.Get(key) 768 require.NoError(t, err) 769 return len(val) != 0 770 } 771 772 func testWaitForPurgerRoutineToFinish(s *Store) { 773 time.Sleep(1 * time.Second) 774 s.purgerLock.Lock() 775 s.purgerLock.Unlock() 776 } 777 778 func testutilWaitForCollElgProcToFinish(s *Store) { 779 s.collElgProcSync.waitForDone() 780 } 781 782 func produceSamplePvtdata(t *testing.T, txNum uint64, nsColls []string) *ledger.TxPvtData { 783 builder := rwsetutil.NewRWSetBuilder() 784 for _, nsColl := range nsColls { 785 nsCollSplit := strings.Split(nsColl, ":") 786 ns := nsCollSplit[0] 787 coll := nsCollSplit[1] 788 builder.AddToPvtAndHashedWriteSet(ns, coll, fmt.Sprintf("key-%s-%s", ns, coll), []byte(fmt.Sprintf("value-%s-%s", ns, coll))) 789 } 790 simRes, err := builder.GetTxSimulationResults() 791 require.NoError(t, err) 792 return &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: simRes.PvtSimulationResults} 793 }