github.com/Finschia/finschia-sdk@v0.49.1/store/prefix/store_test.go (about)

     1  package prefix
     2  
     3  import (
     4  	"crypto/rand"
     5  	"testing"
     6  
     7  	liavl "github.com/cosmos/iavl"
     8  	"github.com/stretchr/testify/require"
     9  	dbm "github.com/tendermint/tm-db"
    10  
    11  	"github.com/Finschia/finschia-sdk/store/cachekv"
    12  	"github.com/Finschia/finschia-sdk/store/dbadapter"
    13  	"github.com/Finschia/finschia-sdk/store/gaskv"
    14  	"github.com/Finschia/finschia-sdk/store/iavl"
    15  	"github.com/Finschia/finschia-sdk/store/types"
    16  	sdk "github.com/Finschia/finschia-sdk/types"
    17  )
    18  
    19  // copied from iavl/store_test.go
    20  var (
    21  	cacheSize = 100
    22  )
    23  
    24  func bz(s string) []byte { return []byte(s) }
    25  
    26  type kvpair struct {
    27  	key   []byte
    28  	value []byte
    29  }
    30  
    31  func genRandomKVPairs(t *testing.T) []kvpair {
    32  	t.Helper()
    33  	kvps := make([]kvpair, 20)
    34  
    35  	for i := 0; i < 20; i++ {
    36  		kvps[i].key = make([]byte, 32)
    37  		_, err := rand.Read(kvps[i].key)
    38  		require.NoError(t, err)
    39  		kvps[i].value = make([]byte, 32)
    40  		_, err = rand.Read(kvps[i].value)
    41  		require.NoError(t, err)
    42  	}
    43  
    44  	return kvps
    45  }
    46  
    47  func setRandomKVPairs(t *testing.T, store types.KVStore) []kvpair {
    48  	t.Helper()
    49  	kvps := genRandomKVPairs(t)
    50  	for _, kvp := range kvps {
    51  		store.Set(kvp.key, kvp.value)
    52  	}
    53  	return kvps
    54  }
    55  
    56  func testPrefixStore(t *testing.T, baseStore types.KVStore, prefix []byte) {
    57  	t.Helper()
    58  	prefixStore := NewStore(baseStore, prefix)
    59  	prefixPrefixStore := NewStore(prefixStore, []byte("prefix"))
    60  
    61  	require.Panics(t, func() { prefixStore.Get(nil) })
    62  	require.Panics(t, func() { prefixStore.Set(nil, []byte{}) })
    63  
    64  	kvps := setRandomKVPairs(t, prefixPrefixStore)
    65  
    66  	for i := 0; i < 20; i++ {
    67  		key := kvps[i].key
    68  		value := kvps[i].value
    69  		require.True(t, prefixPrefixStore.Has(key))
    70  		require.Equal(t, value, prefixPrefixStore.Get(key))
    71  
    72  		key = append([]byte("prefix"), key...)
    73  		require.True(t, prefixStore.Has(key))
    74  		require.Equal(t, value, prefixStore.Get(key))
    75  		key = append(prefix, key...)
    76  		require.True(t, baseStore.Has(key))
    77  		require.Equal(t, value, baseStore.Get(key))
    78  
    79  		key = kvps[i].key
    80  		prefixPrefixStore.Delete(key)
    81  		require.False(t, prefixPrefixStore.Has(key))
    82  		require.Nil(t, prefixPrefixStore.Get(key))
    83  		key = append([]byte("prefix"), key...)
    84  		require.False(t, prefixStore.Has(key))
    85  		require.Nil(t, prefixStore.Get(key))
    86  		key = append(prefix, key...)
    87  		require.False(t, baseStore.Has(key))
    88  		require.Nil(t, baseStore.Get(key))
    89  	}
    90  }
    91  
    92  func TestIAVLStorePrefix(t *testing.T) {
    93  	db := dbm.NewMemDB()
    94  	tree, err := liavl.NewMutableTree(db, cacheSize, false)
    95  	require.NoError(t, err)
    96  	iavlStore := iavl.UnsafeNewStore(tree)
    97  
    98  	testPrefixStore(t, iavlStore, []byte("test"))
    99  }
   100  
   101  func TestPrefixKVStoreNoNilSet(t *testing.T) {
   102  	meter := types.NewGasMeter(100000000)
   103  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
   104  	gasStore := gaskv.NewStore(mem, meter, types.KVGasConfig())
   105  	require.Panics(t, func() { gasStore.Set([]byte("key"), nil) }, "setting a nil value should panic")
   106  }
   107  
   108  func TestPrefixStoreIterate(t *testing.T) {
   109  	db := dbm.NewMemDB()
   110  	baseStore := dbadapter.Store{DB: db}
   111  	prefix := []byte("test")
   112  	prefixStore := NewStore(baseStore, prefix)
   113  
   114  	setRandomKVPairs(t, prefixStore)
   115  
   116  	bIter := types.KVStorePrefixIterator(baseStore, prefix)
   117  	pIter := types.KVStorePrefixIterator(prefixStore, nil)
   118  
   119  	for bIter.Valid() && pIter.Valid() {
   120  		require.Equal(t, bIter.Key(), append(prefix, pIter.Key()...))
   121  		require.Equal(t, bIter.Value(), pIter.Value())
   122  
   123  		bIter.Next()
   124  		pIter.Next()
   125  	}
   126  
   127  	bIter.Close()
   128  	pIter.Close()
   129  }
   130  
   131  func incFirstByte(bz []byte) {
   132  	bz[0]++
   133  }
   134  
   135  func TestCloneAppend(t *testing.T) {
   136  	kvps := genRandomKVPairs(t)
   137  	for _, kvp := range kvps {
   138  		bz := cloneAppend(kvp.key, kvp.value)
   139  		require.Equal(t, bz, append(kvp.key, kvp.value...))
   140  
   141  		incFirstByte(bz)
   142  		require.NotEqual(t, bz, append(kvp.key, kvp.value...))
   143  
   144  		bz = cloneAppend(kvp.key, kvp.value)
   145  		incFirstByte(kvp.key)
   146  		require.NotEqual(t, bz, append(kvp.key, kvp.value...))
   147  
   148  		bz = cloneAppend(kvp.key, kvp.value)
   149  		incFirstByte(kvp.value)
   150  		require.NotEqual(t, bz, append(kvp.key, kvp.value...))
   151  	}
   152  }
   153  
   154  func TestPrefixStoreIteratorEdgeCase(t *testing.T) {
   155  	db := dbm.NewMemDB()
   156  	baseStore := dbadapter.Store{DB: db}
   157  
   158  	// overflow in cpIncr
   159  	prefix := []byte{0xAA, 0xFF, 0xFF}
   160  	prefixStore := NewStore(baseStore, prefix)
   161  
   162  	// ascending order
   163  	baseStore.Set([]byte{0xAA, 0xFF, 0xFE}, []byte{})
   164  	baseStore.Set([]byte{0xAA, 0xFF, 0xFE, 0x00}, []byte{})
   165  	baseStore.Set([]byte{0xAA, 0xFF, 0xFF}, []byte{})
   166  	baseStore.Set([]byte{0xAA, 0xFF, 0xFF, 0x00}, []byte{})
   167  	baseStore.Set([]byte{0xAB}, []byte{})
   168  	baseStore.Set([]byte{0xAB, 0x00}, []byte{})
   169  	baseStore.Set([]byte{0xAB, 0x00, 0x00}, []byte{})
   170  
   171  	iter := prefixStore.Iterator(nil, nil)
   172  
   173  	checkDomain(t, iter, nil, nil)
   174  	checkItem(t, iter, []byte{}, bz(""))
   175  	checkNext(t, iter, true)
   176  	checkItem(t, iter, []byte{0x00}, bz(""))
   177  	checkNext(t, iter, false)
   178  
   179  	checkInvalid(t, iter)
   180  
   181  	iter.Close()
   182  }
   183  
   184  func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) {
   185  	db := dbm.NewMemDB()
   186  	baseStore := dbadapter.Store{DB: db}
   187  
   188  	// overflow in cpIncr
   189  	prefix := []byte{0xAA, 0xFF, 0xFF}
   190  	prefixStore := NewStore(baseStore, prefix)
   191  
   192  	// descending order
   193  	baseStore.Set([]byte{0xAB, 0x00, 0x00}, []byte{})
   194  	baseStore.Set([]byte{0xAB, 0x00}, []byte{})
   195  	baseStore.Set([]byte{0xAB}, []byte{})
   196  	baseStore.Set([]byte{0xAA, 0xFF, 0xFF, 0x00}, []byte{})
   197  	baseStore.Set([]byte{0xAA, 0xFF, 0xFF}, []byte{})
   198  	baseStore.Set([]byte{0xAA, 0xFF, 0xFE, 0x00}, []byte{})
   199  	baseStore.Set([]byte{0xAA, 0xFF, 0xFE}, []byte{})
   200  
   201  	iter := prefixStore.ReverseIterator(nil, nil)
   202  
   203  	checkDomain(t, iter, nil, nil)
   204  	checkItem(t, iter, []byte{0x00}, bz(""))
   205  	checkNext(t, iter, true)
   206  	checkItem(t, iter, []byte{}, bz(""))
   207  	checkNext(t, iter, false)
   208  
   209  	checkInvalid(t, iter)
   210  
   211  	iter.Close()
   212  
   213  	db = dbm.NewMemDB()
   214  	baseStore = dbadapter.Store{DB: db}
   215  
   216  	// underflow in cpDecr
   217  	prefix = []byte{0xAA, 0x00, 0x00}
   218  	prefixStore = NewStore(baseStore, prefix)
   219  
   220  	baseStore.Set([]byte{0xAB, 0x00, 0x01, 0x00, 0x00}, []byte{})
   221  	baseStore.Set([]byte{0xAB, 0x00, 0x01, 0x00}, []byte{})
   222  	baseStore.Set([]byte{0xAB, 0x00, 0x01}, []byte{})
   223  	baseStore.Set([]byte{0xAA, 0x00, 0x00, 0x00}, []byte{})
   224  	baseStore.Set([]byte{0xAA, 0x00, 0x00}, []byte{})
   225  	baseStore.Set([]byte{0xA9, 0xFF, 0xFF, 0x00}, []byte{})
   226  	baseStore.Set([]byte{0xA9, 0xFF, 0xFF}, []byte{})
   227  
   228  	iter = prefixStore.ReverseIterator(nil, nil)
   229  
   230  	checkDomain(t, iter, nil, nil)
   231  	checkItem(t, iter, []byte{0x00}, bz(""))
   232  	checkNext(t, iter, true)
   233  	checkItem(t, iter, []byte{}, bz(""))
   234  	checkNext(t, iter, false)
   235  
   236  	checkInvalid(t, iter)
   237  
   238  	iter.Close()
   239  }
   240  
   241  // Tests below are ported from https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db_test.go
   242  
   243  func mockStoreWithStuff() types.KVStore {
   244  	db := dbm.NewMemDB()
   245  	store := dbadapter.Store{DB: db}
   246  	// Under "key" prefix
   247  	store.Set(bz("key"), bz("value"))
   248  	store.Set(bz("key1"), bz("value1"))
   249  	store.Set(bz("key2"), bz("value2"))
   250  	store.Set(bz("key3"), bz("value3"))
   251  	store.Set(bz("something"), bz("else"))
   252  	store.Set(bz("k"), bz(sdk.PrefixValidator))
   253  	store.Set(bz("ke"), bz("valu"))
   254  	store.Set(bz("kee"), bz("valuu"))
   255  	return store
   256  }
   257  
   258  func checkValue(t *testing.T, store types.KVStore, key, expected []byte) {
   259  	t.Helper()
   260  	bz := store.Get(key)
   261  	require.Equal(t, expected, bz)
   262  }
   263  
   264  func checkValid(t *testing.T, itr types.Iterator, expected bool) {
   265  	t.Helper()
   266  	valid := itr.Valid()
   267  	require.Equal(t, expected, valid)
   268  }
   269  
   270  func checkNext(t *testing.T, itr types.Iterator, expected bool) {
   271  	t.Helper()
   272  	itr.Next()
   273  	valid := itr.Valid()
   274  	require.Equal(t, expected, valid)
   275  }
   276  
   277  func checkDomain(t *testing.T, itr types.Iterator, start, end []byte) {
   278  	t.Helper()
   279  	ds, de := itr.Domain()
   280  	require.Equal(t, start, ds)
   281  	require.Equal(t, end, de)
   282  }
   283  
   284  func checkItem(t *testing.T, itr types.Iterator, key, value []byte) {
   285  	t.Helper()
   286  	require.Exactly(t, key, itr.Key())
   287  	require.Exactly(t, value, itr.Value())
   288  }
   289  
   290  func checkInvalid(t *testing.T, itr types.Iterator) {
   291  	t.Helper()
   292  	checkValid(t, itr, false)
   293  	checkKeyPanics(t, itr)
   294  	checkValuePanics(t, itr)
   295  	checkNextPanics(t, itr)
   296  }
   297  
   298  func checkKeyPanics(t *testing.T, itr types.Iterator) {
   299  	t.Helper()
   300  	require.Panics(t, func() { itr.Key() })
   301  }
   302  
   303  func checkValuePanics(t *testing.T, itr types.Iterator) {
   304  	t.Helper()
   305  	require.Panics(t, func() { itr.Value() })
   306  }
   307  
   308  func checkNextPanics(t *testing.T, itr types.Iterator) {
   309  	t.Helper()
   310  	require.Panics(t, func() { itr.Next() })
   311  }
   312  
   313  func TestPrefixDBSimple(t *testing.T) {
   314  	store := mockStoreWithStuff()
   315  	pstore := NewStore(store, bz("key"))
   316  
   317  	checkValue(t, pstore, bz("key"), nil)
   318  	checkValue(t, pstore, bz(""), bz("value"))
   319  	checkValue(t, pstore, bz("key1"), nil)
   320  	checkValue(t, pstore, bz("1"), bz("value1"))
   321  	checkValue(t, pstore, bz("key2"), nil)
   322  	checkValue(t, pstore, bz("2"), bz("value2"))
   323  	checkValue(t, pstore, bz("key3"), nil)
   324  	checkValue(t, pstore, bz("3"), bz("value3"))
   325  	checkValue(t, pstore, bz("something"), nil)
   326  	checkValue(t, pstore, bz("k"), nil)
   327  	checkValue(t, pstore, bz("ke"), nil)
   328  	checkValue(t, pstore, bz("kee"), nil)
   329  }
   330  
   331  func TestPrefixDBIterator1(t *testing.T) {
   332  	store := mockStoreWithStuff()
   333  	pstore := NewStore(store, bz("key"))
   334  
   335  	itr := pstore.Iterator(nil, nil)
   336  	checkDomain(t, itr, nil, nil)
   337  	checkItem(t, itr, bz(""), bz("value"))
   338  	checkNext(t, itr, true)
   339  	checkItem(t, itr, bz("1"), bz("value1"))
   340  	checkNext(t, itr, true)
   341  	checkItem(t, itr, bz("2"), bz("value2"))
   342  	checkNext(t, itr, true)
   343  	checkItem(t, itr, bz("3"), bz("value3"))
   344  	checkNext(t, itr, false)
   345  	checkInvalid(t, itr)
   346  	itr.Close()
   347  }
   348  
   349  func TestPrefixDBIterator2(t *testing.T) {
   350  	store := mockStoreWithStuff()
   351  	pstore := NewStore(store, bz("key"))
   352  
   353  	itr := pstore.Iterator(nil, bz(""))
   354  	checkDomain(t, itr, nil, bz(""))
   355  	checkInvalid(t, itr)
   356  	itr.Close()
   357  }
   358  
   359  func TestPrefixDBIterator3(t *testing.T) {
   360  	store := mockStoreWithStuff()
   361  	pstore := NewStore(store, bz("key"))
   362  
   363  	itr := pstore.Iterator(bz(""), nil)
   364  	checkDomain(t, itr, bz(""), nil)
   365  	checkItem(t, itr, bz(""), bz("value"))
   366  	checkNext(t, itr, true)
   367  	checkItem(t, itr, bz("1"), bz("value1"))
   368  	checkNext(t, itr, true)
   369  	checkItem(t, itr, bz("2"), bz("value2"))
   370  	checkNext(t, itr, true)
   371  	checkItem(t, itr, bz("3"), bz("value3"))
   372  	checkNext(t, itr, false)
   373  	checkInvalid(t, itr)
   374  	itr.Close()
   375  }
   376  
   377  func TestPrefixDBIterator4(t *testing.T) {
   378  	store := mockStoreWithStuff()
   379  	pstore := NewStore(store, bz("key"))
   380  
   381  	itr := pstore.Iterator(bz(""), bz(""))
   382  	checkDomain(t, itr, bz(""), bz(""))
   383  	checkInvalid(t, itr)
   384  	itr.Close()
   385  }
   386  
   387  func TestPrefixDBReverseIterator1(t *testing.T) {
   388  	store := mockStoreWithStuff()
   389  	pstore := NewStore(store, bz("key"))
   390  
   391  	itr := pstore.ReverseIterator(nil, nil)
   392  	checkDomain(t, itr, nil, nil)
   393  	checkItem(t, itr, bz("3"), bz("value3"))
   394  	checkNext(t, itr, true)
   395  	checkItem(t, itr, bz("2"), bz("value2"))
   396  	checkNext(t, itr, true)
   397  	checkItem(t, itr, bz("1"), bz("value1"))
   398  	checkNext(t, itr, true)
   399  	checkItem(t, itr, bz(""), bz("value"))
   400  	checkNext(t, itr, false)
   401  	checkInvalid(t, itr)
   402  	itr.Close()
   403  }
   404  
   405  func TestPrefixDBReverseIterator2(t *testing.T) {
   406  	store := mockStoreWithStuff()
   407  	pstore := NewStore(store, bz("key"))
   408  
   409  	itr := pstore.ReverseIterator(bz(""), nil)
   410  	checkDomain(t, itr, bz(""), nil)
   411  	checkItem(t, itr, bz("3"), bz("value3"))
   412  	checkNext(t, itr, true)
   413  	checkItem(t, itr, bz("2"), bz("value2"))
   414  	checkNext(t, itr, true)
   415  	checkItem(t, itr, bz("1"), bz("value1"))
   416  	checkNext(t, itr, true)
   417  	checkItem(t, itr, bz(""), bz("value"))
   418  	checkNext(t, itr, false)
   419  	checkInvalid(t, itr)
   420  	itr.Close()
   421  }
   422  
   423  func TestPrefixDBReverseIterator3(t *testing.T) {
   424  	store := mockStoreWithStuff()
   425  	pstore := NewStore(store, bz("key"))
   426  
   427  	itr := pstore.ReverseIterator(nil, bz(""))
   428  	checkDomain(t, itr, nil, bz(""))
   429  	checkInvalid(t, itr)
   430  	itr.Close()
   431  }
   432  
   433  func TestPrefixDBReverseIterator4(t *testing.T) {
   434  	store := mockStoreWithStuff()
   435  	pstore := NewStore(store, bz("key"))
   436  
   437  	itr := pstore.ReverseIterator(bz(""), bz(""))
   438  	checkInvalid(t, itr)
   439  	itr.Close()
   440  }
   441  
   442  func TestCacheWraps(t *testing.T) {
   443  	db := dbm.NewMemDB()
   444  	store := dbadapter.Store{DB: db}
   445  
   446  	cacheWrapper := store.CacheWrap()
   447  	require.IsType(t, &cachekv.Store{}, cacheWrapper)
   448  
   449  	cacheWrappedWithTrace := store.CacheWrapWithTrace(nil, nil)
   450  	require.IsType(t, &cachekv.Store{}, cacheWrappedWithTrace)
   451  
   452  	cacheWrappedWithListeners := store.CacheWrapWithListeners(nil, nil)
   453  	require.IsType(t, &cachekv.Store{}, cacheWrappedWithListeners)
   454  }