From eb4db7f19c93b55465cfcd3d53cae046632e366c Mon Sep 17 00:00:00 2001 From: oren-lava Date: Mon, 20 Feb 2023 19:11:21 +0200 Subject: [PATCH] CNS-291: fix PR issues --- common/fixation_entry.go | 92 +++++++++++++++--- common/fixation_entry_test.go | 33 ++++++- common/fixation_entry_unique_index.go | 14 +-- common/fixation_entry_unique_index_test.go | 108 ++++++++++++++++++++- common/types/constants.go | 12 +++ common/types/fixationEntry.pb.go | 70 +++++++++---- proto/common/fixationEntry.proto | 1 + 7 files changed, 287 insertions(+), 43 deletions(-) create mode 100644 common/types/constants.go diff --git a/common/fixation_entry.go b/common/fixation_entry.go index c5a2b76d4a..48ea8feb74 100644 --- a/common/fixation_entry.go +++ b/common/fixation_entry.go @@ -2,6 +2,7 @@ package common import ( "strconv" + "strings" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -49,7 +50,7 @@ func SetEntry(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, cdc } // Get entry with full index. Full index is the entry index + version num suffix (like "bundle1_0") -func GetEntry(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, cdc codec.BinaryCodec, entryIndex string) (val types.Entry, found bool) { +func GetEntry(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, cdc codec.BinaryCodec, entryIndex string, referenceAction int) (val types.Entry, found bool) { store := prefix.NewStore(ctx.KVStore(storeKey), []byte(entryKeyPrefix)) b := store.Get(entryKey( @@ -60,15 +61,60 @@ func GetEntry(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, cdc } cdc.MustUnmarshal(b, &val) + + switch referenceAction { + case types.ADD_REFERENCE: + val.References += 1 + SetEntry(ctx, storeKey, entryKeyPrefix, cdc, val) + case types.SUB_REFERENCE: + if val.GetReferences() > 0 { + val.References -= 1 + SetEntry(ctx, storeKey, entryKeyPrefix, cdc, val) + } + case types.DO_NOTHING: + } + return val, true } +// Helper function to extract the original index from an older version index (for example: myIndex_2 -> myIndex) +func extractOriginalIndexFromOlderVersionIndex(index string) (originalIndexWithoutVersionNumSuffix string) { + // check that the index's length is non-zero + if len(index) == 0 { + return "" + } + + // if the index doesn't contain "_", it's not an older version index (as defined in this code) so there's nothing to do + if !strings.Contains(index, "_") { + return index + } + + // trim the index string from the start to the last "_" + if i := strings.LastIndex(index, "_"); i > 0 { + index = index[:i] + } + + return index +} + // Remove entry with full index. Full index is the entry index + version num suffix (like "bundle1_0") -func RemoveEntry(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, entryIndex string) { +func RemoveEntry(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec, entryKeyPrefix string, entryIndex string) { store := prefix.NewStore(ctx.KVStore(storeKey), []byte(entryKeyPrefix)) store.Delete(entryKey( entryIndex, )) + + originalIndex := extractOriginalIndexFromOlderVersionIndex(entryIndex) + + entryList := GetAllEntriesForIndex(ctx, storeKey, entryKeyPrefix, cdc, originalIndex) + if len(entryList) == 0 { + uniqueIndices := GetAllFixationEntryUniqueIndex(ctx, storeKey, cdc, entryKeyPrefix) + for _, uniqueIndex := range uniqueIndices { + if originalIndex == uniqueIndex.GetUniqueIndex() { + RemoveFixationEntryUniqueIndex(ctx, storeKey, entryKeyPrefix, uniqueIndex.GetId()) + } + } + } } func entryKey( @@ -83,12 +129,36 @@ func entryKey( return key } +func deleteStaleEntries(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, cdc codec.BinaryCodec, index string) { + // get current block + currentBlock := ctx.BlockHeight() + + // get all the entries of the entry's index + entryList := GetAllEntriesForIndex(ctx, storeKey, entryKeyPrefix, cdc, index) + + // iterate over the entries + for _, entry := range entryList { + // if the entry's references is zero and the entry's block + STALE_ENTRY_TIME (the time it takes for an entry to be stale) is smaller than the current block, remove it + if entry.GetReferences() == 0 && int64(entry.GetBlock())+types.STALE_ENTRY_TIME < currentBlock { + RemoveEntry(ctx, storeKey, cdc, entryKeyPrefix, index) + } + } +} + // Function to create a new fixation entry, add it to the KVStore and update the entry's older versions indices. Note, the entryIndex should be without the version num suffix func AddEntry(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, uniqueIndexEntryKeyPrefix string, cdc codec.BinaryCodec, entryIndex string, marshalledData []byte) error { + // delete stale entries + deleteStaleEntries(ctx, storeKey, entryKeyPrefix, cdc, entryIndex) + + // since we're keeping versions with a "_" suffix, to avoid trouble we forbid that the last character would be "_" + if entryIndex[len(entryIndex)-1:] == "_" { + return utils.LavaError(ctx, ctx.Logger(), "AddEntry_invalid_entryIndex", map[string]string{"entryIndex": entryIndex}, "entry index must not end with \"_\"") + } + // create a new fixated entry entryToSet, err := CreateNewEntry(ctx, entryIndex, uint64(ctx.BlockHeight()), marshalledData) if err != nil { - return utils.LavaError(ctx, ctx.Logger(), "AddFixatedEntry_create_new_fixated_entry_failed", map[string]string{"err": err.Error()}, "could not create new fixated entry") + return utils.LavaError(ctx, ctx.Logger(), "AddEntry_create_new_fixated_entry_failed", map[string]string{"err": err.Error()}, "could not create new fixated entry") } isFirstVersion := false @@ -97,7 +167,7 @@ func AddEntry(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, uni // update the older versions entries indices. Also return whether the entry is a first version entry (no older versions saved in the KVStore) isFirstVersion, err = updateEntryIndices(ctx, storeKey, entryKeyPrefix, cdc, entryToSet.GetIndex()) if err != nil { - return utils.LavaError(ctx, ctx.Logger(), "AddFixatedEntry_entry_indices_update_failed", map[string]string{"entryToSetIndex": entryToSet.Index}, "could not update entries indices") + return utils.LavaError(ctx, ctx.Logger(), "AddEntry_entry_indices_update_failed", map[string]string{"entryToSetIndex": entryToSet.Index}, "could not update entries indices") } } @@ -115,7 +185,7 @@ func AddEntry(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, uni // Function to check whether two entries with the same index are added in the same block func checkEntryProposedInThisBlock(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, cdc codec.BinaryCodec, newEntryToPropose *types.Entry) bool { // try getting an entry with the same index as newEntryToPropose - oldEntry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, newEntryToPropose.GetIndex()) + oldEntry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, newEntryToPropose.GetIndex(), types.DO_NOTHING) if found { // if found, check if the new entry has the same block field if newEntryToPropose.GetBlock() == oldEntry.GetBlock() { @@ -153,12 +223,12 @@ func updateEntryIndices(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix s // Function to create a fixated entry from block and marshaled data func CreateNewEntry(ctx sdk.Context, index string, block uint64, marshaledData []byte) (*types.Entry, error) { // check that marshaledData is not nil - if marshaledData == nil { + if len(marshaledData) == 0 { return nil, utils.LavaError(ctx, ctx.Logger(), "CreateNewFixatedEntry_failed", nil, "can't create new fixated entry, marshaled data is nil") } // create new entry - newEntry := types.Entry{Index: index, Block: block, MarshaledData: marshaledData} + newEntry := types.Entry{Index: index, Block: block, MarshaledData: marshaledData, References: 0} return &newEntry, nil } @@ -166,7 +236,7 @@ func CreateNewEntry(ctx sdk.Context, index string, block uint64, marshaledData [ // Function to search for an entry in the storage (latest version's index is index, older versions' index is index_0, index_1, ...) func GetEntryOlderVersionByBlock(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, cdc codec.BinaryCodec, index string, block uint64) (*types.Entry, bool) { // try getting the entry with the original index. return only if the requested block is larger than the entry's block - entry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, index) + entry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, index, types.DO_NOTHING) if found { if block >= entry.GetBlock() { return &entry, true @@ -183,7 +253,7 @@ func GetEntryOlderVersionByBlock(ctx sdk.Context, storeKey sdk.StoreKey, entryKe versionIndex := CreateOldVersionIndex(index, uint64(versionSuffixCounter)) // get the older version entry - entry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, versionIndex) + entry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, versionIndex, types.DO_NOTHING) if found { if block >= entry.GetBlock() { // entry old version found and the requested block is larger than the entry's block -> found the right entry @@ -211,7 +281,7 @@ func GetAllEntriesForIndex(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefi entryList := []*types.Entry{} // try getting the entry with the original index - entry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, index) + entry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, index, types.DO_NOTHING) if found { entryList = append(entryList, &entry) } else { @@ -226,7 +296,7 @@ func GetAllEntriesForIndex(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefi versionIndex := CreateOldVersionIndex(index, uint64(versionSuffixCounter)) // get the older version entry - oldVersionEntry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, versionIndex) + oldVersionEntry, found := GetEntry(ctx, storeKey, entryKeyPrefix, cdc, versionIndex, types.DO_NOTHING) if found { // entry old version found -> append to entry list and increase suffix counter to look for older versions entryList = append(entryList, &oldVersionEntry) diff --git a/common/fixation_entry_test.go b/common/fixation_entry_test.go index 7c35871c5d..a259cee1e6 100644 --- a/common/fixation_entry_test.go +++ b/common/fixation_entry_test.go @@ -26,6 +26,7 @@ type MockKeeper struct { uniqueEntryKeyPrefix string } +// Helper function to init a mock keeper and context func initMockKeeper(t *testing.T) (MockKeeper, sdk.Context) { db := tmdb.NewMemDB() stateStore := store.NewCommitMultiStore(db) @@ -33,7 +34,7 @@ func initMockKeeper(t *testing.T) (MockKeeper, sdk.Context) { registry := codectypes.NewInterfaceRegistry() cdc := codec.NewProtoCodec(registry) - mockStoreKey := sdk.NewKVStoreKey("mockkeeper") + mockStoreKey := sdk.NewKVStoreKey("store_mockkeeper") mockMemStoreKey := storetypes.NewMemoryStoreKey("mem_mockkeeper") stateStore.MountStoreWithDB(mockStoreKey, sdk.StoreTypeIAVL, db) stateStore.MountStoreWithDB(mockMemStoreKey, sdk.StoreTypeMemory, nil) @@ -52,8 +53,8 @@ func initMockKeeper(t *testing.T) (MockKeeper, sdk.Context) { StoreKey: mockStoreKey, MemKey: mockMemStoreKey, Paramstore: mockparamsSubspace, - entryKeyPrefix: "mock", - uniqueEntryKeyPrefix: "MockKeeper", + entryKeyPrefix: "prefix_mock", + uniqueEntryKeyPrefix: "unique_prefix_mock", } ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.TestingLogger()) @@ -84,11 +85,19 @@ func TestFixationEntryAdditionAndRemoval(t *testing.T) { require.Equal(t, marshaledData, marshaledDataFromStorage) // remove the entry - common.RemoveEntry(ctx, mockkeeper.StoreKey, mockkeeper.entryKeyPrefix, dummyIndex) + common.RemoveEntry(ctx, mockkeeper.StoreKey, mockkeeper.Cdc, mockkeeper.entryKeyPrefix, dummyIndex) // make sure there are no more entries with that index entryListFromStorage = common.GetAllEntriesForIndex(ctx, mockkeeper.StoreKey, mockkeeper.entryKeyPrefix, mockkeeper.Cdc, dummyIndex) require.Equal(t, 0, len(entryListFromStorage)) + + // make sure there is no uniqueIndex object with this index + uniqueIndices := common.GetAllFixationEntryUniqueIndex(ctx, mockkeeper.StoreKey, mockkeeper.Cdc, mockkeeper.entryKeyPrefix) + require.Equal(t, 0, len(uniqueIndices)) + + // make sure that the uniqueIndex count is zero + count := common.GetFixationEntryUniqueIndexCount(ctx, mockkeeper.StoreKey, mockkeeper.entryKeyPrefix) + require.Equal(t, uint64(0), count) } // Test that adds two entries in the same block and makes sure that only the latest one is kept @@ -118,6 +127,14 @@ func TestAdditionOfTwoEntriesWithSameIndexInSameBlock(t *testing.T) { // make sure that one entry's data is the same data of the second dummy entry marshaledDataFromStorage := entryListFromStorage[0].MarshaledData require.Equal(t, marshaledData2, marshaledDataFromStorage) + + // make sure there is only one uniqueIndex object with this index + uniqueIndices := common.GetAllFixationEntryUniqueIndex(ctx, mockkeeper.StoreKey, mockkeeper.Cdc, mockkeeper.uniqueEntryKeyPrefix) + require.Equal(t, 1, len(uniqueIndices)) + + // make sure that the uniqueIndex count is one + count := common.GetFixationEntryUniqueIndexCount(ctx, mockkeeper.StoreKey, mockkeeper.uniqueEntryKeyPrefix) + require.Equal(t, uint64(1), count) } // Test adding entry versions and getting an older version @@ -155,4 +172,12 @@ func TestEntryVersions(t *testing.T) { oldEntryIndex := common.CreateOldVersionIndex(dummyIndex, uint64(0)) require.Equal(t, oldEntryIndex, oldEntry.Index) require.Equal(t, marshaledData, oldEntry.MarshaledData) + + // make sure there is only one uniqueIndex object with this index + uniqueIndices := common.GetAllFixationEntryUniqueIndex(ctx, mockkeeper.StoreKey, mockkeeper.Cdc, mockkeeper.uniqueEntryKeyPrefix) + require.Equal(t, 1, len(uniqueIndices)) + + // make sure that the uniqueIndex count is one + count := common.GetFixationEntryUniqueIndexCount(ctx, mockkeeper.StoreKey, mockkeeper.uniqueEntryKeyPrefix) + require.Equal(t, uint64(1), count) } diff --git a/common/fixation_entry_unique_index.go b/common/fixation_entry_unique_index.go index e6da82b025..9c0db5dc56 100644 --- a/common/fixation_entry_unique_index.go +++ b/common/fixation_entry_unique_index.go @@ -47,26 +47,26 @@ func SetFixationEntryUniqueIndexCount(ctx sdk.Context, storeKey sdk.StoreKey, en store.Set(byteKey, bz) } -// AppendFixationEntryUniqueIndex appends a FixationEntryUniqueIndex in the store with a new id and update the count +// AppendFixationEntryUniqueIndex appends a FixationEntryUniqueIndex in the store with a new id and updates the count. It returns the index in the list of the added value (for example, if the first value of the list is added, it'll return 0 (the first index in the list)) func AppendFixationEntryUniqueIndex( ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec, - entryKeyPrefix string, + uniqueIndexEntryKeyPrefix string, fixationEntryUniqueIndex types.UniqueIndex, -) uint64 { +) (lastAddedIndex uint64) { // Create the FixationEntryUniqueIndex - count := GetFixationEntryUniqueIndexCount(ctx, storeKey, entryKeyPrefix) + count := GetFixationEntryUniqueIndexCount(ctx, storeKey, uniqueIndexEntryKeyPrefix) // Set the ID of the appended value fixationEntryUniqueIndex.Id = count - store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(entryKeyPrefix+types.UniqueIndexKey)) + store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(uniqueIndexEntryKeyPrefix+types.UniqueIndexKey)) appendedValue := cdc.MustMarshal(&fixationEntryUniqueIndex) store.Set(GetFixationEntryUniqueIndexIDBytes(fixationEntryUniqueIndex.Id), appendedValue) // Update FixationEntryUniqueIndex count - SetFixationEntryUniqueIndexCount(ctx, storeKey, entryKeyPrefix, count+1) + SetFixationEntryUniqueIndexCount(ctx, storeKey, uniqueIndexEntryKeyPrefix, count+1) return count } @@ -91,8 +91,10 @@ func GetFixationEntryUniqueIndex(ctx sdk.Context, storeKey sdk.StoreKey, cdc cod // RemoveFixationEntryUniqueIndex removes a FixationEntryUniqueIndex from the store func RemoveFixationEntryUniqueIndex(ctx sdk.Context, storeKey sdk.StoreKey, entryKeyPrefix string, id uint64) { + count := GetFixationEntryUniqueIndexCount(ctx, storeKey, entryKeyPrefix) store := prefix.NewStore(ctx.KVStore(storeKey), types.KeyPrefix(entryKeyPrefix+types.UniqueIndexKey)) store.Delete(GetFixationEntryUniqueIndexIDBytes(id)) + SetFixationEntryUniqueIndexCount(ctx, storeKey, entryKeyPrefix, count-1) } // GetAllFixationEntryUniqueIndex returns all FixationEntryUniqueIndex diff --git a/common/fixation_entry_unique_index_test.go b/common/fixation_entry_unique_index_test.go index 4d26d16780..ba2b85d1c7 100644 --- a/common/fixation_entry_unique_index_test.go +++ b/common/fixation_entry_unique_index_test.go @@ -1,6 +1,7 @@ package common_test import ( + "strconv" "testing" "github.com/cosmos/cosmos-sdk/codec" @@ -11,20 +12,36 @@ import ( "github.com/stretchr/testify/require" ) +// Helper function that creates N fixationEntryUniqueIndex objects func createNUniqueIndex(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec, entryKeyPrefix string, n int) []types.UniqueIndex { + // create an empty array of uniqueIndex objects items := make([]types.UniqueIndex, n) for i := range items { - items[i].Id = common.AppendFixationEntryUniqueIndex(ctx, storeKey, cdc, entryKeyPrefix, items[i]) + // create a uniqueIndex object with id=i, uniqueIndex=entryKeyPrefix+"i" + items[i].UniqueIndex = entryKeyPrefix + strconv.FormatInt(int64(i), 10) + items[i].Id = uint64(i) + + // append the uniqueIndex object to the saved list in the store + common.AppendFixationEntryUniqueIndex(ctx, storeKey, cdc, entryKeyPrefix, items[i]) } + return items } +// Test that creates entries and gets them to verify the getter works properly func TestUniqueIndexGet(t *testing.T) { + // init a mock keeper and context mockKeeper, ctx := initMockKeeper(t) + // create 10 uniqueIndex objects items := createNUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix, 10) + + // iterate over the uniqueIndex objects for _, item := range items { + // get the uniqueIndex object from the store got, found := common.GetFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix, item.Id) + + // verify it's found and it's equal to the one we created earlier require.True(t, found) require.Equal(t, nullify.Fill(&item), @@ -33,28 +50,109 @@ func TestUniqueIndexGet(t *testing.T) { } } +// Test that removes entries and verifies they're not in the storage anymore func TestUniqueIndexRemove(t *testing.T) { + // init a mock keeper and context mockKeeper, ctx := initMockKeeper(t) + + // create 10 uniqueIndex objects items := createNUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix, 10) - for _, item := range items { + + // iterate over the uniqueIndex objects + for i, item := range items { + // remove the uniqueIndex object common.RemoveFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.entryKeyPrefix, item.Id) + + // make sure the removed object cannot be found using the getter (gets from the store) _, found := common.GetFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix, item.Id) require.False(t, found) + + // make sure that the uniqueIndex objects count went down by 1 + count := common.GetFixationEntryUniqueIndexCount(ctx, mockKeeper.StoreKey, mockKeeper.entryKeyPrefix) + require.Equal(t, uint64(10-(i+1)), count) } } +// Test that creates N fixationEntryUniqueIndex objects and gets them all from storage to verify they're the same elements func TestUniqueIndexGetAll(t *testing.T) { + // init a mock keeper and context mockKeeper, ctx := initMockKeeper(t) + + // create 10 uniqueIndex objects items := createNUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix, 10) + + // get all the uniqueIndex objects from the store and verify they're the same as the ones we created earlier + itemsFromStorage := common.GetAllFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix) require.ElementsMatch(t, nullify.Fill(items), - nullify.Fill(common.GetAllFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix)), + nullify.Fill(itemsFromStorage), ) } +// Test that fixationEntryUniqueIndex count works properly func TestUniqueIndexCount(t *testing.T) { + // init a mock keeper and context + mockKeeper, ctx := initMockKeeper(t) + + // create 10 uniqueIndex objects + items := createNUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix, 10) + + // get the amount of uniqueIndex objects + uniqueIndexAmount := uint64(len(items)) + + // verify the count saved in the store is the same as the amount of uniqueIndex objects + require.Equal(t, uniqueIndexAmount, common.GetFixationEntryUniqueIndexCount(ctx, mockKeeper.StoreKey, mockKeeper.entryKeyPrefix)) +} + +// Test that creates N fixationEntryUniqueIndex objects, removes one of them, and gets all the entries from the storage to verify that it doesn't exist +func TestRemoveAndGetAll(t *testing.T) { + // init a mock keeper and context mockKeeper, ctx := initMockKeeper(t) + + // create 10 uniqueIndex objects items := createNUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix, 10) - count := uint64(len(items)) - require.Equal(t, count, common.GetFixationEntryUniqueIndexCount(ctx, mockKeeper.StoreKey, mockKeeper.entryKeyPrefix)) + + // save the uniqueIndex object we're going to remove + itemToRemove := items[1] + + // remove the uniqueIndex object + common.RemoveFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.entryKeyPrefix, 1) + + // get all the uniqueIndex objects from the store and verify the number of objects decreased by one + itemsAfterRemoval := common.GetAllFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix) + require.Equal(t, len(items)-1, len(itemsAfterRemoval)) + + // verify that the removed item is no longer in the itemsAfterRemoval list + for _, item := range itemsAfterRemoval { + require.NotEqual(t, item, itemToRemove) + } + + // verify the uniqueIndex objects count saved in the store also decreased by one + count := common.GetFixationEntryUniqueIndexCount(ctx, mockKeeper.StoreKey, mockKeeper.entryKeyPrefix) + require.Equal(t, uint64(len(items)-1), count) +} + +// Test that creates fixations with different prefixes and verifies they are mutually exclusive +func TestDifferentFixations(t *testing.T) { + // init a mock keeper and context + mockKeeper, ctx := initMockKeeper(t) + + // create 10 uniqueIndex objects and another 9 with a different entryKeyPrefix + items := createNUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix, 10) + itemsWithDifferentPrefix := createNUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix+"1", 9) + + // get all the uniqueIndex objects of the first entryKeyPrefix from the store and verify it's equal to the amount of the uniqueIndex objects we created earlier (with the first entryKeyPrefix) + itemsFromStorage := common.GetAllFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix) + require.Equal(t, len(items), len(itemsFromStorage)) + + // get all the uniqueIndex objects of the second entryKeyPrefix from the store and verify it's equal to the amount of the uniqueIndex objects we created earlier (with the second entryKeyPrefix) + itemsWithDifferentPrefixFromStorage := common.GetAllFixationEntryUniqueIndex(ctx, mockKeeper.StoreKey, mockKeeper.Cdc, mockKeeper.entryKeyPrefix+"1") + require.Equal(t, len(itemsWithDifferentPrefix), len(itemsWithDifferentPrefixFromStorage)) + + // go over all the objects of the two lists and verify none is equal (the value of the created uniqueIndex is dependent on the entryKeyPrefix, so they must be different) + for _, item := range itemsFromStorage { + for _, itemDifferentPrefix := range itemsWithDifferentPrefix { + require.NotEqual(t, item, itemDifferentPrefix) + } + } } diff --git a/common/types/constants.go b/common/types/constants.go new file mode 100644 index 0000000000..e3c77157fa --- /dev/null +++ b/common/types/constants.go @@ -0,0 +1,12 @@ +package types + +const ( + STALE_ENTRY_TIME int64 = 1440 // 1440 blocks (equivalent to 24 hours when block_time = 1min) +) + +// References action enum +const ( + ADD_REFERENCE = 0 + SUB_REFERENCE = 1 + DO_NOTHING = 2 +) diff --git a/common/types/fixationEntry.pb.go b/common/types/fixationEntry.pb.go index ab61329135..27306f2d19 100644 --- a/common/types/fixationEntry.pb.go +++ b/common/types/fixationEntry.pb.go @@ -27,6 +27,7 @@ type Entry struct { Index string `protobuf:"bytes,1,opt,name=index,proto3" json:"index,omitempty"` Block uint64 `protobuf:"varint,2,opt,name=block,proto3" json:"block,omitempty"` MarshaledData []byte `protobuf:"bytes,3,opt,name=marshaled_data,json=marshaledData,proto3" json:"marshaled_data,omitempty"` + References uint64 `protobuf:"varint,4,opt,name=references,proto3" json:"references,omitempty"` } func (m *Entry) Reset() { *m = Entry{} } @@ -83,6 +84,13 @@ func (m *Entry) GetMarshaledData() []byte { return nil } +func (m *Entry) GetReferences() uint64 { + if m != nil { + return m.References + } + return 0 +} + type UniqueIndex struct { Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` UniqueIndex string `protobuf:"bytes,2,opt,name=unique_index,json=uniqueIndex,proto3" json:"unique_index,omitempty"` @@ -143,23 +151,24 @@ func init() { func init() { proto.RegisterFile("common/fixationEntry.proto", fileDescriptor_702478ef0512c95d) } var fileDescriptor_702478ef0512c95d = []byte{ - // 249 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0xce, 0xcf, 0xcd, - 0xcd, 0xcf, 0xd3, 0x4f, 0xcb, 0xac, 0x48, 0x2c, 0xc9, 0xcc, 0xcf, 0x73, 0xcd, 0x2b, 0x29, 0xaa, - 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xce, 0x49, 0x2c, 0x4b, 0xcc, 0x4b, 0x2d, 0xd1, - 0x03, 0xd1, 0x7a, 0x10, 0x85, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0x79, 0x7d, 0x10, 0x0b, - 0xa2, 0x54, 0x29, 0x8a, 0x8b, 0x15, 0xac, 0x53, 0x48, 0x84, 0x8b, 0x35, 0x33, 0x2f, 0x25, 0xb5, - 0x42, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc2, 0x01, 0x89, 0x26, 0xe5, 0xe4, 0x27, 0x67, - 0x4b, 0x30, 0x29, 0x30, 0x6a, 0xb0, 0x04, 0x41, 0x38, 0x42, 0xaa, 0x5c, 0x7c, 0xb9, 0x89, 0x45, - 0xc5, 0x19, 0x89, 0x39, 0xa9, 0x29, 0xf1, 0x29, 0x89, 0x25, 0x89, 0x12, 0xcc, 0x0a, 0x8c, 0x1a, - 0x3c, 0x41, 0xbc, 0x70, 0x51, 0x97, 0xc4, 0x92, 0x44, 0x25, 0x07, 0x2e, 0xee, 0xd0, 0xbc, 0xcc, - 0xc2, 0xd2, 0x54, 0x4f, 0xb0, 0x59, 0x7c, 0x5c, 0x4c, 0x99, 0x29, 0x60, 0xe3, 0x59, 0x82, 0x98, - 0x32, 0x53, 0x84, 0x14, 0xb9, 0x78, 0x4a, 0xc1, 0xd2, 0xf1, 0x10, 0x8b, 0x99, 0xc0, 0x16, 0x73, - 0x97, 0x22, 0xb4, 0x38, 0xd9, 0x9d, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, - 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, - 0x4a, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x12, 0xc8, 0x73, 0xfa, 0x50, 0xdf, 0x82, 0x69, 0x7d, 0x68, - 0xb0, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x3d, 0x69, 0x0c, 0x08, 0x00, 0x00, 0xff, - 0xff, 0xc1, 0x7b, 0xfd, 0x2b, 0x2d, 0x01, 0x00, 0x00, + // 270 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x50, 0xb1, 0x4e, 0xc3, 0x30, + 0x10, 0x8d, 0x43, 0x8a, 0x84, 0x5b, 0x3a, 0x98, 0x0e, 0x51, 0x07, 0x2b, 0x54, 0x20, 0x65, 0x4a, + 0x06, 0x76, 0x84, 0x10, 0x0c, 0xac, 0x91, 0x58, 0x58, 0x2a, 0x27, 0x76, 0x53, 0x8b, 0xc4, 0x2e, + 0x8e, 0x83, 0x5a, 0xbe, 0x82, 0xcf, 0x62, 0xec, 0xc8, 0x88, 0x92, 0x1f, 0x41, 0x39, 0x57, 0xd0, + 0xe9, 0x7c, 0xef, 0xee, 0xf9, 0xbd, 0x7b, 0x78, 0x5e, 0xe8, 0xba, 0xd6, 0x2a, 0x5d, 0xc9, 0x2d, + 0xb3, 0x52, 0xab, 0x47, 0x65, 0xcd, 0x2e, 0xd9, 0x18, 0x6d, 0x35, 0xb9, 0xa8, 0xd8, 0x3b, 0x53, + 0xc2, 0x26, 0x43, 0x4d, 0xdc, 0xe2, 0x7c, 0x56, 0xea, 0x52, 0xc3, 0x3c, 0x1d, 0x5e, 0x6e, 0x75, + 0xf1, 0x81, 0x47, 0xc0, 0x24, 0x33, 0x3c, 0x92, 0x8a, 0x8b, 0x6d, 0x88, 0x22, 0x14, 0x9f, 0x65, + 0xae, 0x19, 0xd0, 0xbc, 0xd2, 0xc5, 0x6b, 0xe8, 0x47, 0x28, 0x0e, 0x32, 0xd7, 0x90, 0x6b, 0x3c, + 0xad, 0x99, 0x69, 0xd6, 0xac, 0x12, 0x7c, 0xc9, 0x99, 0x65, 0xe1, 0x49, 0x84, 0xe2, 0x49, 0x76, + 0xfe, 0x87, 0x3e, 0x30, 0xcb, 0x08, 0xc5, 0xd8, 0x88, 0x95, 0x30, 0x42, 0x15, 0xa2, 0x09, 0x03, + 0xf8, 0xe1, 0x08, 0x59, 0xdc, 0xe1, 0xf1, 0xb3, 0x92, 0x6f, 0xad, 0x78, 0x02, 0xad, 0x29, 0xf6, + 0x25, 0x07, 0xf9, 0x20, 0xf3, 0x25, 0x27, 0x97, 0x78, 0xd2, 0xc2, 0x78, 0xe9, 0x8c, 0xf9, 0x60, + 0x6c, 0xdc, 0xfe, 0x53, 0xee, 0x6f, 0xbf, 0x3a, 0x8a, 0xf6, 0x1d, 0x45, 0x3f, 0x1d, 0x45, 0x9f, + 0x3d, 0xf5, 0xf6, 0x3d, 0xf5, 0xbe, 0x7b, 0xea, 0xbd, 0x5c, 0x95, 0xd2, 0xae, 0xdb, 0x7c, 0x38, + 0x3e, 0x3d, 0xa4, 0x01, 0x35, 0x3d, 0xc4, 0x66, 0x77, 0x1b, 0xd1, 0xe4, 0xa7, 0x10, 0xc2, 0xcd, + 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb4, 0x1c, 0xbc, 0x1a, 0x4d, 0x01, 0x00, 0x00, } func (m *Entry) Marshal() (dAtA []byte, err error) { @@ -182,6 +191,11 @@ func (m *Entry) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.References != 0 { + i = encodeVarintFixationEntry(dAtA, i, uint64(m.References)) + i-- + dAtA[i] = 0x20 + } if len(m.MarshaledData) > 0 { i -= len(m.MarshaledData) copy(dAtA[i:], m.MarshaledData) @@ -267,6 +281,9 @@ func (m *Entry) Size() (n int) { if l > 0 { n += 1 + l + sovFixationEntry(uint64(l)) } + if m.References != 0 { + n += 1 + sovFixationEntry(uint64(m.References)) + } return n } @@ -406,6 +423,25 @@ func (m *Entry) Unmarshal(dAtA []byte) error { m.MarshaledData = []byte{} } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field References", wireType) + } + m.References = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFixationEntry + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.References |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipFixationEntry(dAtA[iNdEx:]) diff --git a/proto/common/fixationEntry.proto b/proto/common/fixationEntry.proto index eb8e5b5a92..78cbb430a0 100644 --- a/proto/common/fixationEntry.proto +++ b/proto/common/fixationEntry.proto @@ -8,6 +8,7 @@ message Entry { string index = 1; // unique entry index uint64 block = 2; // block the entry was created bytes marshaled_data = 3; // marshaled data of the entry + uint64 references = 4; // number of references to this entry (number of entities using it) } message UniqueIndex {