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 1 commit
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
22 changes: 13 additions & 9 deletions modules/core/02-client/legacy/v100/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,19 @@ func MigrateGenesis(cdc codec.BinaryCodec, clientGenState *types.GenesisState, g
// 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{
Key: ibctmtypes.ProcessedHeightKey(height),
Value: []byte(selfHeight.String()),
})
clientMetadata = append(clientMetadata, metadata) // processed time
clientMetadata = append(clientMetadata, types.GenesisMetadata{
Key: ibctmtypes.IterationKey(height),
Value: host.ConsensusStateKey(height),
})
clientMetadata = append(clientMetadata,
// set the processed height using the current self height
// this is safe, it may cause delays in packet processing if there
// is a non zero connection delay time
types.GenesisMetadata{
Key: ibctmtypes.ProcessedHeightKey(height),
Value: []byte(selfHeight.String()),
},
metadata, // processed time
types.GenesisMetadata{
Key: ibctmtypes.IterationKey(height),
Value: host.ConsensusStateKey(height),
})

}
}
Expand Down
5 changes: 0 additions & 5 deletions modules/core/02-client/legacy/v100/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package v100_test
import (
"bytes"
"encoding/json"
"fmt"
"time"

"github.com/cosmos/cosmos-sdk/client"
Expand Down Expand Up @@ -167,8 +166,6 @@ func (suite *LegacyTestSuite) TestMigrateGenesisSolomachine() {
indentedBz, err := json.MarshalIndent(jsonObj, "", "\t")
suite.Require().NoError(err)

fmt.Println(string(indentedBz))

suite.Require().Equal(string(expectedIndentedBz), string(indentedBz))
}

Expand Down Expand Up @@ -310,7 +307,5 @@ func (suite *LegacyTestSuite) TestMigrateGenesisTendermint() {
indentedBz, err := json.MarshalIndent(jsonObj, "", "\t")
suite.Require().NoError(err)

fmt.Println(string(indentedBz))

suite.Require().Equal(string(expectedIndentedBz), string(indentedBz))
}
32 changes: 14 additions & 18 deletions modules/core/02-client/legacy/v100/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,12 @@ func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey, cdc codec.BinaryCodec)
return sdkerrors.Wrap(types.ErrInvalidClient, "client state is not tendermint even though client id contains 07-tendermint")
}

if err = ibctmtypes.PruneAllExpiredConsensusStates(ctx, clientStore, cdc, tmClientState); err != nil {
// add iteration keys so pruning will be successful
if err = addConsensusMetadata(ctx, clientStore, cdc, tmClientState); err != nil {
return err
}

if err = addConsensusMetadata(ctx, clientStore, cdc, tmClientState); err != nil {
if err = ibctmtypes.PruneAllExpiredConsensusStates(ctx, clientStore, cdc, tmClientState); err != nil {
return err
}

Expand Down Expand Up @@ -150,27 +151,22 @@ func pruneSolomachineConsensusStates(clientStore sdk.KVStore) {
}
}

// 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.
// addConsensusMetadata adds the iteration key and processed height for all tendermint consensus states
// These keys were not included in the previous release of the IBC module. Adding the iteration keys allows
// for pruning iteration.
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

var heights []exported.Height
iterator := sdk.KVStorePrefixIterator(clientStore, []byte(host.KeyConsensusStatePrefix))

metadataCb := func(height exported.Height) bool {
consState, err := ibctmtypes.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)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")
// consensus key is in the format "consensusStates/<height>"
if len(keySplit) != 2 {
continue
}

return false
}

if err := ibctmtypes.IterateConsensusStateAscending(clientStore, metadataCb); err != nil {
return err
heights = append(heights, types.MustParseHeight(keySplit[1]))
}

for _, height := range heights {
Expand Down
138 changes: 82 additions & 56 deletions modules/core/02-client/legacy/v100/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,88 +118,114 @@ func (suite *LegacyTestSuite) TestMigrateStoreSolomachine() {
// ensure all expired consensus states are removed from tendermint client stores
func (suite *LegacyTestSuite) TestMigrateStoreTendermint() {
// create path and setup clients
path := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupClients(path)
path1 := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupClients(path1)

// collect all heights expected to be pruned
var pruneHeights []exported.Height
pruneHeights = append(pruneHeights, path.EndpointA.GetClientState().GetLatestHeight())
path2 := ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupClients(path2)
pruneHeightMap := make(map[*ibctesting.Path][]exported.Height)
unexpiredHeightMap := make(map[*ibctesting.Path][]exported.Height)

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

// collect all heights expected to be pruned
var pruneHeights []exported.Height
pruneHeights = append(pruneHeights, path.EndpointA.GetClientState().GetLatestHeight())
}

// double chedck all information is currently stored
for _, pruneHeight := range pruneHeights {
consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight)
suite.Require().True(ok)
suite.Require().NotNil(consState)
// these heights will be expired and also pruned
for i := 0; i < 3; i++ {
path.EndpointA.UpdateClient()
pruneHeights = append(pruneHeights, path.EndpointA.GetClientState().GetLatestHeight())
}

ctx := path.EndpointA.Chain.GetContext()
clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID)
// double chedck all information is currently stored
for _, pruneHeight := range pruneHeights {
consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight)
suite.Require().True(ok)
suite.Require().NotNil(consState)

processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, pruneHeight)
suite.Require().True(ok)
suite.Require().NotNil(processedTime)
ctx := path.EndpointA.Chain.GetContext()
clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID)

processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, pruneHeight)
suite.Require().True(ok)
suite.Require().NotNil(processedHeight)
processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, pruneHeight)
suite.Require().True(ok)
suite.Require().NotNil(processedTime)

expectedConsKey := ibctmtypes.GetIterationKey(clientStore, pruneHeight)
suite.Require().NotNil(expectedConsKey)
processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, pruneHeight)
suite.Require().True(ok)
suite.Require().NotNil(processedHeight)

expectedConsKey := ibctmtypes.GetIterationKey(clientStore, pruneHeight)
suite.Require().NotNil(expectedConsKey)
}
pruneHeightMap[path] = pruneHeights
}

// Increment the time by a week
suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour)

// create the consensus state that can be used as trusted height for next update
path.EndpointA.UpdateClient()
for _, path := range []*ibctesting.Path{path1, path2} {
// create the consensus state that can be used as trusted height for next update
var unexpiredHeights []exported.Height
path.EndpointA.UpdateClient()
unexpiredHeights = append(unexpiredHeights, path.EndpointA.GetClientState().GetLatestHeight())
path.EndpointA.UpdateClient()
unexpiredHeights = append(unexpiredHeights, path.EndpointA.GetClientState().GetLatestHeight())

// 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))
}
Comment on lines +173 to +179
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


unexpiredHeightMap[path] = unexpiredHeights
}

// Increment the time by another week, then update the client.
// This will cause the consensus states created before the first time increment
// to be expired
suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour)
err := v100.MigrateStore(path.EndpointA.Chain.GetContext(), path.EndpointA.Chain.GetSimApp().GetKey(host.StoreKey), path.EndpointA.Chain.App.AppCodec())
err := v100.MigrateStore(path1.EndpointA.Chain.GetContext(), path1.EndpointA.Chain.GetSimApp().GetKey(host.StoreKey), path1.EndpointA.Chain.App.AppCodec())
suite.Require().NoError(err)

ctx := path.EndpointA.Chain.GetContext()
clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID)
for _, path := range []*ibctesting.Path{path1, path2} {
ctx := path.EndpointA.Chain.GetContext()
clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID)

// ensure everything has been pruned
for i, pruneHeight := range pruneHeights {
consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight)
suite.Require().False(ok, i)
suite.Require().Nil(consState, i)
// ensure everything has been pruned
for i, pruneHeight := range pruneHeightMap[path] {
consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight)
suite.Require().False(ok, i)
suite.Require().Nil(consState, i)

processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, pruneHeight)
suite.Require().False(ok, i)
suite.Require().Equal(uint64(0), processedTime, i)
processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, pruneHeight)
suite.Require().False(ok, i)
suite.Require().Equal(uint64(0), processedTime, i)

processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, pruneHeight)
suite.Require().False(ok, i)
suite.Require().Nil(processedHeight, i)
processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, pruneHeight)
suite.Require().False(ok, i)
suite.Require().Nil(processedHeight, i)

expectedConsKey := ibctmtypes.GetIterationKey(clientStore, pruneHeight)
suite.Require().Nil(expectedConsKey, i)
}
expectedConsKey := ibctmtypes.GetIterationKey(clientStore, pruneHeight)
suite.Require().Nil(expectedConsKey, i)
}

// ensure metadata is set for unexpired consensus state
height := path.EndpointA.GetClientState().GetLatestHeight()
consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, height)
suite.Require().True(ok)
suite.Require().NotNil(consState)
// ensure metadata is set for unexpired consensus state
for _, height := range unexpiredHeightMap[path] {
consState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, height)
suite.Require().True(ok)
suite.Require().NotNil(consState)

processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, height)
suite.Require().True(ok)
suite.Require().NotEqual(uint64(0), processedTime)
processedTime, ok := ibctmtypes.GetProcessedTime(clientStore, height)
suite.Require().True(ok)
suite.Require().NotEqual(uint64(0), processedTime)

processedHeight, ok := ibctmtypes.GetProcessedHeight(clientStore, height)
suite.Require().True(ok)
suite.Require().Equal(types.GetSelfHeight(path.EndpointA.Chain.GetContext()), processedHeight)
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)
suite.Require().Equal(host.ConsensusStateKey(height), consKey)
consKey := ibctmtypes.GetIterationKey(clientStore, height)
suite.Require().Equal(host.ConsensusStateKey(height), consKey)
}
}
}