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  }