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 }