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

Conversation

colin-axner
Copy link
Contributor

@colin-axner colin-axner commented May 31, 2021

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.

  • Targeted PR against correct branch (see CONTRIBUTING.md)
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the module structure standards.
  • Wrote unit and integration tests
  • Updated relevant documentation (docs/) or specification (x/<module>/spec/)
  • Added relevant godoc comments.
  • Added a relevant changelog entry to the Unreleased section in CHANGELOG.md
  • Re-reviewed Files changed in the Github PR explorer
  • Review Codecov Report in the comment section below once CI passes

Prunes solomachines and expired tendermint consensus states via an x/upgrade
@colin-axner colin-axner added this to the 1.0.0 milestone May 31, 2021
Copy link
Member

@AdityaSripal AdityaSripal left a 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

modules/core/02-client/legacy/v100/store.go Outdated Show resolved Hide resolved
fix iteration bug
remove solo machine connections
remove solo machine channels
@codecov-commenter
Copy link

codecov-commenter commented Jun 2, 2021

Codecov Report

Merging #205 (fed9443) into main (2548ab5) will decrease coverage by 0.87%.
The diff coverage is 51.64%.

Impacted file tree graph

@@            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     
Impacted Files Coverage Δ
modules/core/03-connection/types/params.go 76.92% <ø> (ø)
modules/core/keeper/migrations.go 0.00% <0.00%> (ø)
modules/light-clients/07-tendermint/types/store.go 78.67% <0.00%> (-8.11%) ⬇️
...odules/light-clients/07-tendermint/types/update.go 81.08% <ø> (ø)
modules/core/02-client/legacy/v100/solomachine.go 4.34% <4.34%> (ø)
modules/core/02-client/keeper/migrations.go 50.00% <50.00%> (ø)
modules/core/02-client/legacy/v100/store.go 64.86% <64.86%> (ø)
modules/core/02-client/legacy/v100/genesis.go 80.76% <80.76%> (ø)
modules/core/legacy/v100/genesis.go 87.50% <87.50%> (ø)
modules/core/module.go 56.09% <100.00%> (+2.25%) ⬆️
... and 7 more

@colin-axner
Copy link
Contributor Author

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
@colin-axner colin-axner changed the title Add in-place migrations Add in-place and genesis migrations Jun 7, 2021
@colin-axner
Copy link
Contributor Author

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

cc @shahankhatch

@colin-axner
Copy link
Contributor Author

Actually, gaia won't need this as it should use the in-place migrations (not a genesis restart)

docs/migrations/ibc-migration-043.md Outdated Show resolved Hide resolved
docs/migrations/ibc-migration-043.md Outdated Show resolved Hide resolved
docs/migrations/ibc-migration-043.md Outdated Show resolved Hide resolved
docs/migrations/ibc-migration-043.md Outdated Show resolved Hide resolved
modules/core/02-client/keeper/migrations.go Outdated Show resolved Hide resolved
modules/core/02-client/legacy/v100/genesis_test.go Outdated Show resolved Hide resolved
modules/core/keeper/migrations.go Outdated Show resolved Hide resolved
modules/core/module.go Show resolved Hide resolved
modules/core/02-client/legacy/v100/store.go Show resolved Hide resolved
modules/core/legacy/v100/genesis.go Outdated Show resolved Hide resolved
@colin-axner colin-axner marked this pull request as ready for review June 9, 2021 16:23
Copy link
Member

@AdityaSripal AdityaSripal left a 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.

docs/migrations/ibc-migration-043.md Outdated Show resolved Hide resolved
modules/core/02-client/legacy/v100/genesis.go Outdated Show resolved Hide resolved
modules/core/02-client/legacy/v100/genesis.go Outdated Show resolved Hide resolved
Comment on lines 90 to 92
if err = ibctmtypes.PruneAllExpiredConsensusStates(ctx, clientStore, cdc, clientState.(*ibctmtypes.ClientState)); err != nil {
return err
}
Copy link
Member

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

AdityaSripal and others added 5 commits June 9, 2021 14:10
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 {
Copy link
Contributor Author

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

Comment on lines +13 to +21
// 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.
Copy link
Contributor Author

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

Comment on lines +145 to +150
// 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)

Copy link
Contributor Author

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)

@colin-axner colin-axner mentioned this pull request Jun 10, 2021
6 tasks
Comment on lines +48 to +61
```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)
})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

tested

Comment on lines +81 to +84
newGenState, err = ibcv100.MigrateGenesis(newGenState, clientCtx, *genDoc, expectedTimePerBlock)
if err != nil {
return err
}
Copy link
Contributor Author

@colin-axner colin-axner Jun 15, 2021

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
Copy link
Member

@AdityaSripal AdityaSripal left a 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),
Copy link
Member

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{
Copy link
Member

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??

Copy link
Contributor Author

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

modules/core/02-client/legacy/v100/store.go Outdated Show resolved Hide resolved
Comment on lines 199 to 203
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)
Copy link
Member

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

Copy link
Contributor Author

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

Copy link
Contributor Author

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

modules/core/02-client/legacy/v100/genesis_test.go Outdated Show resolved Hide resolved
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
Comment on lines +173 to +179

// 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))
}
Copy link
Contributor Author

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} {
Copy link
Contributor Author

@colin-axner colin-axner Jun 17, 2021

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

@colin-axner colin-axner enabled auto-merge (squash) June 17, 2021 11:40
@colin-axner colin-axner merged commit 2e95805 into main Jun 17, 2021
@colin-axner colin-axner deleted the colin/11-migration-scripts branch June 17, 2021 11:43
@colin-axner colin-axner mentioned this pull request Jul 7, 2021
3 tasks
faddat referenced this pull request in notional-labs/ibc-go Feb 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants