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 }