Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add in-place and genesis migrations #205

Merged
merged 27 commits into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4f874d9
add in-place migrations
colin-axner May 31, 2021
f8ca013
update migrations
colin-axner Jun 2, 2021
29c1c48
migrate solomachine from v1 to v2 during in place migration
colin-axner Jun 7, 2021
db0db21
fix build
colin-axner Jun 7, 2021
972ca3c
add genesis migration
colin-axner Jun 7, 2021
314aaba
code cleanup
colin-axner Jun 8, 2021
40a30fa
Merge branch 'main' into colin/11-migration-scripts
colin-axner Jun 8, 2021
863fdbd
add store migration test for expired tendermint consensus states
colin-axner Jun 8, 2021
a36801f
Merge branch 'colin/11-migration-scripts' of github.com:cosmos/ibc-go…
colin-axner Jun 8, 2021
863b50a
finish adding in place migration store tests
colin-axner Jun 9, 2021
545056e
add genesis test for solo machines
colin-axner Jun 9, 2021
40484bb
fix genesis migration bug, add tendermint tests
colin-axner Jun 9, 2021
a24618d
test fix, changelog, migration docs
colin-axner Jun 9, 2021
6d9bcdd
Apply suggestions from code review
colin-axner Jun 9, 2021
6c6fc52
Merge branch 'main' into colin/11-migration-scripts
colin-axner Jun 9, 2021
a67102f
Update docs/migrations/ibc-migration-043.md
AdityaSripal Jun 9, 2021
7e1f40f
apply Aditya's review suggestions
colin-axner Jun 10, 2021
3896a2a
Merge branch 'colin/11-migration-scripts' of github.com:cosmos/ibc-go…
colin-axner Jun 10, 2021
7edac1e
fix tests
colin-axner Jun 10, 2021
e326f74
add genesis json unmarshal test
colin-axner Jun 10, 2021
a970700
Merge branch 'main' into colin/11-migration-scripts
colin-axner Jun 10, 2021
7ceca61
add migration support for max expected time per block
colin-axner Jun 15, 2021
ca070bd
Merge branch 'colin/11-migration-scripts' of github.com:cosmos/ibc-go…
colin-axner Jun 15, 2021
0fcd0c4
fix docs
colin-axner Jun 15, 2021
900b907
fix bug found by Aditya
colin-axner Jun 16, 2021
fed9443
remove unnecessary code
colin-axner Jun 16, 2021
e595b11
apply Aditya review suggestions, fix bug
colin-axner Jun 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions modules/core/02-client/keeper/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

v100 "github.com/cosmos/ibc-go/modules/core/02-client/legacy/v100"
)

// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}

// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}

// Migrate1to2 migrates from version 1 to 2.
// This migration prunes:
// - solo machine clients
// - connections using solo machines
// - channels using solo machines
// - expired tendermint consensus states
//
// Connections are removed if the associated client does not exist.
// Channels are removed if the associated connection does not exist.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v100.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
}
107 changes: 107 additions & 0 deletions modules/core/02-client/legacy/v100/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package v100

import (
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/ibc-go/modules/core/02-client/types"
clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types"
host "github.com/cosmos/ibc-go/modules/core/24-host"
"github.com/cosmos/ibc-go/modules/core/exported"
ibctmtypes "github.com/cosmos/ibc-go/modules/light-clients/07-tendermint/types"
)

// MigrateStore performs in-place store migrations from SDK v0.40 of the IBC module to v1.0.0 of ibc-go.
// The migration includes:
//
// - Pruning solo machine clients
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
// - Pruning expired tendermint consensus states
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) (err error) {
store := ctx.KVStore(storeKey)
iterator := sdk.KVStorePrefixIterator(store, host.KeyClientStorePrefix)

var clients []clienttypes.IdentifiedClientState

defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")
if keySplit[len(keySplit)-1] != host.KeyClientState {
continue
}

// key is clients/{clientid}/clientState
// Thus, keySplit[1] is clientID
clientID := keySplit[1]
clientState := types.MustUnmarshalClientState(cdc, iterator.Value())
clients = append(clients, clienttypes.NewIdentifiedClientState(clientID, clientState))

}

for _, client := range clients {
clientType, _, err := types.ParseClientIdentifier(client.ClientId)
if err != nil {
return err
}

clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, client.ClientId))
clientStore := prefix.NewStore(ctx.KVStore(storeKey), clientPrefix)

switch clientType {
case exported.Solomachine:
pruneSolomachine(clientStore)
store.Delete([]byte(fmt.Sprintf("%s/%s", host.KeyClientStorePrefix, client.ClientId)))

case exported.Tendermint:
clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, client.ClientId))
clientStore := prefix.NewStore(ctx.KVStore(storeKey), clientPrefix)
clientState, err := types.UnpackClientState(client.ClientState)
if err != nil {
return err
}

// ensure client is tendermint type
tmClientState, ok := clientState.(*ibctmtypes.ClientState)
if !ok {
panic("client with identifier '07-tendermint' is not tendermint type!")
}
if err = ibctmtypes.PruneAllExpiredConsensusStates(ctx, clientStore, cdc, tmClientState); err != nil {
return err
}

default:
continue
}
}

return nil
}

// pruneSolomachine removes the client state and all consensus states
// stored in the provided clientStore
func pruneSolomachine(clientStore sdk.KVStore) {
// delete client state
clientStore.Delete(host.ClientStateKey())

// collect consensus states to be pruned
iterator := sdk.KVStorePrefixIterator(clientStore, []byte(host.KeyConsensusStatePrefix))
var heights []exported.Height

defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")
// key is in the format "clients/<clientID>/consensusStates/<height>"
if len(keySplit) != 4 || keySplit[2] != string(host.KeyConsensusStatePrefix) {
continue
}
heights = append(heights, types.MustParseHeight(keySplit[3]))
}

// delete all consensus states
for _, height := range heights {
clientStore.Delete(host.ConsensusStateKey(height))
}
}
25 changes: 25 additions & 0 deletions modules/core/03-connection/keeper/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/ibc-go/modules/core/03-connection/legacy/v100"
)

// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}

// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}

// Migrate1to2 migrates from version 1 to 2.
// This migration prunes:
//
// - connections whose client has been deleted (solomachines)
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v100.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
}
41 changes: 41 additions & 0 deletions modules/core/03-connection/legacy/v100/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package v100

import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/ibc-go/modules/core/03-connection/types"
host "github.com/cosmos/ibc-go/modules/core/24-host"
)

// MigrateStore performs in-place store migrations from SDK v0.40 of the IBC module to v1.0.0 of ibc-go.
// The migration includes:
//
// - Pruning all connections whose client has been removed (solo machines)
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) (err error) {
var connections []types.IdentifiedConnection

// clients and connections use the same store key
store := ctx.KVStore(storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(host.KeyConnectionPrefix))

defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var connection types.ConnectionEnd
cdc.MustUnmarshal(iterator.Value(), &connection)

bz := store.Get(host.FullClientStateKey(connection.ClientId))
if bz == nil {
// client has been pruned, remove connection as well
connectionID := host.MustParseConnectionPath(string(iterator.Key()))
connections = append(connections, types.NewIdentifiedConnection(connectionID, connection))
}

}

for _, conn := range connections {
store.Delete(host.ConnectionKey(conn.Id))
}

return nil
}
25 changes: 25 additions & 0 deletions modules/core/04-channel/keeper/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/ibc-go/modules/core/04-channel/legacy/v100"
)

// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}

// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}

// Migrate1to2 migrates from version 1 to 2.
// This migration prunes:
//
// - channels whose connection has been deleted (solomachines)
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v100.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
}
41 changes: 41 additions & 0 deletions modules/core/04-channel/legacy/v100/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package v100

import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/ibc-go/modules/core/04-channel/types"
host "github.com/cosmos/ibc-go/modules/core/24-host"
)

// MigrateStore performs in-place store migrations from SDK v0.40 of the IBC module to v1.0.0 of ibc-go.
// The migration includes:
//
// - Pruning all channels whose connection has been removed (solo machines)
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec) (err error) {
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
var channels []types.IdentifiedChannel

// connections and channels use the same store key
store := ctx.KVStore(storeKey)

iterator := sdk.KVStorePrefixIterator(store, []byte(host.KeyChannelEndPrefix))

defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var channel types.Channel
cdc.MustUnmarshal(iterator.Value(), &channel)

bz := store.Get(host.ConnectionKey(channel.ConnectionHops[0]))
if bz == nil {
// connection has been pruned, remove channel as well
portID, channelID := host.MustParseChannelPath(string(iterator.Key()))
channels = append(channels, types.NewIdentifiedChannel(portID, channelID, channel))
}
}

for _, channel := range channels {
store.Delete(host.ChannelKey(channel.PortId, channel.ChannelId))
}

return nil
}
47 changes: 47 additions & 0 deletions modules/core/keeper/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

clientkeeper "github.com/cosmos/ibc-go/modules/core/02-client/keeper"
connectionkeeper "github.com/cosmos/ibc-go/modules/core/03-connection/keeper"
channelkeeper "github.com/cosmos/ibc-go/modules/core/04-channel/keeper"
)

// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}

// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}

// Migrate1to2 migrates from version 1 to 2.
// This migration prunes:
// - solo machine clients
// - connections using solo machines
// - channels using solo machines
// - expired tendermint consensus states
//
// Connections are removed if the associated client does not exist.
// Channels are removed if the associated connection does not exist.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
clientMigrator := clientkeeper.NewMigrator(m.keeper.ClientKeeper)
if err := clientMigrator.Migrate1to2(ctx); err != nil {
return err
}

connectionMigrator := connectionkeeper.NewMigrator(m.keeper.ConnectionKeeper)
if err := connectionMigrator.Migrate1to2(ctx); err != nil {
return err
}

channelMigrator := channelkeeper.NewMigrator(m.keeper.ChannelKeeper)
if err := channelMigrator.Migrate1to2(ctx); err != nil {
return err
}

return nil
}
4 changes: 4 additions & 0 deletions modules/core/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
ibcclient "github.com/cosmos/ibc-go/modules/core/02-client"
clientkeeper "github.com/cosmos/ibc-go/modules/core/02-client/keeper"
clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types"
connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types"
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
Expand Down Expand Up @@ -136,6 +137,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
connectiontypes.RegisterMsgServer(cfg.MsgServer(), am.keeper)
channeltypes.RegisterMsgServer(cfg.MsgServer(), am.keeper)
types.RegisterQueryService(cfg.QueryServer(), am.keeper)

m := clientkeeper.NewMigrator(am.keeper.ClientKeeper)
cfg.RegisterMigration(host.ModuleName, 1, m.Migrate1to2)
}

// InitGenesis performs genesis initialization for the ibc module. It returns
Expand Down
36 changes: 36 additions & 0 deletions modules/light-clients/07-tendermint/types/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,42 @@ func GetPreviousConsensusState(clientStore sdk.KVStore, cdc codec.BinaryCodec, h
return getTmConsensusState(clientStore, cdc, csKey)
}

// PruneAllExpiredConsensusStates iterates over all consensus states for a given
// client store. If a consensus state is expired, it is deleted and its metadata
// is deleted.
func PruneAllExpiredConsensusStates(
ctx sdk.Context, clientStore sdk.KVStore,
cdc codec.BinaryCodec, clientState *ClientState,
) (err error) {
var heights []exported.Height

pruneCb := func(height exported.Height) bool {
consState, err := GetConsensusState(clientStore, cdc, height)
// this error should never occur
if err != nil {
return true
}

if clientState.IsExpired(consState.Timestamp, ctx.BlockTime()) {
heights = append(heights, height)
}

return false
}

IterateConsensusStateAscending(clientStore, pruneCb)
if err != nil {
return err
}

for _, height := range heights {
deleteConsensusState(clientStore, height)
deleteConsensusMetadata(clientStore, height)
}

return nil
}

// Helper function for GetNextConsensusState and GetPreviousConsensusState
func getTmConsensusState(clientStore sdk.KVStore, cdc codec.BinaryCodec, key []byte) (*ConsensusState, bool) {
bz := clientStore.Get(key)
Expand Down