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

UpgradeClient Followup #1 #7457

Merged
merged 19 commits into from
Oct 8, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
correctly escape and unescape merkle keys
  • Loading branch information
AdityaSripal committed Oct 7, 2020
commit 86e5d30c63a28af1d2530b620b19e4a0e7b965ca
5 changes: 4 additions & 1 deletion x/ibc/core/02-client/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"fmt"
"net/url"
"reflect"
"strings"

Expand Down Expand Up @@ -253,7 +254,9 @@ func (k Keeper) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientS

if tmClient.UpgradePath != "" {
// For now, SDK IBC implementation assumes that upgrade path (if defined) is defined by SDK upgrade module
expectedUpgradePath := fmt.Sprintf("%s/%s", upgradetypes.StoreKey, upgradetypes.KeyUpgradedClient)
// Must escape any merkle key before adding it to upgrade path
upgradeKey := url.PathEscape(upgradetypes.KeyUpgradedClient)
expectedUpgradePath := fmt.Sprintf("%s/%s", upgradetypes.StoreKey, upgradeKey)
if tmClient.UpgradePath != expectedUpgradePath {
return sdkerrors.Wrapf(types.ErrInvalidClient, "upgrade path must be the upgrade path defined by upgrade module. expected %s, got %s",
expectedUpgradePath, tmClient.UpgradePath)
Expand Down
3 changes: 1 addition & 2 deletions x/ibc/light-clients/07-tendermint/types/tendermint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
ibctestingmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)

const (
Expand All @@ -34,7 +33,7 @@ const (
var (
height = clienttypes.NewHeight(0, 4)
newClientHeight = clienttypes.NewHeight(1, 1)
upgradePath = fmt.Sprintf("%s/%s", "upgrade", upgradetypes.KeyUpgradedClient)
upgradePath = fmt.Sprintf("%s/%s", "upgrade", "upgradedClient")
)

type TendermintTestSuite struct {
Expand Down
17 changes: 13 additions & 4 deletions x/ibc/light-clients/07-tendermint/types/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"fmt"
"net/url"
"reflect"
"strings"

Expand Down Expand Up @@ -29,7 +30,10 @@ func (cs ClientState) VerifyUpgrade(
if cs.UpgradePath == "" {
return sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade client, no upgrade path set")
}
upgradePath := constructUpgradeMerklePath(cs.UpgradePath, upgradeHeight)
upgradePath, err := constructUpgradeMerklePath(cs.UpgradePath, upgradeHeight)
if err != nil {
return sdkerrors.Wrapf(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade client, unescaping key with URL format failed: %v", err)
}

// UpgradeHeight must be in same epoch as client state height
if cs.GetLatestHeight().GetEpochNumber() != upgradeHeight.GetEpochNumber() {
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -101,12 +105,17 @@ func (cs ClientState) VerifyUpgrade(
}

// construct MerklePath from upgradePath
func constructUpgradeMerklePath(upgradePath string, upgradeHeight exported.Height) commitmenttypes.MerklePath {
func constructUpgradeMerklePath(upgradePath string, upgradeHeight exported.Height) (commitmenttypes.MerklePath, error) {
// assume that all keys here are separated by `/` and
// any `/` within a merkle key is correctly escaped
upgradeKeys := strings.Split(upgradePath, "/")
// unescape the last key so that we can append `/{height}` to the last key
lastKey, err := url.PathUnescape(upgradeKeys[len(upgradeKeys)-1])
if err != nil {
return commitmenttypes.MerklePath{}, err
}
// append upgradeHeight to last key in merkle path
// this will create the IAVL key that is used to store client in upgrade store
upgradeKeys[len(upgradeKeys)-1] = fmt.Sprintf("%s/%d", upgradeKeys[len(upgradeKeys)-1], upgradeHeight.GetEpochHeight())
return commitmenttypes.NewMerklePath(upgradeKeys)
upgradeKeys[len(upgradeKeys)-1] = fmt.Sprintf("%s/%d", lastKey, upgradeHeight.GetEpochHeight())
return commitmenttypes.NewMerklePath(upgradeKeys), nil
}
40 changes: 35 additions & 5 deletions x/ibc/light-clients/07-tendermint/types/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
expPass: false,
},
{
name: "unsuccessful upgrade: upgrade path is nil",
name: "unsuccessful upgrade: upgrade path is empty",
setup: func() {

upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
Expand All @@ -206,13 +206,43 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {

proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetEpochHeight())), cs.GetLatestHeight().GetEpochHeight())

// SetClientState with nil upgrade path
// SetClientState with empty upgrade path
tmClient, _ := cs.(*types.ClientState)
tmClient.UpgradePath = ""
suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), clientA, tmClient)
},
expPass: false,
},
{
name: "unsuccessful upgrade: upgrade path is malformed and cannot be correctly unescaped",
setup: func() {

upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)

// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))

// zero custom fields and store in upgrade store
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetEpochHeight()), upgradedClient)

// commit upgrade store changes and update clients

suite.coordinator.CommitBlock(suite.chainB)
err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, ibctesting.Tendermint)
suite.Require().NoError(err)

cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)

proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetEpochHeight())), cs.GetLatestHeight().GetEpochHeight())

// SetClientState with nil upgrade path
tmClient, _ := cs.(*types.ClientState)
tmClient.UpgradePath = "upgraded%Client"
suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), clientA, tmClient)
},
expPass: false,
},
{
name: "unsuccessful upgrade: upgraded height is not greater than current height",
setup: func() {
Expand Down Expand Up @@ -267,9 +297,9 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
name: "unsuccessful upgrade: client is expired",
setup: func() {

upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), &upgradePath, false, false)
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, upgradeHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
// zero custom fields and store in upgrade store
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetEpochHeight()), upgradedClient)

// commit upgrade store changes and update clients

Expand All @@ -283,7 +313,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)

proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(), cs.GetLatestHeight().GetEpochHeight())
proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetEpochHeight())), cs.GetLatestHeight().GetEpochHeight())
},
expPass: false,
},
Expand Down
3 changes: 1 addition & 2 deletions x/ibc/testing/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import (
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
"github.com/cosmos/cosmos-sdk/x/ibc/testing/mock"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)

const (
Expand Down Expand Up @@ -71,7 +70,7 @@ var (
TestHash = tmhash.Sum([]byte("TESTING HASH"))
TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))

UpgradePath = fmt.Sprintf("%s/%s", "upgrade", upgradetypes.KeyUpgradedClient)
UpgradePath = fmt.Sprintf("%s/%s", "upgrade", "upgradedClient")

ConnectionVersion = connectiontypes.GetCompatibleEncodedVersions()[0]

Expand Down