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