-
Notifications
You must be signed in to change notification settings - Fork 586
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
Conversation
Prunes solomachines and expired tendermint consensus states via an x/upgrade
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Just have a question on solo machine cons states
fix iteration bug remove solo machine connections remove solo machine channels
Codecov Report
@@ Coverage Diff @@
## main #205 +/- ##
==========================================
- Coverage 80.11% 79.23% -0.88%
==========================================
Files 109 115 +6
Lines 6507 6719 +212
==========================================
+ Hits 5213 5324 +111
- Misses 932 1017 +85
- Partials 362 378 +16
|
I thought about this some more. Instead of deleting the solo machines I'm going to migrate the proto definitions. I will generate the v1 solo machine proto files in the legacy dir, iterate over the client store and migrate the old proto definition to the new one (changing frozen sequence to be a boolean) The existing solo machines are still considered active so they don't need to be deleted. This avoids risk of deleting the wrong clients/connections/channels and it'll make genesis migration a lot easier. I'm not sure how I would be capable of efficiently iterating all channels to delete those associated with solo machines Genesis migration will do the same, iterate over the clients, unmarshal if solo machine, migrate to new definition, marshal and set in genesis |
Regenerate v1 solo machine definition in 02-client legacy Migrate from v1 to v2 solo machine client state Prune v1 solo machine consensus states
Our genesis migrations will not fit into the interface defined by the SDK since it needs access to the genesis block time (this block time must also be updated before the migration is ran). Even if we didn't need the block time, the interface for adding genesis migrations outside of the SDK is clumsy. We would need to add another version migration. Normally the SDK might go from v0.40 -> v0.43. We would need to add a migration which goes from v0.43 -> v0.43.0-ibc or something like that. Basically doing the migrations for v0.43.0 for IBC The better way to do this is to just explicitly call the IBC migrations without abiding to the migration interface. It'll look something like newIBCGenState, err := v100.Migrate(IBCGenState, genesisTime)
if err != nil {
return err
}
genesis.AppState[ibchost.ModuleName] = newIBCGenState I'll add the code explicitly into our migration doc and open a pr on gaia |
Actually, gaia won't need this as it should use the in-place migrations (not a genesis restart) |
… into colin/11-migration-scripts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe you need to set processedHeight and Iteration keys for the unexpired tendermint consensus states that you migrate over.
if err = ibctmtypes.PruneAllExpiredConsensusStates(ctx, clientStore, cdc, clientState.(*ibctmtypes.ClientState)); err != nil { | ||
return err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need to set iteration and height keys for unexpired consensus states
… into colin/11-migration-scripts
Test that the legacy solo machines can be successfully unmarshalled. This requires registering an implementation for the legacy solo machine. An implemenation which panics has been added. This implementation should only be registered against a clientCtx during a migrate cli cmd. The implementation is only briefly used in order to decode the previous solo machine set in genesis.
|
||
// addConsensusMetadata adds the iteration key and processed height for all unexpired tendermint consensus states | ||
// These keys were not included in the previous release of the IBC module. | ||
func addConsensusMetadata(ctx sdk.Context, clientStore sdk.KVStore, cdc codec.BinaryCodec, clientState *ibctmtypes.ClientState) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided not to modify PruneAllExpiredConsensusStates
as that seems like a useful ibctmtypes function by itself. Since the insertion of the iteration key and processed height key is logic specific to this migration, I decided to iterate the consensus state again and do it in a separate iteration. It is less efficient, but I think better code wise. Open to changing if efficiency is a big concern
// NOTE: this is a mock implmentation for exported.ClientState. This implementation | ||
// should only be registered on the InterfaceRegistry during cli command genesis migration. | ||
// This implementation is only used to successfully unmarshal the previous solo machine | ||
// client state and consensus state and migrate them to the new implementations. When the proto | ||
// codec unmarshals, it calls UnpackInterfaces() to create a cached value of the any. The | ||
// UnpackInterfaces function for IdenitifiedClientState will attempt to unpack the any to | ||
// exported.ClientState. If the solomachine v1 type is not registered against the exported.ClientState | ||
// the unmarshal will fail. This implementation will panic on every interface function. | ||
// The same is done for the ConsensusState. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there's really no way around this. go semantic versioning will help a lot in the future
// migrate store get expected genesis | ||
// store migration and genesis migration should produce identical results | ||
err := clientv100.MigrateStore(path.EndpointA.Chain.GetContext(), path.EndpointA.Chain.GetSimApp().GetKey(host.StoreKey), path.EndpointA.Chain.App.AppCodec()) | ||
suite.Require().NoError(err) | ||
expectedClientGenState := ibcclient.ExportGenesis(path.EndpointA.Chain.GetContext(), path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the main test code added (this was copied from previous tests)
… into colin/11-migration-scripts
```go | ||
app.UpgradeKeeper.SetUpgradeHandler("my-upgrade-proposal", | ||
func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { | ||
// set max expected block time parameter. Replace the default with your expected value | ||
// https://github.com/cosmos/ibc-go/blob/release/v1.0.x/docs/ibc/proto-docs.md#params-2 | ||
app.IBCKeeper.ConnectionKeeper.SetParams(ctx, ibcconnectiontypes.DefaultParams()) | ||
|
||
fromVM := map[string]uint64{ | ||
... // other modules | ||
"ibc": 1, | ||
... | ||
} | ||
return app.mm.RunMigrations(ctx, app.configurator, fromVM) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested
newGenState, err = ibcv100.MigrateGenesis(newGenState, clientCtx, *genDoc, expectedTimePerBlock) | ||
if err != nil { | ||
return err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested, got as far as I could. Final confirmation of IBC breaking upgrades is blocked on upstream changes (SDK is moving protobuf definition for upgrade/gov from v1beta1 to v1 and the current pr on the SDK has minor bugs)
I confirmed the migration updated the genesis, as far as I can tell, everything works on the IBC end, although I didn't get a chance to test that IBC clients were successfully upgraded. At the very least the chain started fine
The genesis client metadata was being set independently for each unexpired height. It needed to be moved outside the unexpired for loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just a couple nits
// iteration key and processed height keys. | ||
if bytes.Equal(metadata.Key, ibctmtypes.ProcessedTimeKey(height)) { | ||
clientMetadata = append(clientMetadata, types.GenesisMetadata{ | ||
Key: ibctmtypes.ProcessedHeightKey(height), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add godoc saying we're setting processed height to self height, which is still safe
// if we find the processed time metadata for an unexpired height, add the | ||
// iteration key and processed height keys. | ||
if bytes.Equal(metadata.Key, ibctmtypes.ProcessedTimeKey(height)) { | ||
clientMetadata = append(clientMetadata, types.GenesisMetadata{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't you do this with just one append call??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow, I've always worked under the impression append()
took only 2 arguments
processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, height) | ||
suite.Require().True(ok) | ||
suite.Require().Equal(types.GetSelfHeight(path.EndpointA.Chain.GetContext()), processedHeight) | ||
|
||
consKey := ibctmtypes.GetIterationKey(clientStore, height) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't this metadata already get created in original client update?
I guess you proved metadata did something by checking value of processed height
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, the purpose of this to ensure the unexpired consensus state metadata did not get pruned. I wrote this before adding the addConsensusMetadata
function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
found a bug, since I was using the iteration keys for iterating, it wasn't updating the metadata since the iteration keys hadn't been set
changed the structure, set new metadata for all consensus states (using traditional iteration), then prune expired consensus states
There was a bug in adding consensus metadata since it relied on the iteration key not yet set. This is fixed by using traditional iteration using the consensus state key, setting metadata for all consensus states, and then pruning expired consensus states. The store test has been updated to set create two tendermint clients
|
||
// remove processed height and iteration keys since these were missing from previous version of ibc module | ||
clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(path.EndpointA.Chain.GetContext(), path.EndpointA.ClientID) | ||
for _, height := range unexpiredHeights { | ||
clientStore.Delete(ibctmtypes.ProcessedHeightKey(height)) | ||
clientStore.Delete(ibctmtypes.IterationKey(height)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this now enforces a check on the metadata being added
// these heights will be expired and also pruned | ||
for i := 0; i < 3; i++ { | ||
path.EndpointA.UpdateClient() | ||
for _, path := range []*ibctesting.Path{path1, path2} { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just added an extra for loop to test multiple paths at the same time
Description
Adds an in-place migration for SDK v0.40 -> ibc-go v1.0.0 and genesis migrations
Solo machine proto definition changed (FrozenSequence because a boolean). This may lead to indeterminate decoding errors. During in-place and genesis migrations, we will decode the solomachine into the v1 definition, then we will migrate it to v2 and set this in the store or genesis. All consensus states for solo machines are removed. The legacy solo machine is generated into
legacy/v100
Also all expired tendermint consensus states are pruned
ref: #11
Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.
docs/
) or specification (x/<module>/spec/
)godoc
comments.Unreleased
section inCHANGELOG.md
Files changed
in the Github PR explorerCodecov Report
in the comment section below once CI passes