-
Notifications
You must be signed in to change notification settings - Fork 624
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: 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. (#2824)
- Loading branch information
1 parent
cbf9fb4
commit e1b1488
Showing
9 changed files
with
414 additions
and
391 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package v7 | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
|
||
clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" | ||
"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 *clienttypes.GenesisState, cdc codec.ProtoCodecMarshaler) (*clienttypes.GenesisState, error) { | ||
// To prune the client and consensus states, we will create new slices to fill up | ||
// with information we want to keep. | ||
var ( | ||
clientsConsensus []clienttypes.ClientConsensusStates | ||
clients []clienttypes.IdentifiedClientState | ||
) | ||
|
||
for _, client := range clientGenState.Clients { | ||
clientType, _, err := clienttypes.ParseClientIdentifier(client.ClientId) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
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) | ||
|
||
protoAny, err := clienttypes.PackClientState(&updatedClientState) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
clients = append(clients, clienttypes.IdentifiedClientState{ | ||
ClientId: client.ClientId, | ||
ClientState: protoAny, | ||
}) | ||
|
||
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, Localhost: | ||
// remove all consensus states for the solo machine and localhost | ||
// 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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
protoAny, err := codectypes.NewAnyWithValue(legacyClientState) | ||
suite.Require().NoError(err) | ||
suite.Require().NotNil(protoAny) | ||
|
||
clients = append(clients, types.IdentifiedClientState{ | ||
ClientId: sm.ClientID, | ||
ClientState: protoAny, | ||
}) | ||
|
||
// 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) | ||
|
||
protoAny, err = codectypes.NewAnyWithValue(legacyClientState.ConsensusState) | ||
suite.Require().NoError(err) | ||
suite.Require().NotNil(protoAny) | ||
|
||
// 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: protoAny, | ||
}) | ||
} | ||
|
||
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) | ||
|
||
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)) | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.