github.com/renegr87/renegr87@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/pvtstatepurgemgmt/purge_mgr_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package pvtstatepurgemgmt 8 9 import ( 10 "os" 11 "testing" 12 13 "github.com/hyperledger/fabric/common/flogging" 14 "github.com/hyperledger/fabric/core/ledger/kvledger/bookkeeping" 15 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/privacyenabledstate" 16 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb" 17 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 18 "github.com/hyperledger/fabric/core/ledger/pvtdatapolicy" 19 btltestutil "github.com/hyperledger/fabric/core/ledger/pvtdatapolicy/testutil" 20 "github.com/hyperledger/fabric/core/ledger/util" 21 "github.com/stretchr/testify/assert" 22 ) 23 24 const ( 25 levelDBtestEnvName = "levelDB_TestEnv" 26 couchDBtestEnvName = "couchDB_TestEnv" 27 ) 28 29 // Tests will be run against each environment in this array 30 // For example, to skip CouchDB tests, remove &couchDBLockBasedEnv{} 31 var testEnvs = map[string]privacyenabledstate.TestEnv{ 32 levelDBtestEnvName: &privacyenabledstate.LevelDBCommonStorageTestEnv{}, 33 couchDBtestEnvName: &privacyenabledstate.CouchDBCommonStorageTestEnv{}, 34 } 35 36 func TestMain(m *testing.M) { 37 flogging.ActivateSpec("pvtstatepurgemgmt,privacyenabledstate=debug") 38 exitCode := m.Run() 39 for _, testEnv := range testEnvs { 40 testEnv.StopExternalResource() 41 } 42 os.Exit(exitCode) 43 } 44 45 func TestPurgeMgr(t *testing.T) { 46 for _, dbEnv := range testEnvs { 47 t.Run(dbEnv.GetName(), func(t *testing.T) { testPurgeMgr(t, dbEnv) }) 48 } 49 } 50 51 func testPurgeMgr(t *testing.T, dbEnv privacyenabledstate.TestEnv) { 52 ledgerid := "testledger-perge-mgr" 53 btlPolicy := btltestutil.SampleBTLPolicy( 54 map[[2]string]uint64{ 55 {"ns1", "coll1"}: 1, 56 {"ns1", "coll2"}: 2, 57 {"ns2", "coll3"}: 4, 58 {"ns2", "coll4"}: 4, 59 }, 60 ) 61 62 testHelper := &testHelper{} 63 testHelper.init(t, ledgerid, btlPolicy, dbEnv) 64 defer testHelper.cleanup() 65 66 block1Updates := privacyenabledstate.NewUpdateBatch() 67 block1Updates.PubUpdates.Put("ns1", "pubkey1", []byte("pubvalue1-1"), version.NewHeight(1, 1)) 68 putPvtAndHashUpdates(t, block1Updates, "ns1", "coll1", "pvtkey1", []byte("pvtvalue1-1"), version.NewHeight(1, 1)) 69 putPvtAndHashUpdates(t, block1Updates, "ns1", "coll2", "pvtkey2", []byte("pvtvalue2-1"), version.NewHeight(1, 1)) 70 putPvtAndHashUpdates(t, block1Updates, "ns2", "coll3", "pvtkey3", []byte("pvtvalue3-1"), version.NewHeight(1, 1)) 71 putPvtAndHashUpdates(t, block1Updates, "ns2", "coll4", "pvtkey4", []byte("pvtvalue4-1"), version.NewHeight(1, 1)) 72 testHelper.commitUpdatesForTesting(1, block1Updates) 73 testHelper.checkPvtdataExists("ns1", "coll1", "pvtkey1", []byte("pvtvalue1-1")) 74 testHelper.checkPvtdataExists("ns1", "coll2", "pvtkey2", []byte("pvtvalue2-1")) 75 testHelper.checkPvtdataExists("ns2", "coll3", "pvtkey3", []byte("pvtvalue3-1")) 76 testHelper.checkPvtdataExists("ns2", "coll4", "pvtkey4", []byte("pvtvalue4-1")) 77 78 block2Updates := privacyenabledstate.NewUpdateBatch() 79 putPvtAndHashUpdates(t, block2Updates, "ns1", "coll2", "pvtkey2", []byte("pvtvalue2-2"), version.NewHeight(2, 1)) 80 deletePvtAndHashUpdates(t, block2Updates, "ns2", "coll4", "pvtkey4", version.NewHeight(2, 1)) 81 testHelper.commitUpdatesForTesting(2, block2Updates) 82 testHelper.checkPvtdataExists("ns1", "coll1", "pvtkey1", []byte("pvtvalue1-1")) 83 testHelper.checkPvtdataExists("ns1", "coll2", "pvtkey2", []byte("pvtvalue2-2")) 84 testHelper.checkPvtdataExists("ns2", "coll3", "pvtkey3", []byte("pvtvalue3-1")) 85 testHelper.checkPvtdataDoesNotExist("ns1", "coll4", "pvtkey4") 86 87 noPvtdataUpdates := privacyenabledstate.NewUpdateBatch() 88 testHelper.commitUpdatesForTesting(3, noPvtdataUpdates) 89 testHelper.checkPvtdataDoesNotExist("ns1", "coll1", "pvtkey1") 90 testHelper.checkPvtdataExists("ns1", "coll2", "pvtkey2", []byte("pvtvalue2-2")) 91 testHelper.checkPvtdataExists("ns2", "coll3", "pvtkey3", []byte("pvtvalue3-1")) 92 testHelper.checkPvtdataDoesNotExist("ns1", "coll4", "pvtkey4") 93 94 testHelper.commitUpdatesForTesting(4, noPvtdataUpdates) 95 testHelper.checkPvtdataDoesNotExist("ns1", "coll1", "pvtkey1") 96 testHelper.checkPvtdataExists("ns1", "coll2", "pvtkey2", []byte("pvtvalue2-2")) 97 testHelper.checkPvtdataExists("ns2", "coll3", "pvtkey3", []byte("pvtvalue3-1")) 98 testHelper.checkPvtdataDoesNotExist("ns1", "coll4", "pvtkey4") 99 100 testHelper.commitUpdatesForTesting(5, noPvtdataUpdates) 101 testHelper.checkPvtdataDoesNotExist("ns1", "coll1", "pvtkey1") 102 testHelper.checkPvtdataDoesNotExist("ns1", "coll2", "pvtkey2") 103 testHelper.checkPvtdataExists("ns2", "coll3", "pvtkey3", []byte("pvtvalue3-1")) 104 testHelper.checkPvtdataDoesNotExist("ns1", "coll4", "pvtkey4") 105 106 testHelper.commitUpdatesForTesting(6, noPvtdataUpdates) 107 testHelper.checkPvtdataDoesNotExist("ns1", "coll1", "pvtkey1") 108 testHelper.checkPvtdataDoesNotExist("ns1", "coll2", "pvtkey2") 109 testHelper.checkPvtdataDoesNotExist("ns2", "coll3", "pvtkey3") 110 testHelper.checkPvtdataDoesNotExist("ns1", "coll4", "pvtkey4") 111 } 112 113 func TestPurgeMgrForCommittingPvtDataOfOldBlocks(t *testing.T) { 114 for _, dbEnv := range testEnvs { 115 t.Run(dbEnv.GetName(), func(t *testing.T) { testPurgeMgrForCommittingPvtDataOfOldBlocks(t, dbEnv) }) 116 } 117 } 118 119 func testPurgeMgrForCommittingPvtDataOfOldBlocks(t *testing.T, dbEnv privacyenabledstate.TestEnv) { 120 ledgerid := "testledger-purge-mgr-pvtdata-oldblocks" 121 btlPolicy := btltestutil.SampleBTLPolicy( 122 map[[2]string]uint64{ 123 {"ns1", "coll1"}: 1, 124 }, 125 ) 126 127 testHelper := &testHelper{} 128 testHelper.init(t, ledgerid, btlPolicy, dbEnv) 129 defer testHelper.cleanup() 130 131 // committing block 1 132 block1Updates := privacyenabledstate.NewUpdateBatch() 133 // pvt data pvtkey1 is missing but the pvtkey2 is present. 134 // pvtkey1 and pvtkey2 both would get expired and purged while committing block 3 135 putHashUpdates(block1Updates, "ns1", "coll1", "pvtkey1", []byte("pvtvalue1-1"), version.NewHeight(1, 1)) 136 putPvtAndHashUpdates(t, block1Updates, "ns1", "coll1", "pvtkey2", []byte("pvtvalue1-2"), version.NewHeight(1, 1)) 137 testHelper.commitUpdatesForTesting(1, block1Updates) 138 139 // pvtkey1 should not exist but pvtkey2 should exist 140 testHelper.checkOnlyPvtKeyDoesNotExist("ns1", "coll1", "pvtkey1") 141 testHelper.checkPvtdataExists("ns1", "coll1", "pvtkey2", []byte("pvtvalue1-2")) 142 143 // committing block 2 144 block2Updates := privacyenabledstate.NewUpdateBatch() 145 testHelper.commitUpdatesForTesting(2, block2Updates) 146 147 // Commit pvtkey1 via commit of missing data and this should be added to toPurge list as it 148 // should be removed while committing block 3 149 block1PvtData := privacyenabledstate.NewUpdateBatch() 150 putPvtUpdates(block1PvtData, "ns1", "coll1", "pvtkey1", []byte("pvtvalue1-1"), version.NewHeight(1, 1)) 151 testHelper.commitPvtDataOfOldBlocksForTesting(block1PvtData) 152 153 // both pvtkey1 and pvtkey1 should exist 154 testHelper.checkPvtdataExists("ns1", "coll1", "pvtkey1", []byte("pvtvalue1-1")) 155 testHelper.checkPvtdataExists("ns1", "coll1", "pvtkey2", []byte("pvtvalue1-2")) 156 157 // committing block 3 158 block3Updates := privacyenabledstate.NewUpdateBatch() 159 testHelper.commitUpdatesForTesting(3, block3Updates) 160 161 // both pvtkey1 and pvtkey1 should not exist 162 testHelper.checkPvtdataDoesNotExist("ns1", "coll1", "pvtkey1") 163 testHelper.checkPvtdataDoesNotExist("ns1", "coll1", "pvtkey2") 164 } 165 166 func TestKeyUpdateBeforeExpiryBlock(t *testing.T) { 167 dbEnv := testEnvs[levelDBtestEnvName] 168 ledgerid := "testledger-perge-mgr" 169 btlPolicy := btltestutil.SampleBTLPolicy( 170 map[[2]string]uint64{ 171 {"ns", "coll"}: 1, // expiry block = committing block + 2 172 }, 173 ) 174 helper := &testHelper{} 175 helper.init(t, ledgerid, btlPolicy, dbEnv) 176 defer helper.cleanup() 177 178 // block-1 updates: Update only hash of the pvt key 179 block1Updates := privacyenabledstate.NewUpdateBatch() 180 putHashUpdates(block1Updates, "ns", "coll", "pvtkey", []byte("pvtvalue-1"), version.NewHeight(1, 1)) 181 helper.commitUpdatesForTesting(1, block1Updates) 182 expInfo, _ := helper.purgeMgr.(*purgeMgr).expKeeper.retrieve(3) 183 assert.Len(t, expInfo, 1) 184 185 // block-2 update: Update both hash and pvt data 186 block2Updates := privacyenabledstate.NewUpdateBatch() 187 putPvtAndHashUpdates(t, block2Updates, "ns", "coll", "pvtkey", []byte("pvtvalue-2"), version.NewHeight(2, 1)) 188 helper.commitUpdatesForTesting(2, block2Updates) 189 helper.checkExpiryEntryExistsForBlockNum(3, 1) 190 helper.checkExpiryEntryExistsForBlockNum(4, 1) 191 192 // block-3 update: no Updates 193 noPvtdataUpdates := privacyenabledstate.NewUpdateBatch() 194 helper.commitUpdatesForTesting(3, noPvtdataUpdates) 195 helper.checkPvtdataExists("ns", "coll", "pvtkey", []byte("pvtvalue-2")) 196 helper.checkNoExpiryEntryExistsForBlockNum(3) 197 helper.checkExpiryEntryExistsForBlockNum(4, 1) 198 199 // block-4 update: no Updates 200 noPvtdataUpdates = privacyenabledstate.NewUpdateBatch() 201 helper.commitUpdatesForTesting(4, noPvtdataUpdates) 202 helper.checkPvtdataDoesNotExist("ns", "coll", "pvtkey") 203 helper.checkNoExpiryEntryExistsForBlockNum(4) 204 } 205 206 func TestOnlyHashUpdateInExpiryBlock(t *testing.T) { 207 dbEnv := testEnvs[levelDBtestEnvName] 208 ledgerid := "testledger-perge-mgr" 209 btlPolicy := btltestutil.SampleBTLPolicy( 210 map[[2]string]uint64{ 211 {"ns", "coll"}: 1, // expiry block = committing block + 2 212 }, 213 ) 214 helper := &testHelper{} 215 helper.init(t, ledgerid, btlPolicy, dbEnv) 216 defer helper.cleanup() 217 218 // block-1 updates: Add pvt data 219 block1Updates := privacyenabledstate.NewUpdateBatch() 220 putPvtAndHashUpdates(t, block1Updates, 221 "ns", "coll", "pvtkey", []byte("pvtvalue-1"), version.NewHeight(1, 1)) 222 helper.commitUpdatesForTesting(1, block1Updates) 223 helper.checkExpiryEntryExistsForBlockNum(3, 1) 224 225 // block-2 update: No Updates 226 noPvtdataUpdates := privacyenabledstate.NewUpdateBatch() 227 helper.commitUpdatesForTesting(2, noPvtdataUpdates) 228 helper.checkPvtdataExists( 229 "ns", "coll", "pvtkey", []byte("pvtvalue-1")) 230 helper.checkExpiryEntryExistsForBlockNum(3, 1) 231 232 // block-3 update: Update hash only 233 block3Updates := privacyenabledstate.NewUpdateBatch() 234 putHashUpdates(block3Updates, 235 "ns", "coll", "pvtkey", []byte("pvtvalue-3"), version.NewHeight(3, 1)) 236 helper.commitUpdatesForTesting(3, block3Updates) 237 helper.checkOnlyKeyHashExists("ns", "coll", "pvtkey") 238 helper.checkNoExpiryEntryExistsForBlockNum(3) 239 helper.checkExpiryEntryExistsForBlockNum(5, 1) 240 241 // block-4 update: no Updates 242 noPvtdataUpdates = privacyenabledstate.NewUpdateBatch() 243 helper.commitUpdatesForTesting(4, noPvtdataUpdates) 244 helper.checkExpiryEntryExistsForBlockNum(5, 1) 245 246 // block-5 update: no Updates 247 noPvtdataUpdates = privacyenabledstate.NewUpdateBatch() 248 helper.commitUpdatesForTesting(5, noPvtdataUpdates) 249 helper.checkPvtdataDoesNotExist("ns", "coll", "pvtkey") 250 helper.checkNoExpiryEntryExistsForBlockNum(5) 251 } 252 253 func TestOnlyHashDeleteBeforeExpiryBlock(t *testing.T) { 254 dbEnv := testEnvs[levelDBtestEnvName] 255 ledgerid := "testledger-perge-mgr" 256 btlPolicy := btltestutil.SampleBTLPolicy( 257 map[[2]string]uint64{ 258 {"ns", "coll"}: 1, // expiry block = committing block + 2 259 }, 260 ) 261 testHelper := &testHelper{} 262 testHelper.init(t, ledgerid, btlPolicy, dbEnv) 263 defer testHelper.cleanup() 264 265 // block-1 updates: add pvt key 266 block1Updates := privacyenabledstate.NewUpdateBatch() 267 putPvtAndHashUpdates(t, block1Updates, 268 "ns", "coll", "pvtkey", []byte("pvtvalue-1"), version.NewHeight(1, 1)) 269 testHelper.commitUpdatesForTesting(1, block1Updates) 270 271 // block-2 update: delete Hash only 272 block2Updates := privacyenabledstate.NewUpdateBatch() 273 deleteHashUpdates(block2Updates, "ns", "coll", "pvtkey", version.NewHeight(2, 1)) 274 testHelper.commitUpdatesForTesting(2, block2Updates) 275 testHelper.checkOnlyPvtKeyExists("ns", "coll", "pvtkey", []byte("pvtvalue-1")) 276 277 // block-3 update: no updates 278 noPvtdataUpdates := privacyenabledstate.NewUpdateBatch() 279 testHelper.commitUpdatesForTesting(3, noPvtdataUpdates) 280 testHelper.checkPvtdataDoesNotExist("ns", "coll", "pvtkey") 281 } 282 283 type testHelper struct { 284 t *testing.T 285 bookkeepingEnv *bookkeeping.TestEnv 286 dbEnv privacyenabledstate.TestEnv 287 288 db privacyenabledstate.DB 289 purgeMgr PurgeMgr 290 } 291 292 func (h *testHelper) init(t *testing.T, ledgerid string, btlPolicy pvtdatapolicy.BTLPolicy, dbEnv privacyenabledstate.TestEnv) { 293 h.t = t 294 h.bookkeepingEnv = bookkeeping.NewTestEnv(t) 295 dbEnv.Init(t) 296 h.dbEnv = dbEnv 297 h.db = h.dbEnv.GetDBHandle(ledgerid) 298 var err error 299 if h.purgeMgr, err = InstantiatePurgeMgr(ledgerid, h.db, btlPolicy, h.bookkeepingEnv.TestProvider); err != nil { 300 t.Fatalf("err:%s", err) 301 } 302 } 303 304 func (h *testHelper) cleanup() { 305 h.bookkeepingEnv.Cleanup() 306 h.dbEnv.Cleanup() 307 } 308 309 func (h *testHelper) commitUpdatesForTesting(blkNum uint64, updates *privacyenabledstate.UpdateBatch) { 310 h.purgeMgr.PrepareForExpiringKeys(blkNum) 311 assert.NoError(h.t, h.purgeMgr.DeleteExpiredAndUpdateBookkeeping(updates.PvtUpdates, updates.HashUpdates)) 312 assert.NoError(h.t, h.db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(blkNum, 1))) 313 h.db.ClearCachedVersions() 314 h.purgeMgr.BlockCommitDone() 315 } 316 317 func (h *testHelper) commitPvtDataOfOldBlocksForTesting(updates *privacyenabledstate.UpdateBatch) { 318 assert.NoError(h.t, h.purgeMgr.UpdateBookkeepingForPvtDataOfOldBlocks(updates.PvtUpdates)) 319 assert.NoError(h.t, h.db.ApplyPrivacyAwareUpdates(updates, nil)) 320 } 321 322 func (h *testHelper) checkPvtdataExists(ns, coll, key string, value []byte) { 323 vv, _ := h.fetchPvtdataFronDB(ns, coll, key) 324 vv, hashVersion := h.fetchPvtdataFronDB(ns, coll, key) 325 assert.NotNil(h.t, vv) 326 assert.Equal(h.t, value, vv.Value) 327 assert.Equal(h.t, vv.Version, hashVersion) 328 } 329 330 func (h *testHelper) checkPvtdataDoesNotExist(ns, coll, key string) { 331 vv, hashVersion := h.fetchPvtdataFronDB(ns, coll, key) 332 assert.Nil(h.t, vv) 333 assert.Nil(h.t, hashVersion) 334 } 335 336 func (h *testHelper) checkOnlyPvtKeyExists(ns, coll, key string, value []byte) { 337 vv, hashVersion := h.fetchPvtdataFronDB(ns, coll, key) 338 assert.NotNil(h.t, vv) 339 assert.Nil(h.t, hashVersion) 340 assert.Equal(h.t, value, vv.Value) 341 } 342 343 func (h *testHelper) checkOnlyPvtKeyDoesNotExist(ns, coll, key string) { 344 kv, err := h.db.GetPrivateData(ns, coll, key) 345 assert.Nil(h.t, err) 346 assert.Nil(h.t, kv) 347 } 348 349 func (h *testHelper) checkOnlyKeyHashExists(ns, coll, key string) { 350 vv, hashVersion := h.fetchPvtdataFronDB(ns, coll, key) 351 assert.Nil(h.t, vv) 352 assert.NotNil(h.t, hashVersion) 353 } 354 355 func (h *testHelper) fetchPvtdataFronDB(ns, coll, key string) (kv *statedb.VersionedValue, hashVersion *version.Height) { 356 var err error 357 kv, err = h.db.GetPrivateData(ns, coll, key) 358 assert.NoError(h.t, err) 359 hashVersion, err = h.db.GetKeyHashVersion(ns, coll, util.ComputeStringHash(key)) 360 assert.NoError(h.t, err) 361 return 362 } 363 364 func (h *testHelper) checkExpiryEntryExistsForBlockNum(expiringBlk uint64, expectedNumEntries int) { 365 expInfo, err := h.purgeMgr.(*purgeMgr).expKeeper.retrieve(expiringBlk) 366 assert.NoError(h.t, err) 367 assert.Len(h.t, expInfo, expectedNumEntries) 368 } 369 370 func (h *testHelper) checkNoExpiryEntryExistsForBlockNum(expiringBlk uint64) { 371 expInfo, err := h.purgeMgr.(*purgeMgr).expKeeper.retrieve(expiringBlk) 372 assert.NoError(h.t, err) 373 assert.Len(h.t, expInfo, 0) 374 }