Add ConsensusState to IBC Upgrades (#7919)

* upgrade progress

* fix build minus cli

* write state at block before upgrade height

* refix build

* Apply suggestions from code review

Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>

* fix upgrade and start with tests

* fix tendermint tests

* add tests and remove unnecessary relayer options on upgradedClient

* fix all tests except weird msg panic

* add invalid final client test and codec stuff

* fix everything but msg issue

* remove problematic test for now

* safer self validation

* upgrade fixes

* proto-linting

* remove unnecessary last height

* add timestamp to committed upgrade consensus state

* address final nits

* address nit

Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
Aditya 2020-11-24 11:45:33 +00:00 committed by GitHub
parent 74435137e9
commit def3c5ba71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 2035 additions and 668 deletions

View File

@ -15760,6 +15760,396 @@ paths:
}
tags:
- Query
'/cosmos/upgrade/v1beta1/upgraded_consensus_state/{last_height}':
get:
summary: |-
UpgradedConsensusState queries the consensus state that will serve
as a trusted kernel for the next version of this chain. It will only be
stored at the last height of this chain.
UpgradedConsensusState RPC not supported with legacy querier
operationId: UpgradedConsensusState
responses:
'200':
description: A successful response.
schema:
type: object
properties:
upgraded_consensus_state:
type: object
properties:
type_url:
type: string
description: >-
A URL/resource name that uniquely identifies the type of
the serialized
protocol buffer message. This string must contain at least
one "/" character. The last segment of the URL's path must
represent
the fully qualified name of the type (as in
`path/google.protobuf.Duration`). The name should be in a
canonical form
(e.g., leading "." is not accepted).
In practice, teams usually precompile into the binary all
types that they
expect it to use in the context of Any. However, for URLs
which use the
scheme `http`, `https`, or no scheme, one can optionally
set up a type
server that maps type URLs to message definitions as
follows:
* If no scheme is provided, `https` is assumed.
* An HTTP GET on the URL must yield a
[google.protobuf.Type][]
value in binary format, or produce an error.
* Applications are allowed to cache lookup results based
on the
URL, or have them precompiled into a binary to avoid any
lookup. Therefore, binary compatibility needs to be preserved
on changes to types. (Use versioned type names to manage
breaking changes.)
Note: this functionality is not currently available in the
official
protobuf release, and it is not used for type URLs
beginning with
type.googleapis.com.
Schemes other than `http`, `https` (or the empty scheme)
might be
used with implementation specific semantics.
value:
type: string
format: byte
description: >-
Must be a valid serialized protocol buffer of the above
specified type.
description: >-
`Any` contains an arbitrary serialized protocol buffer message
along with a
URL that describes the type of the serialized message.
Protobuf library provides support to pack/unpack Any values in
the form
of utility functions or additional generated methods of the
Any type.
Example 1: Pack and unpack a message in C++.
Foo foo = ...;
Any any;
any.PackFrom(foo);
...
if (any.UnpackTo(&foo)) {
...
}
Example 2: Pack and unpack a message in Java.
Foo foo = ...;
Any any = Any.pack(foo);
...
if (any.is(Foo.class)) {
foo = any.unpack(Foo.class);
}
Example 3: Pack and unpack a message in Python.
foo = Foo(...)
any = Any()
any.Pack(foo)
...
if any.Is(Foo.DESCRIPTOR):
any.Unpack(foo)
...
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
...
}
The pack methods provided by protobuf library will by default
use
'type.googleapis.com/full.type.name' as the type URL and the
unpack
methods only use the fully qualified type name after the last
'/'
in the type URL, for example "foo.bar.com/x/y.z" will yield
type
name "y.z".
JSON
====
The JSON representation of an `Any` value uses the regular
representation of the deserialized, embedded message, with an
additional field `@type` which contains the type URL. Example:
package google.profile;
message Person {
string first_name = 1;
string last_name = 2;
}
{
"@type": "type.googleapis.com/google.profile.Person",
"firstName": <string>,
"lastName": <string>
}
If the embedded message type is well-known and has a custom
JSON
representation, that representation will be embedded adding a
field
`value` which holds the custom JSON in addition to the `@type`
field. Example (for message [google.protobuf.Duration][]):
{
"@type": "type.googleapis.com/google.protobuf.Duration",
"value": "1.212s"
}
description: >-
QueryUpgradedConsensusStateResponse is the response type for the
Query/UpgradedConsensusState
RPC method.
default:
description: An unexpected error response.
schema:
type: object
properties:
error:
type: string
code:
type: integer
format: int32
message:
type: string
details:
type: array
items:
type: object
properties:
type_url:
type: string
description: >-
A URL/resource name that uniquely identifies the type of
the serialized
protocol buffer message. This string must contain at
least
one "/" character. The last segment of the URL's path
must represent
the fully qualified name of the type (as in
`path/google.protobuf.Duration`). The name should be in
a canonical form
(e.g., leading "." is not accepted).
In practice, teams usually precompile into the binary
all types that they
expect it to use in the context of Any. However, for
URLs which use the
scheme `http`, `https`, or no scheme, one can optionally
set up a type
server that maps type URLs to message definitions as
follows:
* If no scheme is provided, `https` is assumed.
* An HTTP GET on the URL must yield a
[google.protobuf.Type][]
value in binary format, or produce an error.
* Applications are allowed to cache lookup results based
on the
URL, or have them precompiled into a binary to avoid any
lookup. Therefore, binary compatibility needs to be preserved
on changes to types. (Use versioned type names to manage
breaking changes.)
Note: this functionality is not currently available in
the official
protobuf release, and it is not used for type URLs
beginning with
type.googleapis.com.
Schemes other than `http`, `https` (or the empty scheme)
might be
used with implementation specific semantics.
value:
type: string
format: byte
description: >-
Must be a valid serialized protocol buffer of the above
specified type.
description: >-
`Any` contains an arbitrary serialized protocol buffer
message along with a
URL that describes the type of the serialized message.
Protobuf library provides support to pack/unpack Any values
in the form
of utility functions or additional generated methods of the
Any type.
Example 1: Pack and unpack a message in C++.
Foo foo = ...;
Any any;
any.PackFrom(foo);
...
if (any.UnpackTo(&foo)) {
...
}
Example 2: Pack and unpack a message in Java.
Foo foo = ...;
Any any = Any.pack(foo);
...
if (any.is(Foo.class)) {
foo = any.unpack(Foo.class);
}
Example 3: Pack and unpack a message in Python.
foo = Foo(...)
any = Any()
any.Pack(foo)
...
if any.Is(Foo.DESCRIPTOR):
any.Unpack(foo)
...
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
...
}
The pack methods provided by protobuf library will by
default use
'type.googleapis.com/full.type.name' as the type URL and the
unpack
methods only use the fully qualified type name after the
last '/'
in the type URL, for example "foo.bar.com/x/y.z" will yield
type
name "y.z".
JSON
====
The JSON representation of an `Any` value uses the regular
representation of the deserialized, embedded message, with
an
additional field `@type` which contains the type URL.
Example:
package google.profile;
message Person {
string first_name = 1;
string last_name = 2;
}
{
"@type": "type.googleapis.com/google.profile.Person",
"firstName": <string>,
"lastName": <string>
}
If the embedded message type is well-known and has a custom
JSON
representation, that representation will be embedded adding
a field
`value` which holds the custom JSON in addition to the
`@type`
field. Example (for message [google.protobuf.Duration][]):
{
"@type": "type.googleapis.com/google.protobuf.Duration",
"value": "1.212s"
}
parameters:
- name: last_height
description: |-
last height of the current chain must be sent in request
as this is the height under which next consensus state is stored
in: path
required: true
type: string
format: int64
tags:
- Query
/ibc/core/channel/v1beta1/channels:
get:
summary: Channels queries all the IBC channels of a chain.
@ -31438,6 +31828,173 @@ definitions:
RPC
method.
cosmos.upgrade.v1beta1.QueryUpgradedConsensusStateResponse:
type: object
properties:
upgraded_consensus_state:
type: object
properties:
type_url:
type: string
description: >-
A URL/resource name that uniquely identifies the type of the
serialized
protocol buffer message. This string must contain at least
one "/" character. The last segment of the URL's path must
represent
the fully qualified name of the type (as in
`path/google.protobuf.Duration`). The name should be in a
canonical form
(e.g., leading "." is not accepted).
In practice, teams usually precompile into the binary all types
that they
expect it to use in the context of Any. However, for URLs which
use the
scheme `http`, `https`, or no scheme, one can optionally set up a
type
server that maps type URLs to message definitions as follows:
* If no scheme is provided, `https` is assumed.
* An HTTP GET on the URL must yield a [google.protobuf.Type][]
value in binary format, or produce an error.
* Applications are allowed to cache lookup results based on the
URL, or have them precompiled into a binary to avoid any
lookup. Therefore, binary compatibility needs to be preserved
on changes to types. (Use versioned type names to manage
breaking changes.)
Note: this functionality is not currently available in the
official
protobuf release, and it is not used for type URLs beginning with
type.googleapis.com.
Schemes other than `http`, `https` (or the empty scheme) might be
used with implementation specific semantics.
value:
type: string
format: byte
description: >-
Must be a valid serialized protocol buffer of the above specified
type.
description: >-
`Any` contains an arbitrary serialized protocol buffer message along
with a
URL that describes the type of the serialized message.
Protobuf library provides support to pack/unpack Any values in the
form
of utility functions or additional generated methods of the Any type.
Example 1: Pack and unpack a message in C++.
Foo foo = ...;
Any any;
any.PackFrom(foo);
...
if (any.UnpackTo(&foo)) {
...
}
Example 2: Pack and unpack a message in Java.
Foo foo = ...;
Any any = Any.pack(foo);
...
if (any.is(Foo.class)) {
foo = any.unpack(Foo.class);
}
Example 3: Pack and unpack a message in Python.
foo = Foo(...)
any = Any()
any.Pack(foo)
...
if any.Is(Foo.DESCRIPTOR):
any.Unpack(foo)
...
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
...
}
The pack methods provided by protobuf library will by default use
'type.googleapis.com/full.type.name' as the type URL and the unpack
methods only use the fully qualified type name after the last '/'
in the type URL, for example "foo.bar.com/x/y.z" will yield type
name "y.z".
JSON
====
The JSON representation of an `Any` value uses the regular
representation of the deserialized, embedded message, with an
additional field `@type` which contains the type URL. Example:
package google.profile;
message Person {
string first_name = 1;
string last_name = 2;
}
{
"@type": "type.googleapis.com/google.profile.Person",
"firstName": <string>,
"lastName": <string>
}
If the embedded message type is well-known and has a custom JSON
representation, that representation will be embedded adding a field
`value` which holds the custom JSON in addition to the `@type`
field. Example (for message [google.protobuf.Duration][]):
{
"@type": "type.googleapis.com/google.protobuf.Duration",
"value": "1.212s"
}
description: >-
QueryUpgradedConsensusStateResponse is the response type for the
Query/UpgradedConsensusState
RPC method.
ibc.core.channel.v1.Channel:
type: object
properties:

View File

@ -1,6 +1,7 @@
syntax = "proto3";
package cosmos.upgrade.v1beta1;
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
import "cosmos/upgrade/v1beta1/upgrade.proto";
@ -17,6 +18,14 @@ service Query {
rpc AppliedPlan(QueryAppliedPlanRequest) returns (QueryAppliedPlanResponse) {
option (google.api.http).get = "/cosmos/upgrade/v1beta1/applied_plan/{name}";
}
// UpgradedConsensusState queries the consensus state that will serve
// as a trusted kernel for the next version of this chain. It will only be
// stored at the last height of this chain.
// UpgradedConsensusState RPC not supported with legacy querier
rpc UpgradedConsensusState(QueryUpgradedConsensusStateRequest) returns (QueryUpgradedConsensusStateResponse) {
option (google.api.http).get = "/cosmos/upgrade/v1beta1/upgraded_consensus_state/{last_height}";
}
}
// QueryCurrentPlanRequest is the request type for the Query/CurrentPlan RPC
@ -43,3 +52,17 @@ message QueryAppliedPlanResponse {
// height is the block height at which the plan was applied.
int64 height = 1;
}
// QueryUpgradedConsensusStateRequest is the request type for the Query/UpgradedConsensusState
// RPC method.
message QueryUpgradedConsensusStateRequest {
// last height of the current chain must be sent in request
// as this is the height under which next consensus state is stored
int64 last_height = 1;
}
// QueryUpgradedConsensusStateResponse is the response type for the Query/UpgradedConsensusState
// RPC method.
message QueryUpgradedConsensusStateResponse {
google.protobuf.Any upgraded_consensus_state = 1;
}

View File

@ -60,16 +60,21 @@ message MsgUpdateClientResponse {}
// MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client state
message MsgUpgradeClient {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// client unique identifier
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// upgraded client state
google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""];
// height at which old chain halts and upgrades (i.e last block executed)
Height upgrade_height = 3 [(gogoproto.moretags) = "yaml:\"upgrade_height\""];
// upgraded consensus state, only contains enough information to serve as a basis of trust in update logic
google.protobuf.Any consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""];
// proof that old chain committed to new client
bytes proof_upgrade = 4 [(gogoproto.moretags) = "yaml:\"proof_upgrade\""];
bytes proof_upgrade_client = 4 [(gogoproto.moretags) = "yaml:\"proof_upgrade_client\""];
// proof that old chain committed to new consensus state
bytes proof_upgrade_consensus_state = 5 [(gogoproto.moretags) = "yaml:\"proof_upgrade_consensus_state\""];
// signer address
string signer = 5;
string signer = 6;
}
// MsgUpgradeClientResponse defines the Msg/UpgradeClient response type.

View File

@ -42,8 +42,12 @@ message ClientState {
// Proof specifications used in verifying counterparty state
repeated ics23.ProofSpec proof_specs = 8 [(gogoproto.moretags) = "yaml:\"proof_specs\""];
// Path at which next upgraded client will be committed
string upgrade_path = 9 [(gogoproto.moretags) = "yaml:\"upgrade_path\""];
// Path at which next upgraded client will be committed.
// Each element corresponds to the key for a single CommitmentProof in the chained proof.
// NOTE: ClientState must stored under `{upgradePath}/{upgradeHeight}/clientState`
// ConsensusState must be stored under `{upgradepath}/{upgradeHeight}/consensusState`
// For SDK chains using the default upgrade module, upgrade_path should be []string{"upgrade", "upgradedIBCState"}`
repeated string upgrade_path = 9 [(gogoproto.moretags) = "yaml:\"upgrade_path\""];
// This flag, when set to true, will allow governance to recover a client
// which has expired

View File

@ -107,7 +107,8 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H
// 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, upgradeHeight exported.Height, proofUpgrade []byte) error {
func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState,
proofUpgradeClient, proofUpgradeConsState []byte) error {
clientState, found := k.GetClientState(ctx, clientID)
if !found {
return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID)
@ -118,13 +119,14 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e
return sdkerrors.Wrapf(types.ErrClientFrozen, "cannot update client with ID %s", clientID)
}
updatedClientState, updatedConsensusState, err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, k.ClientStore(ctx, clientID), upgradedClient, upgradeHeight, proofUpgrade)
updatedClientState, updatedConsState, err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, k.ClientStore(ctx, clientID),
upgradedClient, upgradedConsState, proofUpgradeClient, proofUpgradeConsState)
if err != nil {
return sdkerrors.Wrapf(err, "cannot upgrade client with ID %s", clientID)
}
k.SetClientState(ctx, clientID, updatedClientState)
k.SetClientConsensusState(ctx, clientID, updatedClientState.GetLatestHeight(), updatedConsensusState)
k.SetClientConsensusState(ctx, clientID, updatedClientState.GetLatestHeight(), updatedConsState)
k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", updatedClientState.GetLatestHeight().String())

View File

@ -235,10 +235,11 @@ func (suite *KeeperTestSuite) TestUpdateClientLocalhost() {
func (suite *KeeperTestSuite) TestUpgradeClient() {
var (
upgradedClient exported.ClientState
upgradeHeight exported.Height
clientA string
proofUpgrade []byte
upgradedClient exported.ClientState
upgradedConsState exported.ConsensusState
lastHeight exported.Height
clientA string
proofUpgradedClient, proofUpgradedConsState []byte
)
testCases := []struct {
@ -251,12 +252,16 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
setup: func() {
upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
upgradedConsState = &ibctmtypes.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
// last Height is at next block
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// commit upgrade store changes and update clients
@ -267,7 +272,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: true,
},
@ -276,12 +282,16 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
setup: func() {
upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
upgradedConsState = &ibctmtypes.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
// last Height is at next block
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// commit upgrade store changes and update clients
@ -292,7 +302,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
clientA = "wrongclientid"
},
@ -303,12 +314,16 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
setup: func() {
upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
upgradedConsState = &ibctmtypes.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
// last Height is at next block
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// commit upgrade store changes and update clients
@ -319,7 +334,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
// set frozen client in store
tmClient, ok := cs.(*ibctmtypes.ClientState)
@ -334,12 +350,16 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
setup: func() {
upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
upgradedConsState = &ibctmtypes.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
// last Height is at next block
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// change upgradedClient client-specified parameters
upgradedClient = ibctmtypes.NewClientState("wrongchainID", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, true, true)
@ -351,7 +371,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
@ -363,7 +384,10 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
tc.setup()
err := suite.chainA.App.IBCKeeper.ClientKeeper.UpgradeClient(suite.chainA.GetContext(), clientA, upgradedClient, upgradeHeight, proofUpgrade)
// Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient
upgradedClient = upgradedClient.ZeroCustomFields()
err := suite.chainA.App.IBCKeeper.ClientKeeper.UpgradeClient(suite.chainA.GetContext(), clientA, upgradedClient, upgradedConsState, proofUpgradedClient, proofUpgradedConsState)
if tc.expPass {
suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name)

View File

@ -2,7 +2,6 @@ package keeper
import (
"fmt"
"net/url"
"reflect"
"strings"
@ -246,13 +245,11 @@ func (k Keeper) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientS
tmClient.UnbondingPeriod, tmClient.TrustingPeriod)
}
if tmClient.UpgradePath != "" {
if len(tmClient.UpgradePath) != 0 {
// For now, SDK IBC implementation assumes that upgrade path (if defined) is defined by SDK upgrade module
// 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 := []string{upgradetypes.StoreKey, upgradetypes.KeyUpgradedIBCState}
if !reflect.DeepEqual(expectedUpgradePath, tmClient.UpgradePath) {
return sdkerrors.Wrapf(types.ErrInvalidClient, "upgrade path must be the upgrade path defined by upgrade module. expected %v, got %v",
expectedUpgradePath, tmClient.UpgradePath)
}
}

View File

@ -166,7 +166,7 @@ func (suite *KeeperTestSuite) TestValidateSelfClient() {
},
{
"success with nil UpgradePath",
ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), "", false, false),
ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), nil, false, false),
true,
},
{
@ -216,7 +216,7 @@ func (suite *KeeperTestSuite) TestValidateSelfClient() {
},
{
"invalid upgrade path",
ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), "bad/upgrade/path", false, false),
ibctmtypes.NewClientState(suite.chainA.ChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), []string{"bad", "upgrade", "path"}, false, false),
false,
},
}

View File

@ -37,6 +37,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
(*sdk.Msg)(nil),
&MsgCreateClient{},
&MsgUpdateClient{},
&MsgUpgradeClient{},
&MsgSubmitMisbehaviour{},
)

View File

@ -182,23 +182,24 @@ func (msg MsgUpdateClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) err
// NewMsgUpgradeClient creates a new MsgUpgradeClient instance
// nolint: interfacer
func NewMsgUpgradeClient(clientID string, clientState exported.ClientState, upgradeHeight exported.Height, proofUpgrade []byte, signer sdk.AccAddress) (*MsgUpgradeClient, error) {
func NewMsgUpgradeClient(clientID string, clientState exported.ClientState, consState exported.ConsensusState,
proofUpgradeClient, proofUpgradeConsState []byte, signer sdk.AccAddress) (*MsgUpgradeClient, error) {
anyClient, err := PackClientState(clientState)
if err != nil {
return nil, err
}
height, ok := upgradeHeight.(Height)
if !ok {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "invalid height type. expected: %T, got: %T", &Height{}, upgradeHeight)
anyConsState, err := PackConsensusState(consState)
if err != nil {
return nil, err
}
return &MsgUpgradeClient{
ClientId: clientID,
ClientState: anyClient,
ProofUpgrade: proofUpgrade,
UpgradeHeight: &height,
Signer: signer.String(),
ClientId: clientID,
ClientState: anyClient,
ConsensusState: anyConsState,
ProofUpgradeClient: proofUpgradeClient,
ProofUpgradeConsensusState: proofUpgradeConsState,
Signer: signer.String(),
}, nil
}
@ -214,21 +215,28 @@ func (msg MsgUpgradeClient) Type() string {
// ValidateBasic implements sdk.Msg
func (msg MsgUpgradeClient) ValidateBasic() error {
// will not validate client state as committed client may not form a valid client state.
// client implementations are responsible for ensuring final upgraded client is valid.
clientState, err := UnpackClientState(msg.ClientState)
if err != nil {
return err
}
if err := clientState.Validate(); err != nil {
// will not validate consensus state here since the trusted kernel may not form a valid consenus state.
// client implementations are responsible for ensuring client can submit new headers against this consensus state.
consensusState, err := UnpackConsensusState(msg.ConsensusState)
if err != nil {
return err
}
if len(msg.ProofUpgrade) == 0 {
return sdkerrors.Wrap(ErrInvalidUpgradeClient, "proof of upgrade cannot be empty")
if clientState.ClientType() != consensusState.ClientType() {
return sdkerrors.Wrapf(ErrInvalidUpgradeClient, "consensus state's client-type does not match client. expected: %s, got: %s",
clientState.ClientType(), consensusState.ClientType())
}
if msg.UpgradeHeight == nil {
return sdkerrors.Wrap(ErrInvalidUpgradeClient, "upgrade height cannot be nil")
if len(msg.ProofUpgradeClient) == 0 {
return sdkerrors.Wrap(ErrInvalidUpgradeClient, "proof of upgrade client cannot be empty")
}
if msg.UpgradeHeight.IsZero() {
return sdkerrors.Wrap(ErrInvalidUpgradeClient, "upgrade height cannot be zero")
if len(msg.ProofUpgradeConsensusState) == 0 {
return sdkerrors.Wrap(ErrInvalidUpgradeClient, "proof of upgrade consensus state cannot be empty")
}
_, err = sdk.AccAddressFromBech32(msg.Signer)
if err != nil {
@ -254,8 +262,14 @@ func (msg MsgUpgradeClient) GetSigners() []sdk.AccAddress {
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (msg MsgUpgradeClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
var clientState exported.ClientState
return unpacker.UnpackAny(msg.ClientState, &clientState)
var (
clientState exported.ClientState
consState exported.ConsensusState
)
if err := unpacker.UnpackAny(msg.ClientState, &clientState); err != nil {
return err
}
return unpacker.UnpackAny(msg.ConsensusState, &consState)
}
// NewMsgSubmitMisbehaviour creates a new MsgSubmitMisbehaviour instance.

View File

@ -339,8 +339,6 @@ func (suite *TypesTestSuite) TestMarshalMsgUpgradeClient() {
err error
)
newClientHeight := types.NewHeight(1, 1)
testCases := []struct {
name string
malleate func()
@ -349,7 +347,8 @@ func (suite *TypesTestSuite) TestMarshalMsgUpgradeClient() {
"client upgrades to new tendermint client",
func() {
tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
msg, err = types.NewMsgUpgradeClient("clientid", tendermintClient, newClientHeight, []byte("proofUpgrade"), suite.chainA.SenderAccount.GetAddress())
tendermintConsState := &ibctmtypes.ConsensusState{NextValidatorsHash: []byte("nextValsHash")}
msg, err = types.NewMsgUpgradeClient("clientid", tendermintClient, tendermintConsState, []byte("proofUpgradeClient"), []byte("proofUpgradeConsState"), suite.chainA.SenderAccount.GetAddress())
suite.Require().NoError(err)
},
},
@ -357,7 +356,7 @@ func (suite *TypesTestSuite) TestMarshalMsgUpgradeClient() {
"client upgrades to new solomachine client",
func() {
soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 1)
msg, err = types.NewMsgUpgradeClient("clientid", soloMachine.ClientState(), newClientHeight, []byte("proofUpgrade"), suite.chainA.SenderAccount.GetAddress())
msg, err = types.NewMsgUpgradeClient("clientid", soloMachine.ClientState(), soloMachine.ConsensusState(), []byte("proofUpgradeClient"), []byte("proofUpgradeConsState"), suite.chainA.SenderAccount.GetAddress())
suite.Require().NoError(err)
},
},
@ -381,8 +380,6 @@ func (suite *TypesTestSuite) TestMarshalMsgUpgradeClient() {
newMsg := &types.MsgUpgradeClient{}
err = cdc.UnmarshalJSON(bz, newMsg)
suite.Require().NoError(err)
suite.Require().True(proto.Equal(msg, newMsg))
})
}
}
@ -412,20 +409,6 @@ func (suite *TypesTestSuite) TestMsgUpgradeClient_ValidateBasic() {
},
expPass: false,
},
{
name: "upgrade height is nil",
malleate: func(msg *types.MsgUpgradeClient) {
msg.UpgradeHeight = nil
},
expPass: false,
},
{
name: "upgrade height is zero",
malleate: func(msg *types.MsgUpgradeClient) {
msg.UpgradeHeight = &types.Height{}
},
expPass: false,
},
{
name: "unpacking clientstate fails",
malleate: func(msg *types.MsgUpgradeClient) {
@ -434,19 +417,33 @@ func (suite *TypesTestSuite) TestMsgUpgradeClient_ValidateBasic() {
expPass: false,
},
{
name: "invalid client state",
name: "unpacking consensus state fails",
malleate: func(msg *types.MsgUpgradeClient) {
cs := &ibctmtypes.ClientState{}
var err error
msg.ClientState, err = types.PackClientState(cs)
suite.Require().NoError(err)
msg.ConsensusState = nil
},
expPass: false,
},
{
name: "empty proof",
name: "client and consensus type does not match",
malleate: func(msg *types.MsgUpgradeClient) {
msg.ProofUpgrade = nil
soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2)
soloConsensus, err := types.PackConsensusState(soloMachine.ConsensusState())
suite.Require().NoError(err)
msg.ConsensusState = soloConsensus
},
expPass: false,
},
{
name: "empty client proof",
malleate: func(msg *types.MsgUpgradeClient) {
msg.ProofUpgradeClient = nil
},
expPass: false,
},
{
name: "empty consensus state proof",
malleate: func(msg *types.MsgUpgradeClient) {
msg.ProofUpgradeConsensusState = nil
},
expPass: false,
},
@ -463,18 +460,18 @@ func (suite *TypesTestSuite) TestMsgUpgradeClient_ValidateBasic() {
tc := tc
clientState := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
newClientHeight := types.NewHeight(1, 1)
msg, _ := types.NewMsgUpgradeClient("testclientid", clientState, newClientHeight, []byte("proofUpgrade"), suite.chainA.SenderAccount.GetAddress())
consState := &ibctmtypes.ConsensusState{NextValidatorsHash: []byte("nextValsHash")}
msg, err := types.NewMsgUpgradeClient("testclientid", clientState, consState, []byte("proofUpgradeClient"), []byte("proofUpgradeConsState"), suite.chainA.SenderAccount.GetAddress())
suite.Require().NoError(err)
tc.malleate(msg)
err := msg.ValidateBasic()
err = msg.ValidateBasic()
if tc.expPass {
suite.Require().NoError(err, "valid case %s failed", tc.name)
} else {
suite.Require().Error(err, "invalid case %s passed", tc.name)
}
}
}
// tests that different misbehaviours within MsgSubmitMisbehaviour can be marshaled

View File

@ -199,12 +199,14 @@ type MsgUpgradeClient struct {
ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"`
// upgraded client state
ClientState *types.Any `protobuf:"bytes,2,opt,name=client_state,json=clientState,proto3" json:"client_state,omitempty" yaml:"client_state"`
// height at which old chain halts and upgrades (i.e last block executed)
UpgradeHeight *Height `protobuf:"bytes,3,opt,name=upgrade_height,json=upgradeHeight,proto3" json:"upgrade_height,omitempty" yaml:"upgrade_height"`
// upgraded consensus state, only contains enough information to serve as a basis of trust in update logic
ConsensusState *types.Any `protobuf:"bytes,3,opt,name=consensus_state,json=consensusState,proto3" json:"consensus_state,omitempty" yaml:"consensus_state"`
// proof that old chain committed to new client
ProofUpgrade []byte `protobuf:"bytes,4,opt,name=proof_upgrade,json=proofUpgrade,proto3" json:"proof_upgrade,omitempty" yaml:"proof_upgrade"`
ProofUpgradeClient []byte `protobuf:"bytes,4,opt,name=proof_upgrade_client,json=proofUpgradeClient,proto3" json:"proof_upgrade_client,omitempty" yaml:"proof_upgrade_client"`
// proof that old chain committed to new consensus state
ProofUpgradeConsensusState []byte `protobuf:"bytes,5,opt,name=proof_upgrade_consensus_state,json=proofUpgradeConsensusState,proto3" json:"proof_upgrade_consensus_state,omitempty" yaml:"proof_upgrade_consensus_state"`
// signer address
Signer string `protobuf:"bytes,5,opt,name=signer,proto3" json:"signer,omitempty"`
Signer string `protobuf:"bytes,6,opt,name=signer,proto3" json:"signer,omitempty"`
}
func (m *MsgUpgradeClient) Reset() { *m = MsgUpgradeClient{} }
@ -240,41 +242,6 @@ func (m *MsgUpgradeClient) XXX_DiscardUnknown() {
var xxx_messageInfo_MsgUpgradeClient proto.InternalMessageInfo
func (m *MsgUpgradeClient) GetClientId() string {
if m != nil {
return m.ClientId
}
return ""
}
func (m *MsgUpgradeClient) GetClientState() *types.Any {
if m != nil {
return m.ClientState
}
return nil
}
func (m *MsgUpgradeClient) GetUpgradeHeight() *Height {
if m != nil {
return m.UpgradeHeight
}
return nil
}
func (m *MsgUpgradeClient) GetProofUpgrade() []byte {
if m != nil {
return m.ProofUpgrade
}
return nil
}
func (m *MsgUpgradeClient) GetSigner() string {
if m != nil {
return m.Signer
}
return ""
}
// MsgUpgradeClientResponse defines the Msg/UpgradeClient response type.
type MsgUpgradeClientResponse struct {
}
@ -407,45 +374,45 @@ func init() {
func init() { proto.RegisterFile("ibc/core/client/v1/tx.proto", fileDescriptor_cb5dc4651eb49a04) }
var fileDescriptor_cb5dc4651eb49a04 = []byte{
// 608 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0x3f, 0x6f, 0xd3, 0x40,
0x14, 0x8f, 0x1b, 0x88, 0xda, 0x6b, 0xd2, 0x56, 0x26, 0x6d, 0x13, 0x23, 0xec, 0xca, 0x30, 0x14,
0xd1, 0xda, 0x24, 0x0c, 0xa0, 0x4a, 0x0c, 0xa4, 0x0b, 0x0c, 0x91, 0xc0, 0x15, 0x03, 0x08, 0x29,
0xf8, 0xcf, 0xf5, 0x62, 0x91, 0xf8, 0x22, 0xdf, 0x39, 0x6a, 0xbe, 0x01, 0x23, 0x12, 0x7c, 0x80,
0x8a, 0x81, 0xcf, 0xc2, 0xc0, 0xd0, 0x91, 0x29, 0x42, 0xc9, 0xc2, 0x9c, 0x4f, 0x80, 0x7c, 0x77,
0xb1, 0xec, 0x34, 0x89, 0x22, 0x58, 0x98, 0xe2, 0x77, 0xef, 0xf7, 0x7e, 0xef, 0xe7, 0xdf, 0x7b,
0x17, 0x83, 0xdb, 0xbe, 0xe3, 0x9a, 0x2e, 0x0e, 0xa1, 0xe9, 0x76, 0x7c, 0x18, 0x50, 0xb3, 0x5f,
0x33, 0xe9, 0x85, 0xd1, 0x0b, 0x31, 0xc5, 0xb2, 0xec, 0x3b, 0xae, 0x11, 0x27, 0x0d, 0x9e, 0x34,
0xfa, 0x35, 0xa5, 0x8c, 0x30, 0xc2, 0x2c, 0x6d, 0xc6, 0x4f, 0x1c, 0xa9, 0x54, 0x11, 0xc6, 0xa8,
0x03, 0x4d, 0x16, 0x39, 0xd1, 0xb9, 0x69, 0x07, 0x03, 0x91, 0xd2, 0xe6, 0x74, 0x10, 0x74, 0x0c,
0xa0, 0x7f, 0x5e, 0x03, 0xdb, 0x4d, 0x82, 0x4e, 0x43, 0x68, 0x53, 0x78, 0xca, 0x32, 0x72, 0x0d,
0x6c, 0x70, 0x4c, 0xcb, 0xf7, 0x2a, 0xd2, 0x81, 0x74, 0xb8, 0xd1, 0x28, 0x4f, 0x86, 0xda, 0xce,
0xc0, 0xee, 0x76, 0x4e, 0xf4, 0x24, 0xa5, 0x5b, 0xeb, 0xfc, 0xf9, 0x85, 0x27, 0xbf, 0x04, 0x45,
0x71, 0x4e, 0xa8, 0x4d, 0x61, 0x65, 0xed, 0x40, 0x3a, 0xdc, 0xac, 0x97, 0x0d, 0xae, 0xcc, 0x98,
0x2a, 0x33, 0x9e, 0x05, 0x83, 0xc6, 0xfe, 0x64, 0xa8, 0xdd, 0xca, 0x70, 0xb1, 0x1a, 0xdd, 0xda,
0xe4, 0xe1, 0x59, 0x1c, 0xc9, 0x6f, 0xc0, 0xb6, 0x8b, 0x03, 0x02, 0x03, 0x12, 0x11, 0x41, 0x9a,
0x5f, 0x42, 0xaa, 0x4c, 0x86, 0xda, 0x9e, 0x20, 0xcd, 0x96, 0xe9, 0xd6, 0x56, 0x72, 0xc2, 0xa9,
0xf7, 0x40, 0x81, 0xf8, 0x28, 0x80, 0x61, 0xe5, 0x46, 0xfc, 0x72, 0x96, 0x88, 0x4e, 0xd6, 0x3f,
0x5e, 0x6a, 0xb9, 0xdf, 0x97, 0x5a, 0x4e, 0xaf, 0x82, 0xfd, 0x19, 0x53, 0x2c, 0x48, 0x7a, 0x31,
0x8b, 0xfe, 0x45, 0x62, 0x86, 0xbd, 0xee, 0x79, 0xff, 0x64, 0xd8, 0x11, 0x28, 0xb4, 0xa1, 0xed,
0xc1, 0x70, 0x99, 0x55, 0x96, 0xc0, 0xa4, 0x14, 0xe7, 0x97, 0x2a, 0x4e, 0xab, 0x4a, 0x14, 0xff,
0x58, 0x03, 0x3b, 0x2c, 0x87, 0x42, 0xdb, 0xfb, 0xaf, 0x66, 0xfc, 0x0e, 0x6c, 0x45, 0x5c, 0x55,
0xab, 0x0d, 0x7d, 0xd4, 0xa6, 0x62, 0xc4, 0x8a, 0x71, 0x7d, 0xf7, 0x8d, 0xe7, 0x0c, 0xd1, 0xa8,
0x4e, 0x86, 0xda, 0x2e, 0x67, 0xce, 0xd6, 0xea, 0x56, 0x49, 0x1c, 0x70, 0xa4, 0xfc, 0x14, 0x94,
0x7a, 0x21, 0xc6, 0xe7, 0x2d, 0x71, 0xcc, 0xa6, 0x5d, 0x6c, 0x54, 0x26, 0x43, 0xad, 0xcc, 0x09,
0x32, 0x69, 0xdd, 0x2a, 0xb2, 0x58, 0xf8, 0x94, 0xf2, 0xfc, 0x66, 0xda, 0x73, 0x5d, 0x01, 0x95,
0x59, 0x37, 0x13, 0xab, 0xbf, 0x49, 0x60, 0xb7, 0x49, 0xd0, 0x59, 0xe4, 0x74, 0x7d, 0xda, 0xf4,
0x89, 0x03, 0xdb, 0x76, 0xdf, 0xc7, 0x51, 0xf8, 0x37, 0x7e, 0x3f, 0x01, 0xc5, 0x6e, 0x8a, 0x62,
0xe9, 0xa2, 0x64, 0x90, 0x2b, 0xac, 0x8b, 0x06, 0xee, 0xcc, 0xd5, 0x39, 0x7d, 0x93, 0xfa, 0xd7,
0x3c, 0xc8, 0x37, 0x09, 0x92, 0xdf, 0x83, 0x62, 0xe6, 0xbf, 0xe1, 0xee, 0xbc, 0xd1, 0xcc, 0xdc,
0x15, 0xe5, 0xc1, 0x0a, 0xa0, 0x69, 0xa7, 0xb8, 0x43, 0xe6, 0x32, 0x2d, 0xea, 0x90, 0x06, 0x2d,
0xec, 0x30, 0xef, 0x02, 0xc8, 0x2e, 0x28, 0x65, 0x97, 0xff, 0xde, 0xc2, 0xea, 0x14, 0x4a, 0x39,
0x5a, 0x05, 0x95, 0x34, 0x09, 0x81, 0x3c, 0x67, 0xec, 0xf7, 0x17, 0x70, 0x5c, 0x87, 0x2a, 0xb5,
0x95, 0xa1, 0xd3, 0x9e, 0x8d, 0x57, 0xdf, 0x47, 0xaa, 0x74, 0x35, 0x52, 0xa5, 0x5f, 0x23, 0x55,
0xfa, 0x34, 0x56, 0x73, 0x57, 0x63, 0x35, 0xf7, 0x73, 0xac, 0xe6, 0xde, 0x3e, 0x46, 0x3e, 0x6d,
0x47, 0x8e, 0xe1, 0xe2, 0xae, 0xe9, 0x62, 0xd2, 0xc5, 0x44, 0xfc, 0x1c, 0x13, 0xef, 0x83, 0x79,
0x61, 0x26, 0x9f, 0x85, 0x87, 0xf5, 0x63, 0xf1, 0x65, 0xa0, 0x83, 0x1e, 0x24, 0x4e, 0x81, 0xad,
0xd5, 0xa3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb1, 0x03, 0x55, 0x1e, 0x9b, 0x06, 0x00, 0x00,
// 598 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x55, 0x3f, 0x6f, 0xd3, 0x4e,
0x18, 0x8e, 0x9b, 0xdf, 0x2f, 0x6a, 0xaf, 0x81, 0x56, 0x26, 0xb4, 0xa9, 0xab, 0xda, 0x95, 0xe9,
0x10, 0x44, 0xeb, 0x23, 0x61, 0x00, 0x75, 0x23, 0x9d, 0x18, 0x22, 0x51, 0x57, 0x0c, 0xb0, 0x04,
0xff, 0xb9, 0x5e, 0xac, 0x26, 0xbe, 0xc8, 0x67, 0x47, 0xcd, 0x37, 0x60, 0x44, 0x82, 0x0f, 0x50,
0x31, 0xf0, 0x59, 0x18, 0x3b, 0x30, 0x30, 0x45, 0x28, 0x59, 0x98, 0xf3, 0x09, 0x90, 0xef, 0x1c,
0xcb, 0x76, 0xed, 0x28, 0x82, 0x91, 0xc9, 0x7e, 0xef, 0x7d, 0xee, 0x79, 0x9e, 0x7b, 0xdf, 0xf7,
0x6c, 0xb0, 0xef, 0x98, 0x16, 0xb4, 0x88, 0x87, 0xa0, 0xd5, 0x77, 0x90, 0xeb, 0xc3, 0x51, 0x13,
0xfa, 0xd7, 0xda, 0xd0, 0x23, 0x3e, 0x11, 0x45, 0xc7, 0xb4, 0xb4, 0x30, 0xa9, 0xf1, 0xa4, 0x36,
0x6a, 0x4a, 0x35, 0x4c, 0x30, 0x61, 0x69, 0x18, 0xbe, 0x71, 0xa4, 0xb4, 0x87, 0x09, 0xc1, 0x7d,
0x04, 0x59, 0x64, 0x06, 0x97, 0xd0, 0x70, 0xc7, 0x51, 0x4a, 0xc9, 0x51, 0x88, 0xe8, 0x18, 0x40,
0xfd, 0xb4, 0x06, 0xb6, 0x3a, 0x14, 0x9f, 0x79, 0xc8, 0xf0, 0xd1, 0x19, 0xcb, 0x88, 0x4d, 0xb0,
0xc1, 0x31, 0x5d, 0xc7, 0xae, 0x0b, 0x87, 0x42, 0x63, 0xa3, 0x5d, 0x9b, 0x4f, 0x94, 0xed, 0xb1,
0x31, 0xe8, 0x9f, 0xaa, 0x71, 0x4a, 0xd5, 0xd7, 0xf9, 0xfb, 0x2b, 0x5b, 0x7c, 0x0d, 0xaa, 0xd1,
0x3a, 0xf5, 0x0d, 0x1f, 0xd5, 0xd7, 0x0e, 0x85, 0xc6, 0x66, 0xab, 0xa6, 0x71, 0x67, 0xda, 0xc2,
0x99, 0xf6, 0xd2, 0x1d, 0xb7, 0x77, 0xe7, 0x13, 0xe5, 0x41, 0x8a, 0x8b, 0xed, 0x51, 0xf5, 0x4d,
0x1e, 0x5e, 0x84, 0x91, 0xf8, 0x16, 0x6c, 0x59, 0xc4, 0xa5, 0xc8, 0xa5, 0x01, 0x8d, 0x48, 0xcb,
0x4b, 0x48, 0xa5, 0xf9, 0x44, 0xd9, 0x89, 0x48, 0xd3, 0xdb, 0x54, 0xfd, 0x7e, 0xbc, 0xc2, 0xa9,
0x77, 0x40, 0x85, 0x3a, 0xd8, 0x45, 0x5e, 0xfd, 0xbf, 0xf0, 0x70, 0x7a, 0x14, 0x9d, 0xae, 0x7f,
0xb8, 0x51, 0x4a, 0xbf, 0x6e, 0x94, 0x92, 0xba, 0x07, 0x76, 0x33, 0x45, 0xd1, 0x11, 0x1d, 0x86,
0x2c, 0xea, 0x67, 0x81, 0x15, 0xec, 0xcd, 0xd0, 0xfe, 0xab, 0x82, 0x1d, 0x83, 0x4a, 0x0f, 0x19,
0x36, 0xf2, 0x96, 0x95, 0x4a, 0x8f, 0x30, 0x09, 0xc7, 0xe5, 0xa5, 0x8e, 0x93, 0xae, 0x62, 0xc7,
0xdf, 0xcb, 0x60, 0x9b, 0xe5, 0xb0, 0x67, 0xd8, 0xff, 0x4a, 0x8f, 0xcf, 0x41, 0x6d, 0xe8, 0x11,
0x72, 0xd9, 0x0d, 0xf8, 0xb1, 0xbb, 0x5c, 0x97, 0x75, 0xbc, 0xda, 0x56, 0xe6, 0x13, 0x65, 0x9f,
0x33, 0xe5, 0xa1, 0x54, 0x5d, 0x64, 0xcb, 0xe9, 0x92, 0x5d, 0x81, 0x83, 0x0c, 0x38, 0xe3, 0xfd,
0x7f, 0xc6, 0xdd, 0x98, 0x4f, 0x94, 0xa3, 0x5c, 0xee, 0xac, 0x67, 0x29, 0x25, 0x52, 0x34, 0xa3,
0x95, 0x82, 0x8e, 0x4b, 0xa0, 0x9e, 0xed, 0x6a, 0xdc, 0xf2, 0xaf, 0x02, 0x78, 0xd8, 0xa1, 0xf8,
0x22, 0x30, 0x07, 0x8e, 0xdf, 0x71, 0xa8, 0x89, 0x7a, 0xc6, 0xc8, 0x21, 0x81, 0xf7, 0x27, 0x7d,
0x7f, 0x01, 0xaa, 0x83, 0x04, 0xc5, 0xd2, 0x81, 0x4d, 0x21, 0x57, 0x18, 0x5b, 0x05, 0x1c, 0xe4,
0xfa, 0x5c, 0x9c, 0xa4, 0xf5, 0xa5, 0x0c, 0xca, 0x1d, 0x8a, 0xc5, 0xf7, 0xa0, 0x9a, 0xfa, 0x46,
0x3d, 0xd2, 0xee, 0x7e, 0x1e, 0xb5, 0xcc, 0x9d, 0x95, 0x9e, 0xac, 0x00, 0x5a, 0x28, 0x85, 0x0a,
0xa9, 0x4b, 0x5d, 0xa4, 0x90, 0x04, 0x15, 0x2a, 0xe4, 0x5d, 0x44, 0xd1, 0x02, 0xf7, 0xd2, 0x13,
0x75, 0x54, 0xb8, 0x3b, 0x81, 0x92, 0x8e, 0x57, 0x41, 0xc5, 0x22, 0x1e, 0x10, 0x73, 0xda, 0xfe,
0xb8, 0x80, 0xe3, 0x2e, 0x54, 0x6a, 0xae, 0x0c, 0x5d, 0x68, 0xb6, 0xcf, 0xbf, 0x4d, 0x65, 0xe1,
0x76, 0x2a, 0x0b, 0x3f, 0xa7, 0xb2, 0xf0, 0x71, 0x26, 0x97, 0x6e, 0x67, 0x72, 0xe9, 0xc7, 0x4c,
0x2e, 0xbd, 0x7b, 0x8e, 0x1d, 0xbf, 0x17, 0x98, 0x9a, 0x45, 0x06, 0xd0, 0x22, 0x74, 0x40, 0x68,
0xf4, 0x38, 0xa1, 0xf6, 0x15, 0xbc, 0x86, 0xf1, 0xef, 0xe9, 0x69, 0xeb, 0x24, 0xfa, 0x43, 0xf9,
0xe3, 0x21, 0xa2, 0x66, 0x85, 0x8d, 0xd5, 0xb3, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x19,
0x59, 0x52, 0x23, 0x07, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -825,18 +792,25 @@ func (m *MsgUpgradeClient) MarshalToSizedBuffer(dAtA []byte) (int, error) {
copy(dAtA[i:], m.Signer)
i = encodeVarintTx(dAtA, i, uint64(len(m.Signer)))
i--
dAtA[i] = 0x32
}
if len(m.ProofUpgradeConsensusState) > 0 {
i -= len(m.ProofUpgradeConsensusState)
copy(dAtA[i:], m.ProofUpgradeConsensusState)
i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUpgradeConsensusState)))
i--
dAtA[i] = 0x2a
}
if len(m.ProofUpgrade) > 0 {
i -= len(m.ProofUpgrade)
copy(dAtA[i:], m.ProofUpgrade)
i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUpgrade)))
if len(m.ProofUpgradeClient) > 0 {
i -= len(m.ProofUpgradeClient)
copy(dAtA[i:], m.ProofUpgradeClient)
i = encodeVarintTx(dAtA, i, uint64(len(m.ProofUpgradeClient)))
i--
dAtA[i] = 0x22
}
if m.UpgradeHeight != nil {
if m.ConsensusState != nil {
{
size, err := m.UpgradeHeight.MarshalToSizedBuffer(dAtA[:i])
size, err := m.ConsensusState.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
@ -1052,11 +1026,15 @@ func (m *MsgUpgradeClient) Size() (n int) {
l = m.ClientState.Size()
n += 1 + l + sovTx(uint64(l))
}
if m.UpgradeHeight != nil {
l = m.UpgradeHeight.Size()
if m.ConsensusState != nil {
l = m.ConsensusState.Size()
n += 1 + l + sovTx(uint64(l))
}
l = len(m.ProofUpgrade)
l = len(m.ProofUpgradeClient)
if l > 0 {
n += 1 + l + sovTx(uint64(l))
}
l = len(m.ProofUpgradeConsensusState)
if l > 0 {
n += 1 + l + sovTx(uint64(l))
}
@ -1659,7 +1637,7 @@ func (m *MsgUpgradeClient) Unmarshal(dAtA []byte) error {
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field UpgradeHeight", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field ConsensusState", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
@ -1686,16 +1664,16 @@ func (m *MsgUpgradeClient) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.UpgradeHeight == nil {
m.UpgradeHeight = &Height{}
if m.ConsensusState == nil {
m.ConsensusState = &types.Any{}
}
if err := m.UpgradeHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
if err := m.ConsensusState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ProofUpgrade", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field ProofUpgradeClient", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
@ -1722,12 +1700,46 @@ func (m *MsgUpgradeClient) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ProofUpgrade = append(m.ProofUpgrade[:0], dAtA[iNdEx:postIndex]...)
if m.ProofUpgrade == nil {
m.ProofUpgrade = []byte{}
m.ProofUpgradeClient = append(m.ProofUpgradeClient[:0], dAtA[iNdEx:postIndex]...)
if m.ProofUpgradeClient == nil {
m.ProofUpgradeClient = []byte{}
}
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ProofUpgradeConsensusState", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ProofUpgradeConsensusState = append(m.ProofUpgradeConsensusState[:0], dAtA[iNdEx:postIndex]...)
if m.ProofUpgradeConsensusState == nil {
m.ProofUpgradeConsensusState = []byte{}
}
iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType)
}

View File

@ -39,13 +39,19 @@ type ClientState interface {
CheckProposedHeaderAndUpdateState(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, Header) (ClientState, ConsensusState, error)
// Upgrade functions
// NOTE: proof heights are not included as upgrade to a new version is expected to pass only on the last
// height committed by the current version. Clients are responsible for ensuring that the planned last
// height of the current version 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.
VerifyUpgradeAndUpdateState(
ctx sdk.Context,
cdc codec.BinaryMarshaler,
store sdk.KVStore,
newClient ClientState,
upgradeHeight Height,
proofUpgrade []byte,
newConsState ConsensusState,
proofUpgradeClient,
proofUpgradeConsState []byte,
) (ClientState, ConsensusState, error)
// Utility function that zeroes out any client customizable fields in client state
// Ledger enforced fields are maintained while all custom fields are zero values

View File

@ -83,8 +83,13 @@ func (k Keeper) UpgradeClient(goCtx context.Context, msg *clienttypes.MsgUpgrade
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, msg.UpgradeHeight, msg.ProofUpgrade); err != nil {
if err = k.ClientKeeper.UpgradeClient(ctx, msg.ClientId, upgradedClient, upgradedConsState,
msg.ProofUpgradeClient, msg.ProofUpgradeConsensusState); err != nil {
return nil, err
}

View File

@ -2,7 +2,6 @@ package keeper_test
import (
"testing"
"time"
"github.com/stretchr/testify/suite"
@ -611,10 +610,11 @@ func (suite *KeeperTestSuite) TestHandleTimeoutOnClosePacket() {
func (suite *KeeperTestSuite) TestUpgradeClient() {
var (
clientA string
upgradedClient exported.ClientState
upgradeHeight exported.Height
msg *clienttypes.MsgUpgradeClient
clientA string
upgradedClient exported.ClientState
upgradedConsState exported.ConsensusState
lastHeight exported.Height
msg *clienttypes.MsgUpgradeClient
)
newClientHeight := clienttypes.NewHeight(1, 1)
@ -628,13 +628,20 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
name: "successful upgrade",
setup: func() {
upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
// Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient
upgradedClient = upgradedClient.ZeroCustomFields()
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
upgradedConsState = &ibctmtypes.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// last Height is at next block
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// commit upgrade store changes and update clients
@ -645,46 +652,33 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgrade, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradeClient, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, upgradeHeight, proofUpgrade, suite.chainA.SenderAccount.GetAddress())
msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, upgradedConsState,
proofUpgradeClient, proofUpgradedConsState, suite.chainA.SenderAccount.GetAddress())
suite.Require().NoError(err)
},
expPass: true,
},
{
name: "invalid upgrade: msg.ClientState does not contain valid clientstate",
setup: func() {
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
proofUpgrade, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
consState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("app_hash")), []byte("next_vals_hash"))
consAny, err := clienttypes.PackConsensusState(consState)
suite.Require().NoError(err)
height, _ := upgradeHeight.(clienttypes.Height)
msg = &clienttypes.MsgUpgradeClient{ClientId: clientA, ClientState: consAny, UpgradeHeight: &height, ProofUpgrade: proofUpgrade, Signer: suite.chainA.SenderAccount.GetAddress().String()}
},
expPass: false,
},
{
name: "VerifyUpgrade fails",
setup: func() {
upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
upgradedClient = ibctmtypes.NewClientState("newChainId", ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
// Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient
upgradedClient = upgradedClient.ZeroCustomFields()
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
upgradedConsState = &ibctmtypes.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// last Height is at next block
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// commit upgrade store changes and update clients
@ -692,7 +686,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
suite.Require().NoError(err)
msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, upgradeHeight, nil, suite.chainA.SenderAccount.GetAddress())
msg, err = clienttypes.NewMsgUpgradeClient(clientA, upgradedClient, upgradedConsState, nil, nil, suite.chainA.SenderAccount.GetAddress())
suite.Require().NoError(err)
},
expPass: false,
@ -711,7 +705,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
suite.Require().NoError(err, "upgrade handler failed on valid case: %s", tc.name)
newClient, ok := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(ok)
suite.Require().Equal(upgradedClient, newClient)
newChainSpecifiedClient := newClient.ZeroCustomFields()
suite.Require().Equal(upgradedClient, newChainSpecifiedClient)
} else {
suite.Require().Error(err, "upgrade handler passed on invalid case: %s", tc.name)
}

View File

@ -77,7 +77,7 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState {
// VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades
func (cs ClientState) VerifyUpgradeAndUpdateState(
_ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore,
_ exported.ClientState, _ exported.Height, _ []byte,
_ exported.ClientState, _ exported.ConsensusState, _, _ []byte,
) (exported.ClientState, exported.ConsensusState, error) {
return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade solomachine client")
}

View File

@ -39,7 +39,7 @@ func NewCreateClientCmd() *cobra.Command {
Long: `Create a new tendermint IBC client.
- 'trust-level' flag can be a fraction (eg: '1/3') or 'default'
- 'proof-specs' flag can be JSON input, a path to a .json file or 'default'
- 'upgrade-path' flag is a string specifying the upgrade path for this chain where a future upgraded client will be stored. The path represents a keypath for the store with each key separated by a '/'. Any slash within a key must be escaped.
- 'upgrade-path' flag is a string specifying the upgrade path for this chain where a future upgraded client will be stored. The path is a comma-separated list representing the keys in order of the keyPath to the committed upgraded client.
e.g. 'upgrade/upgradedClient'`,
Example: fmt.Sprintf("%s tx ibc %s create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift] --trust-level default --consensus-params [path/to/consensus-params.json] --proof-specs [path/to/proof-specs.json] --upgrade-path upgrade/upgradedClient --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(5),
@ -119,7 +119,8 @@ func NewCreateClientCmd() *cobra.Command {
allowUpdateAfterExpiry, _ := cmd.Flags().GetBool(flagAllowUpdateAfterExpiry)
allowUpdateAfterMisbehaviour, _ := cmd.Flags().GetBool(flagAllowUpdateAfterMisbehaviour)
upgradePath, _ := cmd.Flags().GetString(flagUpgradePath)
upgradePathStr, _ := cmd.Flags().GetString(flagUpgradePath)
upgradePath := strings.Split(upgradePathStr, ",")
// validate header
if err := header.ValidateBasic(); err != nil {

View File

@ -25,7 +25,7 @@ func NewClientState(
chainID string, trustLevel Fraction,
trustingPeriod, ubdPeriod, maxClockDrift time.Duration,
latestHeight clienttypes.Height, specs []*ics23.ProofSpec,
upgradePath string, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour bool,
upgradePath []string, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour bool,
) *ClientState {
return &ClientState{
ChainId: chainID,
@ -105,17 +105,15 @@ func (cs ClientState) Validate() error {
if cs.ProofSpecs == nil {
return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof specs cannot be nil for tm client")
}
for _, spec := range cs.ProofSpecs {
for i, spec := range cs.ProofSpecs {
if spec == nil {
return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof spec cannot be nil")
return sdkerrors.Wrapf(ErrInvalidProofSpecs, "proof spec cannot be nil at index: %d", i)
}
}
if cs.UpgradePath != "" {
keys := strings.Split(cs.UpgradePath, "/")
for _, k := range keys {
if strings.TrimSpace(k) == "" {
return sdkerrors.Wrapf(clienttypes.ErrInvalidUpgradeClient, "upgrade path contains an empty string when splitting by '/': %s", cs.UpgradePath)
}
// UpgradePath may be empty, but if it isn't, each key must be non-empty
for i, k := range cs.UpgradePath {
if strings.TrimSpace(k) == "" {
return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "key in upgrade path at index %d cannot be empty", i)
}
}

View File

@ -38,7 +38,7 @@ func (suite *TendermintTestSuite) TestValidate() {
},
{
name: "valid client with nil upgrade path",
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), "", false, false),
clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), nil, false, false),
expPass: true,
},
{

View File

@ -51,8 +51,12 @@ type ClientState struct {
LatestHeight types.Height `protobuf:"bytes,7,opt,name=latest_height,json=latestHeight,proto3" json:"latest_height" yaml:"latest_height"`
// Proof specifications used in verifying counterparty state
ProofSpecs []*_go.ProofSpec `protobuf:"bytes,8,rep,name=proof_specs,json=proofSpecs,proto3" json:"proof_specs,omitempty" yaml:"proof_specs"`
// Path at which next upgraded client will be committed
UpgradePath string `protobuf:"bytes,9,opt,name=upgrade_path,json=upgradePath,proto3" json:"upgrade_path,omitempty" yaml:"upgrade_path"`
// Path at which next upgraded client will be committed.
// Each element corresponds to the key for a single CommitmentProof in the chained proof.
// NOTE: ClientState must stored under `{upgradePath}/{upgradeHeight}/clientState`
// ConsensusState must be stored under `{upgradepath}/{upgradeHeight}/consensusState`
// For SDK chains using the default upgrade module, upgrade_path should be []string{"upgrade", "upgradedIBCState"}`
UpgradePath []string `protobuf:"bytes,9,rep,name=upgrade_path,json=upgradePath,proto3" json:"upgrade_path,omitempty" yaml:"upgrade_path"`
// This flag, when set to true, will allow governance to recover a client
// which has expired
AllowUpdateAfterExpiry bool `protobuf:"varint,10,opt,name=allow_update_after_expiry,json=allowUpdateAfterExpiry,proto3" json:"allow_update_after_expiry,omitempty" yaml:"allow_update_after_expiry"`
@ -317,75 +321,75 @@ func init() {
}
var fileDescriptor_c6d6cf2b288949be = []byte{
// 1079 bytes of a gzipped FileDescriptorProto
// 1081 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcf, 0x6f, 0xe3, 0xc4,
0x17, 0x6f, 0xda, 0x7e, 0xb7, 0xe9, 0x24, 0xdd, 0xf6, 0xeb, 0x2d, 0xdd, 0xb4, 0x74, 0xe3, 0xc8,
0xa0, 0xa5, 0x42, 0xaa, 0x4d, 0xb2, 0x48, 0x48, 0x15, 0x17, 0xdc, 0x82, 0x5a, 0xc4, 0x4a, 0x95,
0xcb, 0x0f, 0x09, 0x09, 0xcc, 0xc4, 0x9e, 0x24, 0xa3, 0xda, 0x1e, 0xe3, 0x99, 0x84, 0x94, 0xbf,
0x17, 0x6f, 0xda, 0x7e, 0xb7, 0xc9, 0x24, 0xdd, 0xf6, 0xeb, 0x2d, 0xdd, 0xb4, 0x74, 0xe3, 0xc8,
0xa0, 0x25, 0x42, 0xaa, 0x4d, 0xb2, 0x48, 0x48, 0x15, 0x17, 0xdc, 0x82, 0x5a, 0xc4, 0x4a, 0x95,
0xcb, 0x0f, 0x09, 0x09, 0xcc, 0xc4, 0x9e, 0xc4, 0xa3, 0xda, 0x1e, 0xe3, 0x99, 0x84, 0x94, 0xbf,
0x00, 0x0e, 0x48, 0x7b, 0x44, 0x9c, 0x38, 0xf0, 0xc7, 0xec, 0xb1, 0x47, 0x4e, 0x06, 0xb5, 0x17,
0xce, 0x39, 0x72, 0x42, 0xf3, 0xc3, 0xf6, 0x34, 0xdb, 0xa5, 0x5a, 0x2e, 0xed, 0xbc, 0xf7, 0x3e,
0xef, 0xf3, 0xc9, 0xbc, 0x79, 0xf3, 0xc6, 0xc0, 0xc1, 0xfd, 0xc0, 0x89, 0xf0, 0x70, 0xc4, 0x82,
0x08, 0xa3, 0x84, 0x51, 0x87, 0xa1, 0x24, 0x44, 0x59, 0x8c, 0x13, 0xe6, 0x4c, 0xba, 0x9a, 0x65,
0xa7, 0x19, 0x61, 0xc4, 0x68, 0xe3, 0x7e, 0x60, 0xeb, 0x09, 0xb6, 0x06, 0x99, 0x74, 0x77, 0x3a,
0x5a, 0x3e, 0xbb, 0x48, 0x11, 0x75, 0x26, 0x30, 0xc2, 0x21, 0x64, 0x24, 0x93, 0x0c, 0x3b, 0xbb,
0x2f, 0x20, 0xc4, 0x5f, 0x15, 0x7d, 0x10, 0x90, 0x64, 0x80, 0x89, 0x93, 0x66, 0x84, 0x0c, 0x0a,
0x67, 0x7b, 0x48, 0xc8, 0x30, 0x42, 0x8e, 0xb0, 0xfa, 0xe3, 0x81, 0x13, 0x8e, 0x33, 0xc8, 0x30,
0x49, 0x54, 0xdc, 0x9c, 0x8f, 0x33, 0x1c, 0x23, 0xca, 0x60, 0x9c, 0x16, 0x00, 0xbe, 0xcd, 0x80,
0x64, 0xc8, 0x91, 0xbf, 0x9a, 0x6f, 0x4d, 0xae, 0x14, 0xe0, 0xad, 0x0a, 0x40, 0xe2, 0x18, 0xb3,
0xb8, 0x00, 0x95, 0x96, 0x02, 0x6e, 0x0e, 0xc9, 0x90, 0x88, 0xa5, 0xc3, 0x57, 0xd2, 0x6b, 0xfd,
0xb5, 0x02, 0x1a, 0x87, 0x82, 0xef, 0x8c, 0x41, 0x86, 0x8c, 0x6d, 0x50, 0x0f, 0x46, 0x10, 0x27,
0x3e, 0x0e, 0x5b, 0xb5, 0x4e, 0x6d, 0x6f, 0xd5, 0x5b, 0x11, 0xf6, 0x49, 0x68, 0x20, 0xd0, 0x60,
0xd9, 0x98, 0x32, 0x3f, 0x42, 0x13, 0x14, 0xb5, 0x16, 0x3b, 0xb5, 0xbd, 0x46, 0x6f, 0xcf, 0xfe,
0xf7, 0xb2, 0xda, 0x1f, 0x65, 0x30, 0xe0, 0x1b, 0x76, 0x77, 0x9e, 0xe7, 0xe6, 0xc2, 0x2c, 0x37,
0x8d, 0x0b, 0x18, 0x47, 0x07, 0x96, 0x46, 0x65, 0x79, 0x40, 0x58, 0x9f, 0x70, 0xc3, 0x18, 0x80,
0x75, 0x61, 0xe1, 0x64, 0xe8, 0xa7, 0x28, 0xc3, 0x24, 0x6c, 0x2d, 0x09, 0xa9, 0x6d, 0x5b, 0x16,
0xcb, 0x2e, 0x8a, 0x65, 0x1f, 0xa9, 0x62, 0xba, 0x96, 0xe2, 0xde, 0xd2, 0xb8, 0xab, 0x7c, 0xeb,
0xe7, 0x3f, 0xcc, 0x9a, 0x77, 0xbf, 0xf0, 0x9e, 0x0a, 0xa7, 0x81, 0xc1, 0xc6, 0x38, 0xe9, 0x93,
0x24, 0xd4, 0x84, 0x96, 0xef, 0x12, 0x7a, 0x43, 0x09, 0x3d, 0x94, 0x42, 0xf3, 0x04, 0x52, 0x69,
0xbd, 0x74, 0x2b, 0x29, 0x04, 0xd6, 0x63, 0x38, 0xf5, 0x83, 0x88, 0x04, 0xe7, 0x7e, 0x98, 0xe1,
0x01, 0x6b, 0xfd, 0xef, 0x15, 0xb7, 0x34, 0x97, 0x2f, 0x85, 0xd6, 0x62, 0x38, 0x3d, 0xe4, 0xce,
0x23, 0xee, 0x33, 0xbe, 0x02, 0x6b, 0x83, 0x8c, 0x7c, 0x8f, 0x12, 0x7f, 0x84, 0xf8, 0x81, 0xb4,
0xee, 0x09, 0x91, 0x1d, 0x71, 0x44, 0xbc, 0x45, 0x6c, 0xd5, 0x39, 0x93, 0xae, 0x7d, 0x2c, 0x10,
0xee, 0xae, 0x52, 0xd9, 0x94, 0x2a, 0x37, 0xd2, 0x2d, 0xaf, 0x29, 0x6d, 0x89, 0xe5, 0xf4, 0x11,
0x64, 0x88, 0xb2, 0x82, 0x7e, 0xe5, 0x55, 0xe9, 0x6f, 0xa4, 0x5b, 0x5e, 0x53, 0xda, 0x8a, 0xfe,
0x04, 0x34, 0xc4, 0xd5, 0xf1, 0x69, 0x8a, 0x02, 0xda, 0xaa, 0x77, 0x96, 0xf6, 0x1a, 0xbd, 0x0d,
0x1b, 0x07, 0xb4, 0xf7, 0xc4, 0x3e, 0xe5, 0x91, 0xb3, 0x14, 0x05, 0xee, 0x56, 0xd5, 0x42, 0x1a,
0xdc, 0xf2, 0x40, 0x5a, 0x40, 0xa8, 0x71, 0x00, 0x9a, 0xe3, 0x74, 0x98, 0xc1, 0x10, 0xf9, 0x29,
0x64, 0xa3, 0xd6, 0x2a, 0x6f, 0x64, 0xf7, 0xe1, 0x2c, 0x37, 0x1f, 0xa8, 0x73, 0xd3, 0xa2, 0x96,
0xd7, 0x50, 0xe6, 0x29, 0x64, 0x23, 0xc3, 0x07, 0xdb, 0x30, 0x8a, 0xc8, 0x77, 0xfe, 0x38, 0x0d,
0x21, 0x43, 0x3e, 0x1c, 0x30, 0x94, 0xf9, 0x68, 0x9a, 0xe2, 0xec, 0xa2, 0x05, 0x3a, 0xb5, 0xbd,
0xba, 0xfb, 0xe6, 0x2c, 0x37, 0x3b, 0x92, 0xe8, 0xa5, 0x50, 0xcb, 0xdb, 0x12, 0xb1, 0xcf, 0x44,
0xe8, 0x03, 0x1e, 0xf9, 0x50, 0x04, 0x8c, 0x6f, 0x81, 0x79, 0x4b, 0x56, 0x8c, 0x69, 0x1f, 0x8d,
0xe0, 0x04, 0x93, 0x71, 0xd6, 0x6a, 0x08, 0x99, 0xb7, 0x67, 0xb9, 0xf9, 0xf8, 0xa5, 0x32, 0x7a,
0x82, 0xe5, 0xed, 0xce, 0x8b, 0x3d, 0xd5, 0xc2, 0x07, 0xcb, 0x3f, 0xfc, 0x6a, 0x2e, 0x58, 0xbf,
0x2d, 0x82, 0xfb, 0x87, 0x24, 0xa1, 0x28, 0xa1, 0x63, 0x2a, 0x6f, 0xbb, 0x0b, 0x56, 0xcb, 0x81,
0x23, 0xae, 0x3b, 0x3f, 0xce, 0xf9, 0x96, 0xfc, 0xb4, 0x40, 0xb8, 0x75, 0x7e, 0x9c, 0xcf, 0x78,
0xe7, 0x55, 0x69, 0xc6, 0xfb, 0x60, 0x39, 0x23, 0x84, 0xa9, 0x79, 0x60, 0x69, 0xdd, 0x50, 0x4d,
0xa0, 0x49, 0xd7, 0x7e, 0x8a, 0xb2, 0xf3, 0x08, 0x79, 0x84, 0x30, 0x77, 0x99, 0xd3, 0x78, 0x22,
0xcb, 0xf8, 0xb1, 0x06, 0x36, 0x13, 0x34, 0x65, 0x7e, 0x39, 0x6c, 0xa9, 0x3f, 0x82, 0x74, 0x24,
0xee, 0x7c, 0xd3, 0xfd, 0x62, 0x96, 0x9b, 0xaf, 0xcb, 0x1a, 0xdc, 0x86, 0xb2, 0xfe, 0xce, 0xcd,
0x77, 0x87, 0x98, 0x8d, 0xc6, 0x7d, 0x2e, 0xa7, 0x3f, 0x01, 0xda, 0x32, 0xc2, 0x7d, 0xea, 0xf4,
0x2f, 0x18, 0xa2, 0xf6, 0x31, 0x9a, 0xba, 0x7c, 0xe1, 0x19, 0x9c, 0xee, 0xf3, 0x92, 0xed, 0x18,
0xd2, 0x91, 0x2a, 0xd3, 0x4f, 0x8b, 0xa0, 0xa9, 0x57, 0xcf, 0xe8, 0x82, 0x55, 0xd9, 0xd8, 0xe5,
0x4c, 0x74, 0x37, 0x67, 0xb9, 0xb9, 0x21, 0x7f, 0x56, 0x19, 0xb2, 0xbc, 0xba, 0x5c, 0x9f, 0x84,
0x06, 0x04, 0xf5, 0x11, 0x82, 0x21, 0xca, 0xfc, 0xae, 0xaa, 0xcb, 0xe3, 0xbb, 0xe6, 0xe4, 0xb1,
0xc0, 0xbb, 0xed, 0xab, 0xdc, 0x5c, 0x91, 0xeb, 0xee, 0x2c, 0x37, 0xd7, 0xa5, 0x48, 0x41, 0x66,
0x79, 0x2b, 0x72, 0xd9, 0xd5, 0x24, 0x7a, 0x6a, 0x3e, 0xfe, 0x07, 0x89, 0xde, 0x0b, 0x12, 0xbd,
0x52, 0xa2, 0xa7, 0xea, 0xf1, 0xcb, 0x12, 0xb8, 0x27, 0xd1, 0x06, 0x04, 0x6b, 0x14, 0x0f, 0x13,
0x14, 0xfa, 0x12, 0xa2, 0x5a, 0xa6, 0xad, 0xeb, 0xc8, 0x27, 0xf1, 0x4c, 0xc0, 0x94, 0xe0, 0xee,
0x65, 0x6e, 0xd6, 0xaa, 0x29, 0x70, 0x83, 0xc2, 0xf2, 0x9a, 0x54, 0xc3, 0xf2, 0x21, 0x53, 0x9e,
0xb1, 0x4f, 0x51, 0xd1, 0x56, 0xb7, 0x48, 0x94, 0x87, 0x77, 0x86, 0x98, 0xdb, 0xaa, 0xe8, 0x6f,
0xa4, 0x5b, 0x5e, 0x73, 0xa2, 0xe1, 0x8c, 0x6f, 0x80, 0x7c, 0x06, 0x84, 0xbe, 0x18, 0x62, 0x4b,
0x77, 0x0e, 0xb1, 0x47, 0x6a, 0x88, 0xbd, 0xa6, 0x3d, 0x2e, 0x65, 0xbe, 0xe5, 0xad, 0x29, 0x87,
0x1a, 0x63, 0x11, 0x30, 0x0a, 0x44, 0xd5, 0xac, 0xea, 0x61, 0xb9, 0x6b, 0x17, 0x8f, 0x66, 0xb9,
0xb9, 0x7d, 0x53, 0xa5, 0xe2, 0xb0, 0xbc, 0xff, 0x2b, 0x67, 0xd5, 0xb6, 0xd6, 0xc7, 0xa0, 0x5e,
0x3c, 0xb0, 0xc6, 0x2e, 0x58, 0x4d, 0xc6, 0x31, 0xca, 0x78, 0x44, 0x9c, 0xcc, 0xb2, 0x57, 0x39,
0x8c, 0x0e, 0x68, 0x84, 0x28, 0x21, 0x31, 0x4e, 0x44, 0x7c, 0x51, 0xc4, 0x75, 0x97, 0xfb, 0xf5,
0xf3, 0xab, 0x76, 0xed, 0xf2, 0xaa, 0x5d, 0xfb, 0xf3, 0xaa, 0x5d, 0x7b, 0x76, 0xdd, 0x5e, 0xb8,
0xbc, 0x6e, 0x2f, 0xfc, 0x7e, 0xdd, 0x5e, 0xf8, 0xf2, 0x48, 0xbb, 0x62, 0x01, 0xa1, 0x31, 0xa1,
0xea, 0xdf, 0x3e, 0x0d, 0xcf, 0x9d, 0x69, 0xf5, 0x29, 0xb6, 0x5f, 0x7c, 0x8b, 0xbd, 0xf3, 0xde,
0xfe, 0xfc, 0xc7, 0x52, 0xff, 0x9e, 0x98, 0x28, 0x4f, 0xfe, 0x09, 0x00, 0x00, 0xff, 0xff, 0x4c,
0xb7, 0x2c, 0x8e, 0xba, 0x09, 0x00, 0x00,
0xce, 0x39, 0x72, 0x42, 0x9e, 0x19, 0xdb, 0xd3, 0x6c, 0x97, 0x6a, 0xb9, 0xb4, 0xf3, 0xde, 0xfb,
0xbc, 0xcf, 0x27, 0xf3, 0xe6, 0xcd, 0x1b, 0x03, 0x0b, 0x0f, 0x3d, 0x2b, 0xc4, 0xe3, 0x80, 0x79,
0x21, 0x46, 0x31, 0xa3, 0x16, 0x43, 0xb1, 0x8f, 0xd2, 0x08, 0xc7, 0xcc, 0x9a, 0xf6, 0x15, 0xcb,
0x4c, 0x52, 0xc2, 0x88, 0xd6, 0xc1, 0x43, 0xcf, 0x54, 0x13, 0x4c, 0x05, 0x32, 0xed, 0xef, 0x76,
0x95, 0x7c, 0x76, 0x91, 0x20, 0x6a, 0x4d, 0x61, 0x88, 0x7d, 0xc8, 0x48, 0x2a, 0x18, 0x76, 0xf7,
0x5e, 0x40, 0xf0, 0xbf, 0x32, 0xfa, 0xc0, 0x23, 0xf1, 0x08, 0x13, 0x2b, 0x49, 0x09, 0x19, 0x15,
0xce, 0xce, 0x98, 0x90, 0x71, 0x88, 0x2c, 0x6e, 0x0d, 0x27, 0x23, 0xcb, 0x9f, 0xa4, 0x90, 0x61,
0x12, 0xcb, 0xb8, 0xbe, 0x18, 0x67, 0x38, 0x42, 0x94, 0xc1, 0x28, 0x29, 0x00, 0xf9, 0x36, 0x3d,
0x92, 0x22, 0x4b, 0xfc, 0xea, 0x7c, 0x6b, 0x62, 0x25, 0x01, 0x6f, 0x55, 0x00, 0x12, 0x45, 0x98,
0x45, 0x05, 0xa8, 0xb4, 0x24, 0x70, 0x6b, 0x4c, 0xc6, 0x84, 0x2f, 0xad, 0x7c, 0x25, 0xbc, 0xc6,
0x5f, 0x6b, 0xa0, 0x79, 0xc8, 0xf9, 0xce, 0x18, 0x64, 0x48, 0xdb, 0x01, 0x75, 0x2f, 0x80, 0x38,
0x76, 0xb1, 0xdf, 0xae, 0x75, 0x6b, 0xbd, 0x86, 0xb3, 0xc6, 0xed, 0x13, 0x5f, 0x43, 0xa0, 0xc9,
0xd2, 0x09, 0x65, 0x6e, 0x88, 0xa6, 0x28, 0x6c, 0x2f, 0x77, 0x6b, 0xbd, 0xe6, 0xa0, 0x67, 0xfe,
0x7b, 0x59, 0xcd, 0x8f, 0x52, 0xe8, 0xe5, 0x1b, 0xb6, 0x77, 0x9f, 0x67, 0xfa, 0xd2, 0x3c, 0xd3,
0xb5, 0x0b, 0x18, 0x85, 0x07, 0x86, 0x42, 0x65, 0x38, 0x80, 0x5b, 0x9f, 0xe4, 0x86, 0x36, 0x02,
0x1b, 0xdc, 0xc2, 0xf1, 0xd8, 0x4d, 0x50, 0x8a, 0x89, 0xdf, 0x5e, 0xe1, 0x52, 0x3b, 0xa6, 0x28,
0x96, 0x59, 0x14, 0xcb, 0x3c, 0x92, 0xc5, 0xb4, 0x0d, 0xc9, 0xbd, 0xad, 0x70, 0x57, 0xf9, 0xc6,
0xcf, 0x7f, 0xe8, 0x35, 0xe7, 0x7e, 0xe1, 0x3d, 0xe5, 0x4e, 0x0d, 0x83, 0xcd, 0x49, 0x3c, 0x24,
0xb1, 0xaf, 0x08, 0xad, 0xde, 0x25, 0xf4, 0x86, 0x14, 0x7a, 0x28, 0x84, 0x16, 0x09, 0x84, 0xd2,
0x46, 0xe9, 0x96, 0x52, 0x08, 0x6c, 0x44, 0x70, 0xe6, 0x7a, 0x21, 0xf1, 0xce, 0x5d, 0x3f, 0xc5,
0x23, 0xd6, 0xfe, 0xdf, 0x2b, 0x6e, 0x69, 0x21, 0x5f, 0x08, 0xad, 0x47, 0x70, 0x76, 0x98, 0x3b,
0x8f, 0x72, 0x9f, 0xf6, 0x15, 0x58, 0x1f, 0xa5, 0xe4, 0x7b, 0x14, 0xbb, 0x01, 0xca, 0x0f, 0xa4,
0x7d, 0x8f, 0x8b, 0xec, 0xf2, 0x23, 0xca, 0x5b, 0xc4, 0x94, 0x9d, 0x33, 0xed, 0x9b, 0xc7, 0x1c,
0x61, 0xef, 0x49, 0x95, 0x2d, 0xa1, 0x72, 0x23, 0xdd, 0x70, 0x5a, 0xc2, 0x16, 0xd8, 0x9c, 0x3e,
0x84, 0x0c, 0x51, 0x56, 0xd0, 0xaf, 0xbd, 0x2a, 0xfd, 0x8d, 0x74, 0xc3, 0x69, 0x09, 0x5b, 0xd2,
0x9f, 0x80, 0x26, 0xbf, 0x3a, 0x2e, 0x4d, 0x90, 0x47, 0xdb, 0xf5, 0xee, 0x4a, 0xaf, 0x39, 0xd8,
0x34, 0xb1, 0x47, 0x07, 0x4f, 0xcc, 0xd3, 0x3c, 0x72, 0x96, 0x20, 0xcf, 0xde, 0xae, 0x5a, 0x48,
0x81, 0x1b, 0x0e, 0x48, 0x0a, 0x08, 0xd5, 0x0e, 0x40, 0x6b, 0x92, 0x8c, 0x53, 0xe8, 0x23, 0x37,
0x81, 0x2c, 0x68, 0x37, 0xba, 0x2b, 0xbd, 0x86, 0xfd, 0x70, 0x9e, 0xe9, 0x0f, 0xe4, 0xb9, 0x29,
0x51, 0xc3, 0x69, 0x4a, 0xf3, 0x14, 0xb2, 0x40, 0x73, 0xc1, 0x0e, 0x0c, 0x43, 0xf2, 0x9d, 0x3b,
0x49, 0x7c, 0xc8, 0x90, 0x0b, 0x47, 0x0c, 0xa5, 0x2e, 0x9a, 0x25, 0x38, 0xbd, 0x68, 0x83, 0x6e,
0xad, 0x57, 0xb7, 0xdf, 0x9c, 0x67, 0x7a, 0x57, 0x10, 0xbd, 0x14, 0x6a, 0x38, 0xdb, 0x3c, 0xf6,
0x19, 0x0f, 0x7d, 0x90, 0x47, 0x3e, 0xe4, 0x01, 0xed, 0x5b, 0xa0, 0xdf, 0x92, 0x15, 0x61, 0x3a,
0x44, 0x01, 0x9c, 0x62, 0x32, 0x49, 0xdb, 0x4d, 0x2e, 0xf3, 0xf6, 0x3c, 0xd3, 0x1f, 0xbf, 0x54,
0x46, 0x4d, 0x30, 0x9c, 0xbd, 0x45, 0xb1, 0xa7, 0x4a, 0xf8, 0x60, 0xf5, 0x87, 0x5f, 0xf5, 0x25,
0xe3, 0xb7, 0x65, 0x70, 0xff, 0x90, 0xc4, 0x14, 0xc5, 0x74, 0x42, 0xc5, 0x6d, 0xb7, 0x41, 0xa3,
0x1c, 0x38, 0xfc, 0xba, 0xe7, 0xc7, 0xb9, 0xd8, 0x92, 0x9f, 0x16, 0x08, 0xbb, 0x9e, 0x1f, 0xe7,
0xb3, 0xbc, 0xf3, 0xaa, 0x34, 0xed, 0x7d, 0xb0, 0x9a, 0x12, 0xc2, 0xe4, 0x3c, 0x30, 0x94, 0x6e,
0xa8, 0x26, 0xd0, 0xb4, 0x6f, 0x3e, 0x45, 0xe9, 0x79, 0x88, 0x1c, 0x42, 0x98, 0xbd, 0x9a, 0xd3,
0x38, 0x3c, 0x4b, 0xfb, 0xb1, 0x06, 0xb6, 0x62, 0x34, 0x63, 0x6e, 0x39, 0x6c, 0xa9, 0x1b, 0x40,
0x1a, 0xf0, 0x3b, 0xdf, 0xb2, 0xbf, 0x98, 0x67, 0xfa, 0xeb, 0xa2, 0x06, 0xb7, 0xa1, 0x8c, 0xbf,
0x33, 0xfd, 0xdd, 0x31, 0x66, 0xc1, 0x64, 0x98, 0xcb, 0xa9, 0x4f, 0x80, 0xb2, 0x0c, 0xf1, 0x90,
0x5a, 0xc3, 0x0b, 0x86, 0xa8, 0x79, 0x8c, 0x66, 0x76, 0xbe, 0x70, 0xb4, 0x9c, 0xee, 0xf3, 0x92,
0xed, 0x18, 0xd2, 0x40, 0x96, 0xe9, 0xa7, 0x65, 0xd0, 0x52, 0xab, 0xa7, 0xf5, 0x41, 0x43, 0x34,
0x76, 0x39, 0x13, 0xed, 0xad, 0x79, 0xa6, 0x6f, 0x8a, 0x9f, 0x55, 0x86, 0x0c, 0xa7, 0x2e, 0xd6,
0x27, 0xbe, 0x06, 0x41, 0x3d, 0x40, 0xd0, 0x47, 0xa9, 0xdb, 0x97, 0x75, 0x79, 0x7c, 0xd7, 0x9c,
0x3c, 0xe6, 0x78, 0xbb, 0x73, 0x95, 0xe9, 0x6b, 0x62, 0xdd, 0x9f, 0x67, 0xfa, 0x86, 0x10, 0x29,
0xc8, 0x0c, 0x67, 0x4d, 0x2c, 0xfb, 0x8a, 0xc4, 0x40, 0xce, 0xc7, 0xff, 0x20, 0x31, 0x78, 0x41,
0x62, 0x50, 0x4a, 0x0c, 0x64, 0x3d, 0x7e, 0x59, 0x01, 0xf7, 0x04, 0x5a, 0x83, 0x60, 0x9d, 0xe2,
0x71, 0x8c, 0x7c, 0x57, 0x40, 0x64, 0xcb, 0x74, 0x54, 0x1d, 0xf1, 0x24, 0x9e, 0x71, 0x98, 0x14,
0xdc, 0xbb, 0xcc, 0xf4, 0x5a, 0x35, 0x05, 0x6e, 0x50, 0x18, 0x4e, 0x8b, 0x2a, 0xd8, 0x7c, 0xc8,
0x94, 0x67, 0xec, 0x52, 0x54, 0xb4, 0xd5, 0x2d, 0x12, 0xe5, 0xe1, 0x9d, 0x21, 0x66, 0xb7, 0x2b,
0xfa, 0x1b, 0xe9, 0x86, 0xd3, 0x9a, 0x2a, 0x38, 0xed, 0x1b, 0x20, 0x9e, 0x01, 0xae, 0xcf, 0x87,
0xd8, 0xca, 0x9d, 0x43, 0xec, 0x91, 0x1c, 0x62, 0xaf, 0x29, 0x8f, 0x4b, 0x99, 0x6f, 0x38, 0xeb,
0xd2, 0x21, 0xc7, 0x58, 0x08, 0xb4, 0x02, 0x51, 0x35, 0xab, 0x7c, 0x58, 0xee, 0xda, 0xc5, 0xa3,
0x79, 0xa6, 0xef, 0xdc, 0x54, 0xa9, 0x38, 0x0c, 0xe7, 0xff, 0xd2, 0x59, 0xb5, 0xad, 0xf1, 0x31,
0xa8, 0x17, 0x0f, 0xac, 0xb6, 0x07, 0x1a, 0xf1, 0x24, 0x42, 0x69, 0x1e, 0xe1, 0x27, 0xb3, 0xea,
0x54, 0x0e, 0xad, 0x0b, 0x9a, 0x3e, 0x8a, 0x49, 0x84, 0x63, 0x1e, 0x5f, 0xe6, 0x71, 0xd5, 0x65,
0x7f, 0xfd, 0xfc, 0xaa, 0x53, 0xbb, 0xbc, 0xea, 0xd4, 0xfe, 0xbc, 0xea, 0xd4, 0x9e, 0x5d, 0x77,
0x96, 0x2e, 0xaf, 0x3b, 0x4b, 0xbf, 0x5f, 0x77, 0x96, 0xbe, 0x3c, 0x52, 0xae, 0x98, 0x47, 0x68,
0x44, 0xa8, 0xfc, 0xb7, 0x4f, 0xfd, 0x73, 0x6b, 0x56, 0x7d, 0x8a, 0xed, 0x17, 0xdf, 0x62, 0xef,
0xbc, 0xb7, 0xbf, 0xf8, 0xb1, 0x34, 0xbc, 0xc7, 0x27, 0xca, 0x93, 0x7f, 0x02, 0x00, 0x00, 0xff,
0xff, 0x8f, 0xde, 0xf9, 0xa9, 0xba, 0x09, 0x00, 0x00,
}
func (m *ClientState) Marshal() (dAtA []byte, err error) {
@ -429,11 +433,13 @@ func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
dAtA[i] = 0x50
}
if len(m.UpgradePath) > 0 {
i -= len(m.UpgradePath)
copy(dAtA[i:], m.UpgradePath)
i = encodeVarintTendermint(dAtA, i, uint64(len(m.UpgradePath)))
i--
dAtA[i] = 0x4a
for iNdEx := len(m.UpgradePath) - 1; iNdEx >= 0; iNdEx-- {
i -= len(m.UpgradePath[iNdEx])
copy(dAtA[i:], m.UpgradePath[iNdEx])
i = encodeVarintTendermint(dAtA, i, uint64(len(m.UpgradePath[iNdEx])))
i--
dAtA[i] = 0x4a
}
}
if len(m.ProofSpecs) > 0 {
for iNdEx := len(m.ProofSpecs) - 1; iNdEx >= 0; iNdEx-- {
@ -756,9 +762,11 @@ func (m *ClientState) Size() (n int) {
n += 1 + l + sovTendermint(uint64(l))
}
}
l = len(m.UpgradePath)
if l > 0 {
n += 1 + l + sovTendermint(uint64(l))
if len(m.UpgradePath) > 0 {
for _, s := range m.UpgradePath {
l = len(s)
n += 1 + l + sovTendermint(uint64(l))
}
}
if m.AllowUpdateAfterExpiry {
n += 2
@ -1174,7 +1182,7 @@ func (m *ClientState) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.UpgradePath = string(dAtA[iNdEx:postIndex])
m.UpgradePath = append(m.UpgradePath, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
case 10:
if wireType != 0 {

View File

@ -1,7 +1,6 @@
package types_test
import (
"fmt"
"testing"
"time"
@ -32,7 +31,7 @@ const (
var (
height = clienttypes.NewHeight(0, 4)
newClientHeight = clienttypes.NewHeight(1, 1)
upgradePath = fmt.Sprintf("%s/%s", "upgrade", "upgradedClient")
upgradePath = []string{"upgrade", "upgradedIBCState"}
)
type TendermintTestSuite struct {

View File

@ -2,8 +2,6 @@ package types
import (
"fmt"
"net/url"
"strings"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -11,6 +9,7 @@ import (
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/23-commitment/types"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)
// VerifyUpgradeAndUpdateState checks if the upgraded client has been committed by the current client
@ -26,102 +25,130 @@ import (
// and ProofSpecs do not match parameters set by committed client
func (cs ClientState) VerifyUpgradeAndUpdateState(
ctx sdk.Context, cdc codec.BinaryMarshaler, clientStore sdk.KVStore,
upgradedClient exported.ClientState, upgradeHeight exported.Height, proofUpgrade []byte,
upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState,
proofUpgradeClient, proofUpgradeConsState []byte,
) (exported.ClientState, exported.ConsensusState, error) {
if cs.UpgradePath == "" {
if len(cs.UpgradePath) == 0 {
return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade client, no upgrade path set")
}
upgradePath, err := constructUpgradeMerklePath(cs.UpgradePath, upgradeHeight)
if err != nil {
return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade client, unescaping key with URL format failed: %v", err)
}
// UpgradeHeight must be in same version as client state height
if cs.GetLatestHeight().GetVersionNumber() != upgradeHeight.GetVersionNumber() {
return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "version at which upgrade occurs must be same as current client version. expected version %d, got %d",
cs.GetLatestHeight().GetVersionNumber(), upgradeHeight.GetVersionNumber())
}
// last height of current counterparty chain must be client's latest height
lastHeight := cs.GetLatestHeight()
// UpgradeHeight must be greater than or equal to current client state height
if cs.GetLatestHeight().GetVersionHeight() > upgradeHeight.GetVersionHeight() {
return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "version height at which upgrade occurs must be greater than or equal to current client height (%d > %d)",
cs.GetLatestHeight().GetVersionHeight(), upgradeHeight.GetVersionHeight(),
)
}
if !upgradedClient.GetLatestHeight().GT(cs.GetLatestHeight()) {
return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "upgraded client height %s must be greater than current client height %s",
upgradedClient.GetLatestHeight(), cs.GetLatestHeight())
}
if len(proofUpgrade) == 0 {
return nil, nil, sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "proof of upgrade is empty")
}
var merkleProof commitmenttypes.MerkleProof
if err := cdc.UnmarshalBinaryBare(proofUpgrade, &merkleProof); err != nil {
return nil, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal merkle proof: %v", err)
if upgradedClient.GetLatestHeight().GetVersionNumber() <= lastHeight.GetVersionNumber() {
return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "upgraded client height %s must be at greater version than current client height %s",
upgradedClient.GetLatestHeight(), lastHeight)
}
// counterparty chain must commit the upgraded client with all client-customizable fields zeroed out
// at the upgrade path specified by current client
committedClient := upgradedClient.ZeroCustomFields()
bz, err := codec.MarshalAny(cdc, committedClient)
if err != nil {
return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "could not marshal client state: %v", err)
// counterparty must also commit to the upgraded consensus state at a sub-path under the upgrade path specified
tmUpgradeClient, ok := upgradedClient.(*ClientState)
if !ok {
return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "upgraded client must be Tendermint client. expected: %T got: %T",
&ClientState{}, upgradedClient)
}
tmUpgradeConsState, ok := upgradedConsState.(*ConsensusState)
if !ok {
return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "upgraded consensus state must be Tendermint consensus state. expected %T, got: %T",
&ConsensusState{}, upgradedConsState)
}
// unmarshal proofs
var merkleProofClient, merkleProofConsState commitmenttypes.MerkleProof
if err := cdc.UnmarshalBinaryBare(proofUpgradeClient, &merkleProofClient); err != nil {
return nil, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal client merkle proof: %v", err)
}
if err := cdc.UnmarshalBinaryBare(proofUpgradeConsState, &merkleProofConsState); err != nil {
return nil, nil, sdkerrors.Wrapf(commitmenttypes.ErrInvalidProof, "could not unmarshal consensus state merkle proof: %v", err)
}
// Must prove against latest consensus state to ensure we are verifying against latest upgrade plan
// This verifies that upgrade is intended for the provided version, since committed client must exist
// at this consensus state
consState, err := GetConsensusState(clientStore, cdc, upgradeHeight)
consState, err := GetConsensusState(clientStore, cdc, lastHeight)
if err != nil {
return nil, nil, sdkerrors.Wrap(err, "could not retrieve consensus state for upgradeHeight")
return nil, nil, sdkerrors.Wrap(err, "could not retrieve consensus state for lastHeight")
}
if cs.IsExpired(consState.Timestamp, ctx.BlockTime()) {
return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidClient, "cannot upgrade an expired client")
}
tmCommittedClient, ok := committedClient.(*ClientState)
if !ok {
return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "upgraded client must be Tendermint client. expected: %T got: %T",
&ClientState{}, upgradedClient)
// Verify client proof
bz, err := codec.MarshalAny(cdc, upgradedClient)
if err != nil {
return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "could not marshal client state: %v", err)
}
// Relayer chosen client parameters are ignored.
// All chain-chosen parameters come from committed client, all client-chosen parameters
// come from current client.
updatedClientState := NewClientState(
tmCommittedClient.ChainId, cs.TrustLevel, cs.TrustingPeriod, tmCommittedClient.UnbondingPeriod,
cs.MaxClockDrift, tmCommittedClient.LatestHeight, tmCommittedClient.ProofSpecs, tmCommittedClient.UpgradePath,
cs.AllowUpdateAfterExpiry, cs.AllowUpdateAfterMisbehaviour,
)
if err := updatedClientState.Validate(); err != nil {
return nil, nil, sdkerrors.Wrap(err, "updated client state failed basic validation")
}
if err := merkleProof.VerifyMembership(cs.ProofSpecs, consState.GetRoot(), upgradePath, bz); err != nil {
// construct clientState Merkle path
upgradeClientPath := constructUpgradeClientMerklePath(cs.UpgradePath, lastHeight)
if err := merkleProofClient.VerifyMembership(cs.ProofSpecs, consState.GetRoot(), upgradeClientPath, bz); err != nil {
return nil, nil, err
}
// TODO: Return valid consensus state https://github.com/cosmos/cosmos-sdk/issues/7708
return updatedClientState, &ConsensusState{}, nil
// Verify consensus state proof
bz, err = codec.MarshalAny(cdc, upgradedConsState)
if err != nil {
return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "could not marshal consensus state: %v", err)
}
// construct consensus state Merkle path
upgradeConsStatePath := constructUpgradeConsStateMerklePath(cs.UpgradePath, lastHeight)
if err := merkleProofConsState.VerifyMembership(cs.ProofSpecs, consState.GetRoot(), upgradeConsStatePath, bz); err != nil {
return nil, nil, err
}
// Construct new client state and consensus state
// Relayer chosen client parameters are ignored.
// All chain-chosen parameters come from committed client, all client-chosen parameters
// come from current client.
newClientState := NewClientState(
tmUpgradeClient.ChainId, cs.TrustLevel, cs.TrustingPeriod, tmUpgradeClient.UnbondingPeriod,
cs.MaxClockDrift, tmUpgradeClient.LatestHeight, tmUpgradeClient.ProofSpecs, tmUpgradeClient.UpgradePath,
cs.AllowUpdateAfterExpiry, cs.AllowUpdateAfterMisbehaviour,
)
if err := newClientState.Validate(); err != nil {
return nil, nil, sdkerrors.Wrap(err, "updated client state failed basic validation")
}
// The new consensus state is merely used as a trusted kernel against which headers on the new
// chain can be verified. The root is empty as it cannot be known in advance, thus no proof verification will pass.
// The timestamp and the NextValidatorsHash of the consensus state is the blocktime and NextValidatorsHash
// of the last block committed by the old chain. This will allow the first block of the new chain to be verified against
// the last validators of the old chain so long as it is submitted within the TrustingPeriod of this client.
newConsState := NewConsensusState(
tmUpgradeConsState.Timestamp, commitmenttypes.MerkleRoot{}, tmUpgradeConsState.NextValidatorsHash,
)
return newClientState, newConsState, nil
}
// construct MerklePath from upgradePath
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
// construct MerklePath for the committed client from upgradePath
func constructUpgradeClientMerklePath(upgradePath []string, lastHeight exported.Height) commitmenttypes.MerklePath {
// copy all elements from upgradePath except final element
clientPath := make([]string, len(upgradePath)-1)
copy(clientPath, upgradePath)
// append lastHeight and `upgradedClient` to last key of upgradePath and use as lastKey of clientPath
// this will create the IAVL key that is used to store client in upgrade store
upgradeKeys[len(upgradeKeys)-1] = fmt.Sprintf("%s/%d", lastKey, upgradeHeight.GetVersionHeight())
return commitmenttypes.NewMerklePath(upgradeKeys...), nil
lastKey := upgradePath[len(upgradePath)-1]
appendedKey := fmt.Sprintf("%s/%d/%s", lastKey, lastHeight.GetVersionHeight(), upgradetypes.KeyUpgradedClient)
clientPath = append(clientPath, appendedKey)
return commitmenttypes.NewMerklePath(clientPath...)
}
// construct MerklePath for the committed consensus state from upgradePath
func constructUpgradeConsStateMerklePath(upgradePath []string, lastHeight exported.Height) commitmenttypes.MerklePath {
// copy all elements from upgradePath except final element
consPath := make([]string, len(upgradePath)-1)
copy(consPath, upgradePath)
// append lastHeight and `upgradedClient` to last key of upgradePath and use as lastKey of clientPath
// this will create the IAVL key that is used to store client in upgrade store
lastKey := upgradePath[len(upgradePath)-1]
appendedKey := fmt.Sprintf("%s/%d/%s", lastKey, lastHeight.GetVersionHeight(), upgradetypes.KeyUpgradedConsState)
consPath = append(consPath, appendedKey)
return commitmenttypes.NewMerklePath(consPath...)
}

View File

@ -10,10 +10,11 @@ import (
func (suite *TendermintTestSuite) TestVerifyUpgrade() {
var (
upgradedClient exported.ClientState
upgradeHeight clienttypes.Height
clientA string
proofUpgrade []byte
upgradedClient exported.ClientState
upgradedConsState exported.ConsensusState
lastHeight clienttypes.Height
clientA string
proofUpgradedClient, proofUpgradedConsState []byte
)
testCases := []struct {
@ -26,12 +27,16 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// commit upgrade store changes and update clients
@ -42,52 +47,26 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: true,
},
{
name: "successful upgrade with different client chosen parameters set in upgraded client",
name: "unsuccessful upgrade: upgrade height version height is more than the current client version height",
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
// upgrade Height is 10 blocks from now
lastHeight = clienttypes.NewHeight(10, uint64(suite.chainB.GetContext().BlockHeight()+10))
// zero custom fields and store in upgrade store
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetVersionHeight()), upgradedClient)
// change upgradedClient client-specified parameters
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, false)
suite.coordinator.CommitBlock(suite.chainB)
err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
suite.Require().NoError(err)
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
// Previous client-chosen parameters must be the same as upgraded client chosen parameters
tmClient, _ := cs.(*types.ClientState)
oldClient := types.NewClientState(tmClient.ChainId, types.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, tmClient.LatestHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, false)
suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), clientA, oldClient)
proofUpgrade, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: true,
},
{
name: "unsuccessful upgrade: upgrade height version does not match current client version",
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(10, uint64(suite.chainB.GetContext().BlockHeight()+1))
// zero custom fields and store in upgrade store
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// commit upgrade store changes and update clients
@ -98,47 +77,26 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
{
name: "unsuccessful upgrade: upgrade height version height is less than the current client version height",
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(10, uint64(suite.chainB.GetContext().BlockHeight()-1))
// zero custom fields and store in upgrade store
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetVersionHeight()), upgradedClient)
// commit upgrade store changes and update clients
suite.coordinator.CommitBlock(suite.chainB)
err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.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.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
{
name: "unsuccessful upgrade: chain-specified parameters do not match committed client",
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// change upgradedClient client-specified parameters
upgradedClient = types.NewClientState("wrongchainID", types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, true)
@ -150,7 +108,8 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
@ -158,12 +117,17 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
name: "unsuccessful upgrade: client-specified parameters do not match previous client",
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, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// zero custom fields and store in upgrade store
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// change upgradedClient client-specified parameters
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, upgradeHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, false)
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath, true, false)
suite.coordinator.CommitBlock(suite.chainB)
err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
@ -172,39 +136,124 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
{
name: "unsuccessful upgrade: proof is empty",
name: "unsuccessful upgrade: relayer-submitted consensus state does not match counterparty-committed consensus state",
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
proofUpgrade = []byte{}
},
expPass: false,
},
{
name: "unsuccessful upgrade: proof unmarshal failed",
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
proofUpgrade = []byte("proof")
},
expPass: false,
},
{
name: "unsuccessful upgrade: proof verification failed",
setup: func() {
// create but do not store upgraded client
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
lastHeight = 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(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// change submitted upgradedConsensusState
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("maliciousValidators"),
}
// commit upgrade store changes and update clients
suite.coordinator.CommitBlock(suite.chainB)
err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.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.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
{
name: "unsuccessful upgrade: client proof unmarshal failed",
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient = []byte("proof")
},
expPass: false,
},
{
name: "unsuccessful upgrade: consensus state proof unmarshal failed",
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState = []byte("proof")
},
expPass: false,
},
{
name: "unsuccessful upgrade: client proof verification failed",
setup: func() {
// create but do not store upgraded client
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
{
name: "unsuccessful upgrade: consensus state proof verification failed",
setup: func() {
// create but do not store upgraded client
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
@ -213,12 +262,15 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
// commit upgrade store changes and update clients
@ -229,41 +281,12 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
// 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.GetVersionHeight()), upgradedClient)
// commit upgrade store changes and update clients
suite.coordinator.CommitBlock(suite.chainB)
err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.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.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
// SetClientState with nil upgrade path
tmClient, _ := cs.(*types.ClientState)
tmClient.UpgradePath = "upgraded%Client"
tmClient.UpgradePath = []string{""}
suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), clientA, tmClient)
},
expPass: false,
@ -273,12 +296,15 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
// commit upgrade store changes and update clients
@ -289,7 +315,8 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
@ -298,12 +325,15 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+100))
lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+100))
// zero custom fields and store in upgrade store
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
// commit upgrade store changes and update clients
@ -314,7 +344,8 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
@ -322,9 +353,13 @@ 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, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// zero custom fields and store in upgrade store
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
// commit upgrade store changes and update clients
@ -338,7 +373,8 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
@ -347,12 +383,15 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
setup: func() {
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
upgradeHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1))
lastHeight = 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.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedClient)
// commit upgrade store changes and update clients
@ -363,7 +402,39 @@ 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(int64(upgradeHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
{
name: "unsuccessful upgrade: final client is not valid",
setup: func() {
// new client has smaller unbonding period such that old trusting period is no longer valid
upgradedClient = types.NewClientState("newChainId", types.DefaultTrustLevel, trustingPeriod, trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath, false, false)
upgradedConsState = &types.ConsensusState{
NextValidatorsHash: []byte("nextValsHash"),
}
// upgrade Height is at next block
lastHeight = 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(lastHeight.GetVersionHeight()), upgradedClient)
suite.chainB.App.UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetVersionHeight()), upgradedConsState)
// commit upgrade store changes and update clients
suite.coordinator.CommitBlock(suite.chainB)
err := suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
suite.Require().NoError(err)
cs, found := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientA)
suite.Require().True(found)
proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetVersionHeight())), cs.GetLatestHeight().GetVersionHeight())
},
expPass: false,
},
@ -382,13 +453,17 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() {
cs := suite.chainA.GetClientState(clientA)
clientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA)
// Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient
upgradedClient = upgradedClient.ZeroCustomFields()
clientState, consensusState, err := cs.VerifyUpgradeAndUpdateState(
suite.chainA.GetContext(),
suite.cdc,
clientStore,
upgradedClient,
upgradeHeight,
proofUpgrade,
upgradedConsState,
proofUpgradedClient,
proofUpgradedConsState,
)
if tc.expPass {

View File

@ -105,7 +105,7 @@ func (cs ClientState) CheckProposedHeaderAndUpdateState(
// VerifyUpgradeAndUpdateState returns an error since localhost cannot be upgraded
func (cs ClientState) VerifyUpgradeAndUpdateState(
_ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore,
_ exported.ClientState, _ exported.Height, _ []byte,
_ exported.ClientState, _ exported.ConsensusState, _, _ []byte,
) (exported.ClientState, exported.ConsensusState, error) {
return nil, nil, sdkerrors.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client")
}

View File

@ -67,7 +67,7 @@ var (
TestHash = tmhash.Sum([]byte("TESTING HASH"))
TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
UpgradePath = fmt.Sprintf("%s/%s", "upgrade", "upgradedClient")
UpgradePath = []string{"upgrade", "upgradedIBCState"}
ConnectionVersion = connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions())[0]

View File

@ -10,6 +10,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
"github.com/cosmos/cosmos-sdk/x/upgrade/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
)
// BeginBlock will check if there is a scheduled plan and if it is ready to be executed.
@ -28,6 +30,19 @@ func BeginBlocker(k keeper.Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) {
return
}
// Once we are at the last block this chain will commit, set the upgraded consensus state
// so that IBC clients can use the last NextValidatorsHash as a trusted kernel for verifying
// headers on the next version of the chain.
// Set the time to the last block time of the current chain.
// In order for a client to upgrade successfully, the first block of the new chain must be committed
// within the trusting period of the last block time on this chain.
if plan.IsIBCPlan() && ctx.BlockHeight() == plan.Height-1 {
upgradedConsState := &ibctmtypes.ConsensusState{
Timestamp: ctx.BlockTime(),
NextValidatorsHash: ctx.BlockHeader().NextValidatorsHash,
}
k.SetUpgradedConsensusState(ctx, ctx.BlockHeight(), upgradedConsState)
}
// To make sure clear upgrade is executed at the same block
if plan.ShouldExecute(ctx) {
// If skip upgrade has been set for current height, we clear the upgrade plan

View File

@ -120,6 +120,58 @@ func TestCanOverwriteScheduleUpgrade(t *testing.T) {
VerifyDoUpgrade(t)
}
func VerifyDoIBCLastBlock(t *testing.T) {
t.Log("Verify that chain committed to consensus state on the last height it will commit")
nextValsHash := []byte("nextValsHash")
newCtx := s.ctx.WithBlockHeader(tmproto.Header{
Height: s.ctx.BlockHeight(),
NextValidatorsHash: nextValsHash,
})
req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()}
s.module.BeginBlock(newCtx, req)
consState, err := s.keeper.GetUpgradedConsensusState(newCtx, s.ctx.BlockHeight())
require.NoError(t, err)
require.Equal(t, &ibctmtypes.ConsensusState{Timestamp: newCtx.BlockTime(), NextValidatorsHash: nextValsHash}, consState)
}
func VerifyDoIBCUpgrade(t *testing.T) {
t.Log("Verify that a panic happens at the upgrade time/height")
newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now())
// Check IBC state is set before upgrade using last height: s.ctx.BlockHeight()
cs, err := s.keeper.GetUpgradedClient(newCtx, s.ctx.BlockHeight())
require.NoError(t, err, "could not retrieve upgraded client before upgrade plan is applied")
require.NotNil(t, cs, "IBC client is nil before upgrade")
consState, err := s.keeper.GetUpgradedConsensusState(newCtx, s.ctx.BlockHeight())
require.NoError(t, err, "could not retrieve upgraded consensus state before upgrade plan is applied")
require.NotNil(t, consState, "IBC consensus state is nil before upgrade")
req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()}
require.Panics(t, func() {
s.module.BeginBlock(newCtx, req)
})
t.Log("Verify that the upgrade can be successfully applied with a handler")
s.keeper.SetUpgradeHandler("test", func(ctx sdk.Context, plan types.Plan) {})
require.NotPanics(t, func() {
s.module.BeginBlock(newCtx, req)
})
VerifyCleared(t, newCtx)
// Check IBC state is cleared after upgrade using last height: s.ctx.BlockHeight()
cs, err = s.keeper.GetUpgradedClient(newCtx, s.ctx.BlockHeight())
require.Error(t, err, "retrieved upgraded client after upgrade plan is applied")
require.Nil(t, cs, "IBC client is not-nil after upgrade")
consState, err = s.keeper.GetUpgradedConsensusState(newCtx, s.ctx.BlockHeight())
require.Error(t, err, "retrieved upgraded consensus state after upgrade plan is applied")
require.Nil(t, consState, "IBC consensus state is not-nil after upgrade")
}
func VerifyDoUpgrade(t *testing.T) {
t.Log("Verify that a panic happens at the upgrade time/height")
newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now())
@ -414,6 +466,27 @@ func TestUpgradeWithoutSkip(t *testing.T) {
VerifyDone(t, s.ctx, "test")
}
func TestIBCUpgradeWithoutSkip(t *testing.T) {
s := setupTest(10, map[int64]bool{})
cs, err := clienttypes.PackClientState(&ibctmtypes.ClientState{})
require.NoError(t, err)
err = s.handler(s.ctx, &types.SoftwareUpgradeProposal{
Title: "prop",
Plan: types.Plan{
Name: "test",
Height: s.ctx.BlockHeight() + 1,
UpgradedClientState: cs,
},
})
require.Nil(t, err)
t.Log("Verify if last height stores consensus state")
VerifyDoIBCLastBlock(t)
VerifyDoUpgrade(t)
VerifyDone(t, s.ctx, "test")
}
func TestDumpUpgradeInfoToFile(t *testing.T) {
s := setupTest(10, map[int64]bool{})

View File

@ -4,6 +4,7 @@ import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
"github.com/cosmos/cosmos-sdk/x/upgrade/types"
)
@ -32,3 +33,22 @@ func (k Keeper) AppliedPlan(c context.Context, req *types.QueryAppliedPlanReques
return &types.QueryAppliedPlanResponse{Height: applied}, nil
}
// UpgradedConsensusState implements the Query/UpgradedConsensusState gRPC method
func (k Keeper) UpgradedConsensusState(c context.Context, req *types.QueryUpgradedConsensusStateRequest) (*types.QueryUpgradedConsensusStateResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
consState, err := k.GetUpgradedConsensusState(ctx, req.LastHeight)
if err != nil {
return nil, err
}
cs, err := clienttypes.PackConsensusState(consState)
if err != nil {
return nil, err
}
return &types.QueryUpgradedConsensusStateResponse{
UpgradedConsensusState: cs,
}, nil
}

View File

@ -8,8 +8,6 @@ import (
"os"
"path"
"path/filepath"
"strconv"
"strings"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
@ -76,39 +74,33 @@ func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error {
}
store := ctx.KVStore(k.storeKey)
// clear any old IBC state stored by previous plan
oldPlan, exists := k.GetUpgradePlan(ctx)
if exists && oldPlan.IsIBCPlan() {
k.ClearIBCState(ctx, oldPlan.Height-1)
}
bz := k.cdc.MustMarshalBinaryBare(&plan)
store.Set(types.PlanKey(), bz)
if plan.UpgradedClientState == nil {
// if latest UpgradedClientState is nil, but upgraded client exists in store,
// then delete client state from store.
_, height, _ := k.GetUpgradedClient(ctx)
if height != 0 {
store.Delete(types.UpgradedClientKey(height))
if plan.IsIBCPlan() {
// Set UpgradedClientState in store
clientState, err := clienttypes.UnpackClientState(plan.UpgradedClientState)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not unpack clientstate: %v", err)
}
return nil
// sets the new upgraded client in last height committed on this chain is at plan.Height - 1,
// since the chain will panic at plan.Height and new chain will resume at plan.Height
return k.SetUpgradedClient(ctx, plan.Height-1, clientState)
}
// Set UpgradedClientState in store
clientState, err := clienttypes.UnpackClientState(plan.UpgradedClientState)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not unpack clientstate: %v", err)
}
// deletes any previously stored upgraded client and sets the new upgraded client in
return k.SetUpgradedClient(ctx, plan.Height, clientState)
return nil
}
// SetUpgradedClient sets the expected upgraded client for the next version of this chain
func (k Keeper) SetUpgradedClient(ctx sdk.Context, upgradeHeight int64, cs ibcexported.ClientState) error {
// SetUpgradedClient sets the expected upgraded client for the next version of this chain at the last height the current chain will commit.
func (k Keeper) SetUpgradedClient(ctx sdk.Context, lastHeight int64, cs ibcexported.ClientState) error {
store := ctx.KVStore(k.storeKey)
// delete any previously stored upgraded client before setting a new one
// since there should only ever be one upgraded client in the store at any given time
_, setHeight, _ := k.GetUpgradedClient(ctx)
if setHeight != 0 {
store.Delete(types.UpgradedClientKey(setHeight))
}
// zero out any custom fields before setting
cs = cs.ZeroCustomFields()
bz, err := clienttypes.MarshalClientState(k.cdc, cs)
@ -116,49 +108,52 @@ func (k Keeper) SetUpgradedClient(ctx sdk.Context, upgradeHeight int64, cs ibcex
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not marshal clientstate: %v", err)
}
store.Set(types.UpgradedClientKey(upgradeHeight), bz)
store.Set(types.UpgradedClientKey(lastHeight), bz)
return nil
}
// GetUpgradedClient gets the expected upgraded client for the next version of this chain
// along with the planned upgrade height
// Since there is only ever one upgraded client in store, we do not need to know key beforehand
func (k Keeper) GetUpgradedClient(ctx sdk.Context) (ibcexported.ClientState, int64, error) {
func (k Keeper) GetUpgradedClient(ctx sdk.Context, height int64) (ibcexported.ClientState, error) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(types.KeyUpgradedClient))
var (
count, height int
bz []byte
)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
count++
// we must panic if the upgraded clients in store is ever more than one since
// that would break upgrade functionality and chain must halt and fix issue manually
if count > 1 {
panic("more than 1 upgrade client stored in state")
}
keySplit := strings.Split(string(iterator.Key()), "/")
var err error
height, err = strconv.Atoi(keySplit[len(keySplit)-1])
if err != nil {
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not parse upgrade height from key: %s", err)
}
bz = iterator.Value()
}
if count == 0 {
return nil, 0, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade client not found in store")
bz := store.Get(types.UpgradedClientKey(height))
if len(bz) == 0 {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "upgraded client not found in store for height %d", height)
}
clientState, err := clienttypes.UnmarshalClientState(k.cdc, bz)
if err != nil {
return nil, 0, err
return nil, err
}
return clientState, int64(height), nil
return clientState, nil
}
// SetUpgradedConsensusState set the expected upgraded consensus state for the next version of this chain
// using the last height committed on this chain.
func (k Keeper) SetUpgradedConsensusState(ctx sdk.Context, lastHeight int64, cs ibcexported.ConsensusState) error {
store := ctx.KVStore(k.storeKey)
bz, err := clienttypes.MarshalConsensusState(k.cdc, cs)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "could not marshal consensus state: %v", err)
}
store.Set(types.UpgradedConsStateKey(lastHeight), bz)
return nil
}
// GetUpgradedConsensusState set the expected upgraded consensus state for the next version of this chain
func (k Keeper) GetUpgradedConsensusState(ctx sdk.Context, lastHeight int64) (ibcexported.ConsensusState, error) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.UpgradedConsStateKey(lastHeight))
if len(bz) == 0 {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "upgraded consensus state not found in store for height: %d", lastHeight)
}
consState, err := clienttypes.UnmarshalConsensusState(k.cdc, bz)
if err != nil {
return nil, err
}
return consState, nil
}
// GetDoneHeight returns the height at which the given upgrade was executed
@ -172,6 +167,14 @@ func (k Keeper) GetDoneHeight(ctx sdk.Context, name string) int64 {
return int64(binary.BigEndian.Uint64(bz))
}
// ClearIBCState clears any planned IBC state
func (k Keeper) ClearIBCState(ctx sdk.Context, lastHeight int64) {
// delete IBC client and consensus state from store if this is IBC plan
store := ctx.KVStore(k.storeKey)
store.Delete(types.UpgradedClientKey(lastHeight))
store.Delete(types.UpgradedConsStateKey(lastHeight))
}
// ClearUpgradePlan clears any schedule upgrade
func (k Keeper) ClearUpgradePlan(ctx sdk.Context) {
store := ctx.KVStore(k.storeKey)
@ -219,6 +222,11 @@ func (k Keeper) ApplyUpgrade(ctx sdk.Context, plan types.Plan) {
handler(ctx, plan)
// Must clear IBC state after upgrade is applied as it is stored separately from the upgrade plan.
// This will prevent resubmission of upgrade msg after upgrade is already completed.
if plan.IsIBCPlan() {
k.ClearIBCState(ctx, plan.Height-1)
}
k.ClearUpgradePlan(ctx)
k.setDone(ctx, plan.Name)
}

View File

@ -235,13 +235,12 @@ func (s *KeeperTestSuite) TestScheduleUpgrade() {
if tc.expPass {
s.Require().NoError(err, "valid test case failed")
if tc.plan.UpgradedClientState != nil {
got, height, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx)
got, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx, tc.plan.Height-1)
s.Require().NoError(err)
s.Require().Equal(tc.plan.Height, height, "upgradedClient not stored at correct upgrade height")
s.Require().Equal(clientState, got, "upgradedClient not equal to expected value")
} else {
// check that upgraded client is empty if latest plan does not specify an upgraded client
got, _, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx)
got, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx, tc.plan.Height-1)
s.Require().Error(err)
s.Require().Nil(got)
}
@ -255,36 +254,24 @@ func (s *KeeperTestSuite) TestScheduleUpgrade() {
func (s *KeeperTestSuite) TestSetUpgradedClient() {
var (
clientState ibcexported.ClientState
height int64
)
cases := []struct {
name string
height int64
setup func()
exists bool
}{
{
name: "no upgraded client exists",
height: 10,
setup: func() {},
exists: false,
},
{
name: "success",
name: "success",
height: 10,
setup: func() {
clientState = &ibctmtypes.ClientState{ChainId: "gaiachain"}
height = 10
s.app.UpgradeKeeper.SetUpgradedClient(s.ctx, 10, clientState)
},
exists: true,
},
{
name: "successful overwrite",
setup: func() {
clientState = &ibctmtypes.ClientState{ChainId: "gaiachain"}
altCs := &ibctmtypes.ClientState{ChainId: "ethermint"}
height = 10
s.app.UpgradeKeeper.SetUpgradedClient(s.ctx, 50, altCs)
s.app.UpgradeKeeper.SetUpgradedClient(s.ctx, 10, clientState)
},
exists: true,
@ -298,14 +285,12 @@ func (s *KeeperTestSuite) TestSetUpgradedClient() {
// setup test case
tc.setup()
gotCs, gotHeight, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx)
gotCs, err := s.app.UpgradeKeeper.GetUpgradedClient(s.ctx, tc.height)
if tc.exists {
s.Require().Equal(clientState, gotCs, "valid case: %s did not retrieve correct client state", tc.name)
s.Require().Equal(height, gotHeight, "valid case: %s did not retrieve correct upgrade height", tc.name)
s.Require().NoError(err, "valid case: %s returned error")
} else {
s.Require().Nil(gotCs, "invalid case: %s retrieved valid client state", tc.name)
s.Require().Equal(int64(0), gotHeight, "invalid case: %s retrieved valid upgrade height", tc.name)
s.Require().Error(err, "invalid case: %s did not return error", tc.name)
}
}

View File

@ -22,8 +22,14 @@ const (
// DoneByte is a prefix for to look up completed upgrade plan by name
DoneByte = 0x1
// KeyUpgradedClient is the key under which upgraded client is stored in the upgrade store
// KeyUpgradedIBCState is the key under which upgraded ibc state is stored in the upgrade store
KeyUpgradedIBCState = "upgradedIBCState"
// KeyUpgradedClient is the sub-key under which upgraded client state will be stored
KeyUpgradedClient = "upgradedClient"
// KeyUpgradedConsState is the sub-key under which upgraded consensus state will be stored
KeyUpgradedConsState = "upgradedConsState"
)
// PlanKey is the key under which the current plan is saved
@ -36,5 +42,12 @@ func PlanKey() []byte {
// Connecting IBC chains can verify against the upgraded client in this path before
// upgrading their clients
func UpgradedClientKey(height int64) []byte {
return []byte(fmt.Sprintf("%s/%d", KeyUpgradedClient, height))
return []byte(fmt.Sprintf("%s/%d/%s", KeyUpgradedIBCState, height, KeyUpgradedClient))
}
// UpgradedConsStateKey is the key under which the upgraded consensus state is saved
// Connecting IBC chains can verify against the upgraded consensus state in this path before
// upgrading their clients.
func UpgradedConsStateKey(height int64) []byte {
return []byte(fmt.Sprintf("%s/%d/%s", KeyUpgradedIBCState, height, KeyUpgradedConsState))
}

View File

@ -72,6 +72,11 @@ func (p Plan) DueAt() string {
return fmt.Sprintf("height: %d", p.Height)
}
// IsIBCPlan will return true if plan includes IBC client information
func (p Plan) IsIBCPlan() bool {
return p.UpgradedClientState != nil
}
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (p Plan) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
// UpgradedClientState may be nil

View File

@ -1,4 +1,4 @@
package types
package types_test
import (
"fmt"
@ -12,6 +12,7 @@ import (
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
"github.com/cosmos/cosmos-sdk/x/upgrade/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -29,11 +30,11 @@ func TestPlanString(t *testing.T) {
require.NoError(t, err)
cases := map[string]struct {
p Plan
p types.Plan
expect string
}{
"with time": {
p: Plan{
p: types.Plan{
Name: "due_time",
Info: "https://foo.bar",
Time: mustParseTime("2019-07-08T11:33:55Z"),
@ -41,7 +42,7 @@ func TestPlanString(t *testing.T) {
expect: "Upgrade Plan\n Name: due_time\n Time: 2019-07-08T11:33:55Z\n Info: https://foo.bar.\n Upgraded IBC Client: no upgraded client provided",
},
"with height": {
p: Plan{
p: types.Plan{
Name: "by height",
Info: "https://foo.bar/baz",
Height: 7890,
@ -49,7 +50,7 @@ func TestPlanString(t *testing.T) {
expect: "Upgrade Plan\n Name: by height\n Height: 7890\n Info: https://foo.bar/baz.\n Upgraded IBC Client: no upgraded client provided",
},
"with IBC client": {
p: Plan{
p: types.Plan{
Name: "by height",
Info: "https://foo.bar/baz",
Height: 7890,
@ -59,7 +60,7 @@ func TestPlanString(t *testing.T) {
},
"neither": {
p: Plan{
p: types.Plan{
Name: "almost-empty",
},
expect: "Upgrade Plan\n Name: almost-empty\n Height: 0\n Info: .\n Upgraded IBC Client: no upgraded client provided",
@ -80,11 +81,11 @@ func TestPlanValid(t *testing.T) {
require.NoError(t, err)
cases := map[string]struct {
p Plan
p types.Plan
valid bool
}{
"proper": {
p: Plan{
p: types.Plan{
Name: "all-good",
Info: "some text here",
Time: mustParseTime("2019-07-08T11:33:55Z"),
@ -92,7 +93,7 @@ func TestPlanValid(t *testing.T) {
valid: true,
},
"proper ibc upgrade": {
p: Plan{
p: types.Plan{
Name: "ibc-all-good",
Info: "some text here",
Height: 123450000,
@ -101,31 +102,31 @@ func TestPlanValid(t *testing.T) {
valid: true,
},
"proper by height": {
p: Plan{
p: types.Plan{
Name: "all-good",
Height: 123450000,
},
valid: true,
},
"no name": {
p: Plan{
p: types.Plan{
Height: 123450000,
},
},
"no due at": {
p: Plan{
p: types.Plan{
Name: "missing",
Info: "important",
},
},
"negative height": {
p: Plan{
p: types.Plan{
Name: "minus",
Height: -12345,
},
},
"time due date defined for IBC plan": {
p: Plan{
p: types.Plan{
Name: "ibc-all-good",
Info: "some text here",
Time: mustParseTime("2019-07-08T11:33:55Z"),
@ -151,13 +152,13 @@ func TestPlanValid(t *testing.T) {
func TestShouldExecute(t *testing.T) {
cases := map[string]struct {
p Plan
p types.Plan
ctxTime time.Time
ctxHeight int64
expected bool
}{
"past time": {
p: Plan{
p: types.Plan{
Name: "do-good",
Info: "some text here",
Time: mustParseTime("2019-07-08T11:33:55Z"),
@ -167,7 +168,7 @@ func TestShouldExecute(t *testing.T) {
expected: false,
},
"on time": {
p: Plan{
p: types.Plan{
Name: "do-good",
Time: mustParseTime("2019-07-08T11:33:55Z"),
},
@ -176,7 +177,7 @@ func TestShouldExecute(t *testing.T) {
expected: true,
},
"future time": {
p: Plan{
p: types.Plan{
Name: "do-good",
Time: mustParseTime("2019-07-08T11:33:55Z"),
},
@ -185,7 +186,7 @@ func TestShouldExecute(t *testing.T) {
expected: true,
},
"past height": {
p: Plan{
p: types.Plan{
Name: "do-good",
Height: 1234,
},
@ -194,7 +195,7 @@ func TestShouldExecute(t *testing.T) {
expected: false,
},
"on height": {
p: Plan{
p: types.Plan{
Name: "do-good",
Height: 1234,
},
@ -203,7 +204,7 @@ func TestShouldExecute(t *testing.T) {
expected: true,
},
"future height": {
p: Plan{
p: types.Plan{
Name: "do-good",
Height: 1234,
},

View File

@ -1,4 +1,4 @@
package types
package types_test
import (
"testing"
@ -8,6 +8,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
gov "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/upgrade/types"
)
type ProposalWrapper struct {
@ -23,7 +24,7 @@ func TestContentAccessors(t *testing.T) {
str string
}{
"upgrade": {
p: NewSoftwareUpgradeProposal("Title", "desc", Plan{
p: types.NewSoftwareUpgradeProposal("Title", "desc", types.Plan{
Name: "due_time",
Info: "https://foo.bar",
Time: mustParseTime("2019-07-08T11:33:55Z"),
@ -34,7 +35,7 @@ func TestContentAccessors(t *testing.T) {
str: "Software Upgrade Proposal:\n Title: Title\n Description: desc\n",
},
"cancel": {
p: NewCancelSoftwareUpgradeProposal("Cancel", "bad idea"),
p: types.NewCancelSoftwareUpgradeProposal("Cancel", "bad idea"),
title: "Cancel",
desc: "bad idea",
typ: "CancelSoftwareUpgrade",
@ -44,7 +45,7 @@ func TestContentAccessors(t *testing.T) {
cdc := codec.NewLegacyAmino()
gov.RegisterLegacyAminoCodec(cdc)
RegisterLegacyAminoCodec(cdc)
types.RegisterLegacyAminoCodec(cdc)
for name, tc := range cases {
tc := tc // copy to local variable for scopelint

View File

@ -6,6 +6,7 @@ package types
import (
context "context"
fmt "fmt"
types "github.com/cosmos/cosmos-sdk/codec/types"
grpc1 "github.com/gogo/protobuf/grpc"
proto "github.com/gogo/protobuf/proto"
_ "google.golang.org/genproto/googleapis/api/annotations"
@ -207,11 +208,107 @@ func (m *QueryAppliedPlanResponse) GetHeight() int64 {
return 0
}
// QueryUpgradedConsensusStateRequest is the request type for the Query/UpgradedConsensusState
// RPC method.
type QueryUpgradedConsensusStateRequest struct {
// last height of the current chain must be sent in request
// as this is the height under which next consensus state is stored
LastHeight int64 `protobuf:"varint,1,opt,name=last_height,json=lastHeight,proto3" json:"last_height,omitempty"`
}
func (m *QueryUpgradedConsensusStateRequest) Reset() { *m = QueryUpgradedConsensusStateRequest{} }
func (m *QueryUpgradedConsensusStateRequest) String() string { return proto.CompactTextString(m) }
func (*QueryUpgradedConsensusStateRequest) ProtoMessage() {}
func (*QueryUpgradedConsensusStateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_4a334d07ad8374f0, []int{4}
}
func (m *QueryUpgradedConsensusStateRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *QueryUpgradedConsensusStateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_QueryUpgradedConsensusStateRequest.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *QueryUpgradedConsensusStateRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_QueryUpgradedConsensusStateRequest.Merge(m, src)
}
func (m *QueryUpgradedConsensusStateRequest) XXX_Size() int {
return m.Size()
}
func (m *QueryUpgradedConsensusStateRequest) XXX_DiscardUnknown() {
xxx_messageInfo_QueryUpgradedConsensusStateRequest.DiscardUnknown(m)
}
var xxx_messageInfo_QueryUpgradedConsensusStateRequest proto.InternalMessageInfo
func (m *QueryUpgradedConsensusStateRequest) GetLastHeight() int64 {
if m != nil {
return m.LastHeight
}
return 0
}
// QueryUpgradedConsensusStateResponse is the response type for the Query/UpgradedConsensusState
// RPC method.
type QueryUpgradedConsensusStateResponse struct {
UpgradedConsensusState *types.Any `protobuf:"bytes,1,opt,name=upgraded_consensus_state,json=upgradedConsensusState,proto3" json:"upgraded_consensus_state,omitempty"`
}
func (m *QueryUpgradedConsensusStateResponse) Reset() { *m = QueryUpgradedConsensusStateResponse{} }
func (m *QueryUpgradedConsensusStateResponse) String() string { return proto.CompactTextString(m) }
func (*QueryUpgradedConsensusStateResponse) ProtoMessage() {}
func (*QueryUpgradedConsensusStateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_4a334d07ad8374f0, []int{5}
}
func (m *QueryUpgradedConsensusStateResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *QueryUpgradedConsensusStateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_QueryUpgradedConsensusStateResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *QueryUpgradedConsensusStateResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_QueryUpgradedConsensusStateResponse.Merge(m, src)
}
func (m *QueryUpgradedConsensusStateResponse) XXX_Size() int {
return m.Size()
}
func (m *QueryUpgradedConsensusStateResponse) XXX_DiscardUnknown() {
xxx_messageInfo_QueryUpgradedConsensusStateResponse.DiscardUnknown(m)
}
var xxx_messageInfo_QueryUpgradedConsensusStateResponse proto.InternalMessageInfo
func (m *QueryUpgradedConsensusStateResponse) GetUpgradedConsensusState() *types.Any {
if m != nil {
return m.UpgradedConsensusState
}
return nil
}
func init() {
proto.RegisterType((*QueryCurrentPlanRequest)(nil), "cosmos.upgrade.v1beta1.QueryCurrentPlanRequest")
proto.RegisterType((*QueryCurrentPlanResponse)(nil), "cosmos.upgrade.v1beta1.QueryCurrentPlanResponse")
proto.RegisterType((*QueryAppliedPlanRequest)(nil), "cosmos.upgrade.v1beta1.QueryAppliedPlanRequest")
proto.RegisterType((*QueryAppliedPlanResponse)(nil), "cosmos.upgrade.v1beta1.QueryAppliedPlanResponse")
proto.RegisterType((*QueryUpgradedConsensusStateRequest)(nil), "cosmos.upgrade.v1beta1.QueryUpgradedConsensusStateRequest")
proto.RegisterType((*QueryUpgradedConsensusStateResponse)(nil), "cosmos.upgrade.v1beta1.QueryUpgradedConsensusStateResponse")
}
func init() {
@ -219,30 +316,38 @@ func init() {
}
var fileDescriptor_4a334d07ad8374f0 = []byte{
// 362 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x3d, 0x4f, 0xfa, 0x40,
0x1c, 0xc7, 0x39, 0xfe, 0xfc, 0x49, 0x3c, 0xb6, 0x1b, 0x10, 0x09, 0x69, 0xcc, 0x85, 0x18, 0x13,
0xa1, 0xc7, 0xc3, 0x2b, 0x50, 0x13, 0x27, 0x07, 0x65, 0x74, 0x31, 0x07, 0xfc, 0x52, 0x1a, 0xcb,
0xdd, 0xd1, 0xbb, 0x1a, 0x89, 0x71, 0xf1, 0x15, 0x98, 0xb8, 0xbb, 0xf9, 0x5e, 0x1c, 0x49, 0x5c,
0x1c, 0x0d, 0xf8, 0x42, 0x0c, 0xd7, 0x62, 0x6a, 0xa0, 0xc1, 0xa9, 0x6d, 0xfa, 0x7d, 0xf8, 0xdc,
0xb7, 0xc5, 0x74, 0x20, 0xf5, 0x58, 0x6a, 0x16, 0x29, 0x2f, 0xe4, 0x43, 0x60, 0xb7, 0xed, 0x3e,
0x18, 0xde, 0x66, 0x93, 0x08, 0xc2, 0xa9, 0xab, 0x42, 0x69, 0x24, 0x29, 0xc7, 0x1a, 0x37, 0xd1,
0xb8, 0x89, 0xa6, 0x5a, 0xf3, 0xa4, 0xf4, 0x02, 0x60, 0x5c, 0xf9, 0x8c, 0x0b, 0x21, 0x0d, 0x37,
0xbe, 0x14, 0x3a, 0x76, 0x55, 0xeb, 0x19, 0xc9, 0xab, 0x14, 0xab, 0xa2, 0x7b, 0x78, 0xf7, 0x72,
0x59, 0x75, 0x1a, 0x85, 0x21, 0x08, 0x73, 0x11, 0x70, 0xd1, 0x83, 0x49, 0x04, 0xda, 0xd0, 0x73,
0x5c, 0x59, 0x7f, 0xa5, 0x95, 0x14, 0x1a, 0x48, 0x0b, 0x17, 0x54, 0xc0, 0x45, 0x05, 0xed, 0xa3,
0xc3, 0x52, 0xa7, 0xe6, 0x6e, 0x26, 0x74, 0xad, 0xc7, 0x2a, 0x69, 0x33, 0x29, 0x3a, 0x56, 0x2a,
0xf0, 0x61, 0x98, 0x2a, 0x22, 0x04, 0x17, 0x04, 0x1f, 0x83, 0x0d, 0xdb, 0xe9, 0xd9, 0x7b, 0xda,
0x49, 0xca, 0x7f, 0xc9, 0x93, 0xf2, 0x32, 0x2e, 0x8e, 0xc0, 0xf7, 0x46, 0xc6, 0x3a, 0xfe, 0xf5,
0x92, 0xa7, 0xce, 0x2c, 0x8f, 0xff, 0x5b, 0x13, 0x79, 0x41, 0xb8, 0x94, 0xc2, 0x26, 0x2c, 0x0b,
0x30, 0xe3, 0xec, 0xd5, 0xd6, 0xdf, 0x0d, 0x31, 0x14, 0x6d, 0x3c, 0xbe, 0x7f, 0x3d, 0xe7, 0x0f,
0x48, 0x9d, 0x65, 0xec, 0x3e, 0x88, 0x4d, 0xd7, 0xcb, 0x35, 0xc8, 0x2b, 0xc2, 0xa5, 0xd4, 0xd1,
0xb6, 0x00, 0xae, 0x6f, 0xb6, 0x05, 0x70, 0xc3, 0x6a, 0xb4, 0x6b, 0x01, 0x9b, 0xe4, 0x28, 0x0b,
0x90, 0xc7, 0x26, 0x0b, 0xc8, 0xee, 0x97, 0x5f, 0xe1, 0xe1, 0xe4, 0xec, 0x6d, 0xee, 0xa0, 0xd9,
0xdc, 0x41, 0x9f, 0x73, 0x07, 0x3d, 0x2d, 0x9c, 0xdc, 0x6c, 0xe1, 0xe4, 0x3e, 0x16, 0x4e, 0xee,
0xaa, 0xe1, 0xf9, 0x66, 0x14, 0xf5, 0xdd, 0x81, 0x1c, 0xaf, 0x02, 0xe3, 0x4b, 0x53, 0x0f, 0x6f,
0xd8, 0xdd, 0x4f, 0xba, 0x99, 0x2a, 0xd0, 0xfd, 0xa2, 0xfd, 0xdb, 0xba, 0xdf, 0x01, 0x00, 0x00,
0xff, 0xff, 0xca, 0xa9, 0x39, 0xfe, 0xef, 0x02, 0x00, 0x00,
// 487 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x41, 0x8b, 0x13, 0x31,
0x18, 0x6d, 0xb4, 0x2e, 0x98, 0xde, 0x82, 0xd4, 0x6e, 0x59, 0x46, 0x89, 0x8b, 0x08, 0x6e, 0x93,
0xdd, 0xee, 0x4d, 0x41, 0x5c, 0x17, 0x17, 0x0f, 0x22, 0x5a, 0xf1, 0xe2, 0xa5, 0xa4, 0x9d, 0x38,
0x1d, 0x9c, 0x26, 0xd9, 0x49, 0x22, 0x96, 0x65, 0x2f, 0xfe, 0x02, 0xc1, 0xbb, 0x37, 0x6f, 0xfe,
0x10, 0x8f, 0x0b, 0x5e, 0xf4, 0x26, 0xad, 0x3f, 0x44, 0x26, 0xc9, 0x48, 0x97, 0x76, 0x66, 0xc5,
0x53, 0x3b, 0x93, 0xf7, 0xbe, 0xf7, 0xbe, 0xbc, 0x37, 0x10, 0x8f, 0xa5, 0x9e, 0x4a, 0x4d, 0xad,
0x4a, 0x72, 0x16, 0x73, 0xfa, 0x6e, 0x6f, 0xc4, 0x0d, 0xdb, 0xa3, 0xc7, 0x96, 0xe7, 0x33, 0xa2,
0x72, 0x69, 0x24, 0x6a, 0x7b, 0x0c, 0x09, 0x18, 0x12, 0x30, 0xdd, 0xcd, 0x44, 0xca, 0x24, 0xe3,
0xd4, 0xa1, 0x46, 0xf6, 0x0d, 0x65, 0x22, 0x50, 0xba, 0x5b, 0xe1, 0x88, 0xa9, 0x94, 0x32, 0x21,
0xa4, 0x61, 0x26, 0x95, 0x42, 0x87, 0xd3, 0xed, 0x0a, 0xd1, 0x52, 0xc0, 0xa1, 0xf0, 0x26, 0xbc,
0xfe, 0xa2, 0x70, 0x71, 0x68, 0xf3, 0x9c, 0x0b, 0xf3, 0x3c, 0x63, 0x62, 0xc0, 0x8f, 0x2d, 0xd7,
0x06, 0x3f, 0x85, 0x9d, 0xd5, 0x23, 0xad, 0xa4, 0xd0, 0x1c, 0xed, 0xc2, 0xa6, 0xca, 0x98, 0xe8,
0x80, 0x9b, 0xe0, 0x4e, 0xab, 0xbf, 0x45, 0xd6, 0x9b, 0x27, 0x8e, 0xe3, 0x90, 0xb8, 0x17, 0x84,
0x0e, 0x94, 0xca, 0x52, 0x1e, 0x2f, 0x09, 0x21, 0x04, 0x9b, 0x82, 0x4d, 0xb9, 0x1b, 0x76, 0x75,
0xe0, 0xfe, 0xe3, 0x7e, 0x10, 0x3f, 0x07, 0x0f, 0xe2, 0x6d, 0xb8, 0x31, 0xe1, 0x69, 0x32, 0x31,
0x8e, 0x71, 0x79, 0x10, 0x9e, 0xf0, 0x63, 0x88, 0x1d, 0xe7, 0x95, 0x77, 0x11, 0x1f, 0x16, 0x68,
0xa1, 0xad, 0x7e, 0x69, 0x98, 0xe1, 0xa5, 0xda, 0x0d, 0xd8, 0xca, 0x98, 0x36, 0xc3, 0x73, 0x23,
0x60, 0xf1, 0xea, 0x89, 0x1f, 0x63, 0xe1, 0xad, 0xda, 0x31, 0xc1, 0xc5, 0x33, 0xd8, 0x09, 0xeb,
0xc6, 0xc3, 0x71, 0x09, 0x19, 0xea, 0x02, 0x13, 0xae, 0xe5, 0x1a, 0xf1, 0x01, 0x91, 0x32, 0x3b,
0x72, 0x20, 0x66, 0x83, 0xb6, 0x5d, 0x3b, 0xb7, 0xff, 0xb5, 0x09, 0xaf, 0x38, 0x5d, 0xf4, 0x19,
0xc0, 0xd6, 0xd2, 0xa5, 0x23, 0x5a, 0x75, 0xbd, 0x15, 0xc9, 0x75, 0x77, 0xff, 0x9d, 0xe0, 0x97,
0xc1, 0x3b, 0x1f, 0xbe, 0xff, 0xfe, 0x74, 0xe9, 0x36, 0xda, 0xa6, 0x15, 0xad, 0x19, 0x7b, 0xd2,
0xb0, 0xc8, 0x12, 0x7d, 0x01, 0xb0, 0xb5, 0x14, 0xcc, 0x05, 0x06, 0x57, 0x13, 0xbf, 0xc0, 0xe0,
0x9a, 0xcc, 0xf1, 0xbe, 0x33, 0xd8, 0x43, 0x77, 0xab, 0x0c, 0x32, 0x4f, 0x72, 0x06, 0xe9, 0x49,
0xd1, 0xa1, 0x53, 0xf4, 0x13, 0xc0, 0xf6, 0xfa, 0x14, 0xd1, 0xbd, 0x5a, 0x07, 0xb5, 0x0d, 0xea,
0xde, 0xff, 0x2f, 0x6e, 0x58, 0xe4, 0xc8, 0x2d, 0xf2, 0x10, 0x3d, 0xa0, 0xf5, 0xdf, 0xe7, 0x4a,
0xa9, 0xe8, 0xc9, 0x52, 0x6d, 0x4f, 0x1f, 0x1d, 0x7d, 0x9b, 0x47, 0xe0, 0x6c, 0x1e, 0x81, 0x5f,
0xf3, 0x08, 0x7c, 0x5c, 0x44, 0x8d, 0xb3, 0x45, 0xd4, 0xf8, 0xb1, 0x88, 0x1a, 0xaf, 0x77, 0x92,
0xd4, 0x4c, 0xec, 0x88, 0x8c, 0xe5, 0xb4, 0xd4, 0xf0, 0x3f, 0x3d, 0x1d, 0xbf, 0xa5, 0xef, 0xff,
0x0a, 0x9a, 0x99, 0xe2, 0x7a, 0xb4, 0xe1, 0xca, 0xb9, 0xff, 0x27, 0x00, 0x00, 0xff, 0xff, 0xee,
0x4b, 0xe2, 0xe8, 0xa4, 0x04, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -261,6 +366,11 @@ type QueryClient interface {
CurrentPlan(ctx context.Context, in *QueryCurrentPlanRequest, opts ...grpc.CallOption) (*QueryCurrentPlanResponse, error)
// AppliedPlan queries a previously applied upgrade plan by its name.
AppliedPlan(ctx context.Context, in *QueryAppliedPlanRequest, opts ...grpc.CallOption) (*QueryAppliedPlanResponse, error)
// UpgradedConsensusState queries the consensus state that will serve
// as a trusted kernel for the next version of this chain. It will only be
// stored at the last height of this chain.
// UpgradedConsensusState RPC not supported with legacy querier
UpgradedConsensusState(ctx context.Context, in *QueryUpgradedConsensusStateRequest, opts ...grpc.CallOption) (*QueryUpgradedConsensusStateResponse, error)
}
type queryClient struct {
@ -289,12 +399,26 @@ func (c *queryClient) AppliedPlan(ctx context.Context, in *QueryAppliedPlanReque
return out, nil
}
func (c *queryClient) UpgradedConsensusState(ctx context.Context, in *QueryUpgradedConsensusStateRequest, opts ...grpc.CallOption) (*QueryUpgradedConsensusStateResponse, error) {
out := new(QueryUpgradedConsensusStateResponse)
err := c.cc.Invoke(ctx, "/cosmos.upgrade.v1beta1.Query/UpgradedConsensusState", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// QueryServer is the server API for Query service.
type QueryServer interface {
// CurrentPlan queries the current upgrade plan.
CurrentPlan(context.Context, *QueryCurrentPlanRequest) (*QueryCurrentPlanResponse, error)
// AppliedPlan queries a previously applied upgrade plan by its name.
AppliedPlan(context.Context, *QueryAppliedPlanRequest) (*QueryAppliedPlanResponse, error)
// UpgradedConsensusState queries the consensus state that will serve
// as a trusted kernel for the next version of this chain. It will only be
// stored at the last height of this chain.
// UpgradedConsensusState RPC not supported with legacy querier
UpgradedConsensusState(context.Context, *QueryUpgradedConsensusStateRequest) (*QueryUpgradedConsensusStateResponse, error)
}
// UnimplementedQueryServer can be embedded to have forward compatible implementations.
@ -307,6 +431,9 @@ func (*UnimplementedQueryServer) CurrentPlan(ctx context.Context, req *QueryCurr
func (*UnimplementedQueryServer) AppliedPlan(ctx context.Context, req *QueryAppliedPlanRequest) (*QueryAppliedPlanResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AppliedPlan not implemented")
}
func (*UnimplementedQueryServer) UpgradedConsensusState(ctx context.Context, req *QueryUpgradedConsensusStateRequest) (*QueryUpgradedConsensusStateResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpgradedConsensusState not implemented")
}
func RegisterQueryServer(s grpc1.Server, srv QueryServer) {
s.RegisterService(&_Query_serviceDesc, srv)
@ -348,6 +475,24 @@ func _Query_AppliedPlan_Handler(srv interface{}, ctx context.Context, dec func(i
return interceptor(ctx, in, info, handler)
}
func _Query_UpgradedConsensusState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(QueryUpgradedConsensusStateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(QueryServer).UpgradedConsensusState(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cosmos.upgrade.v1beta1.Query/UpgradedConsensusState",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(QueryServer).UpgradedConsensusState(ctx, req.(*QueryUpgradedConsensusStateRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Query_serviceDesc = grpc.ServiceDesc{
ServiceName: "cosmos.upgrade.v1beta1.Query",
HandlerType: (*QueryServer)(nil),
@ -360,6 +505,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{
MethodName: "AppliedPlan",
Handler: _Query_AppliedPlan_Handler,
},
{
MethodName: "UpgradedConsensusState",
Handler: _Query_UpgradedConsensusState_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "cosmos/upgrade/v1beta1/query.proto",
@ -481,6 +630,69 @@ func (m *QueryAppliedPlanResponse) MarshalToSizedBuffer(dAtA []byte) (int, error
return len(dAtA) - i, nil
}
func (m *QueryUpgradedConsensusStateRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *QueryUpgradedConsensusStateRequest) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *QueryUpgradedConsensusStateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.LastHeight != 0 {
i = encodeVarintQuery(dAtA, i, uint64(m.LastHeight))
i--
dAtA[i] = 0x8
}
return len(dAtA) - i, nil
}
func (m *QueryUpgradedConsensusStateResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *QueryUpgradedConsensusStateResponse) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *QueryUpgradedConsensusStateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.UpgradedConsensusState != nil {
{
size, err := m.UpgradedConsensusState.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintQuery(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintQuery(dAtA []byte, offset int, v uint64) int {
offset -= sovQuery(v)
base := offset
@ -539,6 +751,31 @@ func (m *QueryAppliedPlanResponse) Size() (n int) {
return n
}
func (m *QueryUpgradedConsensusStateRequest) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.LastHeight != 0 {
n += 1 + sovQuery(uint64(m.LastHeight))
}
return n
}
func (m *QueryUpgradedConsensusStateResponse) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.UpgradedConsensusState != nil {
l = m.UpgradedConsensusState.Size()
n += 1 + l + sovQuery(uint64(l))
}
return n
}
func sovQuery(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
@ -844,6 +1081,167 @@ func (m *QueryAppliedPlanResponse) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *QueryUpgradedConsensusStateRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: QueryUpgradedConsensusStateRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: QueryUpgradedConsensusStateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field LastHeight", wireType)
}
m.LastHeight = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.LastHeight |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipQuery(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *QueryUpgradedConsensusStateResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: QueryUpgradedConsensusStateResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: QueryUpgradedConsensusStateResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field UpgradedConsensusState", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthQuery
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthQuery
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.UpgradedConsensusState == nil {
m.UpgradedConsensusState = &types.Any{}
}
if err := m.UpgradedConsensusState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipQuery(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipQuery(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0

View File

@ -103,6 +103,60 @@ func local_request_Query_AppliedPlan_0(ctx context.Context, marshaler runtime.Ma
}
func request_Query_UpgradedConsensusState_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryUpgradedConsensusStateRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["last_height"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "last_height")
}
protoReq.LastHeight, err = runtime.Int64(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "last_height", err)
}
msg, err := client.UpgradedConsensusState(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_UpgradedConsensusState_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryUpgradedConsensusStateRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["last_height"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "last_height")
}
protoReq.LastHeight, err = runtime.Int64(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "last_height", err)
}
msg, err := server.UpgradedConsensusState(ctx, &protoReq)
return msg, metadata, err
}
// RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
// UnaryRPC :call QueryServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
@ -149,6 +203,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
})
mux.Handle("GET", pattern_Query_UpgradedConsensusState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_UpgradedConsensusState_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_UpgradedConsensusState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@ -230,6 +304,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
})
mux.Handle("GET", pattern_Query_UpgradedConsensusState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_UpgradedConsensusState_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_UpgradedConsensusState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@ -237,10 +331,14 @@ var (
pattern_Query_CurrentPlan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "upgrade", "v1beta1", "current_plan"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_AppliedPlan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "upgrade", "v1beta1", "applied_plan", "name"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_UpgradedConsensusState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "upgrade", "v1beta1", "upgraded_consensus_state", "last_height"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_Query_CurrentPlan_0 = runtime.ForwardResponseMessage
forward_Query_AppliedPlan_0 = runtime.ForwardResponseMessage
forward_Query_UpgradedConsensusState_0 = runtime.ForwardResponseMessage
)