github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/store/prefix/store_test.go (about)

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