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