github.com/Finschia/finschia-sdk@v0.48.1/store/rootmulti/store_test.go (about) 1 package rootmulti 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "math/rand" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 dbm "github.com/tendermint/tm-db" 14 15 "github.com/Finschia/ostracon/libs/log" 16 abci "github.com/tendermint/tendermint/abci/types" 17 18 "github.com/Finschia/finschia-sdk/codec" 19 codecTypes "github.com/Finschia/finschia-sdk/codec/types" 20 "github.com/Finschia/finschia-sdk/store/cachemulti" 21 "github.com/Finschia/finschia-sdk/store/iavl" 22 sdkmaps "github.com/Finschia/finschia-sdk/store/internal/maps" 23 "github.com/Finschia/finschia-sdk/store/listenkv" 24 "github.com/Finschia/finschia-sdk/store/types" 25 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 26 ) 27 28 func TestStoreType(t *testing.T) { 29 db := dbm.NewMemDB() 30 store := NewStore(db, log.NewNopLogger()) 31 store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, db) 32 } 33 34 func TestGetCommitKVStore(t *testing.T) { 35 var db dbm.DB = dbm.NewMemDB() 36 ms := newMultiStoreWithMounts(db, types.PruneDefault) 37 err := ms.LoadLatestVersion() 38 require.Nil(t, err) 39 40 key := ms.keysByName["store1"] 41 42 store1 := ms.GetCommitKVStore(key) 43 require.NotNil(t, store1) 44 require.IsType(t, &iavl.Store{}, store1) 45 46 store2 := ms.GetCommitStore(key) 47 require.NotNil(t, store2) 48 require.IsType(t, &iavl.Store{}, store2) 49 } 50 51 func TestStoreMount(t *testing.T) { 52 db := dbm.NewMemDB() 53 store := NewStore(db, log.NewNopLogger()) 54 55 key1 := types.NewKVStoreKey("store1") 56 key2 := types.NewKVStoreKey("store2") 57 dup1 := types.NewKVStoreKey("store1") 58 59 require.NotPanics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) }) 60 require.NotPanics(t, func() { store.MountStoreWithDB(key2, types.StoreTypeIAVL, db) }) 61 62 require.Panics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) }) 63 require.Panics(t, func() { store.MountStoreWithDB(nil, types.StoreTypeIAVL, db) }) 64 require.Panics(t, func() { store.MountStoreWithDB(dup1, types.StoreTypeIAVL, db) }) 65 } 66 67 func TestCacheMultiStore(t *testing.T) { 68 var db dbm.DB = dbm.NewMemDB() 69 ms := newMultiStoreWithMounts(db, types.PruneNothing) 70 71 cacheMulti := ms.CacheMultiStore() 72 require.IsType(t, cachemulti.Store{}, cacheMulti) 73 } 74 75 func TestCacheMultiStoreWithVersion(t *testing.T) { 76 var db dbm.DB = dbm.NewMemDB() 77 ms := newMultiStoreWithMounts(db, types.PruneNothing) 78 err := ms.LoadLatestVersion() 79 require.Nil(t, err) 80 81 commitID := types.CommitID{} 82 checkStore(t, ms, commitID, commitID) 83 84 k, v := []byte("wind"), []byte("blows") 85 86 store1 := ms.GetStoreByName("store1").(types.KVStore) 87 store1.Set(k, v) 88 89 cID := ms.Commit() 90 require.Equal(t, int64(1), cID.Version) 91 92 // require no failure when given an invalid or pruned version 93 _, err = ms.CacheMultiStoreWithVersion(cID.Version + 1) 94 require.NoError(t, err) 95 96 // require a valid version can be cache-loaded 97 cms, err := ms.CacheMultiStoreWithVersion(cID.Version) 98 require.NoError(t, err) 99 100 // require a valid key lookup yields the correct value 101 kvStore := cms.GetKVStore(ms.keysByName["store1"]) 102 require.NotNil(t, kvStore) 103 require.Equal(t, kvStore.Get(k), v) 104 105 // require we cannot commit (write) to a cache-versioned multi-store 106 require.Panics(t, func() { 107 kvStore.Set(k, []byte("newValue")) 108 cms.Write() 109 }) 110 } 111 112 func TestHashStableWithEmptyCommit(t *testing.T) { 113 var db dbm.DB = dbm.NewMemDB() 114 ms := newMultiStoreWithMounts(db, types.PruneNothing) 115 err := ms.LoadLatestVersion() 116 require.Nil(t, err) 117 118 commitID := types.CommitID{} 119 checkStore(t, ms, commitID, commitID) 120 121 k, v := []byte("wind"), []byte("blows") 122 123 store1 := ms.GetStoreByName("store1").(types.KVStore) 124 store1.Set(k, v) 125 126 cID := ms.Commit() 127 require.Equal(t, int64(1), cID.Version) 128 hash := cID.Hash 129 130 // make an empty commit, it should update version, but not affect hash 131 cID = ms.Commit() 132 require.Equal(t, int64(2), cID.Version) 133 require.Equal(t, hash, cID.Hash) 134 } 135 136 func TestMultistoreCommitLoad(t *testing.T) { 137 var db dbm.DB = dbm.NewMemDB() 138 store := newMultiStoreWithMounts(db, types.PruneNothing) 139 err := store.LoadLatestVersion() 140 require.Nil(t, err) 141 142 // New store has empty last commit. 143 commitID := types.CommitID{} 144 checkStore(t, store, commitID, commitID) 145 146 // Make sure we can get stores by name. 147 s1 := store.GetStoreByName("store1") 148 require.NotNil(t, s1) 149 s3 := store.GetStoreByName("store3") 150 require.NotNil(t, s3) 151 s77 := store.GetStoreByName("store77") 152 require.Nil(t, s77) 153 154 // Make a few commits and check them. 155 nCommits := int64(3) 156 for i := int64(0); i < nCommits; i++ { 157 commitID = store.Commit() 158 expectedCommitID := getExpectedCommitID(store, i+1) 159 checkStore(t, store, expectedCommitID, commitID) 160 } 161 162 // Load the latest multistore again and check version. 163 store = newMultiStoreWithMounts(db, types.PruneNothing) 164 err = store.LoadLatestVersion() 165 require.Nil(t, err) 166 commitID = getExpectedCommitID(store, nCommits) 167 checkStore(t, store, commitID, commitID) 168 169 // Commit and check version. 170 commitID = store.Commit() 171 expectedCommitID := getExpectedCommitID(store, nCommits+1) 172 checkStore(t, store, expectedCommitID, commitID) 173 174 // Load an older multistore and check version. 175 ver := nCommits - 1 176 store = newMultiStoreWithMounts(db, types.PruneNothing) 177 err = store.LoadVersion(ver) 178 require.Nil(t, err) 179 commitID = getExpectedCommitID(store, ver) 180 checkStore(t, store, commitID, commitID) 181 } 182 183 func TestMultistoreLoadWithUpgrade(t *testing.T) { 184 var db dbm.DB = dbm.NewMemDB() 185 store := newMultiStoreWithMounts(db, types.PruneNothing) 186 err := store.LoadLatestVersion() 187 require.Nil(t, err) 188 189 // write some data in all stores 190 k1, v1 := []byte("first"), []byte("store") 191 s1, _ := store.GetStoreByName("store1").(types.KVStore) 192 require.NotNil(t, s1) 193 s1.Set(k1, v1) 194 195 k2, v2 := []byte("second"), []byte("restore") 196 s2, _ := store.GetStoreByName("store2").(types.KVStore) 197 require.NotNil(t, s2) 198 s2.Set(k2, v2) 199 200 k3, v3 := []byte("third"), []byte("dropped") 201 s3, _ := store.GetStoreByName("store3").(types.KVStore) 202 require.NotNil(t, s3) 203 s3.Set(k3, v3) 204 205 s4, _ := store.GetStoreByName("store4").(types.KVStore) 206 require.Nil(t, s4) 207 208 // do one commit 209 commitID := store.Commit() 210 expectedCommitID := getExpectedCommitID(store, 1) 211 checkStore(t, store, expectedCommitID, commitID) 212 213 ci, err := getCommitInfo(db, 1) 214 require.NoError(t, err) 215 require.Equal(t, int64(1), ci.Version) 216 require.Equal(t, 3, len(ci.StoreInfos)) 217 checkContains(t, ci.StoreInfos, []string{"store1", "store2", "store3"}) 218 219 // Load without changes and make sure it is sensible 220 store = newMultiStoreWithMounts(db, types.PruneNothing) 221 222 err = store.LoadLatestVersion() 223 require.Nil(t, err) 224 commitID = getExpectedCommitID(store, 1) 225 checkStore(t, store, commitID, commitID) 226 227 // let's query data to see it was saved properly 228 s2, _ = store.GetStoreByName("store2").(types.KVStore) 229 require.NotNil(t, s2) 230 require.Equal(t, v2, s2.Get(k2)) 231 232 // now, let's load with upgrades... 233 restore, upgrades := newMultiStoreWithModifiedMounts(db, types.PruneNothing) 234 err = restore.LoadLatestVersionAndUpgrade(upgrades) 235 require.Nil(t, err) 236 237 // s1 was not changed 238 s1, _ = restore.GetStoreByName("store1").(types.KVStore) 239 require.NotNil(t, s1) 240 require.Equal(t, v1, s1.Get(k1)) 241 242 // store3 is mounted, but data deleted are gone 243 s3, _ = restore.GetStoreByName("store3").(types.KVStore) 244 require.NotNil(t, s3) 245 require.Nil(t, s3.Get(k3)) // data was deleted 246 247 // store4 is mounted, with empty data 248 s4, _ = restore.GetStoreByName("store4").(types.KVStore) 249 require.NotNil(t, s4) 250 251 iterator := s4.Iterator(nil, nil) 252 253 values := 0 254 for ; iterator.Valid(); iterator.Next() { 255 values += 1 256 } 257 require.Zero(t, values) 258 259 require.NoError(t, iterator.Close()) 260 261 // write something inside store4 262 k4, v4 := []byte("fourth"), []byte("created") 263 s4.Set(k4, v4) 264 265 // store2 is no longer mounted 266 st2 := restore.GetStoreByName("store2") 267 require.Nil(t, st2) 268 269 // restore2 has the old data 270 rs2, _ := restore.GetStoreByName("restore2").(types.KVStore) 271 require.NotNil(t, rs2) 272 require.Equal(t, v2, rs2.Get(k2)) 273 274 // store this migrated data, and load it again without migrations 275 migratedID := restore.Commit() 276 require.Equal(t, migratedID.Version, int64(2)) 277 278 reload, _ := newMultiStoreWithModifiedMounts(db, types.PruneNothing) 279 err = reload.LoadLatestVersion() 280 require.Nil(t, err) 281 require.Equal(t, migratedID, reload.LastCommitID()) 282 283 // query this new store 284 rl1, _ := reload.GetStoreByName("store1").(types.KVStore) 285 require.NotNil(t, rl1) 286 require.Equal(t, v1, rl1.Get(k1)) 287 288 rl2, _ := reload.GetStoreByName("restore2").(types.KVStore) 289 require.NotNil(t, rl2) 290 require.Equal(t, v2, rl2.Get(k2)) 291 292 rl4, _ := reload.GetStoreByName("store4").(types.KVStore) 293 require.NotNil(t, rl4) 294 require.Equal(t, v4, rl4.Get(k4)) 295 296 // check commitInfo in storage 297 ci, err = getCommitInfo(db, 2) 298 require.NoError(t, err) 299 require.Equal(t, int64(2), ci.Version) 300 require.Equal(t, 4, len(ci.StoreInfos), ci.StoreInfos) 301 checkContains(t, ci.StoreInfos, []string{"store1", "restore2", "store3", "store4"}) 302 } 303 304 func TestParsePath(t *testing.T) { 305 _, _, err := parsePath("foo") 306 require.Error(t, err) 307 308 store, subpath, err := parsePath("/foo") 309 require.NoError(t, err) 310 require.Equal(t, store, "foo") 311 require.Equal(t, subpath, "") 312 313 store, subpath, err = parsePath("/fizz/bang/baz") 314 require.NoError(t, err) 315 require.Equal(t, store, "fizz") 316 require.Equal(t, subpath, "/bang/baz") 317 318 substore, subsubpath, err := parsePath(subpath) 319 require.NoError(t, err) 320 require.Equal(t, substore, "bang") 321 require.Equal(t, subsubpath, "/baz") 322 } 323 324 func TestMultiStoreRestart(t *testing.T) { 325 db := dbm.NewMemDB() 326 pruning := types.PruningOptions{ 327 KeepRecent: 2, 328 KeepEvery: 3, 329 Interval: 1, 330 } 331 multi := newMultiStoreWithMounts(db, pruning) 332 err := multi.LoadLatestVersion() 333 require.Nil(t, err) 334 335 initCid := multi.LastCommitID() 336 337 k, v := "wind", "blows" 338 k2, v2 := "water", "flows" 339 k3, v3 := "fire", "burns" 340 341 for i := 1; i < 3; i++ { 342 // Set and commit data in one store. 343 store1 := multi.GetStoreByName("store1").(types.KVStore) 344 store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, i))) 345 346 // ... and another. 347 store2 := multi.GetStoreByName("store2").(types.KVStore) 348 store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, i))) 349 350 // ... and another. 351 store3 := multi.GetStoreByName("store3").(types.KVStore) 352 store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, i))) 353 354 multi.Commit() 355 356 cinfo, err := getCommitInfo(multi.db, int64(i)) 357 require.NoError(t, err) 358 require.Equal(t, int64(i), cinfo.Version) 359 } 360 361 // Set and commit data in one store. 362 store1 := multi.GetStoreByName("store1").(types.KVStore) 363 store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, 3))) 364 365 // ... and another. 366 store2 := multi.GetStoreByName("store2").(types.KVStore) 367 store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, 3))) 368 369 multi.Commit() 370 371 flushedCinfo, err := getCommitInfo(multi.db, 3) 372 require.Nil(t, err) 373 require.NotEqual(t, initCid, flushedCinfo, "CID is different after flush to disk") 374 375 // ... and another. 376 store3 := multi.GetStoreByName("store3").(types.KVStore) 377 store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, 3))) 378 379 multi.Commit() 380 381 postFlushCinfo, err := getCommitInfo(multi.db, 4) 382 require.NoError(t, err) 383 require.Equal(t, int64(4), postFlushCinfo.Version, "Commit changed after in-memory commit") 384 385 multi = newMultiStoreWithMounts(db, pruning) 386 err = multi.LoadLatestVersion() 387 require.Nil(t, err) 388 389 reloadedCid := multi.LastCommitID() 390 require.Equal(t, int64(4), reloadedCid.Version, "Reloaded CID is not the same as last flushed CID") 391 392 // Check that store1 and store2 retained date from 3rd commit 393 store1 = multi.GetStoreByName("store1").(types.KVStore) 394 val := store1.Get([]byte(k)) 395 require.Equal(t, []byte(fmt.Sprintf("%s:%d", v, 3)), val, "Reloaded value not the same as last flushed value") 396 397 store2 = multi.GetStoreByName("store2").(types.KVStore) 398 val2 := store2.Get([]byte(k2)) 399 require.Equal(t, []byte(fmt.Sprintf("%s:%d", v2, 3)), val2, "Reloaded value not the same as last flushed value") 400 401 // Check that store3 still has data from last commit even though update happened on 2nd commit 402 store3 = multi.GetStoreByName("store3").(types.KVStore) 403 val3 := store3.Get([]byte(k3)) 404 require.Equal(t, []byte(fmt.Sprintf("%s:%d", v3, 3)), val3, "Reloaded value not the same as last flushed value") 405 } 406 407 func TestMultiStoreQuery(t *testing.T) { 408 db := dbm.NewMemDB() 409 multi := newMultiStoreWithMounts(db, types.PruneNothing) 410 err := multi.LoadLatestVersion() 411 require.Nil(t, err) 412 413 k, v := []byte("wind"), []byte("blows") 414 k2, v2 := []byte("water"), []byte("flows") 415 // v3 := []byte("is cold") 416 417 cid1 := multi.Commit() 418 419 // Make sure we can get by name. 420 garbage := multi.GetStoreByName("bad-name") 421 require.Nil(t, garbage) 422 423 // Set and commit data in one store. 424 store1 := multi.GetStoreByName("store1").(types.KVStore) 425 store1.Set(k, v) 426 427 // ... and another. 428 store2 := multi.GetStoreByName("store2").(types.KVStore) 429 store2.Set(k2, v2) 430 431 // Commit the multistore. 432 cid2 := multi.Commit() 433 ver := cid2.Version 434 435 // Reload multistore from database 436 multi = newMultiStoreWithMounts(db, types.PruneNothing) 437 err = multi.LoadLatestVersion() 438 require.Nil(t, err) 439 440 // Test bad path. 441 query := abci.RequestQuery{Path: "/key", Data: k, Height: ver} 442 qres := multi.Query(query) 443 require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) 444 require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) 445 446 query.Path = "h897fy32890rf63296r92" 447 qres = multi.Query(query) 448 require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) 449 require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) 450 451 // Test invalid store name. 452 query.Path = "/garbage/key" 453 qres = multi.Query(query) 454 require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) 455 require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) 456 457 // Test valid query with data. 458 query.Path = "/store1/key" 459 qres = multi.Query(query) 460 require.EqualValues(t, 0, qres.Code) 461 require.Equal(t, v, qres.Value) 462 463 // Test valid but empty query. 464 query.Path = "/store2/key" 465 query.Prove = true 466 qres = multi.Query(query) 467 require.EqualValues(t, 0, qres.Code) 468 require.Nil(t, qres.Value) 469 470 // Test store2 data. 471 query.Data = k2 472 qres = multi.Query(query) 473 require.EqualValues(t, 0, qres.Code) 474 require.Equal(t, v2, qres.Value) 475 476 // Test proofs latest height 477 query.Path = fmt.Sprintf("/%s", proofsPath) 478 qres = multi.Query(query) 479 require.EqualValues(t, 0, qres.Code) 480 require.NotNil(t, qres.ProofOps) 481 require.Equal(t, []byte(proofsPath), qres.Key) 482 require.Equal(t, cid2.Hash, qres.Value) 483 require.Equal(t, cid2.Version, qres.Height) 484 require.Equal(t, 3, len(qres.ProofOps.Ops)) // 3 mounted stores 485 486 // Test proofs second latest height 487 query.Height = query.Height - 1 488 qres = multi.Query(query) 489 require.EqualValues(t, 0, qres.Code) 490 require.NotNil(t, qres.ProofOps) 491 require.Equal(t, []byte(proofsPath), qres.Key) 492 require.Equal(t, cid1.Hash, qres.Value) 493 require.Equal(t, cid1.Version, qres.Height) 494 require.Equal(t, 3, len(qres.ProofOps.Ops)) // 3 mounted stores 495 } 496 497 func TestMultiStore_Pruning(t *testing.T) { 498 testCases := []struct { 499 name string 500 numVersions int64 501 po types.PruningOptions 502 deleted []int64 503 saved []int64 504 }{ 505 {"prune nothing", 10, types.PruneNothing, nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, 506 {"prune everything", 10, types.PruneEverything, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}}, 507 {"prune some; no batch", 10, types.NewPruningOptions(2, 3, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}}, 508 {"prune some; small batch", 10, types.NewPruningOptions(2, 3, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}}, 509 {"prune some; large batch", 10, types.NewPruningOptions(2, 3, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, 510 } 511 512 for _, tc := range testCases { 513 tc := tc 514 515 t.Run(tc.name, func(t *testing.T) { 516 db := dbm.NewMemDB() 517 ms := newMultiStoreWithMounts(db, tc.po) 518 require.NoError(t, ms.LoadLatestVersion()) 519 520 for i := int64(0); i < tc.numVersions; i++ { 521 ms.Commit() 522 } 523 524 for _, v := range tc.saved { 525 _, err := ms.CacheMultiStoreWithVersion(v) 526 require.NoError(t, err, "expected error when loading height: %d", v) 527 } 528 529 for _, v := range tc.deleted { 530 _, err := ms.CacheMultiStoreWithVersion(v) 531 // Line: Pruning is async. store/iavl/store.GetImmutable 532 // returns an empty tree when the version doesn't exist. 533 // However, when it gets caught in between, i.e. version 534 // checking is done before, but iavl.GetImmutable is done 535 // after pruning, it fails with 'version not exist' error. 536 // Simply retry would do. 537 if err != nil { 538 _, err = ms.CacheMultiStoreWithVersion(v) 539 } 540 require.NoError(t, err, "expected error when loading height: %d", v) 541 } 542 }) 543 } 544 } 545 546 func TestMultiStore_PruningRestart(t *testing.T) { 547 db := dbm.NewMemDB() 548 ms := newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11)) 549 require.NoError(t, ms.LoadLatestVersion()) 550 551 // Commit enough to build up heights to prune, where on the next block we should 552 // batch delete. 553 for i := int64(0); i < 10; i++ { 554 ms.Commit() 555 } 556 557 pruneHeights := []int64{1, 2, 4, 5, 7} 558 559 // ensure we've persisted the current batch of heights to prune to the store's DB 560 ph, err := getPruningHeights(ms.db) 561 require.NoError(t, err) 562 require.Equal(t, pruneHeights, ph) 563 564 // "restart" 565 ms = newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11)) 566 err = ms.LoadLatestVersion() 567 require.NoError(t, err) 568 require.Equal(t, pruneHeights, ms.pruneHeights) 569 570 // commit one more block and ensure the heights have been pruned 571 ms.Commit() 572 require.Empty(t, ms.pruneHeights) 573 574 for _, v := range pruneHeights { 575 _, err := ms.CacheMultiStoreWithVersion(v) 576 require.NoError(t, err, "expected error when loading height: %d", v) 577 } 578 } 579 580 func assertStoresEqual(t *testing.T, expect, actual types.CommitKVStore, msgAndArgs ...interface{}) { 581 assert.Equal(t, expect.LastCommitID(), actual.LastCommitID()) 582 expectIter := expect.Iterator(nil, nil) 583 expectMap := map[string][]byte{} 584 for ; expectIter.Valid(); expectIter.Next() { 585 expectMap[string(expectIter.Key())] = expectIter.Value() 586 } 587 require.NoError(t, expectIter.Error()) 588 589 actualIter := expect.Iterator(nil, nil) 590 actualMap := map[string][]byte{} 591 for ; actualIter.Valid(); actualIter.Next() { 592 actualMap[string(actualIter.Key())] = actualIter.Value() 593 } 594 require.NoError(t, actualIter.Error()) 595 596 assert.Equal(t, expectMap, actualMap, msgAndArgs...) 597 } 598 599 func TestSetInitialVersion(t *testing.T) { 600 db := dbm.NewMemDB() 601 multi := newMultiStoreWithMounts(db, types.PruneNothing) 602 603 require.NoError(t, multi.LoadLatestVersion()) 604 605 multi.SetInitialVersion(5) 606 require.Equal(t, int64(5), multi.initialVersion) 607 608 multi.Commit() 609 require.Equal(t, int64(5), multi.LastCommitID().Version) 610 611 ckvs := multi.GetCommitKVStore(multi.keysByName["store1"]) 612 iavlStore, ok := ckvs.(*iavl.Store) 613 require.True(t, ok) 614 require.True(t, iavlStore.VersionExists(5)) 615 } 616 617 func TestAddListenersAndListeningEnabled(t *testing.T) { 618 db := dbm.NewMemDB() 619 multi := newMultiStoreWithMounts(db, types.PruneNothing) 620 testKey := types.NewKVStoreKey("listening_test_key") 621 enabled := multi.ListeningEnabled(testKey) 622 require.False(t, enabled) 623 624 multi.AddListeners(testKey, []types.WriteListener{}) 625 enabled = multi.ListeningEnabled(testKey) 626 require.False(t, enabled) 627 628 mockListener := types.NewStoreKVPairWriteListener(nil, nil) 629 multi.AddListeners(testKey, []types.WriteListener{mockListener}) 630 wrongTestKey := types.NewKVStoreKey("wrong_listening_test_key") 631 enabled = multi.ListeningEnabled(wrongTestKey) 632 require.False(t, enabled) 633 634 enabled = multi.ListeningEnabled(testKey) 635 require.True(t, enabled) 636 } 637 638 var ( 639 interfaceRegistry = codecTypes.NewInterfaceRegistry() 640 testMarshaller = codec.NewProtoCodec(interfaceRegistry) 641 testKey1 = []byte{1, 2, 3, 4, 5} 642 testValue1 = []byte{5, 4, 3, 2, 1} 643 testKey2 = []byte{2, 3, 4, 5, 6} 644 testValue2 = []byte{6, 5, 4, 3, 2} 645 ) 646 647 func TestGetListenWrappedKVStore(t *testing.T) { 648 buf := new(bytes.Buffer) 649 var db dbm.DB = dbm.NewMemDB() 650 ms := newMultiStoreWithMounts(db, types.PruneNothing) 651 ms.LoadLatestVersion() 652 mockListeners := []types.WriteListener{types.NewStoreKVPairWriteListener(buf, testMarshaller)} 653 ms.AddListeners(testStoreKey1, mockListeners) 654 ms.AddListeners(testStoreKey2, mockListeners) 655 656 listenWrappedStore1 := ms.GetKVStore(testStoreKey1) 657 require.IsType(t, &listenkv.Store{}, listenWrappedStore1) 658 659 listenWrappedStore1.Set(testKey1, testValue1) 660 expectedOutputKVPairSet1, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{ 661 Key: testKey1, 662 Value: testValue1, 663 StoreKey: testStoreKey1.Name(), 664 Delete: false, 665 }) 666 require.Nil(t, err) 667 kvPairSet1Bytes := buf.Bytes() 668 buf.Reset() 669 require.Equal(t, expectedOutputKVPairSet1, kvPairSet1Bytes) 670 671 listenWrappedStore1.Delete(testKey1) 672 expectedOutputKVPairDelete1, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{ 673 Key: testKey1, 674 Value: nil, 675 StoreKey: testStoreKey1.Name(), 676 Delete: true, 677 }) 678 require.Nil(t, err) 679 kvPairDelete1Bytes := buf.Bytes() 680 buf.Reset() 681 require.Equal(t, expectedOutputKVPairDelete1, kvPairDelete1Bytes) 682 683 listenWrappedStore2 := ms.GetKVStore(testStoreKey2) 684 require.IsType(t, &listenkv.Store{}, listenWrappedStore2) 685 686 listenWrappedStore2.Set(testKey2, testValue2) 687 expectedOutputKVPairSet2, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{ 688 Key: testKey2, 689 Value: testValue2, 690 StoreKey: testStoreKey2.Name(), 691 Delete: false, 692 }) 693 kvPairSet2Bytes := buf.Bytes() 694 buf.Reset() 695 require.Equal(t, expectedOutputKVPairSet2, kvPairSet2Bytes) 696 697 listenWrappedStore2.Delete(testKey2) 698 expectedOutputKVPairDelete2, err := testMarshaller.MarshalLengthPrefixed(&types.StoreKVPair{ 699 Key: testKey2, 700 Value: nil, 701 StoreKey: testStoreKey2.Name(), 702 Delete: true, 703 }) 704 kvPairDelete2Bytes := buf.Bytes() 705 buf.Reset() 706 require.Equal(t, expectedOutputKVPairDelete2, kvPairDelete2Bytes) 707 708 unwrappedStore := ms.GetKVStore(testStoreKey3) 709 require.IsType(t, &iavl.Store{}, unwrappedStore) 710 711 unwrappedStore.Set(testKey2, testValue2) 712 kvPairSet3Bytes := buf.Bytes() 713 buf.Reset() 714 require.Equal(t, []byte{}, kvPairSet3Bytes) 715 716 unwrappedStore.Delete(testKey2) 717 kvPairDelete3Bytes := buf.Bytes() 718 buf.Reset() 719 require.Equal(t, []byte{}, kvPairDelete3Bytes) 720 } 721 722 func TestCacheWraps(t *testing.T) { 723 db := dbm.NewMemDB() 724 multi := newMultiStoreWithMounts(db, types.PruneNothing) 725 726 cacheWrapper := multi.CacheWrap() 727 require.IsType(t, cachemulti.Store{}, cacheWrapper) 728 729 cacheWrappedWithTrace := multi.CacheWrapWithTrace(nil, nil) 730 require.IsType(t, cachemulti.Store{}, cacheWrappedWithTrace) 731 732 cacheWrappedWithListeners := multi.CacheWrapWithListeners(nil, nil) 733 require.IsType(t, cachemulti.Store{}, cacheWrappedWithListeners) 734 } 735 736 func TestTraceConcurrency(t *testing.T) { 737 db := dbm.NewMemDB() 738 multi := newMultiStoreWithMounts(db, types.PruneNothing) 739 err := multi.LoadLatestVersion() 740 require.NoError(t, err) 741 742 b := &bytes.Buffer{} 743 key := multi.keysByName["store1"] 744 tc := types.TraceContext(map[string]interface{}{"blockHeight": 64}) 745 746 multi.SetTracer(b) 747 multi.SetTracingContext(tc) 748 749 cms := multi.CacheMultiStore() 750 store1 := cms.GetKVStore(key) 751 cw := store1.CacheWrapWithTrace(b, tc) 752 _ = cw 753 require.NotNil(t, store1) 754 755 stop := make(chan struct{}) 756 stopW := make(chan struct{}) 757 758 go func(stop chan struct{}) { 759 for { 760 select { 761 case <-stop: 762 return 763 default: 764 store1.Set([]byte{1}, []byte{1}) 765 cms.Write() 766 } 767 } 768 }(stop) 769 770 go func(stop chan struct{}) { 771 for { 772 select { 773 case <-stop: 774 return 775 default: 776 multi.SetTracingContext(tc) 777 } 778 } 779 }(stopW) 780 781 time.Sleep(3 * time.Second) 782 stop <- struct{}{} 783 stopW <- struct{}{} 784 } 785 786 //----------------------------------------------------------------------- 787 // utils 788 789 var ( 790 testStoreKey1 = types.NewKVStoreKey("store1") 791 testStoreKey2 = types.NewKVStoreKey("store2") 792 testStoreKey3 = types.NewKVStoreKey("store3") 793 ) 794 795 func newMultiStoreWithMounts(db dbm.DB, pruningOpts types.PruningOptions) *Store { 796 store := NewStore(db, log.NewNopLogger()) 797 store.pruningOpts = pruningOpts 798 799 store.MountStoreWithDB(testStoreKey1, types.StoreTypeIAVL, nil) 800 store.MountStoreWithDB(testStoreKey2, types.StoreTypeIAVL, nil) 801 store.MountStoreWithDB(testStoreKey3, types.StoreTypeIAVL, nil) 802 803 return store 804 } 805 806 func newMultiStoreWithMixedMounts(db dbm.DB) *Store { 807 store := NewStore(db, log.NewNopLogger()) 808 store.MountStoreWithDB(types.NewKVStoreKey("iavl1"), types.StoreTypeIAVL, nil) 809 store.MountStoreWithDB(types.NewKVStoreKey("iavl2"), types.StoreTypeIAVL, nil) 810 store.MountStoreWithDB(types.NewKVStoreKey("iavl3"), types.StoreTypeIAVL, nil) 811 store.LoadLatestVersion() 812 813 return store 814 } 815 816 func newMultiStoreWithGeneratedData(db dbm.DB, stores uint8, storeKeys uint64) *Store { 817 multiStore := NewStore(db, log.NewNopLogger()) 818 r := rand.New(rand.NewSource(49872768940)) // Fixed seed for deterministic tests 819 820 keys := []*types.KVStoreKey{} 821 for i := uint8(0); i < stores; i++ { 822 key := types.NewKVStoreKey(fmt.Sprintf("store%v", i)) 823 multiStore.MountStoreWithDB(key, types.StoreTypeIAVL, nil) 824 keys = append(keys, key) 825 } 826 multiStore.LoadLatestVersion() 827 828 for _, key := range keys { 829 store := multiStore.stores[key].(*iavl.Store) 830 for i := uint64(0); i < storeKeys; i++ { 831 k := make([]byte, 8) 832 v := make([]byte, 1024) 833 binary.BigEndian.PutUint64(k, i) 834 _, err := r.Read(v) 835 if err != nil { 836 panic(err) 837 } 838 store.Set(k, v) 839 } 840 } 841 842 multiStore.Commit() 843 multiStore.LoadLatestVersion() 844 845 return multiStore 846 } 847 848 func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions) (*Store, *types.StoreUpgrades) { 849 store := NewStore(db, log.NewNopLogger()) 850 store.pruningOpts = pruningOpts 851 852 store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) 853 store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil) 854 store.MountStoreWithDB(types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil) 855 store.MountStoreWithDB(types.NewKVStoreKey("store4"), types.StoreTypeIAVL, nil) 856 857 upgrades := &types.StoreUpgrades{ 858 Added: []string{"store4"}, 859 Renamed: []types.StoreRename{{ 860 OldKey: "store2", 861 NewKey: "restore2", 862 }}, 863 Deleted: []string{"store3"}, 864 } 865 866 return store, upgrades 867 } 868 869 func checkStore(t *testing.T, store *Store, expect, got types.CommitID) { 870 require.Equal(t, expect, got) 871 require.Equal(t, expect, store.LastCommitID()) 872 } 873 874 func checkContains(t testing.TB, info []types.StoreInfo, wanted []string) { 875 t.Helper() 876 877 for _, want := range wanted { 878 checkHas(t, info, want) 879 } 880 } 881 882 func checkHas(t testing.TB, info []types.StoreInfo, want string) { 883 t.Helper() 884 for _, i := range info { 885 if i.Name == want { 886 return 887 } 888 } 889 t.Fatalf("storeInfo doesn't contain %s", want) 890 } 891 892 func getExpectedCommitID(store *Store, ver int64) types.CommitID { 893 return types.CommitID{ 894 Version: ver, 895 Hash: hashStores(store.stores), 896 } 897 } 898 899 func hashStores(stores map[types.StoreKey]types.CommitKVStore) []byte { 900 m := make(map[string][]byte, len(stores)) 901 for key, store := range stores { 902 name := key.Name() 903 m[name] = types.StoreInfo{ 904 Name: name, 905 CommitId: store.LastCommitID(), 906 }.GetHash() 907 } 908 return sdkmaps.HashFromMap(m) 909 } 910 911 func TestSetIAVLDIsableFastNode(t *testing.T) { 912 db := dbm.NewMemDB() 913 multi := newMultiStoreWithMounts(db, types.PruneNothing) 914 915 multi.SetIAVLDisableFastNode(true) 916 require.Equal(t, multi.iavlDisableFastNode, true) 917 918 multi.SetIAVLDisableFastNode(false) 919 require.Equal(t, multi.iavlDisableFastNode, false) 920 }