Upgrade Guide
This document provides a full guide for upgrading a Cosmos SDK chain from v0.50.x
to v0.53.x
.
This guide includes one required change and three optional features.
After completing this guide, applications will have:
- The
x/protocolpool
module - The
x/epochs
module - Unordered Transaction support
Table of Contents
- App Wiring Changes (REQUIRED)
- Adding ProtocolPool Module (OPTIONAL)
- Adding Epochs Module (OPTIONAL)
- Enable Unordered Transactions (OPTIONAL)
- Upgrade Handler
App Wiring Changes REQUIRED
The x/auth
module now contains a PreBlocker
that must be set in the module manager's SetOrderPreBlockers
method.
app.ModuleManager.SetOrderPreBlockers(
upgradetypes.ModuleName,
authtypes.ModuleName, // NEW
)
Adding ProtocolPool Module OPTIONAL
Using an external community pool such as x/protocolpool
will cause the following x/distribution
handlers to return an error:
QueryService
CommunityPool
MsgService
CommunityPoolSpend
FundCommunityPool
If your services depend on this functionality from x/distribution
, please update them to use either x/protocolpool
or your custom external community pool alternatives.
ProtocolPool Manual Wiring
Import the following:
import (
// ...
"github.com/cosmos/cosmos-sdk/x/protocolpool"
protocolpoolkeeper "github.com/cosmos/cosmos-sdk/x/protocolpool/keeper"
protocolpooltypes "github.com/cosmos/cosmos-sdk/x/protocolpool/types"
)
Set the module account permissions.
maccPerms = map[string][]string{
// ...
protocolpooltypes.ModuleName: nil,
protocolpooltypes.ProtocolPoolEscrowAccount: nil,
}
Add the protocol pool keeper to your application struct.
ProtocolPoolKeeper protocolpoolkeeper.Keeper
Add the store key:
keys := storetypes.NewKVStoreKeys(
// ...
protocolpooltypes.StoreKey,
)
Instantiate the keeper.
Make sure to do this before the distribution module instantiation, as you will pass the keeper there next.
app.ProtocolPoolKeeper = protocolpoolkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[protocolpooltypes.StoreKey]),
app.AccountKeeper,
app.BankKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
Pass the protocolpool keeper to the distribution keeper:
app.DistrKeeper = distrkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[distrtypes.StoreKey]),
app.AccountKeeper,
app.BankKeeper,
app.StakingKeeper,
authtypes.FeeCollectorName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
distrkeeper.WithExternalCommunityPool(app.ProtocolPoolKeeper), // NEW
)
Add the protocolpool module to the module manager:
app.ModuleManager = module.NewManager(
// ...
protocolpool.NewAppModule(appCodec, app.ProtocolPoolKeeper, app.AccountKeeper, app.BankKeeper),
)
Add an entry for SetOrderBeginBlockers, SetOrderEndBlockers, SetOrderInitGenesis, and SetOrderExportGenesis.
app.ModuleManager.SetOrderBeginBlockers(
// must come AFTER distribution.
distrtypes.ModuleName,
protocolpooltypes.ModuleName,
)
app.ModuleManager.SetOrderEndBlockers(
// order does not matter.
protocolpooltypes.ModuleName,
)
app.ModuleManager.SetOrderInitGenesis(
// order does not matter.
protocolpooltypes.ModuleName,
)
app.ModuleManager.SetOrderInitGenesis(
protocolpooltypes.ModuleName, // must be exported before bank.
banktypes.ModuleName,
)
ProtocolPool DI Wiring
First, set up the keeper for the application.
Import the protocolpool keeper:
protocolpoolkeeper "github.com/cosmos/cosmos-sdk/x/protocolpool/keeper"
Add the keeper to your application struct:
ProtocolPoolKeeper protocolpoolkeeper.Keeper
Add the keeper to the depinject system:
depinject.Inject(
appConfig,
&appBuilder,
&app.appCodec,
&app.legacyAmino,
&app.txConfig,
&app.interfaceRegistry,
// ... other modules
&app.ProtocolPoolKeeper, // NEW MODULE!
)
Next, set up configuration for the module.
Import the following:
import (
protocolpoolmodulev1 "cosmossdk.io/api/cosmos/protocolpool/module/v1"
_ "github.com/cosmos/cosmos-sdk/x/protocolpool" // import for side-effects
protocolpooltypes "github.com/cosmos/cosmos-sdk/x/protocolpool/types"
)
The protocolpool module has module accounts that handle funds. Add them to the module account permission configuration:
moduleAccPerms = []*authmodulev1.ModuleAccountPermission{
// ...
{Account: protocolpooltypes.ModuleName},
{Account: protocolpooltypes.ProtocolPoolEscrowAccount},
}
Next, add an entry for BeginBlockers, EndBlockers, InitGenesis, and ExportGenesis.
BeginBlockers: []string{
// ...
// must be AFTER distribution.
distrtypes.ModuleName,
protocolpooltypes.ModuleName,
},
EndBlockers: []string{
// ...
// order for protocolpool does not matter.
protocolpooltypes.ModuleName,
},
InitGenesis: []string{
// ... must be AFTER distribution.
distrtypes.ModuleName,
protocolpooltypes.ModuleName,
},
ExportGenesis: []string{
// ...
// Must be exported before x/bank.
protocolpooltypes.ModuleName,
banktypes.ModuleName,
},
Lastly, add an entry for protocolpool in the ModuleConfig.
{
Name: protocolpooltypes.ModuleName,
Config: appconfig.WrapAny(&protocolpoolmodulev1.Module{}),
},
Adding Epochs Module OPTIONAL
Epochs Manual Wiring
Import the following:
import (
// ...
"github.com/cosmos/cosmos-sdk/x/epochs"
epochskeeper "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
epochstypes "github.com/cosmos/cosmos-sdk/x/epochs/types"
)
Add the epochs keeper to your application struct:
EpochsKeeper epochskeeper.Keeper
Add the store key:
keys := storetypes.NewKVStoreKeys(
// ...
epochstypes.StoreKey,
)
Instantiate the keeper:
app.EpochsKeeper = epochskeeper.NewKeeper(
runtime.NewKVStoreService(keys[epochstypes.StoreKey]),
appCodec,
)
Set up hooks for the epochs keeper:
To learn how to write hooks for the epoch keeper, see the x/epoch README
app.EpochsKeeper.SetHooks(
epochstypes.NewMultiEpochHooks(
// insert epoch hooks receivers here
app.SomeOtherModule
),
)
Add the epochs module to the module manager:
app.ModuleManager = module.NewManager(
// ...
epochs.NewAppModule(appCodec, app.EpochsKeeper),
)
Add entries for SetOrderBeginBlockers and SetOrderInitGenesis:
app.ModuleManager.SetOrderBeginBlockers(
// ...
epochstypes.ModuleName,
)
app.ModuleManager.SetOrderInitGenesis(
// ...
epochstypes.ModuleName,
)
Epochs DI Wiring
First, set up the keeper for the application.
Import the epochs keeper:
epochskeeper "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
Add the keeper to your application struct:
EpochsKeeper epochskeeper.Keeper
Add the keeper to the depinject system:
depinject.Inject(
appConfig,
&appBuilder,
&app.appCodec,
&app.legacyAmino,
&app.txConfig,
&app.interfaceRegistry,
// ... other modules
&app.EpochsKeeper, // NEW MODULE!
)
Next, set up configuration for the module.
Import the following:
import (
epochsmodulev1 "cosmossdk.io/api/cosmos/epochs/module/v1"
_ "github.com/cosmos/cosmos-sdk/x/epochs" // import for side-effects
epochstypes "github.com/cosmos/cosmos-sdk/x/epochs/types"
)
Add an entry for BeginBlockers and InitGenesis:
BeginBlockers: []string{
// ...
epochstypes.ModuleName,
},
InitGenesis: []string{
// ...
epochstypes.ModuleName,
},
Lastly, add an entry for epochs in the ModuleConfig:
{
Name: epochstypes.ModuleName,
Config: appconfig.WrapAny(&epochsmodulev1.Module{}),
},
Enable Unordered Transactions OPTIONAL
To enable unordered transaction support on an application, the ante handler options must be updated.
options := ante.HandlerOptions{
// ...
UnorderedNonceManager: app.AccountKeeper,
// The following options are set by default.
// If you do not want to change these, you may remove the UnorderedTxOptions field entirely.
UnorderedTxOptions: []ante.UnorderedTxDecoratorOptions{
ante.WithUnorderedTxGasCost(2240),
ante.WithTimeoutDuration(10 * time.Minute),
},
}
anteDecorators := []sdk.AnteDecorator{
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
circuitante.NewCircuitBreakerDecorator(options.CircuitKeeper),
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
ante.NewValidateSigCountDecorator(options.AccountKeeper),
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
// NEW !! NEW !! NEW !!
ante.NewUnorderedTxDecorator(options.UnorderedNonceManager, options.UnorderedTxOptions...)
}
Upgrade Handler
The upgrade handler only requires adding the store upgrades for the modules added above.
If your application is not adding x/protocolpool
or x/epochs
, you do not need to add the store upgrade.
// UpgradeName defines the on-chain upgrade name for the sample SimApp upgrade
// from v050 to v053.
//
// NOTE: This upgrade defines a reference implementation of what an upgrade
// could look like when an application is migrating from Cosmos SDK version
// v0.50.x to v0.53.x.
const UpgradeName = "v050-to-v053"
func (app SimApp) RegisterUpgradeHandlers() {
app.UpgradeKeeper.SetUpgradeHandler(
UpgradeName,
func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM)
},
)
upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
if err != nil {
panic(err)
}
if upgradeInfo.Name == UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
storeUpgrades := storetypes.StoreUpgrades{
Added: []string{
epochstypes.ModuleName, // if not adding x/epochs to your chain, remove this line.
protocolpooltypes.ModuleName, // if not adding x/protocolpool to your chain, remove this line.
},
}
// configure store loader that checks if version == upgradeHeight and applies store upgrades
app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
}
}