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 }