github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/cachekv/store_test.go (about)

     1  package cachekv_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	tmrand "github.com/fibonacci-chain/fbc/libs/tendermint/libs/rand"
     8  	dbm "github.com/fibonacci-chain/fbc/libs/tm-db"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/cachekv"
    12  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/dbadapter"
    13  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types"
    14  )
    15  
    16  func newCacheKVStore() types.CacheKVStore {
    17  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    18  	return cachekv.NewStore(mem)
    19  }
    20  
    21  func keyFmt(i int) []byte { return bz(fmt.Sprintf("key%0.8d", i)) }
    22  func valFmt(i int) []byte { return bz(fmt.Sprintf("value%0.8d", i)) }
    23  
    24  func TestCacheKVStore(t *testing.T) {
    25  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    26  	st := cachekv.NewStore(mem)
    27  
    28  	require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
    29  
    30  	// put something in mem and in cache
    31  	mem.Set(keyFmt(1), valFmt(1))
    32  	st.Set(keyFmt(1), valFmt(1))
    33  	require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
    34  
    35  	// update it in cache, shoudn't change mem
    36  	st.Set(keyFmt(1), valFmt(2))
    37  	require.Equal(t, valFmt(2), st.Get(keyFmt(1)))
    38  	require.Equal(t, valFmt(1), mem.Get(keyFmt(1)))
    39  
    40  	// write it. should change mem
    41  	st.Write()
    42  	require.Equal(t, valFmt(2), mem.Get(keyFmt(1)))
    43  	require.Equal(t, valFmt(2), st.Get(keyFmt(1)))
    44  
    45  	// more writes and checks
    46  	st.Write()
    47  	st.Write()
    48  	require.Equal(t, valFmt(2), mem.Get(keyFmt(1)))
    49  	require.Equal(t, valFmt(2), st.Get(keyFmt(1)))
    50  
    51  	// make a new one, check it
    52  	st = cachekv.NewStore(mem)
    53  	require.Equal(t, valFmt(2), st.Get(keyFmt(1)))
    54  
    55  	// make a new one and delete - should not be removed from mem
    56  	st = cachekv.NewStore(mem)
    57  	st.Delete(keyFmt(1))
    58  	require.Empty(t, st.Get(keyFmt(1)))
    59  	require.Equal(t, mem.Get(keyFmt(1)), valFmt(2))
    60  
    61  	// Write. should now be removed from both
    62  	st.Write()
    63  	require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
    64  	require.Empty(t, mem.Get(keyFmt(1)), "Expected `key1` to be empty")
    65  }
    66  
    67  func TestCacheKVStoreNoNilSet(t *testing.T) {
    68  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    69  	st := cachekv.NewStore(mem)
    70  	require.Panics(t, func() { st.Set([]byte("key"), nil) }, "setting a nil value should panic")
    71  }
    72  
    73  func TestCacheKVStoreNested(t *testing.T) {
    74  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    75  	st := cachekv.NewStore(mem)
    76  
    77  	// set. check its there on st and not on mem.
    78  	st.Set(keyFmt(1), valFmt(1))
    79  	require.Empty(t, mem.Get(keyFmt(1)))
    80  	require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
    81  
    82  	// make a new from st and check
    83  	st2 := cachekv.NewStore(st)
    84  	require.Equal(t, valFmt(1), st2.Get(keyFmt(1)))
    85  
    86  	// update the value on st2, check it only effects st2
    87  	st2.Set(keyFmt(1), valFmt(3))
    88  	require.Equal(t, []byte(nil), mem.Get(keyFmt(1)))
    89  	require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
    90  	require.Equal(t, valFmt(3), st2.Get(keyFmt(1)))
    91  
    92  	// st2 writes to its parent, st. doesnt effect mem
    93  	st2.Write()
    94  	require.Equal(t, []byte(nil), mem.Get(keyFmt(1)))
    95  	require.Equal(t, valFmt(3), st.Get(keyFmt(1)))
    96  
    97  	// updates mem
    98  	st.Write()
    99  	require.Equal(t, valFmt(3), mem.Get(keyFmt(1)))
   100  }
   101  
   102  func TestCacheKVIteratorBounds(t *testing.T) {
   103  	st := newCacheKVStore()
   104  
   105  	// set some items
   106  	nItems := 5
   107  	for i := 0; i < nItems; i++ {
   108  		st.Set(keyFmt(i), valFmt(i))
   109  	}
   110  
   111  	// iterate over all of them
   112  	itr := st.Iterator(nil, nil)
   113  	var i = 0
   114  	for ; itr.Valid(); itr.Next() {
   115  		k, v := itr.Key(), itr.Value()
   116  		require.Equal(t, keyFmt(i), k)
   117  		require.Equal(t, valFmt(i), v)
   118  		i++
   119  	}
   120  	require.Equal(t, nItems, i)
   121  
   122  	// iterate over none
   123  	itr = st.Iterator(bz("money"), nil)
   124  	i = 0
   125  	for ; itr.Valid(); itr.Next() {
   126  		i++
   127  	}
   128  	require.Equal(t, 0, i)
   129  
   130  	// iterate over lower
   131  	itr = st.Iterator(keyFmt(0), keyFmt(3))
   132  	i = 0
   133  	for ; itr.Valid(); itr.Next() {
   134  		k, v := itr.Key(), itr.Value()
   135  		require.Equal(t, keyFmt(i), k)
   136  		require.Equal(t, valFmt(i), v)
   137  		i++
   138  	}
   139  	require.Equal(t, 3, i)
   140  
   141  	// iterate over upper
   142  	itr = st.Iterator(keyFmt(2), keyFmt(4))
   143  	i = 2
   144  	for ; itr.Valid(); itr.Next() {
   145  		k, v := itr.Key(), itr.Value()
   146  		require.Equal(t, keyFmt(i), k)
   147  		require.Equal(t, valFmt(i), v)
   148  		i++
   149  	}
   150  	require.Equal(t, 4, i)
   151  }
   152  
   153  func TestCacheKVMergeIteratorBasics(t *testing.T) {
   154  	st := newCacheKVStore()
   155  
   156  	// set and delete an item in the cache, iterator should be empty
   157  	k, v := keyFmt(0), valFmt(0)
   158  	st.Set(k, v)
   159  	st.Delete(k)
   160  	assertIterateDomain(t, st, 0)
   161  
   162  	// now set it and assert its there
   163  	st.Set(k, v)
   164  	assertIterateDomain(t, st, 1)
   165  
   166  	// write it and assert its there
   167  	st.Write()
   168  	assertIterateDomain(t, st, 1)
   169  
   170  	// remove it in cache and assert its not
   171  	st.Delete(k)
   172  	assertIterateDomain(t, st, 0)
   173  
   174  	// write the delete and assert its not there
   175  	st.Write()
   176  	assertIterateDomain(t, st, 0)
   177  
   178  	// add two keys and assert theyre there
   179  	k1, v1 := keyFmt(1), valFmt(1)
   180  	st.Set(k, v)
   181  	st.Set(k1, v1)
   182  	assertIterateDomain(t, st, 2)
   183  
   184  	// write it and assert theyre there
   185  	st.Write()
   186  	assertIterateDomain(t, st, 2)
   187  
   188  	// remove one in cache and assert its not
   189  	st.Delete(k1)
   190  	assertIterateDomain(t, st, 1)
   191  
   192  	// write the delete and assert its not there
   193  	st.Write()
   194  	assertIterateDomain(t, st, 1)
   195  
   196  	// delete the other key in cache and asserts its empty
   197  	st.Delete(k)
   198  	assertIterateDomain(t, st, 0)
   199  }
   200  
   201  func TestCacheKVMergeIteratorDeleteLast(t *testing.T) {
   202  	st := newCacheKVStore()
   203  
   204  	// set some items and write them
   205  	nItems := 5
   206  	for i := 0; i < nItems; i++ {
   207  		st.Set(keyFmt(i), valFmt(i))
   208  	}
   209  	st.Write()
   210  
   211  	// set some more items and leave dirty
   212  	for i := nItems; i < nItems*2; i++ {
   213  		st.Set(keyFmt(i), valFmt(i))
   214  	}
   215  
   216  	// iterate over all of them
   217  	assertIterateDomain(t, st, nItems*2)
   218  
   219  	// delete them all
   220  	for i := 0; i < nItems*2; i++ {
   221  		last := nItems*2 - 1 - i
   222  		st.Delete(keyFmt(last))
   223  		assertIterateDomain(t, st, last)
   224  	}
   225  }
   226  
   227  func TestCacheKVMergeIteratorDeletes(t *testing.T) {
   228  	st := newCacheKVStore()
   229  	truth := dbm.NewMemDB()
   230  
   231  	// set some items and write them
   232  	nItems := 10
   233  	for i := 0; i < nItems; i++ {
   234  		doOp(st, truth, opSet, i)
   235  	}
   236  	st.Write()
   237  
   238  	// delete every other item, starting from 0
   239  	for i := 0; i < nItems; i += 2 {
   240  		doOp(st, truth, opDel, i)
   241  		assertIterateDomainCompare(t, st, truth)
   242  	}
   243  
   244  	// reset
   245  	st = newCacheKVStore()
   246  	truth = dbm.NewMemDB()
   247  
   248  	// set some items and write them
   249  	for i := 0; i < nItems; i++ {
   250  		doOp(st, truth, opSet, i)
   251  	}
   252  	st.Write()
   253  
   254  	// delete every other item, starting from 1
   255  	for i := 1; i < nItems; i += 2 {
   256  		doOp(st, truth, opDel, i)
   257  		assertIterateDomainCompare(t, st, truth)
   258  	}
   259  }
   260  
   261  func TestCacheKVMergeIteratorChunks(t *testing.T) {
   262  	st := newCacheKVStore()
   263  
   264  	// Use the truth to check values on the merge iterator
   265  	truth := dbm.NewMemDB()
   266  
   267  	// sets to the parent
   268  	setRange(st, truth, 0, 20)
   269  	setRange(st, truth, 40, 60)
   270  	st.Write()
   271  
   272  	// sets to the cache
   273  	setRange(st, truth, 20, 40)
   274  	setRange(st, truth, 60, 80)
   275  	assertIterateDomainCheck(t, st, truth, []keyRange{{0, 80}})
   276  
   277  	// remove some parents and some cache
   278  	deleteRange(st, truth, 15, 25)
   279  	assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 80}})
   280  
   281  	// remove some parents and some cache
   282  	deleteRange(st, truth, 35, 45)
   283  	assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 35}, {45, 80}})
   284  
   285  	// write, add more to the cache, and delete some cache
   286  	st.Write()
   287  	setRange(st, truth, 38, 42)
   288  	deleteRange(st, truth, 40, 43)
   289  	assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 35}, {38, 40}, {45, 80}})
   290  }
   291  
   292  func TestCacheKVMergeIteratorRandom(t *testing.T) {
   293  	st := newCacheKVStore()
   294  	truth := dbm.NewMemDB()
   295  
   296  	start, end := 25, 975
   297  	max := 1000
   298  	setRange(st, truth, start, end)
   299  
   300  	// do an op, test the iterator
   301  	for i := 0; i < 2000; i++ {
   302  		doRandomOp(st, truth, max)
   303  		assertIterateDomainCompare(t, st, truth)
   304  	}
   305  }
   306  
   307  //-------------------------------------------------------------------------------------------
   308  // do some random ops
   309  
   310  const (
   311  	opSet      = 0
   312  	opSetRange = 1
   313  	opDel      = 2
   314  	opDelRange = 3
   315  	opWrite    = 4
   316  
   317  	totalOps = 5 // number of possible operations
   318  )
   319  
   320  func randInt(n int) int {
   321  	return tmrand.NewRand().Int() % n
   322  }
   323  
   324  // useful for replaying a error case if we find one
   325  func doOp(st types.CacheKVStore, truth dbm.DB, op int, args ...int) {
   326  	switch op {
   327  	case opSet:
   328  		k := args[0]
   329  		st.Set(keyFmt(k), valFmt(k))
   330  		truth.Set(keyFmt(k), valFmt(k))
   331  	case opSetRange:
   332  		start := args[0]
   333  		end := args[1]
   334  		setRange(st, truth, start, end)
   335  	case opDel:
   336  		k := args[0]
   337  		st.Delete(keyFmt(k))
   338  		truth.Delete(keyFmt(k))
   339  	case opDelRange:
   340  		start := args[0]
   341  		end := args[1]
   342  		deleteRange(st, truth, start, end)
   343  	case opWrite:
   344  		st.Write()
   345  	}
   346  }
   347  
   348  func doRandomOp(st types.CacheKVStore, truth dbm.DB, maxKey int) {
   349  	r := randInt(totalOps)
   350  	switch r {
   351  	case opSet:
   352  		k := randInt(maxKey)
   353  		st.Set(keyFmt(k), valFmt(k))
   354  		truth.Set(keyFmt(k), valFmt(k))
   355  	case opSetRange:
   356  		start := randInt(maxKey - 2)
   357  		end := randInt(maxKey-start) + start
   358  		setRange(st, truth, start, end)
   359  	case opDel:
   360  		k := randInt(maxKey)
   361  		st.Delete(keyFmt(k))
   362  		truth.Delete(keyFmt(k))
   363  	case opDelRange:
   364  		start := randInt(maxKey - 2)
   365  		end := randInt(maxKey-start) + start
   366  		deleteRange(st, truth, start, end)
   367  	case opWrite:
   368  		st.Write()
   369  	}
   370  }
   371  
   372  //-------------------------------------------------------------------------------------------
   373  
   374  // iterate over whole domain
   375  func assertIterateDomain(t *testing.T, st types.KVStore, expectedN int) {
   376  	itr := st.Iterator(nil, nil)
   377  	var i = 0
   378  	for ; itr.Valid(); itr.Next() {
   379  		k, v := itr.Key(), itr.Value()
   380  		require.Equal(t, keyFmt(i), k)
   381  		require.Equal(t, valFmt(i), v)
   382  		i++
   383  	}
   384  	require.Equal(t, expectedN, i)
   385  }
   386  
   387  func assertIterateDomainCheck(t *testing.T, st types.KVStore, mem dbm.DB, r []keyRange) {
   388  	// iterate over each and check they match the other
   389  	itr := st.Iterator(nil, nil)
   390  	itr2, err := mem.Iterator(nil, nil) // ground truth
   391  	require.NoError(t, err)
   392  
   393  	krc := newKeyRangeCounter(r)
   394  	i := 0
   395  
   396  	for ; krc.valid(); krc.next() {
   397  		require.True(t, itr.Valid())
   398  		require.True(t, itr2.Valid())
   399  
   400  		// check the key/val matches the ground truth
   401  		k, v := itr.Key(), itr.Value()
   402  		k2, v2 := itr2.Key(), itr2.Value()
   403  		require.Equal(t, k, k2)
   404  		require.Equal(t, v, v2)
   405  
   406  		// check they match the counter
   407  		require.Equal(t, k, keyFmt(krc.key()))
   408  
   409  		itr.Next()
   410  		itr2.Next()
   411  		i++
   412  	}
   413  
   414  	require.False(t, itr.Valid())
   415  	require.False(t, itr2.Valid())
   416  }
   417  
   418  func assertIterateDomainCompare(t *testing.T, st types.KVStore, mem dbm.DB) {
   419  	// iterate over each and check they match the other
   420  	itr := st.Iterator(nil, nil)
   421  	itr2, err := mem.Iterator(nil, nil) // ground truth
   422  	require.NoError(t, err)
   423  	checkIterators(t, itr, itr2)
   424  	checkIterators(t, itr2, itr)
   425  }
   426  
   427  func checkIterators(t *testing.T, itr, itr2 types.Iterator) {
   428  	for ; itr.Valid(); itr.Next() {
   429  		require.True(t, itr2.Valid())
   430  		k, v := itr.Key(), itr.Value()
   431  		k2, v2 := itr2.Key(), itr2.Value()
   432  		require.Equal(t, k, k2)
   433  		require.Equal(t, v, v2)
   434  		itr2.Next()
   435  	}
   436  	require.False(t, itr.Valid())
   437  	require.False(t, itr2.Valid())
   438  }
   439  
   440  //--------------------------------------------------------
   441  
   442  func setRange(st types.KVStore, mem dbm.DB, start, end int) {
   443  	for i := start; i < end; i++ {
   444  		st.Set(keyFmt(i), valFmt(i))
   445  		mem.Set(keyFmt(i), valFmt(i))
   446  	}
   447  }
   448  
   449  func deleteRange(st types.KVStore, mem dbm.DB, start, end int) {
   450  	for i := start; i < end; i++ {
   451  		st.Delete(keyFmt(i))
   452  		mem.Delete(keyFmt(i))
   453  	}
   454  }
   455  
   456  //--------------------------------------------------------
   457  
   458  type keyRange struct {
   459  	start int
   460  	end   int
   461  }
   462  
   463  func (kr keyRange) len() int {
   464  	return kr.end - kr.start
   465  }
   466  
   467  func newKeyRangeCounter(kr []keyRange) *keyRangeCounter {
   468  	return &keyRangeCounter{keyRanges: kr}
   469  }
   470  
   471  // we can iterate over this and make sure our real iterators have all the right keys
   472  type keyRangeCounter struct {
   473  	rangeIdx  int
   474  	idx       int
   475  	keyRanges []keyRange
   476  }
   477  
   478  func (krc *keyRangeCounter) valid() bool {
   479  	maxRangeIdx := len(krc.keyRanges) - 1
   480  	maxRange := krc.keyRanges[maxRangeIdx]
   481  
   482  	// if we're not in the max range, we're valid
   483  	if krc.rangeIdx <= maxRangeIdx &&
   484  		krc.idx < maxRange.len() {
   485  		return true
   486  	}
   487  
   488  	return false
   489  }
   490  
   491  func (krc *keyRangeCounter) next() {
   492  	thisKeyRange := krc.keyRanges[krc.rangeIdx]
   493  	if krc.idx == thisKeyRange.len()-1 {
   494  		krc.rangeIdx++
   495  		krc.idx = 0
   496  	} else {
   497  		krc.idx++
   498  	}
   499  }
   500  
   501  func (krc *keyRangeCounter) key() int {
   502  	thisKeyRange := krc.keyRanges[krc.rangeIdx]
   503  	return thisKeyRange.start + krc.idx
   504  }
   505  
   506  //--------------------------------------------------------
   507  
   508  func bz(s string) []byte { return []byte(s) }
   509  
   510  func BenchmarkCacheKVStoreGetNoKeyFound(b *testing.B) {
   511  	st := newCacheKVStore()
   512  	b.ResetTimer()
   513  	// assumes b.N < 2**24
   514  	for i := 0; i < b.N; i++ {
   515  		st.Get([]byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)})
   516  	}
   517  }
   518  
   519  func BenchmarkCacheKVStoreGetKeyFound(b *testing.B) {
   520  	st := newCacheKVStore()
   521  	for i := 0; i < b.N; i++ {
   522  		arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)}
   523  		st.Set(arr, arr)
   524  	}
   525  	b.ResetTimer()
   526  	// assumes b.N < 2**24
   527  	for i := 0; i < b.N; i++ {
   528  		st.Get([]byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)})
   529  	}
   530  }