Skip to main content
Version: v0.50

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

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

danger

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))
}
}