Skip to content

Commit

Permalink
02-client routing: implement VerifyUpgradeAndUpdateState in light c…
Browse files Browse the repository at this point in the history
…lient modules (#5827)

* wip: implementation and tests for verify upgrade and update state function in light client modules

* add test case

* fix un-marshaling in tendermint light client module

* add tests for verify upgrade and update state of 08-wasm light client module

* fix linter warnings

* check client state post upgrade

* fix: encoding issue: unmarshal to concrete types and not interfaces in 07-tendermint

* fix import

* cast type before calling zero custom fields

* test: marshal concrete types using chain codec for upgrade tests which bypass msg server entrypoint

* chore: remove basic validation of lc types in tm VerifyUpgradeAndUpdateState

* marshal to concrete type in tests

* keep client/consensus state as interface marshalled

* Apply suggestions from code review

Co-authored-by: colin axnér <[email protected]>

* chore: make lint-fix

* chore: rm redundant test, tested in lightclient module

* fix: remove marshalling of anys to bytes for verify upgrade (#5967)

* fix: remove marshalling of anys to bytes for verify upgrade

* test: refactor 02-client tests for verify upgrade

* test: fix tests in 07-tenderint client module

* chore: rm backwards compatability notice and marshalling of anys in core msg server

* test: cleanup happy path assertions in 07-tendermint verify upgrade test

* nit: update inline code commentin test

* doc: update godoc of UpgradeClient handler in core ibc

* lint: make lint-fix

* nit: inline comments in tests last Height -> upgrade height

* fix: address 08-wasm upgrade client and tests

---------

Co-authored-by: Damian Nolan <[email protected]>
Co-authored-by: colin axnér <[email protected]>
  • Loading branch information
3 people authored Mar 12, 2024
1 parent 63ec69c commit b6d07a5
Show file tree
Hide file tree
Showing 17 changed files with 533 additions and 178 deletions.
38 changes: 16 additions & 22 deletions modules/core/02-client/keeper/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,48 +122,42 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte

// UpgradeClient upgrades the client to a new client state if this new client was committed to
// by the old client at the specified upgrade height
func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState,
upgradeClientProof, upgradeConsensusStateProof []byte,
func (k Keeper) UpgradeClient(
ctx sdk.Context,
clientID string,
upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof []byte,
) error {
clientState, found := k.GetClientState(ctx, clientID)
if !found {
return errorsmod.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID)
}

clientStore := k.ClientStore(ctx, clientID)

if status := k.GetClientStatus(ctx, clientID); status != exported.Active {
return errorsmod.Wrapf(types.ErrClientNotActive, "cannot upgrade client (%s) with status %s", clientID, status)
}

// TODO: This code is removed in https://github.com/cosmos/ibc-go/pull/5827
// last height of current counterparty chain must be client's latest height
// lastHeight := k.GetLatestHeight(ctx, clientID)
clientType, _, err := types.ParseClientIdentifier(clientID)
if err != nil {
return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", clientID)
}

// if !upgradedClient.GetLatestHeight().GT(lastHeight) {
// return errorsmod.Wrapf(ibcerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s",
// upgradedClient.GetLatestHeight(), lastHeight)
// }
clientModule, found := k.router.GetRoute(clientID)
if !found {
return errorsmod.Wrap(types.ErrRouteNotFound, clientID)
}

if err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, clientStore,
upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof,
); err != nil {
if err := clientModule.VerifyUpgradeAndUpdateState(ctx, clientID, upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof); err != nil {
return errorsmod.Wrapf(err, "cannot upgrade client with ID %s", clientID)
}

latestHeight := k.GetLatestHeight(ctx, clientID) // TODO: use clientModule when addressing this func in https://github.com/cosmos/ibc-go/pull/5827
latestHeight := clientModule.LatestHeight(ctx, clientID)
k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", latestHeight.String())

defer telemetry.IncrCounterWithLabels(
[]string{"ibc", "client", "upgrade"},
1,
[]metrics.Label{
telemetry.NewLabel(types.LabelClientType, upgradedClient.ClientType()),
telemetry.NewLabel(types.LabelClientType, clientType),
telemetry.NewLabel(types.LabelClientID, clientID),
},
)

emitUpgradeClientEvent(ctx, clientID, upgradedClient.ClientType(), latestHeight)
emitUpgradeClientEvent(ctx, clientID, clientType, latestHeight)

return nil
}
Expand Down
131 changes: 53 additions & 78 deletions modules/core/02-client/keeper/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

upgradetypes "cosmossdk.io/x/upgrade/types"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"

clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
Expand Down Expand Up @@ -321,9 +322,9 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
path *ibctesting.Path
upgradedClient *ibctm.ClientState
upgradedConsState exported.ConsensusState
lastHeight exported.Height
upgradeHeight exported.Height
upgradedClientAny, upgradedConsStateAny *codectypes.Any
upgradedClientProof, upgradedConsensusStateProof []byte
upgradedClientBz, upgradedConsStateBz []byte
)

testCases := []struct {
Expand All @@ -334,13 +335,13 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
{
name: "successful upgrade",
setup: func() {
// last Height is at next block
lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1))
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1))

// zero custom fields and store in upgrade store
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedClientAny))
suite.Require().NoError(err)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsStateAny))
suite.Require().NoError(err)

// commit upgrade store changes and update clients
Expand All @@ -353,21 +354,21 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
tmCs, ok := cs.(*ibctm.ClientState)
suite.Require().True(ok)

upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
},
expPass: true,
},
{
name: "client state not found",
setup: func() {
// last Height is at next block
lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1))
// upgrade height is at next block
upgradeHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1))

// zero custom fields and store in upgrade store
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedClientAny))
suite.Require().NoError(err)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsStateAny))
suite.Require().NoError(err)

// commit upgrade store changes and update clients
Expand All @@ -381,8 +382,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
tmCs, ok := cs.(*ibctm.ClientState)
suite.Require().True(ok)

upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())

path.EndpointA.ClientID = "wrongclientid"
},
Expand All @@ -393,17 +394,16 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
setup: func() {
// client is frozen

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

// zero custom fields and store in upgrade store
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedClientAny))
suite.Require().NoError(err)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsStateAny))
suite.Require().NoError(err)

// commit upgrade store changes and update clients

suite.coordinator.CommitBlock(suite.chainB)
err = path.EndpointA.UpdateClient()
suite.Require().NoError(err)
Expand All @@ -413,8 +413,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
tmCs, ok := cs.(*ibctm.ClientState)
suite.Require().True(ok)

upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())

// set frozen client in store
tmClient, ok := cs.(*ibctm.ClientState)
Expand All @@ -425,49 +425,22 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
expPass: false,
},
{
name: "tendermint client VerifyUpgrade fails",
name: "light client module VerifyUpgradeAndUpdateState fails",
setup: func() {
// last Height is at next block
lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1))
// upgrade height is at next block
upgradeHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1))

// zero custom fields and store in upgrade store
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedClientAny))
suite.Require().NoError(err)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsStateAny))
suite.Require().NoError(err)

// change upgradedClient client-specified parameters
upgradedClient.ChainId = "wrongchainID"

suite.coordinator.CommitBlock(suite.chainB)
err = path.EndpointA.UpdateClient()
upgradedClientAny, err = codectypes.NewAnyWithValue(upgradedClient)
suite.Require().NoError(err)

cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID)
suite.Require().True(found)
tmCs, ok := cs.(*ibctm.ClientState)
suite.Require().True(ok)

upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
},
expPass: false,
},
{
name: "unsuccessful upgrade: upgraded height is not greater than current height",
setup: func() {
// last Height is at next block
lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1))

// zero custom fields and store in upgrade store
err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
suite.Require().NoError(err)
err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
suite.Require().NoError(err)

// change upgradedClient height to be lower than current client state height
upgradedClient.LatestHeight = clienttypes.NewHeight(0, 1)

suite.coordinator.CommitBlock(suite.chainB)
err = path.EndpointA.UpdateClient()
suite.Require().NoError(err)
Expand All @@ -477,44 +450,46 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
tmCs, ok := cs.(*ibctm.ClientState)
suite.Require().True(ok)

upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight())
},
expPass: false,
},
}

for _, tc := range testCases {
tc := tc
path = ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetupClients()
suite.Run(tc.name, func() {
path = ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetupClients()

clientState := path.EndpointA.GetClientState().(*ibctm.ClientState)
revisionNumber := clienttypes.ParseChainID(clientState.ChainId)
clientState := path.EndpointA.GetClientState().(*ibctm.ClientState)
revisionNumber := clienttypes.ParseChainID(clientState.ChainId)

newChainID, err := clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1)
suite.Require().NoError(err)
newChainID, err := clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1)
suite.Require().NoError(err)

upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath)
upgradedClient = upgradedClient.ZeroCustomFields()
upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient)
suite.Require().NoError(err)
upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath)
upgradedClient = upgradedClient.ZeroCustomFields()

upgradedConsState = &ibctm.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
upgradedConsStateBz, err = clienttypes.MarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState)
suite.Require().NoError(err)
upgradedClientAny, err = codectypes.NewAnyWithValue(upgradedClient)
suite.Require().NoError(err)

upgradedConsState = &ibctm.ConsensusState{NextValidatorsHash: []byte("nextValsHash")}

upgradedConsStateAny, err = codectypes.NewAnyWithValue(upgradedConsState)
suite.Require().NoError(err)

tc.setup()
tc.setup()

err = suite.chainA.App.GetIBCKeeper().ClientKeeper.UpgradeClient(suite.chainA.GetContext(), path.EndpointA.ClientID, upgradedClient, upgradedConsState, upgradedClientProof, upgradedConsensusStateProof)
err = suite.chainA.App.GetIBCKeeper().ClientKeeper.UpgradeClient(suite.chainA.GetContext(), path.EndpointA.ClientID, upgradedClientAny.Value, upgradedConsStateAny.Value, upgradedClientProof, upgradedConsensusStateProof)

if tc.expPass {
suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name)
} else {
suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name)
}
if tc.expPass {
suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name)
} else {
suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name)
}
})
}
}

Expand Down
18 changes: 0 additions & 18 deletions modules/core/exported/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

storetypes "cosmossdk.io/store/types"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand Down Expand Up @@ -141,23 +140,6 @@ type ClientState interface {

ClientType() string
Validate() error

// Upgrade functions
// NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last
// height committed by the current revision. Clients are responsible for ensuring that the planned last
// height of the current revision is somehow encoded in the proof verification process.
// This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty
// may be cancelled or modified before the last planned height.
// If the upgrade is verified, the upgraded client and consensus states must be set in the client store.
VerifyUpgradeAndUpdateState(
ctx sdk.Context,
cdc codec.BinaryCodec,
store storetypes.KVStore,
newClient ClientState,
newConsState ConsensusState,
upgradeClientProof,
upgradeConsensusStateProof []byte,
) error
}

// ConsensusState is the state of the consensus process
Expand Down
23 changes: 12 additions & 11 deletions modules/core/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,21 @@ func (k Keeper) UpdateClient(goCtx context.Context, msg *clienttypes.MsgUpdateCl
}

// UpgradeClient defines a rpc handler method for MsgUpgradeClient.
// NOTE: The raw bytes of the conretes types encoded into protobuf.Any is passed to the client keeper.
// The 02-client handler will route to the appropriate light client module based on client identifier and it is the responsibility
// of the light client module to unmarshal and interpret the proto encoded bytes.
// Backwards compatibility with older versions of ibc-go is maintained through the light client module reconstructing and encoding
// the expected concrete type to the protobuf.Any for proof verification.
func (k Keeper) UpgradeClient(goCtx context.Context, msg *clienttypes.MsgUpgradeClient) (*clienttypes.MsgUpgradeClientResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

upgradedClient, err := clienttypes.UnpackClientState(msg.ClientState)
if err != nil {
return nil, err
}
upgradedConsState, err := clienttypes.UnpackConsensusState(msg.ConsensusState)
if err != nil {
return nil, err
}

if err = k.ClientKeeper.UpgradeClient(ctx, msg.ClientId, upgradedClient, upgradedConsState,
msg.ProofUpgradeClient, msg.ProofUpgradeConsensusState); err != nil {
if err := k.ClientKeeper.UpgradeClient(
ctx, msg.ClientId,
msg.ClientState.Value,
msg.ConsensusState.Value,
msg.ProofUpgradeClient,
msg.ProofUpgradeConsensusState,
); err != nil {
return nil, err
}

Expand Down
Loading

0 comments on commit b6d07a5

Please sign in to comment.