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

feat: add genesis migrations for v7 #2824

Merged
merged 17 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Features

* (core/02-client) [\#2824](https://github.com/cosmos/ibc-go/pull/2824) Add genesis migrations for v6 to v7. The migration migrates the solo machine client state definition, removes all solo machine consensus states and removes the localhost client.
* (core/24-host) [\#2856](https://github.com/cosmos/ibc-go/pull/2856) Add `PrefixedClientStorePath` and `PrefixedClientStoreKey` functions to 24-host
* (core/02-client) [\#2819](https://github.com/cosmos/ibc-go/pull/2819) Add automatic in-place store migrations to remove the localhost client and migrate existing solo machine definitions.
* (light-clients/06-solomachine) [\#2826](https://github.com/cosmos/ibc-go/pull/2826) Add `AppModuleBasic` for the 06-solomachine client and remove solo machine type registration from core IBC. Chains must register the `AppModuleBasic` of light clients.
Expand Down
82 changes: 82 additions & 0 deletions modules/core/02-client/migrations/v7/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package v7

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

"github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
chatton marked this conversation as resolved.
Show resolved Hide resolved
"github.com/cosmos/ibc-go/v6/modules/core/exported"
)

// MigrateGenesis accepts an exported IBC client genesis file and migrates it to:
//
// - Update solo machine client state protobuf definition (v2 to v3)
// - Remove all solo machine consensus states
// - Remove localhost client
func MigrateGenesis(clientGenState *types.GenesisState, cdc codec.ProtoCodecMarshaler) (*types.GenesisState, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of this work is ported from v1 legacy migrations. I cleaned up a lot of it, but there might be some more cleanup. Generally working with genesis isn't very clean though

// To prune the client and consensus states, we will create new slices to fill up
// with information we want to keep.
var (
clientsConsensus []types.ClientConsensusStates
clients []types.IdentifiedClientState
)

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

// update solo machine client state defintions
chatton marked this conversation as resolved.
Show resolved Hide resolved
switch clientType {
case exported.Solomachine:
var clientState ClientState
if err := cdc.Unmarshal(client.ClientState.Value, &clientState); err != nil {
return nil, sdkerrors.Wrap(err, "failed to unmarshal client state bytes into solo machine client state")
}

updatedClientState := migrateSolomachine(clientState)

any, err := types.PackClientState(&updatedClientState)
chatton marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}

clients = append(clients, types.IdentifiedClientState{
ClientId: client.ClientId,
ClientState: any,
})

case Localhost:
// remove localhost client state by not adding client state

default:
// add all other client states
clients = append(clients, client)
}

// iterate consensus states by client
for _, clientConsensusStates := range clientGenState.ClientsConsensus {
// look for consensus states for the current client
if clientConsensusStates.ClientId == client.ClientId {
switch clientType {
case exported.Solomachine:
chatton marked this conversation as resolved.
Show resolved Hide resolved
// remove all consensus states for the solo machine
// do not add to new clientsConsensus

case Localhost:
// remove all consensus states for the solo machine
// do not add to new clientsConsensus

default:
// ensure all consensus states added for other client types
clientsConsensus = append(clientsConsensus, clientConsensusStates)
}
}
}
}

clientGenState.Clients = clients
clientGenState.ClientsConsensus = clientsConsensus
return clientGenState, nil
}
134 changes: 134 additions & 0 deletions modules/core/02-client/migrations/v7/genesis_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package v7_test

import (
"encoding/json"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"

ibcclient "github.com/cosmos/ibc-go/v6/modules/core/02-client"
"github.com/cosmos/ibc-go/v6/modules/core/02-client/migrations/v7"
"github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
host "github.com/cosmos/ibc-go/v6/modules/core/24-host"
ibctesting "github.com/cosmos/ibc-go/v6/testing"
)

func (suite *MigrationsV7TestSuite) TestMigrateGenesisSolomachine() {
// create tendermint clients
for i := 0; i < 3; i++ {
path := ibctesting.NewPath(suite.chainA, suite.chainB)

suite.coordinator.SetupClients(path)

err := path.EndpointA.UpdateClient()
suite.Require().NoError(err)

// update a second time to add more state
err = path.EndpointA.UpdateClient()
suite.Require().NoError(err)
}

// create multiple legacy solo machine clients
solomachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "06-solomachine-0", "testing", 1)
solomachineMulti := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "06-solomachine-1", "testing", 4)

clientGenState := ibcclient.ExportGenesis(suite.chainA.GetContext(), suite.chainA.App.GetIBCKeeper().ClientKeeper)

// manually generate old proto buf definitions and set in genesis
// NOTE: we cannot use 'ExportGenesis' for the solo machines since we are
// using client states and consensus states which do not implement the exported.ClientState
// and exported.ConsensusState interface
var clients []types.IdentifiedClientState
for _, sm := range []*ibctesting.Solomachine{solomachine, solomachineMulti} {
clientState := sm.ClientState()

// generate old client state proto definition
legacyClientState := &v7.ClientState{
Sequence: clientState.Sequence,
ConsensusState: &v7.ConsensusState{
PublicKey: clientState.ConsensusState.PublicKey,
Diversifier: clientState.ConsensusState.Diversifier,
Timestamp: clientState.ConsensusState.Timestamp,
},
AllowUpdateAfterProposal: true,
}

// set client state
any, err := codectypes.NewAnyWithValue(legacyClientState)
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
suite.Require().NoError(err)
suite.Require().NotNil(any)

clients = append(clients, types.IdentifiedClientState{
ClientId: sm.ClientID,
ClientState: any,
})

// set in store for ease of determining expected genesis
clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), sm.ClientID)
bz, err := suite.chainA.App.AppCodec().MarshalInterface(legacyClientState)
suite.Require().NoError(err)
clientStore.Set(host.ClientStateKey(), bz)

any, err = codectypes.NewAnyWithValue(legacyClientState.ConsensusState)
suite.Require().NoError(err)
suite.Require().NotNil(any)

// obtain marshalled bytes to set in client store
bz, err = suite.chainA.App.AppCodec().MarshalInterface(legacyClientState.ConsensusState)
suite.Require().NoError(err)

var consensusStates []types.ConsensusStateWithHeight

// set consensus states in store and genesis
for i := uint64(0); i < numCreations; i++ {
height := types.NewHeight(1, i)
clientStore.Set(host.ConsensusStateKey(height), bz)
consensusStates = append(consensusStates, types.ConsensusStateWithHeight{
Height: height,
ConsensusState: any,
})
}

clientGenState.ClientsConsensus = append(clientGenState.ClientsConsensus, types.ClientConsensusStates{
ClientId: sm.ClientID,
ConsensusStates: consensusStates,
})
}

// solo machine clients must come before tendermint in expected
clientGenState.Clients = append(clients, clientGenState.Clients...)

// migrate store get expected genesis
// store migration and genesis migration should produce identical results
// NOTE: tendermint clients are not pruned in genesis so the test should not have expired tendermint clients
err := v7.MigrateStore(suite.chainA.GetContext(), suite.chainA.GetSimApp().GetKey(host.StoreKey), suite.chainA.App.AppCodec())
suite.Require().NoError(err)
expectedClientGenState := ibcclient.ExportGenesis(suite.chainA.GetContext(), suite.chainA.App.GetIBCKeeper().ClientKeeper)

cdc, ok := suite.chainA.App.AppCodec().(codec.ProtoCodecMarshaler)
suite.Require().True(ok)

migrated, err := v7.MigrateGenesis(&clientGenState, cdc)
suite.Require().NoError(err)

bz, err := cdc.MarshalJSON(&expectedClientGenState)
suite.Require().NoError(err)

// Indent the JSON bz correctly.
var jsonObj map[string]interface{}
err = json.Unmarshal(bz, &jsonObj)
suite.Require().NoError(err)
expectedIndentedBz, err := json.MarshalIndent(jsonObj, "", "\t")
suite.Require().NoError(err)
chatton marked this conversation as resolved.
Show resolved Hide resolved

bz, err = cdc.MarshalJSON(migrated)
suite.Require().NoError(err)

// Indent the JSON bz correctly.
err = json.Unmarshal(bz, &jsonObj)
suite.Require().NoError(err)
indentedBz, err := json.MarshalIndent(jsonObj, "", "\t")
suite.Require().NoError(err)

suite.Require().Equal(string(expectedIndentedBz), string(indentedBz))
}
54 changes: 0 additions & 54 deletions modules/core/legacy/v100/genesis.go

This file was deleted.

Loading