github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/pvtdatastorage/store_test.go (about) 1 /* 2 Copyright hechain. 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/hechain20/hechain/common/ledger/util/leveldbhelper" 19 "github.com/hechain20/hechain/core/ledger" 20 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil" 21 btltestutil "github.com/hechain20/hechain/core/ledger/pvtdatapolicy/testutil" 22 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 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.TxMissingPvtData) 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.TxMissingPvtData) 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 require.EqualError(t, err, "last committed block number [1] smaller than the requested block number [2]") 118 require.Nil(t, retrievedData) 119 120 // pvt data with block 2 - commit 121 require.NoError(t, store.Commit(2, testData, blk2MissingData)) 122 123 // retrieve the stored missing entries using GetMissingPvtDataInfoForMostRecentBlocks 124 // Only the code path of eligible entries would be covered in this unit-test. For 125 // ineligible entries, the code path will be covered in FAB-11437 126 127 expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo) 128 // missing data in block2, tx1 129 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1") 130 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 131 expectedMissingPvtDataInfo.Add(2, 3, "ns-1", "coll-1") 132 133 missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(1) 134 require.NoError(t, err) 135 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 136 137 // missing data in block1, tx1 138 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1") 139 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2") 140 expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1") 141 expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-2") 142 143 // missing data in block1, tx2 144 expectedMissingPvtDataInfo.Add(1, 2, "ns-3", "coll-1") 145 146 missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(2) 147 require.NoError(t, err) 148 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 149 150 missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10) 151 require.NoError(t, err) 152 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 153 } 154 155 func TestStoreIteratorError(t *testing.T) { 156 env := NewTestStoreEnv(t, "TestStoreIteratorError", nil, pvtDataConf()) 157 defer env.Cleanup() 158 store := env.TestStore 159 require.NoError(t, store.Commit(0, nil, nil)) 160 env.TestStoreProvider.Close() 161 errStr := "internal leveldb error while obtaining db iterator: leveldb: closed" 162 163 t.Run("GetPvtDataByBlockNum", func(t *testing.T) { 164 block, err := store.GetPvtDataByBlockNum(0, nil) 165 require.EqualError(t, err, errStr) 166 require.Nil(t, block) 167 }) 168 169 t.Run("GetMissingPvtDataInfoForMostRecentBlocks", func(t *testing.T) { 170 missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(10) 171 require.EqualError(t, err, errStr) 172 require.Nil(t, missingPvtDataInfo) 173 }) 174 175 t.Run("retrieveExpiryEntries", func(t *testing.T) { 176 expiryEntries, err := store.retrieveExpiryEntries(0, 1) 177 require.EqualError(t, err, errStr) 178 require.Nil(t, expiryEntries) 179 }) 180 181 t.Run("processCollElgEvents", func(t *testing.T) { 182 storeDir, err := ioutil.TempDir("", "pdstore") 183 require.NoError(t, err) 184 s := &Store{} 185 dbProvider, err := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: storeDir}) 186 require.NoError(t, err) 187 s.db = dbProvider.GetDBHandle("test-ledger") 188 dbProvider.Close() 189 require.EqualError(t, s.processCollElgEvents(), errStr) 190 }) 191 } 192 193 func TestGetMissingDataInfo(t *testing.T) { 194 setup := func(ledgerid string, c *PrivateDataConfig) *Store { 195 btlPolicy := btltestutil.SampleBTLPolicy( 196 map[[2]string]uint64{ 197 {"ns-1", "coll-1"}: 0, 198 {"ns-1", "coll-2"}: 0, 199 }, 200 ) 201 202 env := NewTestStoreEnv(t, ledgerid, btlPolicy, c) 203 t.Cleanup( 204 func() { 205 defer env.Cleanup() 206 }, 207 ) 208 store := env.TestStore 209 210 // construct missing data for block 1 211 blk1MissingData := make(ledger.TxMissingPvtData) 212 blk1MissingData.Add(1, "ns-1", "coll-1", true) 213 blk1MissingData.Add(1, "ns-1", "coll-2", true) 214 215 require.NoError(t, store.Commit(0, nil, nil)) 216 require.NoError(t, store.Commit(1, nil, blk1MissingData)) 217 218 deprioritizedList := ledger.MissingPvtDataInfo{ 219 1: ledger.MissingBlockPvtdataInfo{ 220 1: { 221 { 222 Namespace: "ns-1", 223 Collection: "coll-2", 224 }, 225 }, 226 }, 227 } 228 require.NoError(t, store.CommitPvtDataOfOldBlocks(nil, deprioritizedList)) 229 230 return env.TestStore 231 } 232 233 t.Run("always access deprioritized missing data", func(t *testing.T) { 234 conf := pvtDataConf() 235 conf.DeprioritizedDataReconcilerInterval = 0 236 store := setup("testGetMissingDataInfoFromDeprioList", conf) 237 238 expectedDeprioMissingDataInfo := ledger.MissingPvtDataInfo{ 239 1: ledger.MissingBlockPvtdataInfo{ 240 1: { 241 { 242 Namespace: "ns-1", 243 Collection: "coll-2", 244 }, 245 }, 246 }, 247 } 248 249 for i := 0; i < 2; i++ { 250 assertMissingDataInfo(t, store, expectedDeprioMissingDataInfo, 2) 251 } 252 }) 253 254 t.Run("change the deprioritized missing data access time", func(t *testing.T) { 255 conf := pvtDataConf() 256 conf.DeprioritizedDataReconcilerInterval = 300 * time.Minute 257 store := setup("testGetMissingDataInfoFromPrioAndDeprioList", conf) 258 259 expectedPrioMissingDataInfo := ledger.MissingPvtDataInfo{ 260 1: ledger.MissingBlockPvtdataInfo{ 261 1: { 262 { 263 Namespace: "ns-1", 264 Collection: "coll-1", 265 }, 266 }, 267 }, 268 } 269 270 expectedDeprioMissingDataInfo := ledger.MissingPvtDataInfo{ 271 1: ledger.MissingBlockPvtdataInfo{ 272 1: { 273 { 274 Namespace: "ns-1", 275 Collection: "coll-2", 276 }, 277 }, 278 }, 279 } 280 281 for i := 0; i < 3; i++ { 282 assertMissingDataInfo(t, store, expectedPrioMissingDataInfo, 2) 283 } 284 285 store.accessDeprioMissingDataAfter = time.Now().Add(-time.Second) 286 lesserThanNextAccessTime := time.Now().Add(store.deprioritizedDataReconcilerInterval).Add(-2 * time.Second) 287 greaterThanNextAccessTime := time.Now().Add(store.deprioritizedDataReconcilerInterval).Add(2 * time.Second) 288 assertMissingDataInfo(t, store, expectedDeprioMissingDataInfo, 2) 289 290 require.True(t, store.accessDeprioMissingDataAfter.After(lesserThanNextAccessTime)) 291 require.False(t, store.accessDeprioMissingDataAfter.After(greaterThanNextAccessTime)) 292 for i := 0; i < 3; i++ { 293 assertMissingDataInfo(t, store, expectedPrioMissingDataInfo, 2) 294 } 295 }) 296 } 297 298 func TestExpiryDataNotIncluded(t *testing.T) { 299 ledgerid := "TestExpiryDataNotIncluded" 300 btlPolicy := btltestutil.SampleBTLPolicy( 301 map[[2]string]uint64{ 302 {"ns-1", "coll-1"}: 1, 303 {"ns-1", "coll-2"}: 0, 304 {"ns-2", "coll-1"}: 0, 305 {"ns-2", "coll-2"}: 2, 306 {"ns-3", "coll-1"}: 1, 307 {"ns-3", "coll-2"}: 0, 308 }, 309 ) 310 env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf()) 311 defer env.Cleanup() 312 store := env.TestStore 313 314 // construct missing data for block 1 315 blk1MissingData := make(ledger.TxMissingPvtData) 316 // eligible missing data in tx1 317 blk1MissingData.Add(1, "ns-1", "coll-1", true) 318 blk1MissingData.Add(1, "ns-1", "coll-2", true) 319 // ineligible missing data in tx4 320 blk1MissingData.Add(4, "ns-3", "coll-1", false) 321 blk1MissingData.Add(4, "ns-3", "coll-2", false) 322 323 // construct missing data for block 2 324 blk2MissingData := make(ledger.TxMissingPvtData) 325 // eligible missing data in tx1 326 blk2MissingData.Add(1, "ns-1", "coll-1", true) 327 blk2MissingData.Add(1, "ns-1", "coll-2", true) 328 329 // no pvt data with block 0 330 require.NoError(t, store.Commit(0, nil, nil)) 331 332 // write pvt data for block 1 333 testDataForBlk1 := []*ledger.TxPvtData{ 334 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 335 produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 336 } 337 require.NoError(t, store.Commit(1, testDataForBlk1, blk1MissingData)) 338 339 // write pvt data for block 2 340 testDataForBlk2 := []*ledger.TxPvtData{ 341 produceSamplePvtdata(t, 3, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 342 produceSamplePvtdata(t, 5, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 343 } 344 require.NoError(t, store.Commit(2, testDataForBlk2, blk2MissingData)) 345 346 retrievedData, _ := store.GetPvtDataByBlockNum(1, nil) 347 // block 1 data should still be not expired 348 for i, data := range retrievedData { 349 require.Equal(t, data.SeqInBlock, testDataForBlk1[i].SeqInBlock) 350 require.True(t, proto.Equal(data.WriteSet, testDataForBlk1[i].WriteSet)) 351 } 352 353 // none of the missing data entries would have expired 354 expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo) 355 // missing data in block2, tx1 356 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1") 357 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 358 359 // missing data in block1, tx1 360 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1") 361 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2") 362 363 missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(10) 364 require.NoError(t, err) 365 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 366 367 // Commit block 3 with no pvtdata 368 require.NoError(t, store.Commit(3, nil, nil)) 369 370 // After committing block 3, the data for "ns-1:coll1" of block 1 should have expired and should not be returned by the store 371 expectedPvtdataFromBlock1 := []*ledger.TxPvtData{ 372 produceSamplePvtdata(t, 2, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 373 produceSamplePvtdata(t, 4, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 374 } 375 retrievedData, _ = store.GetPvtDataByBlockNum(1, nil) 376 require.Equal(t, expectedPvtdataFromBlock1, retrievedData) 377 378 // After committing block 3, the missing data of "ns1-coll1" in block1-tx1 should have expired 379 expectedMissingPvtDataInfo = make(ledger.MissingPvtDataInfo) 380 // missing data in block2, tx1 381 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1") 382 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 383 // missing data in block1, tx1 384 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2") 385 386 missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10) 387 require.NoError(t, err) 388 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 389 390 // Commit block 4 with no pvtdata 391 require.NoError(t, store.Commit(4, nil, nil)) 392 393 // 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 394 expectedPvtdataFromBlock1 = []*ledger.TxPvtData{ 395 produceSamplePvtdata(t, 2, []string{"ns-1:coll-2", "ns-2:coll-1"}), 396 produceSamplePvtdata(t, 4, []string{"ns-1:coll-2", "ns-2:coll-1"}), 397 } 398 retrievedData, _ = store.GetPvtDataByBlockNum(1, nil) 399 require.Equal(t, expectedPvtdataFromBlock1, retrievedData) 400 401 // Now, for block 2, "ns-1:coll1" should also have expired 402 expectedPvtdataFromBlock2 := []*ledger.TxPvtData{ 403 produceSamplePvtdata(t, 3, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 404 produceSamplePvtdata(t, 5, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 405 } 406 retrievedData, _ = store.GetPvtDataByBlockNum(2, nil) 407 require.Equal(t, expectedPvtdataFromBlock2, retrievedData) 408 409 // After committing block 4, the missing data of "ns1-coll1" in block2-tx1 should have expired 410 expectedMissingPvtDataInfo = make(ledger.MissingPvtDataInfo) 411 // missing data in block2, tx1 412 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 413 414 // missing data in block1, tx1 415 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2") 416 417 missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10) 418 require.NoError(t, err) 419 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 420 } 421 422 func TestStorePurge(t *testing.T) { 423 ledgerid := "TestStorePurge" 424 btlPolicy := btltestutil.SampleBTLPolicy( 425 map[[2]string]uint64{ 426 {"ns-1", "coll-1"}: 1, 427 {"ns-1", "coll-2"}: 0, 428 {"ns-2", "coll-1"}: 0, 429 {"ns-2", "coll-2"}: 4, 430 {"ns-3", "coll-1"}: 1, 431 {"ns-3", "coll-2"}: 0, 432 }, 433 ) 434 env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf()) 435 defer env.Cleanup() 436 s := env.TestStore 437 438 // no pvt data with block 0 439 require.NoError(t, s.Commit(0, nil, nil)) 440 441 // construct missing data for block 1 442 blk1MissingData := make(ledger.TxMissingPvtData) 443 // eligible missing data in tx1 444 blk1MissingData.Add(1, "ns-1", "coll-1", true) 445 blk1MissingData.Add(1, "ns-1", "coll-2", true) 446 // eligible missing data in tx3 447 blk1MissingData.Add(3, "ns-1", "coll-1", true) 448 blk1MissingData.Add(3, "ns-1", "coll-2", true) 449 // ineligible missing data in tx4 450 blk1MissingData.Add(4, "ns-3", "coll-1", false) 451 blk1MissingData.Add(4, "ns-3", "coll-2", false) 452 453 // write pvt data for block 1 454 testDataForBlk1 := []*ledger.TxPvtData{ 455 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 456 produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 457 } 458 require.NoError(t, s.Commit(1, testDataForBlk1, blk1MissingData)) 459 460 // write pvt data for block 2 461 require.NoError(t, s.Commit(2, nil, nil)) 462 // data for ns-1:coll-1 and ns-2:coll-2 should exist in store 463 ns1Coll1 := &dataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-1", blkNum: 1}, txNum: 2} 464 ns2Coll2 := &dataKey{nsCollBlk: nsCollBlk{ns: "ns-2", coll: "coll-2", blkNum: 1}, txNum: 2} 465 466 // eligible missingData entries for ns-1:coll-1, ns-1:coll-2 (neverExpires) should exist in store 467 ns1Coll1elgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-1", blkNum: 1}} 468 ns1Coll2elgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-2", blkNum: 1}} 469 470 // ineligible missingData entries for ns-3:col-1, ns-3:coll-2 (neverExpires) should exist in store 471 ns3Coll1inelgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-3", coll: "coll-1", blkNum: 1}} 472 ns3Coll2inelgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-3", coll: "coll-2", blkNum: 1}} 473 474 testWaitForPurgerRoutineToFinish(s) 475 require.True(t, testDataKeyExists(t, s, ns1Coll1)) 476 require.True(t, testDataKeyExists(t, s, ns2Coll2)) 477 478 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 479 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 480 481 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD)) 482 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD)) 483 484 deprioritizedList := ledger.MissingPvtDataInfo{ 485 1: ledger.MissingBlockPvtdataInfo{ 486 3: { 487 { 488 Namespace: "ns-1", 489 Collection: "coll-1", 490 }, 491 { 492 Namespace: "ns-1", 493 Collection: "coll-2", 494 }, 495 }, 496 }, 497 } 498 require.NoError(t, s.CommitPvtDataOfOldBlocks(nil, deprioritizedList)) 499 500 // write pvt data for block 3 501 require.NoError(t, s.Commit(3, nil, nil)) 502 // data for ns-1:coll-1 and ns-2:coll-2 should exist in store (because purger should not be launched at block 3) 503 testWaitForPurgerRoutineToFinish(s) 504 require.True(t, testDataKeyExists(t, s, ns1Coll1)) 505 require.True(t, testDataKeyExists(t, s, ns2Coll2)) 506 // eligible missingData entries for ns-1:coll-1, ns-1:coll-2 (neverExpires) should exist in store 507 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 508 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 509 // some transactions which miss ns-1:coll-1 and ns-1:coll-2 has be moved to deprioritizedList list 510 require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 511 require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 512 // ineligible missingData entries for ns-3:col-1, ns-3:coll-2 (neverExpires) should exist in store 513 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD)) 514 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD)) 515 516 // write pvt data for block 4 517 require.NoError(t, s.Commit(4, nil, nil)) 518 // data for ns-1:coll-1 should not exist in store (because purger should be launched at block 4) 519 // but ns-2:coll-2 should exist because it expires at block 5 520 testWaitForPurgerRoutineToFinish(s) 521 require.False(t, testDataKeyExists(t, s, ns1Coll1)) 522 require.True(t, testDataKeyExists(t, s, ns2Coll2)) 523 // eligible missingData entries for ns-1:coll-1 should have expired and ns-1:coll-2 (neverExpires) should exist in store 524 require.False(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 525 require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 526 require.False(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll1elgMD)) 527 require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll2elgMD)) 528 // ineligible missingData entries for ns-3:col-1 should have expired and ns-3:coll-2 (neverExpires) should exist in store 529 require.False(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD)) 530 require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD)) 531 532 // write pvt data for block 5 533 require.NoError(t, s.Commit(5, nil, nil)) 534 // ns-2:coll-2 should exist because though the data expires at block 5 but purger is launched every second block 535 testWaitForPurgerRoutineToFinish(s) 536 require.False(t, testDataKeyExists(t, s, ns1Coll1)) 537 require.True(t, testDataKeyExists(t, s, ns2Coll2)) 538 539 // write pvt data for block 6 540 require.NoError(t, s.Commit(6, nil, nil)) 541 // ns-2:coll-2 should not exists now (because purger should be launched at block 6) 542 testWaitForPurgerRoutineToFinish(s) 543 require.False(t, testDataKeyExists(t, s, ns1Coll1)) 544 require.False(t, testDataKeyExists(t, s, ns2Coll2)) 545 546 // "ns-2:coll-1" should never have been purged (because, it was no btl was declared for this) 547 require.True(t, testDataKeyExists(t, s, &dataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-2", blkNum: 1}, txNum: 2})) 548 } 549 550 func TestStoreState(t *testing.T) { 551 btlPolicy := btltestutil.SampleBTLPolicy( 552 map[[2]string]uint64{ 553 {"ns-1", "coll-1"}: 0, 554 {"ns-1", "coll-2"}: 0, 555 }, 556 ) 557 env := NewTestStoreEnv(t, "TestStoreState", btlPolicy, pvtDataConf()) 558 defer env.Cleanup() 559 store := env.TestStore 560 testData := []*ledger.TxPvtData{ 561 produceSamplePvtdata(t, 0, []string{"ns-1:coll-1", "ns-1:coll-2"}), 562 } 563 564 require.EqualError(t, 565 store.Commit(1, testData, nil), 566 "expected block number=0, received block number=1", 567 ) 568 } 569 570 func TestPendingBatch(t *testing.T) { 571 btlPolicy := btltestutil.SampleBTLPolicy( 572 map[[2]string]uint64{ 573 {"ns-1", "coll-1"}: 0, 574 {"ns-1", "coll-2"}: 0, 575 }, 576 ) 577 env := NewTestStoreEnv(t, "TestPendingBatch", btlPolicy, pvtDataConf()) 578 defer env.Cleanup() 579 s := env.TestStore 580 existingLastBlockNum := uint64(25) 581 batch := s.db.NewUpdateBatch() 582 batch.Put(lastCommittedBlkkey, encodeLastCommittedBlockVal(existingLastBlockNum)) 583 require.NoError(t, s.db.WriteBatch(batch, true)) 584 s.lastCommittedBlock = existingLastBlockNum 585 s.isEmpty = false 586 testLastCommittedBlockHeight(t, existingLastBlockNum+1, s) 587 588 // assume that a block has been prepared in v142 and the peer was 589 // killed for upgrade. When the pvtdataStore is opened again with 590 // v2.0 peer, the pendingBatch should be marked as committed. 591 batch = s.db.NewUpdateBatch() 592 593 // store pvtData entries 594 dataKey := &dataKey{nsCollBlk{"ns-1", "coll-1", 26}, 1} 595 dataValue := &rwset.CollectionPvtReadWriteSet{CollectionName: "coll-1", Rwset: []byte("pvtdata")} 596 keyBytes := encodeDataKey(dataKey) 597 valueBytes, err := encodeDataValue(dataValue) 598 require.NoError(t, err) 599 batch.Put(keyBytes, valueBytes) 600 601 // store pendingBatch marker 602 batch.Put(pendingCommitKey, emptyValue) 603 604 // write to the store 605 require.NoError(t, s.db.WriteBatch(batch, true)) 606 testLastCommittedBlockHeight(t, existingLastBlockNum+1, s) 607 608 // as the block commit is pending, we cannot read the pvtData 609 hasPendingBatch, err := s.hasPendingCommit() 610 require.NoError(t, err) 611 require.Equal(t, true, hasPendingBatch) 612 pvtData, err := s.GetPvtDataByBlockNum(26, nil) 613 require.EqualError(t, err, "last committed block number [25] smaller than the requested block number [26]") 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 TestDrop(t *testing.T) { 652 ledgerid := "testremove" 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 662 env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf()) 663 defer env.Cleanup() 664 store := env.TestStore 665 666 testData := []*ledger.TxPvtData{ 667 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 668 produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}), 669 } 670 671 // construct missing data for block 1 672 blk1MissingData := make(ledger.TxMissingPvtData) 673 674 // eligible missing data in tx1 675 blk1MissingData.Add(1, "ns-1", "coll-1", true) 676 blk1MissingData.Add(1, "ns-1", "coll-2", true) 677 blk1MissingData.Add(1, "ns-2", "coll-1", true) 678 blk1MissingData.Add(1, "ns-2", "coll-2", true) 679 680 // no pvt data with block 0 681 require.NoError(t, store.Commit(0, nil, nil)) 682 683 // pvt data with block 1 - commit 684 require.NoError(t, store.Commit(1, testData, blk1MissingData)) 685 686 // pvt data retrieval for block 0 should return nil 687 var nilFilter ledger.PvtNsCollFilter 688 retrievedData, err := store.GetPvtDataByBlockNum(0, nilFilter) 689 require.NoError(t, err) 690 require.Nil(t, retrievedData) 691 692 // pvt data retrieval for block 1 should return full pvtdata 693 retrievedData, err = store.GetPvtDataByBlockNum(1, nilFilter) 694 require.NoError(t, err) 695 require.Equal(t, len(testData), len(retrievedData)) 696 for i, data := range retrievedData { 697 require.Equal(t, data.SeqInBlock, testData[i].SeqInBlock) 698 require.True(t, proto.Equal(data.WriteSet, testData[i].WriteSet)) 699 } 700 701 require.NoError(t, env.TestStoreProvider.Drop(ledgerid)) 702 703 // pvt data should be removed 704 retrievedData, err = store.GetPvtDataByBlockNum(0, nilFilter) 705 require.NoError(t, err) 706 require.Nil(t, retrievedData) 707 708 retrievedData, err = store.GetPvtDataByBlockNum(1, nilFilter) 709 require.NoError(t, err) 710 require.Nil(t, retrievedData) 711 712 itr, err := env.TestStoreProvider.dbProvider.GetDBHandle(ledgerid).GetIterator(nil, nil) 713 require.NoError(t, err) 714 require.False(t, itr.Next()) 715 716 // drop again is not an error 717 require.NoError(t, env.TestStoreProvider.Drop(ledgerid)) 718 719 // negative test 720 env.TestStoreProvider.Close() 721 require.EqualError(t, env.TestStoreProvider.Drop(ledgerid), "internal leveldb error while obtaining db iterator: leveldb: closed") 722 } 723 724 func testCollElgEnabled(t *testing.T, conf *PrivateDataConfig) { 725 ledgerid := "TestCollElgEnabled" 726 btlPolicy := btltestutil.SampleBTLPolicy( 727 map[[2]string]uint64{ 728 {"ns-1", "coll-1"}: 0, 729 {"ns-1", "coll-2"}: 0, 730 {"ns-2", "coll-1"}: 0, 731 {"ns-2", "coll-2"}: 0, 732 }, 733 ) 734 env := NewTestStoreEnv(t, ledgerid, btlPolicy, conf) 735 defer env.Cleanup() 736 testStore := env.TestStore 737 738 // Initial state: eligible for {ns-1:coll-1 and ns-2:coll-1 } 739 740 // no pvt data with block 0 741 require.NoError(t, testStore.Commit(0, nil, nil)) 742 743 // construct and commit block 1 744 blk1MissingData := make(ledger.TxMissingPvtData) 745 blk1MissingData.Add(1, "ns-1", "coll-1", true) 746 blk1MissingData.Add(1, "ns-2", "coll-1", true) 747 blk1MissingData.Add(4, "ns-1", "coll-2", false) 748 blk1MissingData.Add(4, "ns-2", "coll-2", false) 749 testDataForBlk1 := []*ledger.TxPvtData{ 750 produceSamplePvtdata(t, 2, []string{"ns-1:coll-1"}), 751 } 752 require.NoError(t, testStore.Commit(1, testDataForBlk1, blk1MissingData)) 753 754 // construct and commit block 2 755 blk2MissingData := make(ledger.TxMissingPvtData) 756 // ineligible missing data in tx1 757 blk2MissingData.Add(1, "ns-1", "coll-2", false) 758 blk2MissingData.Add(1, "ns-2", "coll-2", false) 759 testDataForBlk2 := []*ledger.TxPvtData{ 760 produceSamplePvtdata(t, 3, []string{"ns-1:coll-1"}), 761 } 762 require.NoError(t, testStore.Commit(2, testDataForBlk2, blk2MissingData)) 763 764 // Retrieve and verify missing data reported 765 // Expected missing data should be only blk1-tx1 (because, the other missing data is marked as ineliigible) 766 expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo) 767 expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1") 768 expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1") 769 missingPvtDataInfo, err := testStore.GetMissingPvtDataInfoForMostRecentBlocks(10) 770 require.NoError(t, err) 771 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 772 773 // Enable eligibility for {ns-1:coll2} 774 require.NoError(t, 775 testStore.ProcessCollsEligibilityEnabled( 776 5, 777 map[string][]string{ 778 "ns-1": {"coll-2"}, 779 }, 780 )) 781 testutilWaitForCollElgProcToFinish(testStore) 782 783 // Retrieve and verify missing data reported 784 // Expected missing data should include newly eiligible collections 785 expectedMissingPvtDataInfo.Add(1, 4, "ns-1", "coll-2") 786 expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2") 787 missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10) 788 require.NoError(t, err) 789 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 790 791 // Enable eligibility for {ns-2:coll2} 792 require.NoError(t, 793 testStore.ProcessCollsEligibilityEnabled(6, 794 map[string][]string{ 795 "ns-2": {"coll-2"}, 796 }, 797 )) 798 testutilWaitForCollElgProcToFinish(testStore) 799 800 // Retrieve and verify missing data reported 801 // Expected missing data should include newly eiligible collections 802 expectedMissingPvtDataInfo.Add(1, 4, "ns-2", "coll-2") 803 expectedMissingPvtDataInfo.Add(2, 1, "ns-2", "coll-2") 804 missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10) 805 require.NoError(t, err) 806 require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo) 807 } 808 809 func testLastCommittedBlockHeight(t *testing.T, expectedBlockHt uint64, store *Store) { 810 blkHt, err := store.LastCommittedBlockHeight() 811 require.NoError(t, err) 812 require.Equal(t, expectedBlockHt, blkHt) 813 } 814 815 func testDataKeyExists(t *testing.T, s *Store, dataKey *dataKey) bool { 816 dataKeyBytes := encodeDataKey(dataKey) 817 val, err := s.db.Get(dataKeyBytes) 818 require.NoError(t, err) 819 return len(val) != 0 820 } 821 822 func testElgPrioMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool { 823 key := encodeElgPrioMissingDataKey(missingDataKey) 824 825 val, err := s.db.Get(key) 826 require.NoError(t, err) 827 return len(val) != 0 828 } 829 830 func testElgDeprioMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool { 831 key := encodeElgDeprioMissingDataKey(missingDataKey) 832 833 val, err := s.db.Get(key) 834 require.NoError(t, err) 835 return len(val) != 0 836 } 837 838 func testInelgMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool { 839 key := encodeInelgMissingDataKey(missingDataKey) 840 841 val, err := s.db.Get(key) 842 require.NoError(t, err) 843 return len(val) != 0 844 } 845 846 func testWaitForPurgerRoutineToFinish(s *Store) { 847 time.Sleep(1 * time.Second) 848 s.purgerLock.Lock() 849 s.purgerLock.Unlock() //lint:ignore SA2001 syncpoint 850 } 851 852 func testutilWaitForCollElgProcToFinish(s *Store) { 853 s.collElgProcSync.waitForDone() 854 } 855 856 func produceSamplePvtdata(t *testing.T, txNum uint64, nsColls []string) *ledger.TxPvtData { 857 builder := rwsetutil.NewRWSetBuilder() 858 for _, nsColl := range nsColls { 859 nsCollSplit := strings.Split(nsColl, ":") 860 ns := nsCollSplit[0] 861 coll := nsCollSplit[1] 862 builder.AddToPvtAndHashedWriteSet(ns, coll, fmt.Sprintf("key-%s-%s", ns, coll), []byte(fmt.Sprintf("value-%s-%s", ns, coll))) 863 } 864 simRes, err := builder.GetTxSimulationResults() 865 require.NoError(t, err) 866 return &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: simRes.PvtSimulationResults} 867 }