diff --git a/CHANGELOG.md b/CHANGELOG.md index 78ca5dee788..07b8b5bccf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +## Improvements + +* (store) [#14410](https://github.com/cosmos/cosmos-sdk/pull/14410) `rootmulti.Store.loadVersion` has validation to check if all the module stores' height is correct, it will error if any module store has incorrect height. + ## [v0.45.14](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.45.14) - 2023-02-16 ### Features diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index e134961b5ef..ab37e7ec01d 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -231,7 +231,7 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { if upgrades.IsAdded(key.Name()) || upgrades.RenamedFrom(key.Name()) != "" { storeParams.initialVersion = uint64(ver) + 1 } else if commitID.Version != ver && storeParams.typ == types.StoreTypeIAVL { - return fmt.Errorf("version of store %q mismatch root store's version; expected %d got %d; new stores should be added using StoreUpgrades", key.Name(), ver, commitID.Version) + return fmt.Errorf("version of store %s mismatch root store's version; expected %d got %d", key.Name(), ver, commitID.Version) } store, err := rs.loadCommitStoreFromParams(key, commitID, storeParams) @@ -1026,6 +1026,15 @@ type storeParams struct { initialVersion uint64 } +func newStoreParams(key types.StoreKey, db dbm.DB, typ types.StoreType, initialVersion uint64) storeParams { // nolint + return storeParams{ + key: key, + db: db, + typ: typ, + initialVersion: initialVersion, + } +} + func GetLatestVersion(db dbm.DB) int64 { bz, err := db.Get([]byte(latestVersionKey)) if err != nil { diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index db17f788fee..c4d760ae4b2 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -301,7 +301,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { migratedID := restore.Commit() require.Equal(t, migratedID.Version, int64(2)) - reload, _ := newMultiStoreWithModifiedMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) + reload, _ := newMultiStoreWithModifiedMounts(db, types.PruneNothing) // unmount store3 since store3 was deleted unmountStore(reload, "store3") @@ -643,6 +643,32 @@ func TestMultiStore_PruningRestart(t *testing.T) { } } +// TestUnevenStoresHeightCheck tests if loading root store correctly errors when +// there's any module store with the wrong height +func TestUnevenStoresHeightCheck(t *testing.T) { + var db dbm.DB = dbm.NewMemDB() + store := newMultiStoreWithMounts(db, types.PruneNothing) + err := store.LoadLatestVersion() + require.Nil(t, err) + + // commit to increment store's height + store.Commit() + + // mount store4 to root store + store.MountStoreWithDB(types.NewKVStoreKey("store4"), types.StoreTypeIAVL, nil) + + // load the stores without upgrades + err = store.LoadLatestVersion() + require.Error(t, err) + + // now, let's load with upgrades... + upgrades := &types.StoreUpgrades{ + Added: []string{"store4"}, + } + err = store.LoadLatestVersionAndUpgrade(upgrades) + require.Nil(t, err) +} + func TestSetInitialVersion(t *testing.T) { db := coretesting.NewMemDB() multi := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) @@ -780,6 +806,13 @@ func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions return store, upgrades } +func unmountStore(rootStore *Store, storeKeyName string) { + sk := rootStore.keysByName[storeKeyName] + delete(rootStore.stores, sk) + delete(rootStore.storesParams, sk) + delete(rootStore.keysByName, storeKeyName) +} + func checkStore(t *testing.T, store *Store, expect, got types.CommitID) { t.Helper() require.Equal(t, expect, got)