Skip to content

Commit

Permalink
feat(runtime/v2): store loader on simappv2 (#21704)
Browse files Browse the repository at this point in the history
Co-authored-by: marbar3778 <[email protected]>
  • Loading branch information
randygrok and tac0turtle authored Sep 13, 2024
1 parent b712516 commit 7d6ff0d
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
### Features

* (baseapp) [#20291](https://github.com/cosmos/cosmos-sdk/pull/20291) Simulate nested messages.
* (runtime) [#21704](https://github.com/cosmos/cosmos-sdk/pull/21704) Add StoreLoader in simappv2.

### Improvements

Expand Down
21 changes: 21 additions & 0 deletions runtime/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"cosmossdk.io/core/store"
storetypes "cosmossdk.io/store/types"

"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand Down Expand Up @@ -179,3 +180,23 @@ func (s kvStoreAdapter) ReverseIterator(start, end []byte) store.Iterator {
func KVStoreAdapter(store store.KVStore) storetypes.KVStore {
return &kvStoreAdapter{store}
}

// UpgradeStoreLoader is used to prepare baseapp with a fixed StoreLoader
// pattern. This is useful for custom upgrade loading logic.
func UpgradeStoreLoader(upgradeHeight int64, storeUpgrades *store.StoreUpgrades) baseapp.StoreLoader {
return func(ms storetypes.CommitMultiStore) error {
if upgradeHeight == ms.LastCommitID().Version+1 {
// Check if the current commit version and upgrade height matches
if len(storeUpgrades.Deleted) > 0 || len(storeUpgrades.Added) > 0 {
stup := &storetypes.StoreUpgrades{
Added: storeUpgrades.Added,
Deleted: storeUpgrades.Deleted,
}
return ms.LoadLatestVersionAndUpgrade(stup)
}
}

// Otherwise load default store loader
return baseapp.DefaultStoreLoader(ms)
}
}
9 changes: 8 additions & 1 deletion runtime/v2/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ type App[T transaction.Tx] struct {
// GRPCMethodsToMessageMap maps gRPC method name to a function that decodes the request
// bytes into a gogoproto.Message, which then can be passed to appmanager.
GRPCMethodsToMessageMap map[string]func() gogoproto.Message

storeLoader StoreLoader
}

// Name returns the app name.
Expand All @@ -68,9 +70,14 @@ func (a *App[T]) DefaultGenesis() map[string]json.RawMessage {
return a.moduleManager.DefaultGenesis()
}

// SetStoreLoader sets the store loader.
func (a *App[T]) SetStoreLoader(loader StoreLoader) {
a.storeLoader = loader
}

// LoadLatest loads the latest version.
func (a *App[T]) LoadLatest() error {
return a.db.LoadLatestVersion()
return a.storeLoader(a.db)
}

// LoadHeight loads a particular height
Expand Down
1 change: 1 addition & 0 deletions runtime/v2/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func ProvideAppBuilder[T transaction.Tx](
msgRouterBuilder: msgRouterBuilder,
queryRouterBuilder: stf.NewMsgRouterBuilder(), // TODO dedicated query router
GRPCMethodsToMessageMap: map[string]func() proto.Message{},
storeLoader: DefaultStoreLoader,
}
appBuilder := &AppBuilder[T]{app: app}

Expand Down
33 changes: 33 additions & 0 deletions runtime/v2/store.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package runtime

import (
"fmt"

"cosmossdk.io/core/store"
"cosmossdk.io/server/v2/stf"
storev2 "cosmossdk.io/store/v2"
Expand Down Expand Up @@ -55,3 +57,34 @@ type Store interface {
// LastCommitID returns the latest commit ID
LastCommitID() (proof.CommitID, error)
}

// StoreLoader allows for custom loading of the store, this is useful when upgrading the store from a previous version
type StoreLoader func(store Store) error

// DefaultStoreLoader just calls LoadLatestVersion on the store
func DefaultStoreLoader(store Store) error {
return store.LoadLatestVersion()
}

// UpgradeStoreLoader upgrades the store if the upgrade height matches the current version, it is used as a replacement
// for the DefaultStoreLoader when there are store upgrades
func UpgradeStoreLoader(upgradeHeight int64, storeUpgrades *store.StoreUpgrades) StoreLoader {
return func(store Store) error {
latestVersion, err := store.GetLatestVersion()
if err != nil {
return err
}

if uint64(upgradeHeight) == latestVersion+1 {
if len(storeUpgrades.Deleted) > 0 || len(storeUpgrades.Added) > 0 {
if upgrader, ok := store.(storev2.UpgradeableStore); ok {
return upgrader.LoadVersionAndUpgrade(latestVersion, storeUpgrades)
}

return fmt.Errorf("store does not support upgrades")
}
}

return DefaultStoreLoader(store)
}
}
5 changes: 2 additions & 3 deletions simapp/v2/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/store"
"cosmossdk.io/runtime/v2"
"cosmossdk.io/x/accounts"
bankv2types "cosmossdk.io/x/bank/v2/types"
epochstypes "cosmossdk.io/x/epochs/types"
Expand Down Expand Up @@ -44,8 +45,6 @@ func (app *SimApp[T]) RegisterUpgradeHandlers() {
Deleted: []string{"crisis"}, // The SDK discontinued the crisis module in v0.52.0
}

// configure store loader that checks if version == upgradeHeight and applies store upgrades
_ = storeUpgrades
// app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
app.SetStoreLoader(runtime.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
}
}
3 changes: 3 additions & 0 deletions x/upgrade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ expected upgrade. It eliminiates the chances for the new binary to execute `Stor
times every time on restart. Also if there are multiple upgrades planned on same height, the `Name`
will ensure these `StoreUpgrades` takes place only in planned upgrade handler.

**Note:** The `StoreLoader` helper function for StoreUpgrades in v2 is not part of the `x/upgrade` module;
instead, you can find it in the runtime v2 module.

### Proposal

Typically, a `Plan` is proposed and submitted through governance via a proposal
Expand Down
28 changes: 3 additions & 25 deletions x/upgrade/types/storeloader.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,6 @@
package types

import (
corestore "cosmossdk.io/core/store"
storetypes "cosmossdk.io/store/types"
import "github.com/cosmos/cosmos-sdk/runtime"

"github.com/cosmos/cosmos-sdk/baseapp"
)

// UpgradeStoreLoader is used to prepare baseapp with a fixed StoreLoader
// pattern. This is useful for custom upgrade loading logic.
func UpgradeStoreLoader(upgradeHeight int64, storeUpgrades *corestore.StoreUpgrades) baseapp.StoreLoader {
return func(ms storetypes.CommitMultiStore) error {
if upgradeHeight == ms.LastCommitID().Version+1 {
// Check if the current commit version and upgrade height matches
if len(storeUpgrades.Deleted) > 0 || len(storeUpgrades.Added) > 0 {
stup := &storetypes.StoreUpgrades{
Added: storeUpgrades.Added,
Deleted: storeUpgrades.Deleted,
}
return ms.LoadLatestVersionAndUpgrade(stup)
}
}

// Otherwise load default store loader
return baseapp.DefaultStoreLoader(ms)
}
}
// UpgradeStoreLoader moved to runtime package, keeping this for backwards compatibility
var UpgradeStoreLoader = runtime.UpgradeStoreLoader

0 comments on commit 7d6ff0d

Please sign in to comment.