github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/transientstore/store_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package transientstore 8 9 import ( 10 "fmt" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 "sort" 15 "testing" 16 17 "github.com/golang/protobuf/proto" 18 "github.com/hechain20/hechain/common/policydsl" 19 commonutil "github.com/hechain20/hechain/common/util" 20 "github.com/hechain20/hechain/core/ledger" 21 "github.com/hechain20/hechain/core/ledger/util" 22 "github.com/hyperledger/fabric-protos-go/common" 23 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 24 "github.com/hyperledger/fabric-protos-go/peer" 25 "github.com/hyperledger/fabric-protos-go/transientstore" 26 "github.com/stretchr/testify/require" 27 ) 28 29 func TestMain(m *testing.M) { 30 tempdir, err := ioutil.TempDir("", "ts") 31 if err != nil { 32 panic(err) 33 } 34 35 rc := m.Run() 36 37 os.RemoveAll(tempdir) 38 os.Exit(rc) 39 } 40 41 type testEnv struct { 42 storeProvider StoreProvider 43 store *Store 44 tempdir string 45 storedir string 46 cleanup func() 47 } 48 49 func initTestEnv(t *testing.T) *testEnv { 50 tempdir, err := ioutil.TempDir("", "ts") 51 require.NoErrorf(t, err, "failed to create test directory [%s]", tempdir) 52 53 storedir := filepath.Join(tempdir, "transientstore") 54 storeProvider, err := NewStoreProvider(storedir) 55 require.NoError(t, err) 56 require.NotNil(t, storeProvider) 57 58 store, err := storeProvider.OpenStore("TestStore") 59 require.NoError(t, err) 60 require.NotNil(t, store) 61 62 return &testEnv{ 63 storeProvider: storeProvider, 64 store: store, 65 tempdir: tempdir, 66 storedir: storedir, 67 cleanup: func() { 68 require.NoError(t, os.RemoveAll(tempdir)) 69 }, 70 } 71 } 72 73 func TestPurgeIndexKeyCodingEncoding(t *testing.T) { 74 require := require.New(t) 75 blkHts := []uint64{0, 10, 20000} 76 txids := []string{"txid", ""} 77 uuids := []string{"uuid", ""} 78 for _, blkHt := range blkHts { 79 for _, txid := range txids { 80 for _, uuid := range uuids { 81 testCase := fmt.Sprintf("blkHt=%d,txid=%s,uuid=%s", blkHt, txid, uuid) 82 t.Run(testCase, func(t *testing.T) { 83 t.Logf("Running test case [%s]", testCase) 84 purgeIndexKey := createCompositeKeyForPurgeIndexByHeight(blkHt, txid, uuid) 85 txid1, uuid1, blkHt1, err := splitCompositeKeyOfPurgeIndexByHeight(purgeIndexKey) 86 require.NoError(err) 87 require.Equal(txid, txid1) 88 require.Equal(uuid, uuid1) 89 require.Equal(blkHt, blkHt1) 90 }) 91 } 92 } 93 } 94 } 95 96 func TestRWSetKeyCodingEncoding(t *testing.T) { 97 require := require.New(t) 98 blkHts := []uint64{0, 10, 20000} 99 txids := []string{"txid", ""} 100 uuids := []string{"uuid", ""} 101 for _, blkHt := range blkHts { 102 for _, txid := range txids { 103 for _, uuid := range uuids { 104 testCase := fmt.Sprintf("blkHt=%d,txid=%s,uuid=%s", blkHt, txid, uuid) 105 t.Run(testCase, func(t *testing.T) { 106 t.Logf("Running test case [%s]", testCase) 107 rwsetKey := createCompositeKeyForPvtRWSet(txid, uuid, blkHt) 108 uuid1, blkHt1, err := splitCompositeKeyOfPvtRWSet(rwsetKey) 109 require.NoError(err) 110 require.Equal(uuid, uuid1) 111 require.Equal(blkHt, blkHt1) 112 }) 113 } 114 } 115 } 116 } 117 118 func TestTransientStorePersistAndRetrieve(t *testing.T) { 119 env := initTestEnv(t) 120 defer env.cleanup() 121 testStore := env.store 122 require := require.New(t) 123 txid := "txid-1" 124 samplePvtRWSetWithConfig := samplePvtDataWithConfigInfo(t) 125 126 // Create private simulation results for txid-1 127 var endorsersResults []*EndorserPvtSimulationResults 128 129 // Results produced by endorser 1 130 endorser0SimulationResults := &EndorserPvtSimulationResults{ 131 ReceivedAtBlockHeight: 10, 132 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 133 } 134 endorsersResults = append(endorsersResults, endorser0SimulationResults) 135 136 // Results produced by endorser 2 137 endorser1SimulationResults := &EndorserPvtSimulationResults{ 138 ReceivedAtBlockHeight: 10, 139 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 140 } 141 endorsersResults = append(endorsersResults, endorser1SimulationResults) 142 143 // Persist simulation results into store 144 var err error 145 for i := 0; i < len(endorsersResults); i++ { 146 err = testStore.Persist(txid, endorsersResults[i].ReceivedAtBlockHeight, 147 endorsersResults[i].PvtSimulationResultsWithConfig) 148 require.NoError(err) 149 } 150 151 // Retrieve simulation results of txid-1 from store 152 iter, err := testStore.GetTxPvtRWSetByTxid(txid, nil) 153 require.NoError(err) 154 155 var actualEndorsersResults []*EndorserPvtSimulationResults 156 for { 157 result, err := iter.Next() 158 require.NoError(err) 159 if result == nil { 160 break 161 } 162 actualEndorsersResults = append(actualEndorsersResults, result) 163 } 164 iter.Close() 165 sortResults(endorsersResults) 166 sortResults(actualEndorsersResults) 167 require.Equal(endorsersResults, actualEndorsersResults) 168 } 169 170 func TestTransientStorePersistAndRetrieveBothOldAndNewProto(t *testing.T) { 171 env := initTestEnv(t) 172 defer env.cleanup() 173 testStore := env.store 174 require := require.New(t) 175 txid := "txid-1" 176 var receivedAtBlockHeight uint64 = 10 177 var err error 178 179 // Create and persist private simulation results with old proto for txid-1 180 samplePvtRWSet := samplePvtData(t) 181 err = testStore.persistOldProto(txid, receivedAtBlockHeight, samplePvtRWSet) 182 require.NoError(err) 183 184 // Create and persist private simulation results with new proto for txid-1 185 samplePvtRWSetWithConfig := samplePvtDataWithConfigInfo(t) 186 err = testStore.Persist(txid, receivedAtBlockHeight, samplePvtRWSetWithConfig) 187 require.NoError(err) 188 189 // Construct the expected results 190 var expectedEndorsersResults []*EndorserPvtSimulationResults 191 192 pvtRWSetWithConfigInfo := &transientstore.TxPvtReadWriteSetWithConfigInfo{ 193 PvtRwset: samplePvtRWSet, 194 } 195 196 endorser0SimulationResults := &EndorserPvtSimulationResults{ 197 ReceivedAtBlockHeight: receivedAtBlockHeight, 198 PvtSimulationResultsWithConfig: pvtRWSetWithConfigInfo, 199 } 200 expectedEndorsersResults = append(expectedEndorsersResults, endorser0SimulationResults) 201 202 endorser1SimulationResults := &EndorserPvtSimulationResults{ 203 ReceivedAtBlockHeight: receivedAtBlockHeight, 204 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 205 } 206 expectedEndorsersResults = append(expectedEndorsersResults, endorser1SimulationResults) 207 208 // Retrieve simulation results of txid-1 from store 209 iter, err := testStore.GetTxPvtRWSetByTxid(txid, nil) 210 require.NoError(err) 211 212 var actualEndorsersResults []*EndorserPvtSimulationResults 213 for { 214 result, err := iter.Next() 215 require.NoError(err) 216 if result == nil { 217 break 218 } 219 actualEndorsersResults = append(actualEndorsersResults, result) 220 } 221 iter.Close() 222 sortResults(expectedEndorsersResults) 223 sortResults(actualEndorsersResults) 224 require.Equal(expectedEndorsersResults, actualEndorsersResults) 225 } 226 227 func TestTransientStorePurgeByTxids(t *testing.T) { 228 env := initTestEnv(t) 229 defer env.cleanup() 230 testStore := env.store 231 require := require.New(t) 232 233 var txids []string 234 var endorsersResults []*EndorserPvtSimulationResults 235 236 samplePvtRWSetWithConfig := samplePvtDataWithConfigInfo(t) 237 238 // Create two private write set entry for txid-1 239 txids = append(txids, "txid-1") 240 endorser0SimulationResults := &EndorserPvtSimulationResults{ 241 ReceivedAtBlockHeight: 10, 242 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 243 } 244 endorsersResults = append(endorsersResults, endorser0SimulationResults) 245 246 txids = append(txids, "txid-1") 247 endorser1SimulationResults := &EndorserPvtSimulationResults{ 248 ReceivedAtBlockHeight: 11, 249 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 250 } 251 endorsersResults = append(endorsersResults, endorser1SimulationResults) 252 253 // Create one private write set entry for txid-2 254 txids = append(txids, "txid-2") 255 endorser2SimulationResults := &EndorserPvtSimulationResults{ 256 ReceivedAtBlockHeight: 11, 257 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 258 } 259 endorsersResults = append(endorsersResults, endorser2SimulationResults) 260 261 // Create three private write set entry for txid-3 262 txids = append(txids, "txid-3") 263 endorser3SimulationResults := &EndorserPvtSimulationResults{ 264 ReceivedAtBlockHeight: 12, 265 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 266 } 267 endorsersResults = append(endorsersResults, endorser3SimulationResults) 268 269 txids = append(txids, "txid-3") 270 endorser4SimulationResults := &EndorserPvtSimulationResults{ 271 ReceivedAtBlockHeight: 12, 272 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 273 } 274 endorsersResults = append(endorsersResults, endorser4SimulationResults) 275 276 txids = append(txids, "txid-3") 277 endorser5SimulationResults := &EndorserPvtSimulationResults{ 278 ReceivedAtBlockHeight: 13, 279 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 280 } 281 endorsersResults = append(endorsersResults, endorser5SimulationResults) 282 283 var err error 284 for i := 0; i < len(txids); i++ { 285 err = testStore.Persist(txids[i], endorsersResults[i].ReceivedAtBlockHeight, 286 endorsersResults[i].PvtSimulationResultsWithConfig) 287 require.NoError(err) 288 } 289 290 // Retrieve simulation results of txid-2 from store 291 iter, err := testStore.GetTxPvtRWSetByTxid("txid-2", nil) 292 require.NoError(err) 293 294 // Expected results for txid-2 295 var expectedEndorsersResults []*EndorserPvtSimulationResults 296 expectedEndorsersResults = append(expectedEndorsersResults, endorser2SimulationResults) 297 298 // Check whether actual results and expected results are same 299 var actualEndorsersResults []*EndorserPvtSimulationResults 300 for { 301 result, err := iter.Next() 302 require.NoError(err) 303 if result == nil { 304 break 305 } 306 actualEndorsersResults = append(actualEndorsersResults, result) 307 } 308 iter.Close() 309 310 // Note that the ordering of actualRes and expectedRes is dependent on the uuid. Hence, we are sorting 311 // expectedRes and actualRes. 312 sortResults(expectedEndorsersResults) 313 sortResults(actualEndorsersResults) 314 315 require.Equal(len(expectedEndorsersResults), len(actualEndorsersResults)) 316 for i, expected := range expectedEndorsersResults { 317 require.Equal(expected.ReceivedAtBlockHeight, actualEndorsersResults[i].ReceivedAtBlockHeight) 318 require.True(proto.Equal(expected.PvtSimulationResultsWithConfig, actualEndorsersResults[i].PvtSimulationResultsWithConfig)) 319 } 320 321 // Remove all private write set of txid-2 and txid-3 322 toRemoveTxids := []string{"txid-2", "txid-3"} 323 err = testStore.PurgeByTxids(toRemoveTxids) 324 require.NoError(err) 325 326 for _, txid := range toRemoveTxids { 327 328 // Check whether private write sets of txid-2 are removed 329 var expectedEndorsersResults *EndorserPvtSimulationResults = nil 330 iter, err = testStore.GetTxPvtRWSetByTxid(txid, nil) 331 require.NoError(err) 332 // Should return nil, nil 333 result, err := iter.Next() 334 require.NoError(err) 335 require.Equal(expectedEndorsersResults, result) 336 } 337 338 // Retrieve simulation results of txid-1 from store 339 iter, err = testStore.GetTxPvtRWSetByTxid("txid-1", nil) 340 require.NoError(err) 341 342 // Expected results for txid-1 343 expectedEndorsersResults = nil 344 expectedEndorsersResults = append(expectedEndorsersResults, endorser0SimulationResults) 345 expectedEndorsersResults = append(expectedEndorsersResults, endorser1SimulationResults) 346 347 // Check whether actual results and expected results are same 348 actualEndorsersResults = nil 349 for { 350 result, err := iter.Next() 351 require.NoError(err) 352 if result == nil { 353 break 354 } 355 actualEndorsersResults = append(actualEndorsersResults, result) 356 } 357 iter.Close() 358 359 // Note that the ordering of actualRes and expectedRes is dependent on the uuid. Hence, we are sorting 360 // expectedRes and actualRes. 361 sortResults(expectedEndorsersResults) 362 sortResults(actualEndorsersResults) 363 364 require.Equal(len(expectedEndorsersResults), len(actualEndorsersResults)) 365 for i, expected := range expectedEndorsersResults { 366 require.Equal(expected.ReceivedAtBlockHeight, actualEndorsersResults[i].ReceivedAtBlockHeight) 367 require.True(proto.Equal(expected.PvtSimulationResultsWithConfig, actualEndorsersResults[i].PvtSimulationResultsWithConfig)) 368 } 369 370 toRemoveTxids = []string{"txid-1"} 371 err = testStore.PurgeByTxids(toRemoveTxids) 372 require.NoError(err) 373 374 for _, txid := range toRemoveTxids { 375 376 // Check whether private write sets of txid-1 are removed 377 var expectedEndorsersResults *EndorserPvtSimulationResults = nil 378 iter, err = testStore.GetTxPvtRWSetByTxid(txid, nil) 379 require.NoError(err) 380 // Should return nil, nil 381 result, err := iter.Next() 382 require.NoError(err) 383 require.Equal(expectedEndorsersResults, result) 384 } 385 386 // There should be no entries in the store 387 _, err = testStore.GetMinTransientBlkHt() 388 require.Equal(err, ErrStoreEmpty) 389 } 390 391 func TestTransientStorePurgeBelowHeight(t *testing.T) { 392 env := initTestEnv(t) 393 defer env.cleanup() 394 testStore := env.store 395 require := require.New(t) 396 397 txid := "txid-1" 398 samplePvtRWSetWithConfig := samplePvtDataWithConfigInfo(t) 399 400 // Create private simulation results for txid-1 401 var endorsersResults []*EndorserPvtSimulationResults 402 403 // Results produced by endorser 1 404 endorser0SimulationResults := &EndorserPvtSimulationResults{ 405 ReceivedAtBlockHeight: 10, 406 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 407 } 408 endorsersResults = append(endorsersResults, endorser0SimulationResults) 409 410 // Results produced by endorser 2 411 endorser1SimulationResults := &EndorserPvtSimulationResults{ 412 ReceivedAtBlockHeight: 11, 413 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 414 } 415 endorsersResults = append(endorsersResults, endorser1SimulationResults) 416 417 // Results produced by endorser 3 418 endorser2SimulationResults := &EndorserPvtSimulationResults{ 419 ReceivedAtBlockHeight: 12, 420 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 421 } 422 endorsersResults = append(endorsersResults, endorser2SimulationResults) 423 424 // Results produced by endorser 4 425 endorser3SimulationResults := &EndorserPvtSimulationResults{ 426 ReceivedAtBlockHeight: 12, 427 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 428 } 429 endorsersResults = append(endorsersResults, endorser3SimulationResults) 430 431 // Results produced by endorser 5 432 endorser4SimulationResults := &EndorserPvtSimulationResults{ 433 ReceivedAtBlockHeight: 13, 434 PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig, 435 } 436 endorsersResults = append(endorsersResults, endorser4SimulationResults) 437 438 // Persist simulation results into store 439 var err error 440 for i := 0; i < 5; i++ { 441 err = testStore.Persist(txid, endorsersResults[i].ReceivedAtBlockHeight, 442 endorsersResults[i].PvtSimulationResultsWithConfig) 443 require.NoError(err) 444 } 445 446 // Retain results generate at block height greater than or equal to 12 447 minTransientBlkHtToRetain := uint64(12) 448 err = testStore.PurgeBelowHeight(minTransientBlkHtToRetain) 449 require.NoError(err) 450 451 // Retrieve simulation results of txid-1 from store 452 iter, err := testStore.GetTxPvtRWSetByTxid(txid, nil) 453 require.NoError(err) 454 455 // Expected results for txid-1 456 var expectedEndorsersResults []*EndorserPvtSimulationResults 457 expectedEndorsersResults = append(expectedEndorsersResults, endorser2SimulationResults) // endorsed at height 12 458 expectedEndorsersResults = append(expectedEndorsersResults, endorser3SimulationResults) // endorsed at height 12 459 expectedEndorsersResults = append(expectedEndorsersResults, endorser4SimulationResults) // endorsed at height 13 460 461 // Check whether actual results and expected results are same 462 var actualEndorsersResults []*EndorserPvtSimulationResults 463 for { 464 result, err := iter.Next() 465 require.NoError(err) 466 if result == nil { 467 break 468 } 469 actualEndorsersResults = append(actualEndorsersResults, result) 470 } 471 iter.Close() 472 473 // Note that the ordering of actualRes and expectedRes is dependent on the uuid. Hence, we are sorting 474 // expectedRes and actualRes. 475 sortResults(expectedEndorsersResults) 476 sortResults(actualEndorsersResults) 477 478 require.Equal(len(expectedEndorsersResults), len(actualEndorsersResults)) 479 for i, expected := range expectedEndorsersResults { 480 require.Equal(expected.ReceivedAtBlockHeight, actualEndorsersResults[i].ReceivedAtBlockHeight) 481 require.True(proto.Equal(expected.PvtSimulationResultsWithConfig, actualEndorsersResults[i].PvtSimulationResultsWithConfig)) 482 } 483 484 // Get the minimum block height remaining in transient store 485 var actualMinTransientBlkHt uint64 486 actualMinTransientBlkHt, err = testStore.GetMinTransientBlkHt() 487 require.NoError(err) 488 require.Equal(minTransientBlkHtToRetain, actualMinTransientBlkHt) 489 490 // Retain results at block height greater than or equal to 15 491 minTransientBlkHtToRetain = uint64(15) 492 err = testStore.PurgeBelowHeight(minTransientBlkHtToRetain) 493 require.NoError(err) 494 495 // There should be no entries in the store 496 actualMinTransientBlkHt, err = testStore.GetMinTransientBlkHt() 497 require.Equal(err, ErrStoreEmpty) 498 require.Equal(uint64(0), actualMinTransientBlkHt) 499 500 // Retain results at block height greater than or equal to 15 501 minTransientBlkHtToRetain = uint64(15) 502 err = testStore.PurgeBelowHeight(minTransientBlkHtToRetain) 503 // Should not return any error 504 require.NoError(err) 505 } 506 507 func TestTransientStoreRetrievalWithFilter(t *testing.T) { 508 env := initTestEnv(t) 509 defer env.cleanup() 510 testStore := env.store 511 512 samplePvtSimResWithConfig := samplePvtDataWithConfigInfo(t) 513 514 testTxid := "testTxid" 515 numEntries := 5 516 for i := 0; i < numEntries; i++ { 517 testStore.Persist(testTxid, uint64(i), samplePvtSimResWithConfig) 518 } 519 520 filter := ledger.NewPvtNsCollFilter() 521 filter.Add("ns-1", "coll-1") 522 filter.Add("ns-2", "coll-2") 523 524 itr, err := testStore.GetTxPvtRWSetByTxid(testTxid, filter) 525 require.NoError(t, err) 526 527 var actualRes []*EndorserPvtSimulationResults 528 for { 529 res, err := itr.Next() 530 if res == nil || err != nil { 531 require.NoError(t, err) 532 break 533 } 534 actualRes = append(actualRes, res) 535 } 536 537 // prepare the trimmed pvtrwset manually - retain only "ns-1/coll-1" and "ns-2/coll-2" 538 expectedSimulationRes := samplePvtSimResWithConfig 539 expectedSimulationRes.GetPvtRwset().NsPvtRwset[0].CollectionPvtRwset = expectedSimulationRes.GetPvtRwset().NsPvtRwset[0].CollectionPvtRwset[0:1] 540 expectedSimulationRes.GetPvtRwset().NsPvtRwset[1].CollectionPvtRwset = expectedSimulationRes.GetPvtRwset().NsPvtRwset[1].CollectionPvtRwset[1:] 541 expectedSimulationRes.CollectionConfigs, err = trimPvtCollectionConfigs(expectedSimulationRes.CollectionConfigs, filter) 542 require.NoError(t, err) 543 for ns, colName := range map[string]string{"ns-1": "coll-1", "ns-2": "coll-2"} { 544 config := expectedSimulationRes.CollectionConfigs[ns] 545 require.NotNil(t, config) 546 ns1Config := config.Config 547 require.Equal(t, len(ns1Config), 1) 548 ns1ColConfig := ns1Config[0].GetStaticCollectionConfig() 549 require.NotNil(t, ns1ColConfig.Name, colName) 550 } 551 552 var expectedRes []*EndorserPvtSimulationResults 553 for i := 0; i < numEntries; i++ { 554 expectedRes = append(expectedRes, &EndorserPvtSimulationResults{uint64(i), expectedSimulationRes}) 555 } 556 557 // Note that the ordering of actualRes and expectedRes is dependent on the uuid. Hence, we are sorting 558 // expectedRes and actualRes. 559 sortResults(expectedRes) 560 sortResults(actualRes) 561 require.Equal(t, len(expectedRes), len(actualRes)) 562 for i, expected := range expectedRes { 563 require.Equal(t, expected.ReceivedAtBlockHeight, actualRes[i].ReceivedAtBlockHeight) 564 require.True(t, proto.Equal(expected.PvtSimulationResultsWithConfig, actualRes[i].PvtSimulationResultsWithConfig)) 565 } 566 } 567 568 func sortResults(res []*EndorserPvtSimulationResults) { 569 // Results are sorted by ascending order of received at block height. When the block 570 // heights are same, we sort by comparing the hash of private write set. 571 sortCondition := func(i, j int) bool { 572 if res[i].ReceivedAtBlockHeight == res[j].ReceivedAtBlockHeight { 573 resI, _ := proto.Marshal(res[i].PvtSimulationResultsWithConfig) 574 resJ, _ := proto.Marshal(res[j].PvtSimulationResultsWithConfig) 575 // if hashes are same, any order would work. 576 return string(util.ComputeHash(resI)) < string(util.ComputeHash(resJ)) 577 } 578 return res[i].ReceivedAtBlockHeight < res[j].ReceivedAtBlockHeight 579 } 580 sort.SliceStable(res, sortCondition) 581 } 582 583 func samplePvtData(t *testing.T) *rwset.TxPvtReadWriteSet { 584 pvtWriteSet := &rwset.TxPvtReadWriteSet{DataModel: rwset.TxReadWriteSet_KV} 585 pvtWriteSet.NsPvtRwset = []*rwset.NsPvtReadWriteSet{ 586 { 587 Namespace: "ns-1", 588 CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{ 589 { 590 CollectionName: "coll-1", 591 Rwset: []byte("RandomBytes-PvtRWSet-ns1-coll1"), 592 }, 593 { 594 CollectionName: "coll-2", 595 Rwset: []byte("RandomBytes-PvtRWSet-ns1-coll2"), 596 }, 597 }, 598 }, 599 600 { 601 Namespace: "ns-2", 602 CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{ 603 { 604 CollectionName: "coll-1", 605 Rwset: []byte("RandomBytes-PvtRWSet-ns2-coll1"), 606 }, 607 { 608 CollectionName: "coll-2", 609 Rwset: []byte("RandomBytes-PvtRWSet-ns2-coll2"), 610 }, 611 }, 612 }, 613 } 614 return pvtWriteSet 615 } 616 617 func samplePvtDataWithConfigInfo(t *testing.T) *transientstore.TxPvtReadWriteSetWithConfigInfo { 618 pvtWriteSet := samplePvtData(t) 619 pvtRWSetWithConfigInfo := &transientstore.TxPvtReadWriteSetWithConfigInfo{ 620 PvtRwset: pvtWriteSet, 621 CollectionConfigs: map[string]*peer.CollectionConfigPackage{ 622 "ns-1": { 623 Config: []*peer.CollectionConfig{ 624 sampleCollectionConfigPackage("coll-1"), 625 sampleCollectionConfigPackage("coll-2"), 626 }, 627 }, 628 "ns-2": { 629 Config: []*peer.CollectionConfig{ 630 sampleCollectionConfigPackage("coll-1"), 631 sampleCollectionConfigPackage("coll-2"), 632 }, 633 }, 634 }, 635 } 636 return pvtRWSetWithConfigInfo 637 } 638 639 func createCollectionConfig(collectionName string, signaturePolicyEnvelope *common.SignaturePolicyEnvelope, 640 requiredPeerCount int32, maximumPeerCount int32, 641 ) *peer.CollectionConfig { 642 signaturePolicy := &peer.CollectionPolicyConfig_SignaturePolicy{ 643 SignaturePolicy: signaturePolicyEnvelope, 644 } 645 accessPolicy := &peer.CollectionPolicyConfig{ 646 Payload: signaturePolicy, 647 } 648 649 return &peer.CollectionConfig{ 650 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 651 StaticCollectionConfig: &peer.StaticCollectionConfig{ 652 Name: collectionName, 653 MemberOrgsPolicy: accessPolicy, 654 RequiredPeerCount: requiredPeerCount, 655 MaximumPeerCount: maximumPeerCount, 656 }, 657 }, 658 } 659 } 660 661 func sampleCollectionConfigPackage(colName string) *peer.CollectionConfig { 662 signers := [][]byte{[]byte("signer0"), []byte("signer1")} 663 policyEnvelope := policydsl.Envelope(policydsl.Or(policydsl.SignedBy(0), policydsl.SignedBy(1)), signers) 664 665 var requiredPeerCount, maximumPeerCount int32 666 requiredPeerCount = 1 667 maximumPeerCount = 2 668 669 return createCollectionConfig(colName, policyEnvelope, requiredPeerCount, maximumPeerCount) 670 } 671 672 // persistOldProto is the code from 1.1 to populate stores with old proto message 673 // this is used only for testing 674 func (s *Store) persistOldProto(txid string, blockHeight uint64, 675 privateSimulationResults *rwset.TxPvtReadWriteSet) error { 676 logger.Debugf("Persisting private data to transient store for txid [%s] at block height [%d]", txid, blockHeight) 677 678 dbBatch := s.db.NewUpdateBatch() 679 680 // Create compositeKey with appropriate prefix, txid, uuid and blockHeight 681 // Due to the fact that the txid may have multiple private write sets persisted from different 682 // endorsers (via Gossip), we postfix an uuid with the txid to avoid collision. 683 uuid := commonutil.GenerateUUID() 684 compositeKeyPvtRWSet := createCompositeKeyForPvtRWSet(txid, uuid, blockHeight) 685 privateSimulationResultsBytes, err := proto.Marshal(privateSimulationResults) 686 if err != nil { 687 return err 688 } 689 dbBatch.Put(compositeKeyPvtRWSet, privateSimulationResultsBytes) 690 691 // Create two index: (i) by txid, and (ii) by height 692 693 // Create compositeKey for purge index by height with appropriate prefix, blockHeight, 694 // txid, uuid and store the compositeKey (purge index) with a nil byte as value. Note that 695 // the purge index is used to remove orphan entries in the transient store (which are not removed 696 // by PurgeTxids()) using BTL policy by PurgeBelowHeight(). Note that orphan entries are due to transaction 697 // that gets endorsed but not submitted by the client for commit) 698 compositeKeyPurgeIndexByHeight := createCompositeKeyForPurgeIndexByHeight(blockHeight, txid, uuid) 699 dbBatch.Put(compositeKeyPurgeIndexByHeight, emptyValue) 700 701 // Create compositeKey for purge index by txid with appropriate prefix, txid, uuid, 702 // blockHeight and store the compositeKey (purge index) with a nil byte as value. 703 // Though compositeKeyPvtRWSet itself can be used to purge private write set by txid, 704 // we create a separate composite key with a nil byte as value. The reason is that 705 // if we use compositeKeyPvtRWSet, we unnecessarily read (potentially large) private write 706 // set associated with the key from db. Note that this purge index is used to remove non-orphan 707 // entries in the transient store and is used by PurgeTxids() 708 // Note: We can create compositeKeyPurgeIndexByTxid by just replacing the prefix of compositeKeyPvtRWSet 709 // with purgeIndexByTxidPrefix. For code readability and to be expressive, we use a 710 // createCompositeKeyForPurgeIndexByTxid() instead. 711 compositeKeyPurgeIndexByTxid := createCompositeKeyForPurgeIndexByTxid(txid, uuid, blockHeight) 712 dbBatch.Put(compositeKeyPurgeIndexByTxid, emptyValue) 713 714 return s.db.WriteBatch(dbBatch, true) 715 } 716 717 func TestIteratorErrorCases(t *testing.T) { 718 env := initTestEnv(t) 719 defer env.cleanup() 720 testStore := env.store 721 env.storeProvider.Close() 722 723 errStr := "internal leveldb error while obtaining db iterator: leveldb: closed" 724 itr, err := testStore.GetTxPvtRWSetByTxid("tx1", nil) 725 require.EqualError(t, err, errStr) 726 require.Nil(t, itr) 727 728 minHt, err := testStore.GetMinTransientBlkHt() 729 require.EqualError(t, err, errStr) 730 require.Equal(t, uint64(0), minHt) 731 732 require.EqualError(t, testStore.PurgeBelowHeight(0), errStr) 733 require.EqualError(t, testStore.PurgeByTxids([]string{"tx1"}), errStr) 734 } 735 736 func TestDeleteTransientStore(t *testing.T) { 737 env := initTestEnv(t) 738 defer env.cleanup() 739 740 ledgerID := "test-deleted-tx-count" 741 store, err := env.storeProvider.OpenStore(ledgerID) 742 require.NoError(t, err) 743 require.NotNil(t, store) 744 745 // Write some transactions into the transient storage. 746 samplePvtSimResWithConfig := samplePvtDataWithConfigInfo(t) 747 testTxid := "testTxid" 748 numEntries := 5 749 for i := 0; i < numEntries; i++ { 750 store.Persist(testTxid, uint64(i), samplePvtSimResWithConfig) 751 } 752 753 height, err := store.GetMinTransientBlkHt() 754 require.NoError(t, err) 755 require.Equal(t, uint64(0), height) 756 757 // undercut a few blocks, and we should still have a lower tx bound. 758 require.NoError(t, store.PurgeBelowHeight(3)) 759 height, err = store.GetMinTransientBlkHt() 760 require.NoError(t, err) 761 require.Equal(t, uint64(3), height) 762 763 // Delete the store 764 sp := env.storeProvider.(*storeProvider) 765 require.NoError(t, sp.deleteStore(ledgerID)) 766 767 // After delete the storage should be empty. 768 height, err = store.GetMinTransientBlkHt() 769 require.EqualError(t, err, "Transient store is empty") 770 require.Equal(t, uint64(0), height) 771 772 isEmpty, err := store.db.IsEmpty() 773 require.NoError(t, err) 774 require.True(t, isEmpty) 775 } 776 777 func TestDeleteMissingTransientStoreIsOK(t *testing.T) { 778 env := initTestEnv(t) 779 defer env.cleanup() 780 781 sp := env.storeProvider.(*storeProvider) 782 require.NoError(t, sp.deleteStore("_not_a_valid_store")) 783 }