From 971d253214ba3aec8064e6260874a860cbfb3d99 Mon Sep 17 00:00:00 2001 From: Aditya Date: Mon, 7 Dec 2020 12:13:06 +0000 Subject: [PATCH] Implement Connection-specified delay (#8069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * start with initialization and metadata * start by fixing delay period during connection handshake * fix connection handshake tests * add delay period logic to packet verification * proto format * fix err issue * appease linter * document upgrade special case * Update x/ibc/light-clients/07-tendermint/types/client_state.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update x/ibc/light-clients/07-tendermint/types/store.go * add sanity check * fix build * fix tests Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Colin Axner --- proto/ibc/core/client/v1/genesis.proto | 27 +- proto/ibc/core/connection/v1/connection.proto | 12 +- proto/ibc/core/connection/v1/tx.proto | 18 +- x/ibc/core/02-client/genesis.go | 14 +- x/ibc/core/02-client/keeper/client.go | 12 +- x/ibc/core/02-client/keeper/keeper.go | 43 ++ x/ibc/core/02-client/keeper/keeper_test.go | 31 + x/ibc/core/02-client/types/errors.go | 39 +- x/ibc/core/02-client/types/genesis.go | 67 +- x/ibc/core/02-client/types/genesis.pb.go | 594 +++++++++++++++++- x/ibc/core/02-client/types/genesis_test.go | 97 ++- x/ibc/core/03-connection/client/cli/tx.go | 19 +- x/ibc/core/03-connection/genesis.go | 2 +- .../03-connection/keeper/grpc_query_test.go | 8 +- x/ibc/core/03-connection/keeper/handshake.go | 17 +- .../03-connection/keeper/handshake_test.go | 30 +- .../core/03-connection/keeper/keeper_test.go | 4 +- x/ibc/core/03-connection/keeper/verify.go | 4 + .../core/03-connection/keeper/verify_test.go | 64 +- x/ibc/core/03-connection/types/connection.go | 11 +- .../core/03-connection/types/connection.pb.go | 148 +++-- .../03-connection/types/connection_test.go | 14 +- .../core/03-connection/types/genesis_test.go | 12 +- x/ibc/core/03-connection/types/msgs.go | 8 +- x/ibc/core/03-connection/types/msgs_test.go | 50 +- x/ibc/core/03-connection/types/tx.pb.go | 215 ++++--- x/ibc/core/exported/client.go | 25 + x/ibc/core/exported/connection.go | 1 + x/ibc/core/genesis_test.go | 33 +- x/ibc/core/keeper/msg_server.go | 4 +- .../06-solomachine/types/client_state.go | 24 + .../06-solomachine/types/client_state_test.go | 60 +- .../06-solomachine/types/codec_test.go | 4 +- .../07-tendermint/types/client_state.go | 57 ++ .../07-tendermint/types/client_state_test.go | 109 +++- .../07-tendermint/types/consensus_state.go | 7 +- .../07-tendermint/types/errors.go | 10 +- .../07-tendermint/types/genesis.go | 21 + .../07-tendermint/types/genesis_test.go | 38 ++ .../07-tendermint/types/proposal_handle.go | 8 +- .../07-tendermint/types/store.go | 52 ++ .../07-tendermint/types/store_test.go | 37 ++ .../07-tendermint/types/update.go | 10 +- .../07-tendermint/types/upgrade.go | 2 + .../09-localhost/types/client_state.go | 21 + .../09-localhost/types/client_state_test.go | 47 +- x/ibc/testing/chain.go | 11 +- x/ibc/testing/coordinator.go | 29 +- 48 files changed, 1852 insertions(+), 318 deletions(-) create mode 100644 x/ibc/light-clients/07-tendermint/types/genesis.go create mode 100644 x/ibc/light-clients/07-tendermint/types/genesis_test.go diff --git a/proto/ibc/core/client/v1/genesis.proto b/proto/ibc/core/client/v1/genesis.proto index 06b4bbd0648..16febbceef8 100644 --- a/proto/ibc/core/client/v1/genesis.proto +++ b/proto/ibc/core/client/v1/genesis.proto @@ -17,9 +17,30 @@ message GenesisState { (gogoproto.castrepeated) = "ClientsConsensusStates", (gogoproto.moretags) = "yaml:\"clients_consensus\"" ]; - Params params = 3 [(gogoproto.nullable) = false]; + // metadata from each client + repeated IdentifiedGenesisMetadata clients_metadata = 3 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"clients_metadata\""]; + Params params = 4 [(gogoproto.nullable) = false]; // create localhost on initialization - bool create_localhost = 4 [(gogoproto.moretags) = "yaml:\"create_localhost\""]; + bool create_localhost = 5 [(gogoproto.moretags) = "yaml:\"create_localhost\""]; // the sequence for the next generated client identifier - uint64 next_client_sequence = 5 [(gogoproto.moretags) = "yaml:\"next_client_sequence\""]; + uint64 next_client_sequence = 6 [(gogoproto.moretags) = "yaml:\"next_client_sequence\""]; } + +// GenesisMetadata defines the genesis type for metadata that clients may return +// with ExportMetadata +message GenesisMetadata { + option (gogoproto.goproto_getters) = false; + + // store key of metadata without clientID-prefix + bytes key = 1; + // metadata value + bytes value = 2; +} + +// IdentifiedGenesisMetadata has the client metadata with the corresponding client id. +message IdentifiedGenesisMetadata { + string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + repeated GenesisMetadata client_metadata = 2 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_metadata\""]; +} \ No newline at end of file diff --git a/proto/ibc/core/connection/v1/connection.proto b/proto/ibc/core/connection/v1/connection.proto index 0cf4f2092eb..d21e5951653 100644 --- a/proto/ibc/core/connection/v1/connection.proto +++ b/proto/ibc/core/connection/v1/connection.proto @@ -10,19 +10,23 @@ import "ibc/core/commitment/v1/commitment.proto"; // https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures // ConnectionEnd defines a stateful object on a chain connected to another -// separate one. NOTE: there must only be 2 defined ConnectionEnds to establish +// separate one. +// NOTE: there must only be 2 defined ConnectionEnds to establish // a connection between two chains. message ConnectionEnd { option (gogoproto.goproto_getters) = false; // client associated with this connection. string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; // IBC version which can be utilised to determine encodings or protocols for - // channels or packets utilising this connection + // channels or packets utilising this connection. repeated Version versions = 2; // current state of the connection end. State state = 3; // counterparty chain associated with this connection. Counterparty counterparty = 4 [(gogoproto.nullable) = false]; + // delay period that must pass before a consensus state can be used for packet-verification + // NOTE: delay period logic is only implemented by some clients. + uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; } // IdentifiedConnection defines a connection with additional connection @@ -40,6 +44,8 @@ message IdentifiedConnection { State state = 4; // counterparty chain associated with this connection. Counterparty counterparty = 5 [(gogoproto.nullable) = false]; + // delay period associated with this connection. + uint64 delay_period = 6 [(gogoproto.moretags) = "yaml:\"delay_period\""]; } // State defines if a connection is in one of the following states: @@ -68,7 +74,7 @@ message Counterparty { // identifies the connection end on the counterparty chain associated with a // given connection. string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - // commitment merkle prefix of the counterparty chain + // commitment merkle prefix of the counterparty chain. ibc.core.commitment.v1.MerklePrefix prefix = 3 [(gogoproto.nullable) = false]; } diff --git a/proto/ibc/core/connection/v1/tx.proto b/proto/ibc/core/connection/v1/tx.proto index 21c283545d6..19b40c69c30 100644 --- a/proto/ibc/core/connection/v1/tx.proto +++ b/proto/ibc/core/connection/v1/tx.proto @@ -32,7 +32,8 @@ message MsgConnectionOpenInit { string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; Counterparty counterparty = 2 [(gogoproto.nullable) = false]; Version version = 3; - string signer = 4; + uint64 delay_period = 4 [(gogoproto.moretags) = "yaml:\"delay_period\""]; + string signer = 5; } // MsgConnectionOpenInitResponse defines the Msg/ConnectionOpenInit response type. @@ -50,19 +51,20 @@ message MsgConnectionOpenTry { string previous_connection_id = 2 [(gogoproto.moretags) = "yaml:\"previous_connection_id\""]; google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""]; Counterparty counterparty = 4 [(gogoproto.nullable) = false]; - repeated Version counterparty_versions = 5 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""]; - ibc.core.client.v1.Height proof_height = 6 + uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; + repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""]; + ibc.core.client.v1.Height proof_height = 7 [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; // proof of the initialization the connection on Chain A: `UNITIALIZED -> // INIT` - bytes proof_init = 7 [(gogoproto.moretags) = "yaml:\"proof_init\""]; + bytes proof_init = 8 [(gogoproto.moretags) = "yaml:\"proof_init\""]; // proof of client state included in message - bytes proof_client = 8 [(gogoproto.moretags) = "yaml:\"proof_client\""]; + bytes proof_client = 9 [(gogoproto.moretags) = "yaml:\"proof_client\""]; // proof of client consensus state - bytes proof_consensus = 9 [(gogoproto.moretags) = "yaml:\"proof_consensus\""]; - ibc.core.client.v1.Height consensus_height = 10 + bytes proof_consensus = 10 [(gogoproto.moretags) = "yaml:\"proof_consensus\""]; + ibc.core.client.v1.Height consensus_height = 11 [(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false]; - string signer = 11; + string signer = 12; } // MsgConnectionOpenTryResponse defines the Msg/ConnectionOpenTry response type. diff --git a/x/ibc/core/02-client/genesis.go b/x/ibc/core/02-client/genesis.go index 6e77b20e36f..26635f0784c 100644 --- a/x/ibc/core/02-client/genesis.go +++ b/x/ibc/core/02-client/genesis.go @@ -14,6 +14,12 @@ import ( func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) { k.SetParams(ctx, gs.Params) + // Set all client metadata first. This will allow client keeper to overwrite client and consensus state keys + // if clients accidentally write to ClientKeeper reserved keys. + if len(gs.ClientsMetadata) != 0 { + k.SetAllClientMetadata(ctx, gs.ClientsMetadata) + } + for _, client := range gs.Clients { cs, ok := client.ClientState.GetCachedValue().(exported.ClientState) if !ok { @@ -48,8 +54,14 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) { // NOTE: CreateLocalhost should always be false on export since a // created localhost will be included in the exported clients. func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { + genClients := k.GetAllGenesisClients(ctx) + clientsMetadata, err := k.GetAllClientMetadata(ctx, genClients) + if err != nil { + panic(err) + } return types.GenesisState{ - Clients: k.GetAllGenesisClients(ctx), + Clients: genClients, + ClientsMetadata: clientsMetadata, ClientsConsensus: k.GetAllConsensusStates(ctx), Params: k.GetParams(ctx), CreateLocalhost: false, diff --git a/x/ibc/core/02-client/keeper/client.go b/x/ibc/core/02-client/keeper/client.go index 49d5a04eb36..672dcf5d74d 100644 --- a/x/ibc/core/02-client/keeper/client.go +++ b/x/ibc/core/02-client/keeper/client.go @@ -12,8 +12,6 @@ import ( // CreateClient creates a new client state and populates it with a given consensus // state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create -// -// CONTRACT: ClientState was constructed correctly from given initial consensusState func (k Keeper) CreateClient( ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState, ) (string, error) { @@ -27,12 +25,20 @@ func (k Keeper) CreateClient( clientID := k.GenerateClientIdentifier(ctx, clientState.ClientType()) + k.SetClientState(ctx, clientID, clientState) + k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) + + // verifies initial consensus state against client state and initializes client store with any client-specific metadata + // e.g. set ProcessedTime in Tendermint clients + if err := clientState.Initialize(ctx, k.cdc, k.ClientStore(ctx, clientID), consensusState); err != nil { + return "", err + } + // check if consensus state is nil in case the created client is Localhost if consensusState != nil { k.SetClientConsensusState(ctx, clientID, clientState.GetLatestHeight(), consensusState) } - k.SetClientState(ctx, clientID, clientState) k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) defer func() { diff --git a/x/ibc/core/02-client/keeper/keeper.go b/x/ibc/core/02-client/keeper/keeper.go index bae7d3627cf..67c5c0658d4 100644 --- a/x/ibc/core/02-client/keeper/keeper.go +++ b/x/ibc/core/02-client/keeper/keeper.go @@ -152,6 +152,49 @@ func (k Keeper) GetAllGenesisClients(ctx sdk.Context) types.IdentifiedClientStat return genClients.Sort() } +// GetAllClientMetadata will take a list of IdentifiedClientState and return a list +// of IdentifiedGenesisMetadata necessary for exporting and importing client metadata +// into the client store. +func (k Keeper) GetAllClientMetadata(ctx sdk.Context, genClients []types.IdentifiedClientState) ([]types.IdentifiedGenesisMetadata, error) { + genMetadata := make([]types.IdentifiedGenesisMetadata, 0) + for _, ic := range genClients { + cs, err := types.UnpackClientState(ic.ClientState) + if err != nil { + return nil, err + } + gms := cs.ExportMetadata(k.ClientStore(ctx, ic.ClientId)) + if len(gms) == 0 { + continue + } + clientMetadata := make([]types.GenesisMetadata, len(gms)) + for i, metadata := range gms { + cmd, ok := metadata.(types.GenesisMetadata) + if !ok { + return nil, sdkerrors.Wrapf(types.ErrInvalidClientMetadata, "expected metadata type: %T, got: %T", + types.GenesisMetadata{}, cmd) + } + clientMetadata[i] = cmd + } + genMetadata = append(genMetadata, types.NewIdentifiedGenesisMetadata( + ic.ClientId, + clientMetadata, + )) + } + return genMetadata, nil +} + +// SetAllClientMetadata takes a list of IdentifiedGenesisMetadata and stores all of the metadata in the client store at the appropriate paths. +func (k Keeper) SetAllClientMetadata(ctx sdk.Context, genMetadata []types.IdentifiedGenesisMetadata) { + for _, igm := range genMetadata { + // create client store + store := k.ClientStore(ctx, igm.ClientId) + // set all metadata kv pairs in client store + for _, md := range igm.ClientMetadata { + store.Set(md.GetKey(), md.GetValue()) + } + } +} + // GetAllConsensusStates returns all stored client consensus states. func (k Keeper) GetAllConsensusStates(ctx sdk.Context) types.ClientsConsensusStates { clientConsStates := make(types.ClientsConsensusStates, 0) diff --git a/x/ibc/core/02-client/keeper/keeper_test.go b/x/ibc/core/02-client/keeper/keeper_test.go index ec3c0229ca5..c22e80cc9ec 100644 --- a/x/ibc/core/02-client/keeper/keeper_test.go +++ b/x/ibc/core/02-client/keeper/keeper_test.go @@ -258,6 +258,37 @@ func (suite KeeperTestSuite) TestGetAllGenesisClients() { suite.Require().Equal(expGenClients.Sort(), genClients) } +func (suite KeeperTestSuite) TestGetAllGenesisMetadata() { + expectedGenMetadata := []types.IdentifiedGenesisMetadata{ + types.NewIdentifiedGenesisMetadata( + "clientA", + []types.GenesisMetadata{ + types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(0, 1)), []byte("foo")), + types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(0, 2)), []byte("bar")), + types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(0, 3)), []byte("baz")), + }, + ), + types.NewIdentifiedGenesisMetadata( + "clientB", + []types.GenesisMetadata{ + types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(1, 100)), []byte("val1")), + types.NewGenesisMetadata(ibctmtypes.ProcessedTimeKey(types.NewHeight(2, 300)), []byte("val2")), + }, + ), + } + + genClients := []types.IdentifiedClientState{ + types.NewIdentifiedClientState("clientA", &ibctmtypes.ClientState{}), types.NewIdentifiedClientState("clientB", &ibctmtypes.ClientState{}), + types.NewIdentifiedClientState("clientC", &ibctmtypes.ClientState{}), types.NewIdentifiedClientState("clientD", &localhosttypes.ClientState{}), + } + + suite.chainA.App.IBCKeeper.ClientKeeper.SetAllClientMetadata(suite.chainA.GetContext(), expectedGenMetadata) + + actualGenMetadata, err := suite.chainA.App.IBCKeeper.ClientKeeper.GetAllClientMetadata(suite.chainA.GetContext(), genClients) + suite.Require().NoError(err, "get client metadata returned error unexpectedly") + suite.Require().Equal(expectedGenMetadata, actualGenMetadata, "retrieved metadata is unexpected") +} + func (suite KeeperTestSuite) TestGetConsensusState() { suite.ctx = suite.ctx.WithBlockHeight(10) cases := []struct { diff --git a/x/ibc/core/02-client/types/errors.go b/x/ibc/core/02-client/types/errors.go index ca0131823a1..09dc92959a2 100644 --- a/x/ibc/core/02-client/types/errors.go +++ b/x/ibc/core/02-client/types/errors.go @@ -10,23 +10,24 @@ var ( ErrInvalidClient = sdkerrors.Register(SubModuleName, 3, "light client is invalid") ErrClientNotFound = sdkerrors.Register(SubModuleName, 4, "light client not found") ErrClientFrozen = sdkerrors.Register(SubModuleName, 5, "light client is frozen due to misbehaviour") - ErrConsensusStateNotFound = sdkerrors.Register(SubModuleName, 6, "consensus state not found") - ErrInvalidConsensus = sdkerrors.Register(SubModuleName, 7, "invalid consensus state") - ErrClientTypeNotFound = sdkerrors.Register(SubModuleName, 8, "client type not found") - ErrInvalidClientType = sdkerrors.Register(SubModuleName, 9, "invalid client type") - ErrRootNotFound = sdkerrors.Register(SubModuleName, 10, "commitment root not found") - ErrInvalidHeader = sdkerrors.Register(SubModuleName, 11, "invalid client header") - ErrInvalidMisbehaviour = sdkerrors.Register(SubModuleName, 12, "invalid light client misbehaviour") - ErrFailedClientStateVerification = sdkerrors.Register(SubModuleName, 13, "client state verification failed") - ErrFailedClientConsensusStateVerification = sdkerrors.Register(SubModuleName, 14, "client consensus state verification failed") - ErrFailedConnectionStateVerification = sdkerrors.Register(SubModuleName, 15, "connection state verification failed") - ErrFailedChannelStateVerification = sdkerrors.Register(SubModuleName, 16, "channel state verification failed") - ErrFailedPacketCommitmentVerification = sdkerrors.Register(SubModuleName, 17, "packet commitment verification failed") - ErrFailedPacketAckVerification = sdkerrors.Register(SubModuleName, 18, "packet acknowledgement verification failed") - ErrFailedPacketReceiptVerification = sdkerrors.Register(SubModuleName, 19, "packet receipt verification failed") - ErrFailedNextSeqRecvVerification = sdkerrors.Register(SubModuleName, 20, "next sequence receive verification failed") - ErrSelfConsensusStateNotFound = sdkerrors.Register(SubModuleName, 21, "self consensus state not found") - ErrUpdateClientFailed = sdkerrors.Register(SubModuleName, 22, "unable to update light client") - ErrInvalidUpdateClientProposal = sdkerrors.Register(SubModuleName, 23, "invalid update client proposal") - ErrInvalidUpgradeClient = sdkerrors.Register(SubModuleName, 24, "invalid client upgrade") + ErrInvalidClientMetadata = sdkerrors.Register(SubModuleName, 6, "invalid client metadata") + ErrConsensusStateNotFound = sdkerrors.Register(SubModuleName, 7, "consensus state not found") + ErrInvalidConsensus = sdkerrors.Register(SubModuleName, 8, "invalid consensus state") + ErrClientTypeNotFound = sdkerrors.Register(SubModuleName, 9, "client type not found") + ErrInvalidClientType = sdkerrors.Register(SubModuleName, 10, "invalid client type") + ErrRootNotFound = sdkerrors.Register(SubModuleName, 11, "commitment root not found") + ErrInvalidHeader = sdkerrors.Register(SubModuleName, 12, "invalid client header") + ErrInvalidMisbehaviour = sdkerrors.Register(SubModuleName, 13, "invalid light client misbehaviour") + ErrFailedClientStateVerification = sdkerrors.Register(SubModuleName, 14, "client state verification failed") + ErrFailedClientConsensusStateVerification = sdkerrors.Register(SubModuleName, 15, "client consensus state verification failed") + ErrFailedConnectionStateVerification = sdkerrors.Register(SubModuleName, 16, "connection state verification failed") + ErrFailedChannelStateVerification = sdkerrors.Register(SubModuleName, 17, "channel state verification failed") + ErrFailedPacketCommitmentVerification = sdkerrors.Register(SubModuleName, 18, "packet commitment verification failed") + ErrFailedPacketAckVerification = sdkerrors.Register(SubModuleName, 19, "packet acknowledgement verification failed") + ErrFailedPacketReceiptVerification = sdkerrors.Register(SubModuleName, 20, "packet receipt verification failed") + ErrFailedNextSeqRecvVerification = sdkerrors.Register(SubModuleName, 21, "next sequence receive verification failed") + ErrSelfConsensusStateNotFound = sdkerrors.Register(SubModuleName, 22, "self consensus state not found") + ErrUpdateClientFailed = sdkerrors.Register(SubModuleName, 23, "unable to update light client") + ErrInvalidUpdateClientProposal = sdkerrors.Register(SubModuleName, 24, "invalid update client proposal") + ErrInvalidUpgradeClient = sdkerrors.Register(SubModuleName, 25, "invalid client upgrade") ) diff --git a/x/ibc/core/02-client/types/genesis.go b/x/ibc/core/02-client/types/genesis.go index 18f33160c28..3f197208e33 100644 --- a/x/ibc/core/02-client/types/genesis.go +++ b/x/ibc/core/02-client/types/genesis.go @@ -16,7 +16,10 @@ var ( _ codectypes.UnpackInterfacesMessage = GenesisState{} ) -var _ sort.Interface = ClientsConsensusStates{} +var ( + _ sort.Interface = ClientsConsensusStates{} + _ exported.GenesisMetadata = GenesisMetadata{} +) // ClientsConsensusStates defines a slice of ClientConsensusStates that supports the sort interface type ClientsConsensusStates []ClientConsensusStates @@ -66,12 +69,13 @@ func (ccs ClientConsensusStates) UnpackInterfaces(unpacker codectypes.AnyUnpacke // NewGenesisState creates a GenesisState instance. func NewGenesisState( - clients []IdentifiedClientState, clientsConsensus ClientsConsensusStates, + clients []IdentifiedClientState, clientsConsensus ClientsConsensusStates, clientsMetadata []IdentifiedGenesisMetadata, params Params, createLocalhost bool, nextClientSequence uint64, ) GenesisState { return GenesisState{ Clients: clients, ClientsConsensus: clientsConsensus, + ClientsMetadata: clientsMetadata, Params: params, CreateLocalhost: createLocalhost, NextClientSequence: nextClientSequence, @@ -151,14 +155,14 @@ func (gs GenesisState) Validate() error { validClients[client.ClientId] = clientState.ClientType() } - for i, cc := range gs.ClientsConsensus { + for _, cc := range gs.ClientsConsensus { // check that consensus state is for a client in the genesis clients list clientType, ok := validClients[cc.ClientId] if !ok { return fmt.Errorf("consensus state in genesis has a client id %s that does not map to a genesis client", cc.ClientId) } - for _, consensusState := range cc.ConsensusStates { + for i, consensusState := range cc.ConsensusStates { if consensusState.Height.IsZero() { return fmt.Errorf("consensus state height cannot be zero") } @@ -169,7 +173,7 @@ func (gs GenesisState) Validate() error { } if err := cs.ValidateBasic(); err != nil { - return fmt.Errorf("invalid client consensus state %v index %d: %w", cs, i, err) + return fmt.Errorf("invalid client consensus state %v clientID %s index %d: %w", cs, cc.ClientId, i, err) } // ensure consensus state type matches client state type @@ -178,6 +182,21 @@ func (gs GenesisState) Validate() error { } } + } + + for _, clientMetadata := range gs.ClientsMetadata { + // check that metadata is for a client in the genesis clients list + _, ok := validClients[clientMetadata.ClientId] + if !ok { + return fmt.Errorf("metadata in genesis has a client id %s that does not map to a genesis client", clientMetadata.ClientId) + } + + for i, gm := range clientMetadata.ClientMetadata { + if err := gm.Validate(); err != nil { + return fmt.Errorf("invalid client metadata %v clientID %s index %d: %w", gm, clientMetadata.ClientId, i, err) + } + + } } @@ -191,3 +210,41 @@ func (gs GenesisState) Validate() error { return nil } + +// NewGenesisMetadata is a constructor for GenesisMetadata +func NewGenesisMetadata(key, val []byte) GenesisMetadata { + return GenesisMetadata{ + Key: key, + Value: val, + } +} + +// GetKey returns the key of metadata. Implements exported.GenesisMetadata interface. +func (gm GenesisMetadata) GetKey() []byte { + return gm.Key +} + +// GetValue returns the value of metadata. Implements exported.GenesisMetadata interface. +func (gm GenesisMetadata) GetValue() []byte { + return gm.Value +} + +// Validate ensures key and value of metadata are not empty +func (gm GenesisMetadata) Validate() error { + if len(gm.Key) == 0 { + return fmt.Errorf("genesis metadata key cannot be empty") + } + if len(gm.Value) == 0 { + return fmt.Errorf("genesis metadata value cannot be empty") + } + return nil +} + +// NewIdentifiedGenesisMetadata takes in a client ID and list of genesis metadata for that client +// and constructs a new IdentifiedGenesisMetadata. +func NewIdentifiedGenesisMetadata(clientID string, gms []GenesisMetadata) IdentifiedGenesisMetadata { + return IdentifiedGenesisMetadata{ + ClientId: clientID, + ClientMetadata: gms, + } +} diff --git a/x/ibc/core/02-client/types/genesis.pb.go b/x/ibc/core/02-client/types/genesis.pb.go index becfa1baba1..07f996ac203 100644 --- a/x/ibc/core/02-client/types/genesis.pb.go +++ b/x/ibc/core/02-client/types/genesis.pb.go @@ -29,11 +29,13 @@ type GenesisState struct { Clients IdentifiedClientStates `protobuf:"bytes,1,rep,name=clients,proto3,castrepeated=IdentifiedClientStates" json:"clients"` // consensus states from each client ClientsConsensus ClientsConsensusStates `protobuf:"bytes,2,rep,name=clients_consensus,json=clientsConsensus,proto3,castrepeated=ClientsConsensusStates" json:"clients_consensus" yaml:"clients_consensus"` - Params Params `protobuf:"bytes,3,opt,name=params,proto3" json:"params"` + // metadata from each client + ClientsMetadata []IdentifiedGenesisMetadata `protobuf:"bytes,3,rep,name=clients_metadata,json=clientsMetadata,proto3" json:"clients_metadata" yaml:"clients_metadata"` + Params Params `protobuf:"bytes,4,opt,name=params,proto3" json:"params"` // create localhost on initialization - CreateLocalhost bool `protobuf:"varint,4,opt,name=create_localhost,json=createLocalhost,proto3" json:"create_localhost,omitempty" yaml:"create_localhost"` + CreateLocalhost bool `protobuf:"varint,5,opt,name=create_localhost,json=createLocalhost,proto3" json:"create_localhost,omitempty" yaml:"create_localhost"` // the sequence for the next generated client identifier - NextClientSequence uint64 `protobuf:"varint,5,opt,name=next_client_sequence,json=nextClientSequence,proto3" json:"next_client_sequence,omitempty" yaml:"next_client_sequence"` + NextClientSequence uint64 `protobuf:"varint,6,opt,name=next_client_sequence,json=nextClientSequence,proto3" json:"next_client_sequence,omitempty" yaml:"next_client_sequence"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -83,6 +85,13 @@ func (m *GenesisState) GetClientsConsensus() ClientsConsensusStates { return nil } +func (m *GenesisState) GetClientsMetadata() []IdentifiedGenesisMetadata { + if m != nil { + return m.ClientsMetadata + } + return nil +} + func (m *GenesisState) GetParams() Params { if m != nil { return m.Params @@ -104,39 +113,145 @@ func (m *GenesisState) GetNextClientSequence() uint64 { return 0 } +// GenesisMetadata defines the genesis type for metadata that clients may return +// with ExportMetadata +type GenesisMetadata struct { + // store key of metadata without clientID-prefix + Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // metadata value + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *GenesisMetadata) Reset() { *m = GenesisMetadata{} } +func (m *GenesisMetadata) String() string { return proto.CompactTextString(m) } +func (*GenesisMetadata) ProtoMessage() {} +func (*GenesisMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_bcd0c0f1f2e6a91a, []int{1} +} +func (m *GenesisMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisMetadata.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 *GenesisMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisMetadata.Merge(m, src) +} +func (m *GenesisMetadata) XXX_Size() int { + return m.Size() +} +func (m *GenesisMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisMetadata proto.InternalMessageInfo + +// IdentifiedGenesisMetadata has the client metadata with the corresponding client id. +type IdentifiedGenesisMetadata struct { + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` + ClientMetadata []GenesisMetadata `protobuf:"bytes,2,rep,name=client_metadata,json=clientMetadata,proto3" json:"client_metadata" yaml:"client_metadata"` +} + +func (m *IdentifiedGenesisMetadata) Reset() { *m = IdentifiedGenesisMetadata{} } +func (m *IdentifiedGenesisMetadata) String() string { return proto.CompactTextString(m) } +func (*IdentifiedGenesisMetadata) ProtoMessage() {} +func (*IdentifiedGenesisMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_bcd0c0f1f2e6a91a, []int{2} +} +func (m *IdentifiedGenesisMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IdentifiedGenesisMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IdentifiedGenesisMetadata.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 *IdentifiedGenesisMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_IdentifiedGenesisMetadata.Merge(m, src) +} +func (m *IdentifiedGenesisMetadata) XXX_Size() int { + return m.Size() +} +func (m *IdentifiedGenesisMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_IdentifiedGenesisMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_IdentifiedGenesisMetadata proto.InternalMessageInfo + +func (m *IdentifiedGenesisMetadata) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + +func (m *IdentifiedGenesisMetadata) GetClientMetadata() []GenesisMetadata { + if m != nil { + return m.ClientMetadata + } + return nil +} + func init() { proto.RegisterType((*GenesisState)(nil), "ibc.core.client.v1.GenesisState") + proto.RegisterType((*GenesisMetadata)(nil), "ibc.core.client.v1.GenesisMetadata") + proto.RegisterType((*IdentifiedGenesisMetadata)(nil), "ibc.core.client.v1.IdentifiedGenesisMetadata") } func init() { proto.RegisterFile("ibc/core/client/v1/genesis.proto", fileDescriptor_bcd0c0f1f2e6a91a) } var fileDescriptor_bcd0c0f1f2e6a91a = []byte{ - // 400 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x8e, 0x9a, 0x40, - 0x1c, 0xc6, 0x99, 0x6a, 0x6d, 0x83, 0x4d, 0x6a, 0x27, 0xa6, 0x25, 0x9a, 0x00, 0xe1, 0x44, 0x0f, - 0x32, 0xd5, 0x1e, 0xda, 0x78, 0xc4, 0xa4, 0x4d, 0x93, 0x1e, 0x2a, 0xbd, 0xf5, 0x42, 0x60, 0x9c, - 0x22, 0x29, 0x30, 0x96, 0x19, 0x8d, 0xbe, 0xc5, 0x66, 0x1f, 0x63, 0x9f, 0xc4, 0xa3, 0xc7, 0xbd, - 0x2c, 0xbb, 0xd1, 0x37, 0xf0, 0x09, 0x36, 0x30, 0xe3, 0x1e, 0x94, 0x3d, 0xf1, 0xcf, 0x37, 0xbf, - 0xef, 0xfb, 0xfe, 0x21, 0x7f, 0xd5, 0x8c, 0x43, 0x8c, 0x30, 0xcd, 0x09, 0xc2, 0x49, 0x4c, 0x32, - 0x8e, 0x56, 0x43, 0x14, 0x91, 0x8c, 0xb0, 0x98, 0x39, 0x8b, 0x9c, 0x72, 0x0a, 0x61, 0x1c, 0x62, - 0xa7, 0x24, 0x1c, 0x41, 0x38, 0xab, 0x61, 0xcf, 0xa8, 0x71, 0xc9, 0xd7, 0xca, 0xd4, 0xeb, 0x46, - 0x34, 0xa2, 0xd5, 0x88, 0xca, 0x49, 0xa8, 0xd6, 0x5d, 0x43, 0x7d, 0xf3, 0x5d, 0x84, 0xff, 0xe6, - 0x01, 0x27, 0x10, 0xab, 0xaf, 0x84, 0x8d, 0x69, 0xc0, 0x6c, 0xd8, 0xed, 0xd1, 0x47, 0xe7, 0xb2, - 0xcd, 0xf9, 0x31, 0x23, 0x19, 0x8f, 0xff, 0xc6, 0x64, 0x36, 0xa9, 0xb4, 0xca, 0xeb, 0xea, 0xdb, - 0xc2, 0x50, 0x6e, 0xee, 0x8d, 0xf7, 0xb5, 0xcf, 0xcc, 0x3b, 0x25, 0xc3, 0x6b, 0xa0, 0xbe, 0x93, - 0xb3, 0x8f, 0x69, 0xc6, 0x48, 0xc6, 0x96, 0x4c, 0x7b, 0xf1, 0x7c, 0x9f, 0x88, 0x99, 0x9c, 0x50, - 0x91, 0xe7, 0x8e, 0xcb, 0xbe, 0x63, 0x61, 0x68, 0x9b, 0x20, 0x4d, 0xc6, 0xd6, 0x45, 0xa2, 0x55, - 0xee, 0x22, 0xac, 0xec, 0xcc, 0xeb, 0x75, 0xf0, 0x99, 0x0e, 0xbf, 0xaa, 0xad, 0x45, 0x90, 0x07, - 0x29, 0xd3, 0x1a, 0x26, 0xb0, 0xdb, 0xa3, 0x5e, 0xdd, 0x22, 0xbf, 0x2a, 0xc2, 0x6d, 0x96, 0xcd, - 0x9e, 0xe4, 0xe1, 0x37, 0xb5, 0x83, 0x73, 0x12, 0x70, 0xe2, 0x27, 0x14, 0x07, 0xc9, 0x9c, 0x32, - 0xae, 0x35, 0x4d, 0x60, 0xbf, 0x76, 0xfb, 0xc7, 0xc2, 0xf8, 0x20, 0xb7, 0x3b, 0x23, 0x2c, 0xef, - 0xad, 0x90, 0x7e, 0x9e, 0x14, 0x38, 0x55, 0xbb, 0x19, 0x59, 0x73, 0x5f, 0xd4, 0xf9, 0x8c, 0xfc, - 0x5f, 0x92, 0x0c, 0x13, 0xed, 0xa5, 0x09, 0xec, 0xa6, 0x6b, 0x1c, 0x0b, 0xa3, 0x2f, 0xb2, 0xea, - 0x28, 0xcb, 0x83, 0xa5, 0x2c, 0x7f, 0xb8, 0x14, 0xdd, 0xe9, 0x76, 0xaf, 0x83, 0xdd, 0x5e, 0x07, - 0x0f, 0x7b, 0x1d, 0x5c, 0x1d, 0x74, 0x65, 0x77, 0xd0, 0x95, 0xdb, 0x83, 0xae, 0xfc, 0xf9, 0x12, - 0xc5, 0x7c, 0xbe, 0x0c, 0x1d, 0x4c, 0x53, 0x84, 0x29, 0x4b, 0x29, 0x93, 0x9f, 0x01, 0x9b, 0xfd, - 0x43, 0x6b, 0xf4, 0x74, 0x4f, 0x9f, 0x46, 0x03, 0x79, 0x52, 0x7c, 0xb3, 0x20, 0x2c, 0x6c, 0x55, - 0x97, 0xf3, 0xf9, 0x31, 0x00, 0x00, 0xff, 0xff, 0x7c, 0xcd, 0xe7, 0x85, 0xa8, 0x02, 0x00, 0x00, + // 535 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0x4d, 0x6e, 0xd3, 0x40, + 0x14, 0xce, 0x34, 0x69, 0x68, 0xa7, 0x15, 0x0d, 0xa3, 0xa8, 0x98, 0x54, 0xb2, 0x2d, 0xb3, 0x09, + 0x8b, 0xd8, 0x24, 0x2c, 0x40, 0xd9, 0x20, 0xb9, 0x12, 0xa8, 0x12, 0x48, 0xd4, 0xec, 0xd8, 0x58, + 0x93, 0xf1, 0x90, 0x5a, 0x75, 0x3c, 0x21, 0x33, 0x89, 0x9a, 0x1b, 0xb0, 0x44, 0x9c, 0x80, 0x35, + 0x67, 0xe0, 0x00, 0x5d, 0x76, 0xd9, 0x55, 0x40, 0xc9, 0x0d, 0x72, 0x02, 0xe4, 0x99, 0x71, 0x7f, + 0x5c, 0xb7, 0xab, 0xbc, 0x7c, 0xf3, 0x7d, 0xdf, 0x7b, 0xfa, 0x9e, 0x1f, 0xb4, 0xe3, 0x01, 0xf1, + 0x08, 0x9b, 0x50, 0x8f, 0x24, 0x31, 0x4d, 0x85, 0x37, 0xeb, 0x7a, 0x43, 0x9a, 0x52, 0x1e, 0x73, + 0x77, 0x3c, 0x61, 0x82, 0x21, 0x14, 0x0f, 0x88, 0x9b, 0x31, 0x5c, 0xc5, 0x70, 0x67, 0xdd, 0x96, + 0x55, 0xa2, 0xd2, 0xaf, 0x52, 0xd4, 0x6a, 0x0e, 0xd9, 0x90, 0xc9, 0xd2, 0xcb, 0x2a, 0x85, 0x3a, + 0x97, 0x35, 0xb8, 0xfb, 0x5e, 0x99, 0x7f, 0x16, 0x58, 0x50, 0x44, 0xe0, 0x23, 0x25, 0xe3, 0x06, + 0xb0, 0xab, 0xed, 0x9d, 0xde, 0x0b, 0xf7, 0x6e, 0x37, 0xf7, 0x28, 0xa2, 0xa9, 0x88, 0xbf, 0xc6, + 0x34, 0x3a, 0x94, 0x98, 0xd4, 0xfa, 0xe6, 0xf9, 0xc2, 0xaa, 0xfc, 0xfe, 0x6b, 0xed, 0x97, 0x3e, + 0xf3, 0x20, 0x77, 0x46, 0x3f, 0x01, 0x7c, 0xa2, 0xeb, 0x90, 0xb0, 0x94, 0xd3, 0x94, 0x4f, 0xb9, + 0xb1, 0x71, 0x7f, 0x3f, 0x65, 0x73, 0x98, 0x53, 0x95, 0x9f, 0xdf, 0xcf, 0xfa, 0xad, 0x17, 0x96, + 0x31, 0xc7, 0xa3, 0xa4, 0xef, 0xdc, 0x71, 0x74, 0xb2, 0x59, 0x94, 0x94, 0x17, 0xb4, 0x41, 0x83, + 0x14, 0x70, 0x34, 0x87, 0x39, 0x16, 0x8e, 0xa8, 0xc0, 0x11, 0x16, 0xd8, 0xa8, 0xca, 0x91, 0x3a, + 0x0f, 0x47, 0xa0, 0xf3, 0xfb, 0xa8, 0x45, 0xbe, 0xa5, 0xc7, 0x7a, 0x7a, 0x7b, 0xac, 0xdc, 0xd4, + 0x09, 0xf6, 0x34, 0x94, 0x2b, 0xd0, 0x1b, 0x58, 0x1f, 0xe3, 0x09, 0x1e, 0x71, 0xa3, 0x66, 0x83, + 0xf6, 0x4e, 0xaf, 0x55, 0xd6, 0xf0, 0x93, 0x64, 0xf8, 0xb5, 0xcc, 0x3d, 0xd0, 0x7c, 0xf4, 0x0e, + 0x36, 0xc8, 0x84, 0x62, 0x41, 0xc3, 0x84, 0x11, 0x9c, 0x9c, 0x30, 0x2e, 0x8c, 0x4d, 0x1b, 0xb4, + 0xb7, 0xfc, 0x83, 0x1b, 0x13, 0x14, 0x18, 0xd9, 0x04, 0x12, 0xfa, 0x90, 0x23, 0xe8, 0x18, 0x36, + 0x53, 0x7a, 0x26, 0x42, 0xd5, 0x2e, 0xe4, 0xf4, 0xdb, 0x94, 0xa6, 0x84, 0x1a, 0x75, 0x1b, 0xb4, + 0x6b, 0xbe, 0xb5, 0x5e, 0x58, 0x07, 0xca, 0xab, 0x8c, 0xe5, 0x04, 0x28, 0x83, 0xf5, 0xae, 0x73, + 0xf0, 0x2d, 0xdc, 0x2b, 0x24, 0x83, 0x1a, 0xb0, 0x7a, 0x4a, 0xe7, 0x06, 0xb0, 0x41, 0x7b, 0x37, + 0xc8, 0x4a, 0xd4, 0x84, 0x9b, 0x33, 0x9c, 0x4c, 0xa9, 0xb1, 0x21, 0x31, 0xf5, 0xa7, 0x5f, 0xfb, + 0xfe, 0xcb, 0xaa, 0x38, 0x7f, 0x00, 0x7c, 0x76, 0x6f, 0xca, 0xa8, 0x0b, 0xb7, 0xf5, 0x18, 0x71, + 0x24, 0x1d, 0xb7, 0xfd, 0xe6, 0x7a, 0x61, 0x35, 0x6e, 0x86, 0x1e, 0xc6, 0x91, 0x13, 0x6c, 0xa9, + 0xfa, 0x28, 0x42, 0x09, 0xd4, 0xc9, 0x5f, 0x2f, 0x58, 0x7d, 0x73, 0xcf, 0xcb, 0xf2, 0x2e, 0xae, + 0xd5, 0xd4, 0x6b, 0xdd, 0xbf, 0xd5, 0xe1, 0x7a, 0xab, 0x8f, 0x15, 0x72, 0xc5, 0x3f, 0x3e, 0x5f, + 0x9a, 0xe0, 0x62, 0x69, 0x82, 0x7f, 0x4b, 0x13, 0xfc, 0x58, 0x99, 0x95, 0x8b, 0x95, 0x59, 0xb9, + 0x5c, 0x99, 0x95, 0x2f, 0xaf, 0x87, 0xb1, 0x38, 0x99, 0x0e, 0x5c, 0xc2, 0x46, 0x1e, 0x61, 0x7c, + 0xc4, 0xb8, 0xfe, 0xe9, 0xf0, 0xe8, 0xd4, 0x3b, 0xf3, 0xae, 0x4e, 0xf9, 0x65, 0xaf, 0xa3, 0xaf, + 0x59, 0xcc, 0xc7, 0x94, 0x0f, 0xea, 0xf2, 0x68, 0x5f, 0xfd, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x61, + 0x6f, 0x94, 0xed, 0x23, 0x04, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -162,7 +277,7 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.NextClientSequence != 0 { i = encodeVarintGenesis(dAtA, i, uint64(m.NextClientSequence)) i-- - dAtA[i] = 0x28 + dAtA[i] = 0x30 } if m.CreateLocalhost { i-- @@ -172,7 +287,7 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0 } i-- - dAtA[i] = 0x20 + dAtA[i] = 0x28 } { size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) @@ -183,7 +298,21 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 + if len(m.ClientsMetadata) > 0 { + for iNdEx := len(m.ClientsMetadata) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ClientsMetadata[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } if len(m.ClientsConsensus) > 0 { for iNdEx := len(m.ClientsConsensus) - 1; iNdEx >= 0; iNdEx-- { { @@ -215,6 +344,87 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *GenesisMetadata) 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 *GenesisMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *IdentifiedGenesisMetadata) 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 *IdentifiedGenesisMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IdentifiedGenesisMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ClientMetadata) > 0 { + for iNdEx := len(m.ClientMetadata) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ClientMetadata[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -244,6 +454,12 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.ClientsMetadata) > 0 { + for _, e := range m.ClientsMetadata { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } l = m.Params.Size() n += 1 + l + sovGenesis(uint64(l)) if m.CreateLocalhost { @@ -255,6 +471,42 @@ func (m *GenesisState) Size() (n int) { return n } +func (m *GenesisMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *IdentifiedGenesisMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if len(m.ClientMetadata) > 0 { + for _, e := range m.ClientMetadata { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + func sovGenesis(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -359,6 +611,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientsMetadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientsMetadata = append(m.ClientsMetadata, IdentifiedGenesisMetadata{}) + if err := m.ClientsMetadata[len(m.ClientsMetadata)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) } @@ -391,7 +677,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 4: + case 5: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field CreateLocalhost", wireType) } @@ -411,7 +697,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } } m.CreateLocalhost = bool(v != 0) - case 5: + case 6: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field NextClientSequence", wireType) } @@ -454,6 +740,246 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } return nil } +func (m *GenesisMetadata) 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 ErrIntOverflowGenesis + } + 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: GenesisMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *IdentifiedGenesisMetadata) 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 ErrIntOverflowGenesis + } + 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: IdentifiedGenesisMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IdentifiedGenesisMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientMetadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientMetadata = append(m.ClientMetadata, GenesisMetadata{}) + if err := m.ClientMetadata[len(m.ClientMetadata)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipGenesis(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ibc/core/02-client/types/genesis_test.go b/x/ibc/core/02-client/types/genesis_test.go index 12cfba69dd4..d57b8d1ba53 100644 --- a/x/ibc/core/02-client/types/genesis_test.go +++ b/x/ibc/core/02-client/types/genesis_test.go @@ -91,6 +91,15 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + []types.IdentifiedGenesisMetadata{ + types.NewIdentifiedGenesisMetadata( + clientID, + []types.GenesisMetadata{ + types.NewGenesisMetadata([]byte("key1"), []byte("val1")), + types.NewGenesisMetadata([]byte("key2"), []byte("val2")), + }, + ), + }, types.NewParams(exported.Tendermint, exported.Localhost), false, 2, @@ -121,6 +130,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Tendermint), false, 0, @@ -137,6 +147,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { types.NewIdentifiedClientState(exported.Localhost, localhosttypes.NewClientState("chaindID", types.ZeroHeight())), }, nil, + nil, types.NewParams(exported.Tendermint), false, 0, @@ -159,7 +170,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { tmClientID1, []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight( - types.ZeroHeight(), + types.NewHeight(0, 1), ibctmtypes.NewConsensusState( header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, ), @@ -167,6 +178,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Tendermint), false, 0, @@ -197,6 +209,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Tendermint), false, 0, @@ -227,6 +240,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Tendermint), false, 0, @@ -257,12 +271,87 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Solomachine), false, 0, ), expPass: false, }, + { + name: "metadata client-id does not match a genesis client", + genState: types.NewGenesisState( + []types.IdentifiedClientState{ + types.NewIdentifiedClientState( + clientID, ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ), + types.NewIdentifiedClientState( + exported.Localhost, localhosttypes.NewClientState("chainID", clientHeight), + ), + }, + []types.ClientConsensusStates{ + types.NewClientConsensusStates( + clientID, + []types.ConsensusStateWithHeight{ + types.NewConsensusStateWithHeight( + header.GetHeight().(types.Height), + ibctmtypes.NewConsensusState( + header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, + ), + ), + }, + ), + }, + []types.IdentifiedGenesisMetadata{ + types.NewIdentifiedGenesisMetadata( + "wrongclientid", + []types.GenesisMetadata{ + types.NewGenesisMetadata([]byte("key1"), []byte("val1")), + types.NewGenesisMetadata([]byte("key2"), []byte("val2")), + }, + ), + }, + types.NewParams(exported.Tendermint, exported.Localhost), + false, + 0, + ), + expPass: false, + }, + { + name: "invalid metadata", + genState: types.NewGenesisState( + []types.IdentifiedClientState{ + types.NewIdentifiedClientState( + clientID, ibctmtypes.NewClientState(chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), + ), + }, + []types.ClientConsensusStates{ + types.NewClientConsensusStates( + clientID, + []types.ConsensusStateWithHeight{ + types.NewConsensusStateWithHeight( + header.GetHeight().(types.Height), + ibctmtypes.NewConsensusState( + header.GetTime(), commitmenttypes.NewMerkleRoot(header.Header.GetAppHash()), header.Header.NextValidatorsHash, + ), + ), + }, + ), + }, + []types.IdentifiedGenesisMetadata{ + types.NewIdentifiedGenesisMetadata( + clientID, + []types.GenesisMetadata{ + types.NewGenesisMetadata([]byte(""), []byte("val1")), + types.NewGenesisMetadata([]byte("key2"), []byte("val2")), + }, + ), + }, + types.NewParams(exported.Tendermint), + false, + 0, + ), + }, { name: "invalid params", genState: types.NewGenesisState( @@ -287,6 +376,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(" "), false, 0, @@ -317,6 +407,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(" "), true, 0, @@ -347,6 +438,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Tendermint), true, 2, @@ -377,6 +469,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Tendermint, exported.Localhost), false, 0, @@ -407,6 +500,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Tendermint, exported.Localhost), false, 5, @@ -434,6 +528,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, ), }, + nil, types.NewParams(exported.Tendermint, exported.Localhost), false, 5, diff --git a/x/ibc/core/03-connection/client/cli/tx.go b/x/ibc/core/03-connection/client/cli/tx.go index bff4c5da947..5044f003d24 100644 --- a/x/ibc/core/03-connection/client/cli/tx.go +++ b/x/ibc/core/03-connection/client/cli/tx.go @@ -22,6 +22,7 @@ import ( const ( flagVersionIdentifier = "version-identifier" flagVersionFeatures = "version-features" + flagDelayPeriod = "delay-period" ) // NewConnectionOpenInitCmd defines the command to initialize a connection on @@ -34,7 +35,7 @@ func NewConnectionOpenInitCmd() *cobra.Command { - 'version-identifier' flag can be a single pre-selected version identifier to be used in the handshake. - 'version-features' flag can be a list of features separated by commas to accompany the version identifier.`, Example: fmt.Sprintf( - "%s tx %s %s open-init [client-id] [counterparty-client-id] [path/to/counterparty_prefix.json] --version-identifier=\"1.0\" --version-features=\"ORDER_UNORDERED\"", + "%s tx %s %s open-init [client-id] [counterparty-client-id] [path/to/counterparty_prefix.json] --version-identifier=\"1.0\" --version-features=\"ORDER_UNORDERED\" --delay-period=500", version.AppName, host.ModuleName, types.SubModuleName, ), Args: cobra.ExactArgs(3), @@ -67,9 +68,14 @@ func NewConnectionOpenInitCmd() *cobra.Command { version = types.NewVersion(versionIdentifier, features) } + delayPeriod, err := cmd.Flags().GetUint64(flagDelayPeriod) + if err != nil { + return err + } + msg := types.NewMsgConnectionOpenInit( clientID, counterpartyClientID, - counterpartyPrefix, version, clientCtx.GetFromAddress(), + counterpartyPrefix, version, delayPeriod, clientCtx.GetFromAddress(), ) if err := msg.ValidateBasic(); err != nil { @@ -84,6 +90,7 @@ func NewConnectionOpenInitCmd() *cobra.Command { // at this step in the handshake. cmd.Flags().String(flagVersionIdentifier, "", "version identifier to be used in the connection handshake version negotiation") cmd.Flags().String(flagVersionFeatures, "", "version features list separated by commas without spaces. The features must function with the version identifier.") + cmd.Flags().Uint64(flagDelayPeriod, 0, "delay period that must pass before packet verification can pass against a consensus state") flags.AddTxFlagsToCmd(cmd) return cmd @@ -174,9 +181,14 @@ func NewConnectionOpenTryCmd() *cobra.Command { return err } + delayPeriod, err := cmd.Flags().GetUint64(flagDelayPeriod) + if err != nil { + return err + } + msg := types.NewMsgConnectionOpenTry( connectionID, clientID, counterpartyConnectionID, counterpartyClientID, - counterpartyClient, counterpartyPrefix, counterpartyVersions, + counterpartyClient, counterpartyPrefix, counterpartyVersions, delayPeriod, proofInit, proofClient, proofConsensus, proofHeight, consensusHeight, clientCtx.GetFromAddress(), ) @@ -189,6 +201,7 @@ func NewConnectionOpenTryCmd() *cobra.Command { }, } + cmd.Flags().Uint64(flagDelayPeriod, 0, "delay period that must pass before packet verification can pass against a consensus state") flags.AddTxFlagsToCmd(cmd) return cmd diff --git a/x/ibc/core/03-connection/genesis.go b/x/ibc/core/03-connection/genesis.go index 4f97ed37ba9..a1bb30f1fe5 100644 --- a/x/ibc/core/03-connection/genesis.go +++ b/x/ibc/core/03-connection/genesis.go @@ -10,7 +10,7 @@ import ( // state. func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) { for _, connection := range gs.Connections { - conn := types.NewConnectionEnd(connection.State, connection.ClientId, connection.Counterparty, connection.Versions) + conn := types.NewConnectionEnd(connection.State, connection.ClientId, connection.Counterparty, connection.Versions, connection.DelayPeriod) k.SetConnection(ctx, connection.Id, conn) } for _, connPaths := range gs.ClientConnectionPaths { diff --git a/x/ibc/core/03-connection/keeper/grpc_query_test.go b/x/ibc/core/03-connection/keeper/grpc_query_test.go index 6a3497667ac..faa77b3c3e9 100644 --- a/x/ibc/core/03-connection/keeper/grpc_query_test.go +++ b/x/ibc/core/03-connection/keeper/grpc_query_test.go @@ -52,7 +52,7 @@ func (suite *KeeperTestSuite) TestQueryConnection() { connB := suite.chainB.GetFirstTestConnection(clientB, clientA) counterparty := types.NewCounterparty(clientB, connB.ID, suite.chainB.GetPrefix()) - expConnection = types.NewConnectionEnd(types.INIT, clientA, counterparty, types.ExportedVersionsToProto(types.GetCompatibleVersions())) + expConnection = types.NewConnectionEnd(types.INIT, clientA, counterparty, types.ExportedVersionsToProto(types.GetCompatibleVersions()), 500) suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), connA.ID, expConnection) req = &types.QueryConnectionRequest{ @@ -121,9 +121,9 @@ func (suite *KeeperTestSuite) TestQueryConnections() { // counterparty connection id is blank after open init counterparty3 := types.NewCounterparty(clientB, "", suite.chainB.GetPrefix()) - conn1 := types.NewConnectionEnd(types.OPEN, clientA, counterparty1, types.ExportedVersionsToProto(types.GetCompatibleVersions())) - conn2 := types.NewConnectionEnd(types.OPEN, clientA1, counterparty2, types.ExportedVersionsToProto(types.GetCompatibleVersions())) - conn3 := types.NewConnectionEnd(types.INIT, clientA, counterparty3, types.ExportedVersionsToProto(types.GetCompatibleVersions())) + conn1 := types.NewConnectionEnd(types.OPEN, clientA, counterparty1, types.ExportedVersionsToProto(types.GetCompatibleVersions()), 0) + conn2 := types.NewConnectionEnd(types.OPEN, clientA1, counterparty2, types.ExportedVersionsToProto(types.GetCompatibleVersions()), 0) + conn3 := types.NewConnectionEnd(types.INIT, clientA, counterparty3, types.ExportedVersionsToProto(types.GetCompatibleVersions()), 0) iconn1 := types.NewIdentifiedConnection(connA0.ID, conn1) iconn2 := types.NewIdentifiedConnection(connA1.ID, conn2) diff --git a/x/ibc/core/03-connection/keeper/handshake.go b/x/ibc/core/03-connection/keeper/handshake.go index 7a7d700570e..b8f7466f159 100644 --- a/x/ibc/core/03-connection/keeper/handshake.go +++ b/x/ibc/core/03-connection/keeper/handshake.go @@ -24,6 +24,7 @@ func (k Keeper) ConnOpenInit( clientID string, counterparty types.Counterparty, // counterpartyPrefix, counterpartyClientIdentifier version *types.Version, + delayPeriod uint64, ) (string, error) { versions := types.GetCompatibleVersions() if version != nil { @@ -36,7 +37,7 @@ func (k Keeper) ConnOpenInit( // connection defines chain A's ConnectionEnd connectionID := k.GenerateConnectionIdentifier(ctx) - connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, types.ExportedVersionsToProto(versions)) + connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, types.ExportedVersionsToProto(versions), delayPeriod) k.SetConnection(ctx, connectionID, connection) if err := k.addConnectionToClient(ctx, clientID, connectionID); err != nil { @@ -62,6 +63,7 @@ func (k Keeper) ConnOpenTry( ctx sdk.Context, previousConnectionID string, // previousIdentifier counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier + delayPeriod uint64, clientID string, // clientID of chainA clientState exported.ClientState, // clientState that chainA has for chainB counterpartyVersions []exported.Version, // supported versions of chain A @@ -89,10 +91,12 @@ func (k Keeper) ConnOpenTry( // counterparty is chainA and connection is on INIT stage. // Check that existing connection versions for initialized connection is equal to compatible // versions for this chain. + // ensure that existing connection's delay period is the same as desired delay period. if !(previousConnection.Counterparty.ConnectionId == "" && bytes.Equal(previousConnection.Counterparty.Prefix.Bytes(), counterparty.Prefix.Bytes()) && previousConnection.ClientId == clientID && - previousConnection.Counterparty.ClientId == counterparty.ClientId) { + previousConnection.Counterparty.ClientId == counterparty.ClientId && + previousConnection.DelayPeriod == delayPeriod) { return "", sdkerrors.Wrap(types.ErrInvalidConnection, "connection fields mismatch previous connection fields") } @@ -128,9 +132,10 @@ func (k Keeper) ConnOpenTry( // expectedConnection defines Chain A's ConnectionEnd // NOTE: chain A's counterparty is chain B (i.e where this code is executed) + // NOTE: chainA and chainB must have the same delay period prefix := k.GetCommitmentPrefix() expectedCounterparty := types.NewCounterparty(clientID, "", commitmenttypes.NewMerklePrefix(prefix.Bytes())) - expectedConnection := types.NewConnectionEnd(types.INIT, counterparty.ClientId, expectedCounterparty, types.ExportedVersionsToProto(counterpartyVersions)) + expectedConnection := types.NewConnectionEnd(types.INIT, counterparty.ClientId, expectedCounterparty, types.ExportedVersionsToProto(counterpartyVersions), delayPeriod) supportedVersions := types.GetCompatibleVersions() if len(previousConnection.Versions) != 0 { @@ -146,7 +151,7 @@ func (k Keeper) ConnOpenTry( } // connection defines chain B's ConnectionEnd - connection := types.NewConnectionEnd(types.TRYOPEN, clientID, counterparty, []*types.Version{version}) + connection := types.NewConnectionEnd(types.TRYOPEN, clientID, counterparty, []*types.Version{version}, delayPeriod) // Check that ChainA committed expectedConnectionEnd to its state if err := k.VerifyConnectionState( @@ -252,7 +257,7 @@ func (k Keeper) ConnOpenAck( prefix := k.GetCommitmentPrefix() expectedCounterparty := types.NewCounterparty(connection.ClientId, connectionID, commitmenttypes.NewMerklePrefix(prefix.Bytes())) - expectedConnection := types.NewConnectionEnd(types.TRYOPEN, connection.Counterparty.ClientId, expectedCounterparty, []*types.Version{version}) + expectedConnection := types.NewConnectionEnd(types.TRYOPEN, connection.Counterparty.ClientId, expectedCounterparty, []*types.Version{version}, connection.DelayPeriod) // Ensure that ChainB stored expected connectionEnd in its state during ConnOpenTry if err := k.VerifyConnectionState( @@ -314,7 +319,7 @@ func (k Keeper) ConnOpenConfirm( prefix := k.GetCommitmentPrefix() expectedCounterparty := types.NewCounterparty(connection.ClientId, connectionID, commitmenttypes.NewMerklePrefix(prefix.Bytes())) - expectedConnection := types.NewConnectionEnd(types.OPEN, connection.Counterparty.ClientId, expectedCounterparty, connection.Versions) + expectedConnection := types.NewConnectionEnd(types.OPEN, connection.Counterparty.ClientId, expectedCounterparty, connection.Versions, connection.DelayPeriod) // Check that connection on ChainA is open if err := k.VerifyConnectionState( diff --git a/x/ibc/core/03-connection/keeper/handshake_test.go b/x/ibc/core/03-connection/keeper/handshake_test.go index d70fd013dcc..01c0f68ae80 100644 --- a/x/ibc/core/03-connection/keeper/handshake_test.go +++ b/x/ibc/core/03-connection/keeper/handshake_test.go @@ -17,6 +17,7 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { clientA string clientB string version *types.Version + delayPeriod uint64 emptyConnBID bool ) @@ -36,6 +37,11 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint) version = types.ExportedVersionsToProto(types.GetCompatibleVersions())[0] }, true}, + {"success with non zero delayPeriod", func() { + clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint) + delayPeriod = uint64(time.Hour.Nanoseconds()) + }, true}, + {"invalid version", func() { clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint) version = &types.Version{} @@ -62,7 +68,7 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { } counterparty := types.NewCounterparty(clientB, connB.ID, suite.chainB.GetPrefix()) - connectionID, err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenInit(suite.chainA.GetContext(), clientA, counterparty, version) + connectionID, err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenInit(suite.chainA.GetContext(), clientA, counterparty, version, delayPeriod) if tc.expPass { suite.Require().NoError(err) @@ -81,6 +87,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { var ( clientA string clientB string + delayPeriod uint64 previousConnectionID string versions []exported.Version consensusHeight exported.Height @@ -110,6 +117,25 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { previousConnectionID = connB.ID }, true}, + {"success with delay period", func() { + clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint) + connA, _, err := suite.coordinator.ConnOpenInit(suite.chainA, suite.chainB, clientA, clientB) + suite.Require().NoError(err) + + delayPeriod = uint64(time.Hour.Nanoseconds()) + + // set delay period on counterparty to non-zero value + conn := suite.chainA.GetConnection(connA) + conn.DelayPeriod = delayPeriod + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), connA.ID, conn) + + // commit in order for proof to return correct value + suite.coordinator.CommitBlock(suite.chainA) + suite.coordinator.UpdateClient(suite.chainB, suite.chainA, clientB, exported.Tendermint) + + // retrieve client state of chainA to pass as counterpartyClient + counterpartyClient = suite.chainA.GetClientState(clientA) + }, true}, {"invalid counterparty client", func() { clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint) _, _, err := suite.coordinator.ConnOpenInit(suite.chainA, suite.chainB, clientA, clientB) @@ -283,7 +309,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { proofClient, _ := suite.chainA.QueryProof(clientKey) connectionID, err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenTry( - suite.chainB.GetContext(), previousConnectionID, counterparty, clientB, counterpartyClient, + suite.chainB.GetContext(), previousConnectionID, counterparty, delayPeriod, clientB, counterpartyClient, versions, proofInit, proofClient, proofConsensus, proofHeight, consensusHeight, ) diff --git a/x/ibc/core/03-connection/keeper/keeper_test.go b/x/ibc/core/03-connection/keeper/keeper_test.go index cf8f447179f..f2a1124b551 100644 --- a/x/ibc/core/03-connection/keeper/keeper_test.go +++ b/x/ibc/core/03-connection/keeper/keeper_test.go @@ -62,8 +62,8 @@ func (suite KeeperTestSuite) TestGetAllConnections() { counterpartyB0 := types.NewCounterparty(clientB, connB0.ID, suite.chainB.GetPrefix()) // connection B0 counterpartyB1 := types.NewCounterparty(clientB, connB1.ID, suite.chainB.GetPrefix()) // connection B1 - conn1 := types.NewConnectionEnd(types.OPEN, clientA, counterpartyB0, types.ExportedVersionsToProto(types.GetCompatibleVersions())) // A0 - B0 - conn2 := types.NewConnectionEnd(types.OPEN, clientA, counterpartyB1, types.ExportedVersionsToProto(types.GetCompatibleVersions())) // A1 - B1 + conn1 := types.NewConnectionEnd(types.OPEN, clientA, counterpartyB0, types.ExportedVersionsToProto(types.GetCompatibleVersions()), 0) // A0 - B0 + conn2 := types.NewConnectionEnd(types.OPEN, clientA, counterpartyB1, types.ExportedVersionsToProto(types.GetCompatibleVersions()), 0) // A1 - B1 iconn1 := types.NewIdentifiedConnection(connA0.ID, conn1) iconn2 := types.NewIdentifiedConnection(connA1.ID, conn2) diff --git a/x/ibc/core/03-connection/keeper/verify.go b/x/ibc/core/03-connection/keeper/verify.go index 2b9e00706c4..ddb1ea6b961 100644 --- a/x/ibc/core/03-connection/keeper/verify.go +++ b/x/ibc/core/03-connection/keeper/verify.go @@ -128,6 +128,7 @@ func (k Keeper) VerifyPacketCommitment( if err := clientState.VerifyPacketCommitment( k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height, + uint64(ctx.BlockTime().UnixNano()), connection.GetDelayPeriod(), connection.GetCounterparty().GetPrefix(), proof, portID, channelID, sequence, commitmentBytes, ); err != nil { @@ -156,6 +157,7 @@ func (k Keeper) VerifyPacketAcknowledgement( if err := clientState.VerifyPacketAcknowledgement( k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height, + uint64(ctx.BlockTime().UnixNano()), connection.GetDelayPeriod(), connection.GetCounterparty().GetPrefix(), proof, portID, channelID, sequence, acknowledgement, ); err != nil { @@ -184,6 +186,7 @@ func (k Keeper) VerifyPacketReceiptAbsence( if err := clientState.VerifyPacketReceiptAbsence( k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height, + uint64(ctx.BlockTime().UnixNano()), connection.GetDelayPeriod(), connection.GetCounterparty().GetPrefix(), proof, portID, channelID, sequence, ); err != nil { @@ -211,6 +214,7 @@ func (k Keeper) VerifyNextSequenceRecv( if err := clientState.VerifyNextSequenceRecv( k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height, + uint64(ctx.BlockTime().UnixNano()), connection.GetDelayPeriod(), connection.GetCounterparty().GetPrefix(), proof, portID, channelID, nextSequenceRecv, ); err != nil { diff --git a/x/ibc/core/03-connection/keeper/verify_test.go b/x/ibc/core/03-connection/keeper/verify_test.go index 4bf1bfb9da6..2d94955d8ef 100644 --- a/x/ibc/core/03-connection/keeper/verify_test.go +++ b/x/ibc/core/03-connection/keeper/verify_test.go @@ -258,12 +258,15 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { changeClientID bool changePacketCommitmentState bool heightDiff uint64 + delayPeriod uint64 expPass bool }{ - {"verification success", false, false, 0, true}, - {"client state not found- changed client ID", true, false, 0, false}, - {"consensus state not found - increased proof height", false, false, 5, false}, - {"verification failed - changed packet commitment state", false, true, 0, false}, + {"verification success", false, false, 0, 0, true}, + {"verification success: delay period passed", false, false, 0, uint64(1 * time.Second.Nanoseconds()), true}, + {"delay period has not passed", false, false, 0, uint64(1 * time.Hour.Nanoseconds()), false}, + {"client state not found- changed client ID", true, false, 0, 0, false}, + {"consensus state not found - increased proof height", false, false, 5, 0, false}, + {"verification failed - changed packet commitment state", false, true, 0, 0, false}, } for _, tc := range cases { @@ -273,7 +276,9 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { suite.SetupTest() // reset _, clientB, _, connB, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, channeltypes.UNORDERED) + connection := suite.chainB.GetConnection(connB) + connection.DelayPeriod = tc.delayPeriod if tc.changeClientID { connection.ClientId = ibctesting.InvalidID } @@ -313,12 +318,15 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { changeClientID bool changeAcknowledgement bool heightDiff uint64 + delayPeriod uint64 expPass bool }{ - {"verification success", false, false, 0, true}, - {"client state not found- changed client ID", true, false, 0, false}, - {"consensus state not found - increased proof height", false, false, 5, false}, - {"verification failed - changed acknowledgement", false, true, 0, false}, + {"verification success", false, false, 0, 0, true}, + {"verification success: delay period passed", false, false, 0, uint64(1 * time.Second.Nanoseconds()), true}, + {"delay period has not passed", false, false, 0, uint64(1 * time.Hour.Nanoseconds()), false}, + {"client state not found- changed client ID", true, false, 0, 0, false}, + {"consensus state not found - increased proof height", false, false, 5, 0, false}, + {"verification failed - changed acknowledgement", false, true, 0, 0, false}, } for _, tc := range cases { @@ -328,7 +336,9 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { suite.SetupTest() // reset clientA, clientB, connA, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, channeltypes.UNORDERED) + connection := suite.chainA.GetConnection(connA) + connection.DelayPeriod = tc.delayPeriod if tc.changeClientID { connection.ClientId = ibctesting.InvalidID } @@ -338,6 +348,10 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB) suite.Require().NoError(err) + // increment receiving chain's (chainB) time by 2 hour to always pass receive + suite.coordinator.IncrementTimeBy(time.Hour * 2) + suite.coordinator.CommitBlock(suite.chainB) + err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet) suite.Require().NoError(err) @@ -372,12 +386,15 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { changeClientID bool recvAck bool heightDiff uint64 + delayPeriod uint64 expPass bool }{ - {"verification success", false, false, 0, true}, - {"client state not found - changed client ID", true, false, 0, false}, - {"consensus state not found - increased proof height", false, false, 5, false}, - {"verification failed - acknowledgement was received", false, true, 0, false}, + {"verification success", false, false, 0, 0, true}, + {"verification success: delay period passed", false, false, 0, uint64(1 * time.Second.Nanoseconds()), true}, + {"delay period has not passed", false, false, 0, uint64(1 * time.Hour.Nanoseconds()), false}, + {"client state not found - changed client ID", true, false, 0, 0, false}, + {"consensus state not found - increased proof height", false, false, 5, 0, false}, + {"verification failed - acknowledgement was received", false, true, 0, 0, false}, } for _, tc := range cases { @@ -387,7 +404,9 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { suite.SetupTest() // reset clientA, clientB, connA, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, channeltypes.UNORDERED) + connection := suite.chainA.GetConnection(connA) + connection.DelayPeriod = tc.delayPeriod if tc.changeClientID { connection.ClientId = ibctesting.InvalidID } @@ -398,6 +417,10 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { suite.Require().NoError(err) if tc.recvAck { + // increment receiving chain's (chainB) time by 2 hour to always pass receive + suite.coordinator.IncrementTimeBy(time.Hour * 2) + suite.coordinator.CommitBlock(suite.chainB) + err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet) suite.Require().NoError(err) } else { @@ -432,12 +455,15 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { changeClientID bool offsetSeq uint64 heightDiff uint64 + delayPeriod uint64 expPass bool }{ - {"verification success", false, 0, 0, true}, - {"client state not found- changed client ID", true, 0, 0, false}, - {"consensus state not found - increased proof height", false, 0, 5, false}, - {"verification failed - wrong expected next seq recv", false, 1, 0, false}, + {"verification success", false, 0, 0, 0, true}, + {"verification success: delay period passed", false, 0, 0, uint64(1 * time.Second.Nanoseconds()), true}, + {"delay period has not passed", false, 0, 0, uint64(1 * time.Hour.Nanoseconds()), false}, + {"client state not found- changed client ID", true, 0, 0, 0, false}, + {"consensus state not found - increased proof height", false, 0, 5, 0, false}, + {"verification failed - wrong expected next seq recv", false, 1, 0, 0, false}, } for _, tc := range cases { @@ -447,7 +473,9 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { suite.SetupTest() // reset clientA, clientB, connA, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, channeltypes.UNORDERED) + connection := suite.chainA.GetConnection(connA) + connection.DelayPeriod = tc.delayPeriod if tc.changeClientID { connection.ClientId = ibctesting.InvalidID } @@ -457,6 +485,10 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { err := suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB) suite.Require().NoError(err) + // increment receiving chain's (chainB) time by 2 hour to always pass receive + suite.coordinator.IncrementTimeBy(time.Hour * 2) + suite.coordinator.CommitBlock(suite.chainB) + err = suite.coordinator.RecvPacket(suite.chainA, suite.chainB, clientA, packet) suite.Require().NoError(err) diff --git a/x/ibc/core/03-connection/types/connection.go b/x/ibc/core/03-connection/types/connection.go index 224998c6a9b..197af83cad9 100644 --- a/x/ibc/core/03-connection/types/connection.go +++ b/x/ibc/core/03-connection/types/connection.go @@ -10,12 +10,13 @@ import ( var _ exported.ConnectionI = (*ConnectionEnd)(nil) // NewConnectionEnd creates a new ConnectionEnd instance. -func NewConnectionEnd(state State, clientID string, counterparty Counterparty, versions []*Version) ConnectionEnd { +func NewConnectionEnd(state State, clientID string, counterparty Counterparty, versions []*Version, delayPeriod uint64) ConnectionEnd { return ConnectionEnd{ ClientId: clientID, Versions: versions, State: state, Counterparty: counterparty, + DelayPeriod: delayPeriod, } } @@ -39,6 +40,11 @@ func (c ConnectionEnd) GetVersions() []exported.Version { return ProtoVersionsToExported(c.Versions) } +// GetDelayPeriod implements the Connection interface +func (c ConnectionEnd) GetDelayPeriod() uint64 { + return c.DelayPeriod +} + // ValidateBasic implements the Connection interface. // NOTE: the protocol supports that the connection and client IDs match the // counterparty's. @@ -107,6 +113,7 @@ func NewIdentifiedConnection(connectionID string, conn ConnectionEnd) Identified Versions: conn.Versions, State: conn.State, Counterparty: conn.Counterparty, + DelayPeriod: conn.DelayPeriod, } } @@ -115,6 +122,6 @@ func (ic IdentifiedConnection) ValidateBasic() error { if err := host.ConnectionIdentifierValidator(ic.Id); err != nil { return sdkerrors.Wrap(err, "invalid connection ID") } - connection := NewConnectionEnd(ic.State, ic.ClientId, ic.Counterparty, ic.Versions) + connection := NewConnectionEnd(ic.State, ic.ClientId, ic.Counterparty, ic.Versions, ic.DelayPeriod) return connection.ValidateBasic() } diff --git a/x/ibc/core/03-connection/types/connection.pb.go b/x/ibc/core/03-connection/types/connection.pb.go index ff0f6db1fa0..cdfb752b907 100644 --- a/x/ibc/core/03-connection/types/connection.pb.go +++ b/x/ibc/core/03-connection/types/connection.pb.go @@ -63,18 +63,22 @@ func (State) EnumDescriptor() ([]byte, []int) { } // ConnectionEnd defines a stateful object on a chain connected to another -// separate one. NOTE: there must only be 2 defined ConnectionEnds to establish +// separate one. +// NOTE: there must only be 2 defined ConnectionEnds to establish // a connection between two chains. type ConnectionEnd struct { // client associated with this connection. ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` // IBC version which can be utilised to determine encodings or protocols for - // channels or packets utilising this connection + // channels or packets utilising this connection. Versions []*Version `protobuf:"bytes,2,rep,name=versions,proto3" json:"versions,omitempty"` // current state of the connection end. State State `protobuf:"varint,3,opt,name=state,proto3,enum=ibc.core.connection.v1.State" json:"state,omitempty"` // counterparty chain associated with this connection. Counterparty Counterparty `protobuf:"bytes,4,opt,name=counterparty,proto3" json:"counterparty"` + // delay period that must pass before a consensus state can be used for packet-verification + // NOTE: delay period logic is only implemented by some clients. + DelayPeriod uint64 `protobuf:"varint,5,opt,name=delay_period,json=delayPeriod,proto3" json:"delay_period,omitempty" yaml:"delay_period"` } func (m *ConnectionEnd) Reset() { *m = ConnectionEnd{} } @@ -124,6 +128,8 @@ type IdentifiedConnection struct { State State `protobuf:"varint,4,opt,name=state,proto3,enum=ibc.core.connection.v1.State" json:"state,omitempty"` // counterparty chain associated with this connection. Counterparty Counterparty `protobuf:"bytes,5,opt,name=counterparty,proto3" json:"counterparty"` + // delay period associated with this connection. + DelayPeriod uint64 `protobuf:"varint,6,opt,name=delay_period,json=delayPeriod,proto3" json:"delay_period,omitempty" yaml:"delay_period"` } func (m *IdentifiedConnection) Reset() { *m = IdentifiedConnection{} } @@ -167,7 +173,7 @@ type Counterparty struct { // identifies the connection end on the counterparty chain associated with a // given connection. ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"` - // commitment merkle prefix of the counterparty chain + // commitment merkle prefix of the counterparty chain. Prefix types.MerklePrefix `protobuf:"bytes,3,opt,name=prefix,proto3" json:"prefix"` } @@ -362,46 +368,48 @@ func init() { } var fileDescriptor_90572467c054e43a = []byte{ - // 617 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xc1, 0x6a, 0xdb, 0x4c, - 0x10, 0x96, 0x64, 0x39, 0xb1, 0xd7, 0xf1, 0xff, 0xbb, 0x8b, 0x29, 0x42, 0x10, 0x49, 0xa8, 0x85, - 0x9a, 0x42, 0xa4, 0x3a, 0x81, 0x1e, 0x12, 0x7a, 0x88, 0x1d, 0x15, 0x44, 0x5b, 0xd7, 0x28, 0x4e, - 0xa1, 0xb9, 0x04, 0x5b, 0xda, 0x24, 0x4b, 0x62, 0xc9, 0x48, 0x6b, 0x13, 0xbf, 0x41, 0xf0, 0xa9, - 0xd7, 0x1e, 0x0c, 0x85, 0xbe, 0x40, 0x1f, 0x23, 0xf4, 0x94, 0x63, 0x4f, 0xa6, 0xd8, 0x6f, 0xe0, - 0x27, 0x28, 0xd2, 0xca, 0xb2, 0x12, 0x9a, 0x43, 0xdd, 0x9e, 0x34, 0xb3, 0xf3, 0x7d, 0x9f, 0x76, - 0xbe, 0x1d, 0x06, 0x3c, 0xc3, 0x1d, 0x5b, 0xb7, 0x3d, 0x1f, 0xe9, 0xb6, 0xe7, 0xba, 0xc8, 0x26, - 0xd8, 0x73, 0xf5, 0x41, 0x35, 0x95, 0x69, 0x3d, 0xdf, 0x23, 0x1e, 0x7c, 0x8c, 0x3b, 0xb6, 0x16, - 0x02, 0xb5, 0x54, 0x69, 0x50, 0x15, 0xcb, 0x67, 0xde, 0x99, 0x17, 0x41, 0xf4, 0x30, 0xa2, 0x68, - 0x31, 0x2d, 0xdb, 0xed, 0x62, 0xd2, 0x45, 0x2e, 0xa1, 0xb2, 0x8b, 0x8c, 0x02, 0xd5, 0x11, 0x07, - 0x8a, 0xf5, 0x44, 0xd0, 0x70, 0x1d, 0x58, 0x05, 0x79, 0xfb, 0x12, 0x23, 0x97, 0x9c, 0x60, 0x47, - 0x60, 0x15, 0xb6, 0x92, 0xaf, 0x95, 0xe7, 0x13, 0xb9, 0x34, 0x6c, 0x77, 0x2f, 0x77, 0xd5, 0xa4, - 0xa4, 0x5a, 0x39, 0x1a, 0x9b, 0x0e, 0xdc, 0x03, 0xb9, 0x01, 0xf2, 0x03, 0xec, 0xb9, 0x81, 0xc0, - 0x29, 0x99, 0x4a, 0x61, 0x5b, 0xd6, 0x7e, 0x7f, 0x5d, 0xed, 0x03, 0xc5, 0x59, 0x09, 0x01, 0xee, - 0x80, 0x6c, 0x40, 0xda, 0x04, 0x09, 0x19, 0x85, 0xad, 0xfc, 0xb7, 0xbd, 0xf9, 0x10, 0xf3, 0x30, - 0x04, 0x59, 0x14, 0x0b, 0x1b, 0x60, 0xc3, 0xf6, 0xfa, 0x2e, 0x41, 0x7e, 0xaf, 0xed, 0x93, 0xa1, - 0xc0, 0x2b, 0x6c, 0xa5, 0xb0, 0xfd, 0xf4, 0x21, 0x6e, 0x3d, 0x85, 0xad, 0xf1, 0x37, 0x13, 0x99, - 0xb1, 0xee, 0xf0, 0x77, 0xf9, 0xeb, 0x2f, 0x32, 0xa3, 0x7e, 0xe3, 0x40, 0xd9, 0x74, 0x90, 0x4b, - 0xf0, 0x29, 0x46, 0xce, 0xd2, 0x16, 0xb8, 0x09, 0xb8, 0xc4, 0x8c, 0xe2, 0x7c, 0x22, 0xe7, 0xa9, - 0x19, 0xa1, 0x0b, 0x1c, 0xbe, 0x67, 0x19, 0xf7, 0xc7, 0x96, 0x65, 0x56, 0xb6, 0x8c, 0xff, 0x0b, - 0xcb, 0xb2, 0xff, 0xc4, 0xb2, 0xef, 0x2c, 0xd8, 0x48, 0x43, 0x57, 0x19, 0x9f, 0x57, 0xa0, 0xb8, - 0xfc, 0xf7, 0xd2, 0x42, 0x61, 0x3e, 0x91, 0xcb, 0x31, 0x2d, 0x5d, 0x56, 0xc3, 0x8b, 0x2c, 0x72, - 0xd3, 0x81, 0x35, 0xb0, 0xd6, 0xf3, 0xd1, 0x29, 0xbe, 0x8a, 0x26, 0xe8, 0x5e, 0x4b, 0xc9, 0xb8, - 0x0f, 0xaa, 0xda, 0x3b, 0xe4, 0x5f, 0x5c, 0xa2, 0x66, 0x84, 0x8d, 0x5b, 0x8a, 0x99, 0x71, 0x33, - 0x4f, 0x40, 0xa1, 0x1e, 0x5d, 0xaa, 0xd9, 0x26, 0xe7, 0x01, 0x2c, 0x83, 0x6c, 0x2f, 0x0c, 0x04, - 0x56, 0xc9, 0x54, 0xf2, 0x16, 0x4d, 0xd4, 0x63, 0xf0, 0xff, 0x72, 0x32, 0x28, 0x70, 0x85, 0x9e, - 0x13, 0x6d, 0x2e, 0xad, 0xfd, 0x06, 0xac, 0xc7, 0xaf, 0x0d, 0x25, 0x00, 0xf0, 0x62, 0x14, 0x7d, - 0x2a, 0x6a, 0xa5, 0x4e, 0xa0, 0x08, 0x72, 0xa7, 0xa8, 0x4d, 0xfa, 0x3e, 0x5a, 0x68, 0x24, 0x39, - 0xed, 0xe6, 0xf9, 0x67, 0x16, 0x64, 0xa3, 0x09, 0x80, 0x2f, 0x81, 0x7c, 0xd8, 0xda, 0x6f, 0x19, - 0x27, 0x47, 0x0d, 0xb3, 0x61, 0xb6, 0xcc, 0xfd, 0xb7, 0xe6, 0xb1, 0x71, 0x70, 0x72, 0xd4, 0x38, - 0x6c, 0x1a, 0x75, 0xf3, 0xb5, 0x69, 0x1c, 0x94, 0x18, 0xf1, 0xd1, 0x68, 0xac, 0x14, 0xef, 0x00, - 0xa0, 0x00, 0x00, 0xe5, 0x85, 0x87, 0x25, 0x56, 0xcc, 0x8d, 0xc6, 0x0a, 0x1f, 0xc6, 0x50, 0x02, - 0x45, 0x5a, 0x69, 0x59, 0x1f, 0xdf, 0x37, 0x8d, 0x46, 0x89, 0x13, 0x0b, 0xa3, 0xb1, 0xb2, 0x1e, - 0xa7, 0x4b, 0x66, 0x54, 0xcc, 0x50, 0x66, 0x18, 0x8b, 0xfc, 0xf5, 0x57, 0x89, 0xa9, 0x1d, 0xdd, - 0x4c, 0x25, 0xf6, 0x76, 0x2a, 0xb1, 0x3f, 0xa7, 0x12, 0xfb, 0x69, 0x26, 0x31, 0xb7, 0x33, 0x89, - 0xf9, 0x31, 0x93, 0x98, 0xe3, 0xbd, 0x33, 0x4c, 0xce, 0xfb, 0x9d, 0xf0, 0xe9, 0x74, 0xdb, 0x0b, - 0xba, 0x5e, 0x10, 0x7f, 0xb6, 0x02, 0xe7, 0x42, 0xbf, 0xd2, 0x93, 0xc5, 0xf6, 0x62, 0x67, 0x2b, - 0xb5, 0x32, 0xc9, 0xb0, 0x87, 0x82, 0xce, 0x5a, 0xb4, 0xd4, 0x76, 0x7e, 0x05, 0x00, 0x00, 0xff, - 0xff, 0x6d, 0xfb, 0xee, 0xb6, 0x56, 0x05, 0x00, 0x00, + // 654 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x41, 0x6b, 0xdb, 0x4c, + 0x14, 0x94, 0x64, 0x39, 0xb1, 0xd7, 0xf1, 0xf7, 0xb9, 0x5b, 0xd3, 0x0a, 0x41, 0x24, 0xa1, 0x16, + 0x6a, 0x0a, 0xb1, 0xea, 0x04, 0x7a, 0x48, 0xe8, 0x21, 0x76, 0x5c, 0x10, 0x6d, 0x5d, 0xa3, 0x38, + 0x85, 0xe6, 0x62, 0x6c, 0x69, 0x93, 0x2c, 0xb1, 0xb5, 0x42, 0xda, 0x98, 0xf8, 0x1f, 0x84, 0x9c, + 0x7a, 0xed, 0x21, 0x50, 0xe8, 0x7f, 0x29, 0xa1, 0xa7, 0x1c, 0x7b, 0x32, 0x25, 0xb9, 0xf6, 0xe4, + 0x5f, 0x50, 0xa4, 0x95, 0x65, 0x25, 0x34, 0x87, 0xa4, 0x3d, 0xf9, 0xcd, 0xbe, 0x99, 0xf1, 0xbe, + 0xf1, 0xf3, 0x82, 0x67, 0xb8, 0x6f, 0x1b, 0x36, 0xf1, 0x91, 0x61, 0x13, 0xd7, 0x45, 0x36, 0xc5, + 0xc4, 0x35, 0x46, 0xb5, 0x14, 0xaa, 0x7a, 0x3e, 0xa1, 0x04, 0x3e, 0xc2, 0x7d, 0xbb, 0x1a, 0x12, + 0xab, 0xa9, 0xd6, 0xa8, 0x26, 0x97, 0xf7, 0xc9, 0x3e, 0x89, 0x28, 0x46, 0x58, 0x31, 0xb6, 0x9c, + 0xb6, 0x1d, 0x0e, 0x31, 0x1d, 0x22, 0x97, 0x32, 0xdb, 0x19, 0x62, 0x44, 0xfd, 0x9b, 0x00, 0x8a, + 0x8d, 0xc4, 0xb0, 0xe9, 0x3a, 0xb0, 0x06, 0xf2, 0xf6, 0x00, 0x23, 0x97, 0x76, 0xb1, 0x23, 0xf1, + 0x1a, 0x5f, 0xc9, 0xd7, 0xcb, 0xd3, 0x89, 0x5a, 0x1a, 0xf7, 0x86, 0x83, 0x75, 0x3d, 0x69, 0xe9, + 0x56, 0x8e, 0xd5, 0xa6, 0x03, 0x37, 0x40, 0x6e, 0x84, 0xfc, 0x00, 0x13, 0x37, 0x90, 0x04, 0x2d, + 0x53, 0x29, 0xac, 0xaa, 0xd5, 0x3f, 0x5f, 0xb7, 0xfa, 0x81, 0xf1, 0xac, 0x44, 0x00, 0xd7, 0x40, + 0x36, 0xa0, 0x3d, 0x8a, 0xa4, 0x8c, 0xc6, 0x57, 0xfe, 0x5b, 0x5d, 0xbe, 0x4d, 0xb9, 0x1d, 0x92, + 0x2c, 0xc6, 0x85, 0x2d, 0xb0, 0x64, 0x93, 0x23, 0x97, 0x22, 0xdf, 0xeb, 0xf9, 0x74, 0x2c, 0x89, + 0x1a, 0x5f, 0x29, 0xac, 0x3e, 0xbd, 0x4d, 0xdb, 0x48, 0x71, 0xeb, 0xe2, 0xf9, 0x44, 0xe5, 0xac, + 0x6b, 0x7a, 0xb8, 0x0e, 0x96, 0x1c, 0x34, 0xe8, 0x8d, 0xbb, 0x1e, 0xf2, 0x31, 0x71, 0xa4, 0xac, + 0xc6, 0x57, 0xc4, 0xfa, 0xe3, 0xe9, 0x44, 0x7d, 0xc8, 0xe6, 0x4e, 0x77, 0x75, 0xab, 0x10, 0xc1, + 0x76, 0x84, 0xd6, 0xc5, 0x93, 0x2f, 0x2a, 0xa7, 0xff, 0x12, 0x40, 0xd9, 0x74, 0x90, 0x4b, 0xf1, + 0x1e, 0x46, 0xce, 0x3c, 0x52, 0xb8, 0x0c, 0x84, 0x24, 0xc8, 0xe2, 0x74, 0xa2, 0xe6, 0x99, 0x61, + 0x98, 0xa0, 0x80, 0x6f, 0xc4, 0x2d, 0xdc, 0x39, 0xee, 0xcc, 0xbd, 0xe3, 0x16, 0xff, 0x22, 0xee, + 0xec, 0x3f, 0x8e, 0x7b, 0xe1, 0xce, 0x71, 0x7f, 0xe7, 0xc1, 0x52, 0xfa, 0x6b, 0xee, 0xb3, 0xb6, + 0xaf, 0x40, 0x71, 0x7e, 0xef, 0x79, 0xfc, 0xd2, 0x74, 0xa2, 0x96, 0x63, 0x59, 0xba, 0xad, 0x87, + 0x43, 0xcc, 0xb0, 0xe9, 0xc0, 0x3a, 0x58, 0xf0, 0x7c, 0xb4, 0x87, 0x8f, 0xa3, 0xcd, 0xbd, 0x11, + 0x47, 0xf2, 0x37, 0x1b, 0xd5, 0xaa, 0xef, 0x90, 0x7f, 0x38, 0x40, 0xed, 0x88, 0x1b, 0xc7, 0x11, + 0x2b, 0xe3, 0x61, 0x9e, 0x80, 0x42, 0x23, 0xba, 0x54, 0xbb, 0x47, 0x0f, 0x02, 0x58, 0x06, 0x59, + 0x2f, 0x2c, 0x24, 0x5e, 0xcb, 0x54, 0xf2, 0x16, 0x03, 0xfa, 0x2e, 0xf8, 0x7f, 0xbe, 0x55, 0x8c, + 0x78, 0x8f, 0x99, 0x13, 0x6f, 0x21, 0xed, 0xfd, 0x06, 0x2c, 0xc6, 0x9b, 0x02, 0x15, 0x00, 0xf0, + 0x6c, 0x8d, 0x7d, 0x66, 0x6a, 0xa5, 0x4e, 0xa0, 0x0c, 0x72, 0x7b, 0xa8, 0x47, 0x8f, 0x7c, 0x34, + 0xf3, 0x48, 0x30, 0x9b, 0xe6, 0xf9, 0x67, 0x1e, 0x64, 0xa3, 0xed, 0x81, 0x2f, 0x81, 0xba, 0xdd, + 0xd9, 0xec, 0x34, 0xbb, 0x3b, 0x2d, 0xb3, 0x65, 0x76, 0xcc, 0xcd, 0xb7, 0xe6, 0x6e, 0x73, 0xab, + 0xbb, 0xd3, 0xda, 0x6e, 0x37, 0x1b, 0xe6, 0x6b, 0xb3, 0xb9, 0x55, 0xe2, 0xe4, 0x07, 0xa7, 0x67, + 0x5a, 0xf1, 0x1a, 0x01, 0x4a, 0x00, 0x30, 0x5d, 0x78, 0x58, 0xe2, 0xe5, 0xdc, 0xe9, 0x99, 0x26, + 0x86, 0x35, 0x54, 0x40, 0x91, 0x75, 0x3a, 0xd6, 0xc7, 0xf7, 0xed, 0x66, 0xab, 0x24, 0xc8, 0x85, + 0xd3, 0x33, 0x6d, 0x31, 0x86, 0x73, 0x65, 0xd4, 0xcc, 0x30, 0x65, 0x58, 0xcb, 0xe2, 0xc9, 0x57, + 0x85, 0xab, 0xef, 0x9c, 0x5f, 0x2a, 0xfc, 0xc5, 0xa5, 0xc2, 0xff, 0xbc, 0x54, 0xf8, 0x4f, 0x57, + 0x0a, 0x77, 0x71, 0xa5, 0x70, 0x3f, 0xae, 0x14, 0x6e, 0x77, 0x63, 0x1f, 0xd3, 0x83, 0xa3, 0x7e, + 0xf8, 0xd3, 0x19, 0x36, 0x09, 0x86, 0x24, 0x88, 0x3f, 0x56, 0x02, 0xe7, 0xd0, 0x38, 0x36, 0x92, + 0x07, 0xf5, 0xc5, 0xda, 0x4a, 0xea, 0xa9, 0xa6, 0x63, 0x0f, 0x05, 0xfd, 0x85, 0xe8, 0x31, 0x5d, + 0xfb, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x48, 0x0f, 0xf2, 0xaa, 0xce, 0x05, 0x00, 0x00, } func (m *ConnectionEnd) Marshal() (dAtA []byte, err error) { @@ -424,6 +432,11 @@ func (m *ConnectionEnd) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.DelayPeriod != 0 { + i = encodeVarintConnection(dAtA, i, uint64(m.DelayPeriod)) + i-- + dAtA[i] = 0x28 + } { size, err := m.Counterparty.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -483,6 +496,11 @@ func (m *IdentifiedConnection) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.DelayPeriod != 0 { + i = encodeVarintConnection(dAtA, i, uint64(m.DelayPeriod)) + i-- + dAtA[i] = 0x30 + } { size, err := m.Counterparty.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -718,6 +736,9 @@ func (m *ConnectionEnd) Size() (n int) { } l = m.Counterparty.Size() n += 1 + l + sovConnection(uint64(l)) + if m.DelayPeriod != 0 { + n += 1 + sovConnection(uint64(m.DelayPeriod)) + } return n } @@ -746,6 +767,9 @@ func (m *IdentifiedConnection) Size() (n int) { } l = m.Counterparty.Size() n += 1 + l + sovConnection(uint64(l)) + if m.DelayPeriod != 0 { + n += 1 + sovConnection(uint64(m.DelayPeriod)) + } return n } @@ -974,6 +998,25 @@ func (m *ConnectionEnd) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DelayPeriod", wireType) + } + m.DelayPeriod = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConnection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DelayPeriod |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipConnection(dAtA[iNdEx:]) @@ -1177,6 +1220,25 @@ func (m *IdentifiedConnection) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DelayPeriod", wireType) + } + m.DelayPeriod = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConnection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DelayPeriod |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipConnection(dAtA[iNdEx:]) diff --git a/x/ibc/core/03-connection/types/connection_test.go b/x/ibc/core/03-connection/types/connection_test.go index 133bb1e5c68..e7e91538c4e 100644 --- a/x/ibc/core/03-connection/types/connection_test.go +++ b/x/ibc/core/03-connection/types/connection_test.go @@ -29,27 +29,27 @@ func TestConnectionValidateBasic(t *testing.T) { }{ { "valid connection", - types.ConnectionEnd{clientID, []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}}, + types.ConnectionEnd{clientID, []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, 500}, true, }, { "invalid client id", - types.ConnectionEnd{"(clientID1)", []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}}, + types.ConnectionEnd{"(clientID1)", []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, 500}, false, }, { "empty versions", - types.ConnectionEnd{clientID, nil, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}}, + types.ConnectionEnd{clientID, nil, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, 500}, false, }, { "invalid version", - types.ConnectionEnd{clientID, []*types.Version{{}}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}}, + types.ConnectionEnd{clientID, []*types.Version{{}}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, 500}, false, }, { "invalid counterparty", - types.ConnectionEnd{clientID, []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, emptyPrefix}}, + types.ConnectionEnd{clientID, []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, emptyPrefix}, 500}, false, }, } @@ -98,12 +98,12 @@ func TestIdentifiedConnectionValidateBasic(t *testing.T) { }{ { "valid connection", - types.NewIdentifiedConnection(clientID, types.ConnectionEnd{clientID, []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}}), + types.NewIdentifiedConnection(clientID, types.ConnectionEnd{clientID, []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, 500}), true, }, { "invalid connection id", - types.NewIdentifiedConnection("(connectionIDONE)", types.ConnectionEnd{clientID, []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}}), + types.NewIdentifiedConnection("(connectionIDONE)", types.ConnectionEnd{clientID, []*types.Version{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, 500}), false, }, } diff --git a/x/ibc/core/03-connection/types/genesis_test.go b/x/ibc/core/03-connection/types/genesis_test.go index 8d343d1f031..846837f9af7 100644 --- a/x/ibc/core/03-connection/types/genesis_test.go +++ b/x/ibc/core/03-connection/types/genesis_test.go @@ -26,7 +26,7 @@ func TestValidateGenesis(t *testing.T) { name: "valid genesis", genState: types.NewGenesisState( []types.IdentifiedConnection{ - types.NewIdentifiedConnection(connectionID, types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion})), + types.NewIdentifiedConnection(connectionID, types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion}, 500)), }, []types.ConnectionPaths{ {clientID, []string{connectionID}}, @@ -39,7 +39,7 @@ func TestValidateGenesis(t *testing.T) { name: "invalid connection", genState: types.NewGenesisState( []types.IdentifiedConnection{ - types.NewIdentifiedConnection(connectionID, types.NewConnectionEnd(types.INIT, "(CLIENTIDONE)", types.Counterparty{clientID, connectionID, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion})), + types.NewIdentifiedConnection(connectionID, types.NewConnectionEnd(types.INIT, "(CLIENTIDONE)", types.Counterparty{clientID, connectionID, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion}, 500)), }, []types.ConnectionPaths{ {clientID, []string{connectionID}}, @@ -52,7 +52,7 @@ func TestValidateGenesis(t *testing.T) { name: "invalid client id", genState: types.NewGenesisState( []types.IdentifiedConnection{ - types.NewIdentifiedConnection(connectionID, types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion})), + types.NewIdentifiedConnection(connectionID, types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion}, 500)), }, []types.ConnectionPaths{ {"(CLIENTIDONE)", []string{connectionID}}, @@ -65,7 +65,7 @@ func TestValidateGenesis(t *testing.T) { name: "invalid path", genState: types.NewGenesisState( []types.IdentifiedConnection{ - types.NewIdentifiedConnection(connectionID, types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion})), + types.NewIdentifiedConnection(connectionID, types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion}, 500)), }, []types.ConnectionPaths{ {clientID, []string{invalidConnectionID}}, @@ -78,7 +78,7 @@ func TestValidateGenesis(t *testing.T) { name: "invalid connection identifier", genState: types.NewGenesisState( []types.IdentifiedConnection{ - types.NewIdentifiedConnection("conn-0", types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion})), + types.NewIdentifiedConnection("conn-0", types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion}, 500)), }, []types.ConnectionPaths{ {clientID, []string{connectionID}}, @@ -91,7 +91,7 @@ func TestValidateGenesis(t *testing.T) { name: "next connection sequence is not greater than maximum connection identifier sequence provided", genState: types.NewGenesisState( []types.IdentifiedConnection{ - types.NewIdentifiedConnection(types.FormatConnectionIdentifier(10), types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion})), + types.NewIdentifiedConnection(types.FormatConnectionIdentifier(10), types.NewConnectionEnd(types.INIT, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []*types.Version{ibctesting.ConnectionVersion}, 500)), }, []types.ConnectionPaths{ {clientID, []string{connectionID}}, diff --git a/x/ibc/core/03-connection/types/msgs.go b/x/ibc/core/03-connection/types/msgs.go index a734f986081..34a4b9d6305 100644 --- a/x/ibc/core/03-connection/types/msgs.go +++ b/x/ibc/core/03-connection/types/msgs.go @@ -18,13 +18,15 @@ var _ sdk.Msg = &MsgConnectionOpenInit{} func NewMsgConnectionOpenInit( clientID, counterpartyClientID string, counterpartyPrefix commitmenttypes.MerklePrefix, - version *Version, signer sdk.AccAddress, + version *Version, delayPeriod uint64, signer sdk.AccAddress, ) *MsgConnectionOpenInit { + // counterparty must have the same delay period counterparty := NewCounterparty(counterpartyClientID, "", counterpartyPrefix) return &MsgConnectionOpenInit{ ClientId: clientID, Counterparty: counterparty, Version: version, + DelayPeriod: delayPeriod, Signer: signer.String(), } } @@ -83,7 +85,8 @@ var _ sdk.Msg = &MsgConnectionOpenTry{} func NewMsgConnectionOpenTry( previousConnectionID, clientID, counterpartyConnectionID, counterpartyClientID string, counterpartyClient exported.ClientState, - counterpartyPrefix commitmenttypes.MerklePrefix, counterpartyVersions []*Version, + counterpartyPrefix commitmenttypes.MerklePrefix, + counterpartyVersions []*Version, delayPeriod uint64, proofInit, proofClient, proofConsensus []byte, proofHeight, consensusHeight clienttypes.Height, signer sdk.AccAddress, ) *MsgConnectionOpenTry { @@ -95,6 +98,7 @@ func NewMsgConnectionOpenTry( ClientState: csAny, Counterparty: counterparty, CounterpartyVersions: counterpartyVersions, + DelayPeriod: delayPeriod, ProofInit: proofInit, ProofClient: proofClient, ProofConsensus: proofConsensus, diff --git a/x/ibc/core/03-connection/types/msgs_test.go b/x/ibc/core/03-connection/types/msgs_test.go index 9c09ec1f7b1..57c1925f66d 100644 --- a/x/ibc/core/03-connection/types/msgs_test.go +++ b/x/ibc/core/03-connection/types/msgs_test.go @@ -87,13 +87,13 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenInit() { msg *types.MsgConnectionOpenInit expPass bool }{ - {"invalid client ID", types.NewMsgConnectionOpenInit("test/iris", "clienttotest", prefix, version, signer), false}, - {"invalid counterparty client ID", types.NewMsgConnectionOpenInit("clienttotest", "(clienttotest)", prefix, version, signer), false}, - {"invalid counterparty connection ID", &types.MsgConnectionOpenInit{connectionID, types.NewCounterparty("clienttotest", "connectiontotest", prefix), version, signer.String()}, false}, - {"empty counterparty prefix", types.NewMsgConnectionOpenInit("clienttotest", "clienttotest", emptyPrefix, version, signer), false}, - {"supplied version fails basic validation", types.NewMsgConnectionOpenInit("clienttotest", "clienttotest", prefix, &types.Version{}, signer), false}, - {"empty singer", types.NewMsgConnectionOpenInit("clienttotest", "clienttotest", prefix, version, nil), false}, - {"success", types.NewMsgConnectionOpenInit("clienttotest", "clienttotest", prefix, version, signer), true}, + {"invalid client ID", types.NewMsgConnectionOpenInit("test/iris", "clienttotest", prefix, version, 500, signer), false}, + {"invalid counterparty client ID", types.NewMsgConnectionOpenInit("clienttotest", "(clienttotest)", prefix, version, 500, signer), false}, + {"invalid counterparty connection ID", &types.MsgConnectionOpenInit{connectionID, types.NewCounterparty("clienttotest", "connectiontotest", prefix), version, 500, signer.String()}, false}, + {"empty counterparty prefix", types.NewMsgConnectionOpenInit("clienttotest", "clienttotest", emptyPrefix, version, 500, signer), false}, + {"supplied version fails basic validation", types.NewMsgConnectionOpenInit("clienttotest", "clienttotest", prefix, &types.Version{}, 500, signer), false}, + {"empty singer", types.NewMsgConnectionOpenInit("clienttotest", "clienttotest", prefix, version, 500, nil), false}, + {"success", types.NewMsgConnectionOpenInit("clienttotest", "clienttotest", prefix, version, 500, signer), true}, } for _, tc := range testCases { @@ -131,24 +131,24 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { msg *types.MsgConnectionOpenTry expPass bool }{ - {"invalid connection ID", types.NewMsgConnectionOpenTry("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"invalid connection ID", types.NewMsgConnectionOpenTry("(invalidconnection)", "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"invalid client ID", types.NewMsgConnectionOpenTry(connectionID, "test/iris", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"invalid counterparty connection ID", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "ibc/test", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"invalid counterparty client ID", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "test/conn1", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"invalid nil counterparty client", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", nil, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"invalid client unpacking", &types.MsgConnectionOpenTry{connectionID, "clienttotesta", invalidAny, counterparty, []*types.Version{ibctesting.ConnectionVersion}, clientHeight, suite.proof, suite.proof, suite.proof, clientHeight, signer.String()}, false}, - {"counterparty failed Validate", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", invalidClient, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"empty counterparty prefix", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, emptyPrefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"empty counterpartyVersions", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"empty proofInit", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, emptyProof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, - {"empty proofClient", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, emptyProof, suite.proof, clientHeight, clientHeight, signer), false}, - {"empty proofConsensus", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, emptyProof, clientHeight, clientHeight, signer), false}, - {"invalid proofHeight", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clienttypes.ZeroHeight(), clientHeight, signer), false}, - {"invalid consensusHeight", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clienttypes.ZeroHeight(), signer), false}, - {"empty singer", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, nil), false}, - {"success", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), true}, - {"invalid version", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{{}}, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"invalid connection ID", types.NewMsgConnectionOpenTry("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"invalid connection ID", types.NewMsgConnectionOpenTry("(invalidconnection)", "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"invalid client ID", types.NewMsgConnectionOpenTry(connectionID, "test/iris", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"invalid counterparty connection ID", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "ibc/test", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"invalid counterparty client ID", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "test/conn1", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"invalid nil counterparty client", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", nil, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"invalid client unpacking", &types.MsgConnectionOpenTry{connectionID, "clienttotesta", invalidAny, counterparty, 500, []*types.Version{ibctesting.ConnectionVersion}, clientHeight, suite.proof, suite.proof, suite.proof, clientHeight, signer.String()}, false}, + {"counterparty failed Validate", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", invalidClient, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"empty counterparty prefix", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, emptyPrefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"empty counterpartyVersions", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"empty proofInit", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, emptyProof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, + {"empty proofClient", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, emptyProof, suite.proof, clientHeight, clientHeight, signer), false}, + {"empty proofConsensus", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, emptyProof, clientHeight, clientHeight, signer), false}, + {"invalid proofHeight", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clienttypes.ZeroHeight(), clientHeight, signer), false}, + {"invalid consensusHeight", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clienttypes.ZeroHeight(), signer), false}, + {"empty singer", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, nil), false}, + {"success", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{ibctesting.ConnectionVersion}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), true}, + {"invalid version", types.NewMsgConnectionOpenTry(connectionID, "clienttotesta", "connectiontotest", "clienttotest", clientState, prefix, []*types.Version{{}}, 500, suite.proof, suite.proof, suite.proof, clientHeight, clientHeight, signer), false}, } for _, tc := range testCases { diff --git a/x/ibc/core/03-connection/types/tx.pb.go b/x/ibc/core/03-connection/types/tx.pb.go index 05e60cf3e1f..5b1ce774649 100644 --- a/x/ibc/core/03-connection/types/tx.pb.go +++ b/x/ibc/core/03-connection/types/tx.pb.go @@ -36,7 +36,8 @@ type MsgConnectionOpenInit struct { ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` Counterparty Counterparty `protobuf:"bytes,2,opt,name=counterparty,proto3" json:"counterparty"` Version *Version `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` - Signer string `protobuf:"bytes,4,opt,name=signer,proto3" json:"signer,omitempty"` + DelayPeriod uint64 `protobuf:"varint,4,opt,name=delay_period,json=delayPeriod,proto3" json:"delay_period,omitempty" yaml:"delay_period"` + Signer string `protobuf:"bytes,5,opt,name=signer,proto3" json:"signer,omitempty"` } func (m *MsgConnectionOpenInit) Reset() { *m = MsgConnectionOpenInit{} } @@ -118,17 +119,18 @@ type MsgConnectionOpenTry struct { PreviousConnectionId string `protobuf:"bytes,2,opt,name=previous_connection_id,json=previousConnectionId,proto3" json:"previous_connection_id,omitempty" yaml:"previous_connection_id"` ClientState *types.Any `protobuf:"bytes,3,opt,name=client_state,json=clientState,proto3" json:"client_state,omitempty" yaml:"client_state"` Counterparty Counterparty `protobuf:"bytes,4,opt,name=counterparty,proto3" json:"counterparty"` - CounterpartyVersions []*Version `protobuf:"bytes,5,rep,name=counterparty_versions,json=counterpartyVersions,proto3" json:"counterparty_versions,omitempty" yaml:"counterparty_versions"` - ProofHeight types1.Height `protobuf:"bytes,6,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height" yaml:"proof_height"` + DelayPeriod uint64 `protobuf:"varint,5,opt,name=delay_period,json=delayPeriod,proto3" json:"delay_period,omitempty" yaml:"delay_period"` + CounterpartyVersions []*Version `protobuf:"bytes,6,rep,name=counterparty_versions,json=counterpartyVersions,proto3" json:"counterparty_versions,omitempty" yaml:"counterparty_versions"` + ProofHeight types1.Height `protobuf:"bytes,7,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height" yaml:"proof_height"` // proof of the initialization the connection on Chain A: `UNITIALIZED -> // INIT` - ProofInit []byte `protobuf:"bytes,7,opt,name=proof_init,json=proofInit,proto3" json:"proof_init,omitempty" yaml:"proof_init"` + ProofInit []byte `protobuf:"bytes,8,opt,name=proof_init,json=proofInit,proto3" json:"proof_init,omitempty" yaml:"proof_init"` // proof of client state included in message - ProofClient []byte `protobuf:"bytes,8,opt,name=proof_client,json=proofClient,proto3" json:"proof_client,omitempty" yaml:"proof_client"` + ProofClient []byte `protobuf:"bytes,9,opt,name=proof_client,json=proofClient,proto3" json:"proof_client,omitempty" yaml:"proof_client"` // proof of client consensus state - ProofConsensus []byte `protobuf:"bytes,9,opt,name=proof_consensus,json=proofConsensus,proto3" json:"proof_consensus,omitempty" yaml:"proof_consensus"` - ConsensusHeight types1.Height `protobuf:"bytes,10,opt,name=consensus_height,json=consensusHeight,proto3" json:"consensus_height" yaml:"consensus_height"` - Signer string `protobuf:"bytes,11,opt,name=signer,proto3" json:"signer,omitempty"` + ProofConsensus []byte `protobuf:"bytes,10,opt,name=proof_consensus,json=proofConsensus,proto3" json:"proof_consensus,omitempty" yaml:"proof_consensus"` + ConsensusHeight types1.Height `protobuf:"bytes,11,opt,name=consensus_height,json=consensusHeight,proto3" json:"consensus_height" yaml:"consensus_height"` + Signer string `protobuf:"bytes,12,opt,name=signer,proto3" json:"signer,omitempty"` } func (m *MsgConnectionOpenTry) Reset() { *m = MsgConnectionOpenTry{} } @@ -384,62 +386,65 @@ func init() { func init() { proto.RegisterFile("ibc/core/connection/v1/tx.proto", fileDescriptor_5d00fde5fc97399e) } var fileDescriptor_5d00fde5fc97399e = []byte{ - // 880 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x31, 0x73, 0xda, 0x58, - 0x10, 0x46, 0x06, 0x63, 0x78, 0x70, 0x67, 0x5b, 0x07, 0x58, 0xa7, 0xb3, 0x11, 0xd6, 0xdc, 0xcd, - 0xb9, 0x38, 0x4b, 0xc6, 0xf6, 0xcd, 0xdc, 0xf9, 0xe6, 0x0a, 0xa0, 0x39, 0x17, 0xbe, 0x64, 0x14, - 0x27, 0x99, 0x71, 0xc3, 0x80, 0x10, 0xb2, 0x06, 0xa3, 0xc7, 0xe8, 0x09, 0x62, 0xa5, 0x4d, 0x93, - 0x49, 0x95, 0x9f, 0xe0, 0x9f, 0xe3, 0xd2, 0x65, 0xd2, 0x68, 0x12, 0xbb, 0x49, 0xad, 0x26, 0x93, - 0x2e, 0xa3, 0xf7, 0x24, 0x21, 0x40, 0x8c, 0x21, 0x38, 0x15, 0x5a, 0xed, 0xf7, 0xed, 0xae, 0x76, - 0xf7, 0x7b, 0x3c, 0xc0, 0x69, 0x4d, 0x59, 0x94, 0xa1, 0xa1, 0x88, 0x32, 0xd4, 0x75, 0x45, 0x36, - 0x35, 0xa8, 0x8b, 0x83, 0xb2, 0x68, 0x5e, 0x0a, 0x3d, 0x03, 0x9a, 0x90, 0x2e, 0x68, 0x4d, 0x59, - 0x70, 0x01, 0xc2, 0x10, 0x20, 0x0c, 0xca, 0x6c, 0x4e, 0x85, 0x2a, 0xc4, 0x10, 0xd1, 0x7d, 0x22, - 0x68, 0xf6, 0x67, 0x15, 0x42, 0xf5, 0x42, 0x11, 0xb1, 0xd5, 0xec, 0xb7, 0xc5, 0x86, 0x6e, 0x79, - 0xae, 0x50, 0xa6, 0x0b, 0x4d, 0xd1, 0x4d, 0x37, 0x0b, 0x79, 0xf2, 0x00, 0xbf, 0x4f, 0x29, 0x25, - 0x94, 0x17, 0x03, 0xf9, 0xcf, 0x14, 0xc8, 0x9f, 0x20, 0xb5, 0x16, 0xbc, 0x7f, 0xd4, 0x53, 0xf4, - 0x63, 0x5d, 0x33, 0xe9, 0x32, 0x48, 0x93, 0x90, 0x75, 0xad, 0xc5, 0x50, 0x25, 0x6a, 0x27, 0x5d, - 0xcd, 0x39, 0x36, 0xb7, 0x66, 0x35, 0xba, 0x17, 0x47, 0x7c, 0xe0, 0xe2, 0xa5, 0x14, 0x79, 0x3e, - 0x6e, 0xd1, 0xff, 0x83, 0xac, 0x0c, 0xfb, 0xba, 0xa9, 0x18, 0xbd, 0x86, 0x61, 0x5a, 0xcc, 0x52, - 0x89, 0xda, 0xc9, 0xec, 0xff, 0x2a, 0x44, 0x7f, 0xb6, 0x50, 0x0b, 0x61, 0xab, 0x89, 0x6b, 0x9b, - 0x8b, 0x49, 0x23, 0x7c, 0xfa, 0x6f, 0xb0, 0x32, 0x50, 0x0c, 0xa4, 0x41, 0x9d, 0x89, 0xe3, 0x50, - 0xdc, 0xb4, 0x50, 0xcf, 0x08, 0x4c, 0xf2, 0xf1, 0x74, 0x01, 0x24, 0x91, 0xa6, 0xea, 0x8a, 0xc1, - 0x24, 0xdc, 0xd2, 0x25, 0xcf, 0x3a, 0x4a, 0xbd, 0xbe, 0xe2, 0x62, 0x9f, 0xae, 0xb8, 0x18, 0xcf, - 0x81, 0xad, 0xc8, 0x0f, 0x97, 0x14, 0xd4, 0x83, 0x3a, 0x52, 0xf8, 0xf7, 0x49, 0x90, 0x9b, 0x40, - 0x9c, 0x1a, 0xd6, 0xb7, 0x74, 0xe6, 0x39, 0x28, 0xf4, 0x0c, 0x65, 0xa0, 0xc1, 0x3e, 0xaa, 0x0f, - 0x2b, 0x77, 0xf9, 0x4b, 0x98, 0xbf, 0xed, 0xd8, 0xdc, 0x16, 0xe1, 0x47, 0xe3, 0x78, 0x29, 0xe7, - 0x3b, 0x86, 0x05, 0x1d, 0xb7, 0xe8, 0xc7, 0x20, 0xeb, 0x25, 0x44, 0x66, 0xc3, 0x54, 0xbc, 0x3e, - 0xe5, 0x04, 0xb2, 0x3b, 0x82, 0xbf, 0x3b, 0x42, 0x45, 0xb7, 0xaa, 0x1b, 0x8e, 0xcd, 0xfd, 0x34, - 0x52, 0x24, 0xe6, 0xf0, 0x52, 0x86, 0x98, 0x4f, 0x5c, 0x6b, 0x62, 0x88, 0x89, 0x05, 0x87, 0x38, - 0x00, 0xf9, 0xb0, 0x5d, 0xf7, 0x26, 0x84, 0x98, 0xe5, 0x52, 0x7c, 0x86, 0x91, 0x56, 0x4b, 0x8e, - 0xcd, 0x6d, 0x7a, 0x55, 0x47, 0xc5, 0xe1, 0xa5, 0x5c, 0xf8, 0xbd, 0x47, 0x43, 0xf4, 0x19, 0xc8, - 0xf6, 0x0c, 0x08, 0xdb, 0xf5, 0x73, 0x45, 0x53, 0xcf, 0x4d, 0x26, 0x89, 0xbf, 0x83, 0x0d, 0xa5, - 0x23, 0x82, 0x19, 0x94, 0x85, 0xff, 0x30, 0xa2, 0xfa, 0x8b, 0x5b, 0xfd, 0xb0, 0x47, 0x61, 0x36, - 0x2f, 0x65, 0xb0, 0x49, 0x90, 0xf4, 0x21, 0x00, 0xc4, 0xab, 0xe9, 0x9a, 0xc9, 0xac, 0x94, 0xa8, - 0x9d, 0x6c, 0x35, 0xef, 0xd8, 0xdc, 0x7a, 0x98, 0xe9, 0xfa, 0x78, 0x29, 0x8d, 0x0d, 0xac, 0xa8, - 0x23, 0xbf, 0x22, 0x92, 0x99, 0x49, 0x61, 0xde, 0xc6, 0x78, 0x46, 0xe2, 0xf5, 0x33, 0xd6, 0xb0, - 0x45, 0xd7, 0xc0, 0xaa, 0xe7, 0x75, 0x77, 0x53, 0x47, 0x7d, 0xc4, 0xa4, 0x31, 0x9d, 0x75, 0x6c, - 0xae, 0x30, 0x42, 0xf7, 0x01, 0xbc, 0xf4, 0x23, 0x89, 0xe0, 0xbf, 0xa0, 0xdb, 0x60, 0x2d, 0xf0, - 0xfa, 0x6d, 0x01, 0xf7, 0xb6, 0x85, 0xf3, 0xda, 0xb2, 0xe1, 0x0f, 0x61, 0x34, 0x02, 0x2f, 0xad, - 0x06, 0xaf, 0xbc, 0xf6, 0x0c, 0xc5, 0x97, 0x99, 0x22, 0xbe, 0x22, 0xd8, 0x8c, 0x92, 0x56, 0xa0, - 0xbd, 0x8f, 0xcb, 0x11, 0xda, 0xab, 0xc8, 0x1d, 0xfa, 0x5f, 0xf0, 0xc3, 0xa8, 0x7e, 0x88, 0xfe, - 0x18, 0xc7, 0xe6, 0x72, 0x41, 0x7d, 0x61, 0xd9, 0x64, 0xe5, 0xb0, 0x5c, 0x64, 0xc0, 0x8e, 0x2c, - 0x51, 0x94, 0x16, 0x7f, 0x73, 0x6c, 0x6e, 0x3b, 0x62, 0xe1, 0xc6, 0x02, 0x33, 0x61, 0xe7, 0x88, - 0x26, 0x17, 0x38, 0xb6, 0xc6, 0xe5, 0x9c, 0x58, 0x58, 0xce, 0xe3, 0x32, 0x58, 0x7e, 0x40, 0x19, - 0x94, 0x01, 0xd9, 0xee, 0xba, 0x69, 0x58, 0x58, 0x5f, 0xd9, 0xf0, 0x41, 0x18, 0xb8, 0x78, 0x29, - 0x85, 0x9f, 0xdd, 0xb3, 0x73, 0x5c, 0x03, 0x2b, 0x8b, 0x69, 0x20, 0xf5, 0x20, 0x1a, 0x48, 0x7f, - 0x57, 0x0d, 0x80, 0x39, 0x34, 0x50, 0x91, 0x3b, 0x81, 0x06, 0xde, 0x2c, 0x01, 0x66, 0x02, 0x50, - 0x83, 0x7a, 0x5b, 0x33, 0xba, 0x8b, 0xea, 0x20, 0x98, 0x5c, 0x43, 0xee, 0xe0, 0xb5, 0x8f, 0x98, - 0x5c, 0x43, 0xee, 0xf8, 0x93, 0x73, 0x95, 0x37, 0xbe, 0x48, 0xf1, 0x07, 0x5c, 0xa4, 0xfb, 0xff, - 0xad, 0x79, 0x50, 0x9a, 0xd6, 0x0b, 0xbf, 0x61, 0xfb, 0x5f, 0xe2, 0x20, 0x7e, 0x82, 0x54, 0xfa, - 0x25, 0xa0, 0x23, 0xee, 0x33, 0xbb, 0xd3, 0x44, 0x18, 0x79, 0x0b, 0x60, 0xff, 0x9c, 0x0b, 0xee, - 0xd7, 0x40, 0xbf, 0x00, 0xeb, 0x93, 0x17, 0x86, 0x3f, 0x66, 0x8e, 0x75, 0x6a, 0x58, 0xec, 0xe1, - 0x3c, 0xe8, 0xe9, 0x89, 0xdd, 0x99, 0xcd, 0x9e, 0xb8, 0x22, 0x77, 0xe6, 0x48, 0x1c, 0x5a, 0x53, - 0xfa, 0x15, 0x05, 0xf2, 0xd1, 0x3b, 0xba, 0x37, 0x73, 0x3c, 0x8f, 0xc1, 0xfe, 0x35, 0x2f, 0xc3, - 0xaf, 0xa2, 0xfa, 0xf4, 0xfa, 0xb6, 0x48, 0xdd, 0xdc, 0x16, 0xa9, 0x0f, 0xb7, 0x45, 0xea, 0xed, - 0x5d, 0x31, 0x76, 0x73, 0x57, 0x8c, 0xbd, 0xbb, 0x2b, 0xc6, 0xce, 0xfe, 0x51, 0x35, 0xf3, 0xbc, - 0xdf, 0x14, 0x64, 0xd8, 0x15, 0x65, 0x88, 0xba, 0x10, 0x79, 0x3f, 0xbb, 0xa8, 0xd5, 0x11, 0x2f, - 0xc5, 0xe0, 0xa6, 0xbc, 0x77, 0xb0, 0x1b, 0xba, 0x2c, 0x9b, 0x56, 0x4f, 0x41, 0xcd, 0x24, 0x3e, - 0x71, 0x0f, 0xbe, 0x06, 0x00, 0x00, 0xff, 0xff, 0x1a, 0x4a, 0xeb, 0x3e, 0xdb, 0x0b, 0x00, 0x00, + // 921 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x31, 0x93, 0xdb, 0x44, + 0x14, 0xb6, 0xce, 0xbe, 0x3b, 0x7b, 0x6d, 0x48, 0xb2, 0xf8, 0xee, 0x84, 0x48, 0x2c, 0x47, 0x03, + 0x83, 0x0b, 0x4e, 0x8a, 0x93, 0x30, 0x03, 0x66, 0x28, 0x6c, 0x37, 0x5c, 0x11, 0xc8, 0x88, 0x00, + 0x33, 0x69, 0x3c, 0xb6, 0xbc, 0xd6, 0x69, 0x6c, 0x6b, 0x35, 0x5a, 0xd9, 0x44, 0xb4, 0x34, 0x0c, + 0x15, 0x0d, 0x7d, 0xfe, 0x03, 0x7f, 0x22, 0xe5, 0x95, 0x54, 0x1a, 0xb8, 0x6b, 0xa8, 0xd5, 0xd1, + 0x31, 0xda, 0x95, 0xe4, 0xb5, 0x2d, 0x0f, 0x36, 0x3e, 0x2a, 0xe9, 0xed, 0xfb, 0xde, 0x7b, 0xbb, + 0xef, 0x7d, 0xdf, 0xce, 0x02, 0xd9, 0x1a, 0x18, 0x9a, 0x81, 0x5d, 0xa4, 0x19, 0xd8, 0xb6, 0x91, + 0xe1, 0x59, 0xd8, 0xd6, 0xe6, 0x4d, 0xcd, 0x7b, 0xa5, 0x3a, 0x2e, 0xf6, 0x30, 0x3c, 0xb5, 0x06, + 0x86, 0x1a, 0x01, 0xd4, 0x05, 0x40, 0x9d, 0x37, 0xa5, 0xaa, 0x89, 0x4d, 0x4c, 0x21, 0x5a, 0xf4, + 0xc7, 0xd0, 0xd2, 0xbb, 0x26, 0xc6, 0xe6, 0x04, 0x69, 0xd4, 0x1a, 0xcc, 0x46, 0x5a, 0xdf, 0xf6, + 0x63, 0x17, 0x57, 0x69, 0x62, 0x21, 0xdb, 0x8b, 0xaa, 0xb0, 0xbf, 0x18, 0xf0, 0xe1, 0x86, 0xad, + 0x70, 0x75, 0x29, 0x50, 0xf9, 0xed, 0x00, 0x9c, 0x3c, 0x23, 0x66, 0x37, 0x5d, 0xff, 0xca, 0x41, + 0xf6, 0x85, 0x6d, 0x79, 0xb0, 0x09, 0x4a, 0x2c, 0x65, 0xcf, 0x1a, 0x8a, 0x42, 0x5d, 0x68, 0x94, + 0x3a, 0xd5, 0x30, 0x90, 0xef, 0xfa, 0xfd, 0xe9, 0xa4, 0xa5, 0xa4, 0x2e, 0x45, 0x2f, 0xb2, 0xff, + 0x8b, 0x21, 0xfc, 0x12, 0x54, 0x0c, 0x3c, 0xb3, 0x3d, 0xe4, 0x3a, 0x7d, 0xd7, 0xf3, 0xc5, 0x83, + 0xba, 0xd0, 0x28, 0x3f, 0x7e, 0x5f, 0xcd, 0x3e, 0xb6, 0xda, 0xe5, 0xb0, 0x9d, 0xc2, 0x9b, 0x40, + 0xce, 0xe9, 0x4b, 0xf1, 0xf0, 0x53, 0x70, 0x3c, 0x47, 0x2e, 0xb1, 0xb0, 0x2d, 0xe6, 0x69, 0x2a, + 0x79, 0x53, 0xaa, 0x6f, 0x19, 0x4c, 0x4f, 0xf0, 0xb0, 0x05, 0x2a, 0x43, 0x34, 0xe9, 0xfb, 0x3d, + 0x07, 0xb9, 0x16, 0x1e, 0x8a, 0x85, 0xba, 0xd0, 0x28, 0x74, 0xce, 0xc2, 0x40, 0x7e, 0x87, 0x1d, + 0x80, 0xf7, 0x2a, 0x7a, 0x99, 0x9a, 0xcf, 0xa9, 0x05, 0x4f, 0xc1, 0x11, 0xb1, 0x4c, 0x1b, 0xb9, + 0xe2, 0x61, 0x74, 0x6c, 0x3d, 0xb6, 0x5a, 0xc5, 0x9f, 0x5e, 0xcb, 0xb9, 0xbf, 0x5e, 0xcb, 0x39, + 0x45, 0x06, 0x0f, 0x32, 0x9b, 0xa6, 0x23, 0xe2, 0x60, 0x9b, 0x20, 0xe5, 0xd7, 0x63, 0x50, 0x5d, + 0x43, 0xbc, 0x70, 0xfd, 0xff, 0xd2, 0xd5, 0xef, 0xc0, 0xa9, 0xe3, 0xa2, 0xb9, 0x85, 0x67, 0xa4, + 0xb7, 0x38, 0x75, 0x14, 0x7f, 0x40, 0xe3, 0x1f, 0x86, 0x81, 0xfc, 0x80, 0xc5, 0x67, 0xe3, 0x14, + 0xbd, 0x9a, 0x38, 0x16, 0x1b, 0xba, 0x18, 0xc2, 0xe7, 0xa0, 0x12, 0x17, 0x24, 0x5e, 0xdf, 0x43, + 0x71, 0x8f, 0xab, 0x2a, 0xe3, 0x9d, 0x9a, 0xf0, 0x4e, 0x6d, 0xdb, 0x3e, 0xdf, 0x39, 0x3e, 0x46, + 0xd1, 0xcb, 0xcc, 0xfc, 0x3a, 0xb2, 0xd6, 0x08, 0x50, 0xd8, 0x93, 0x00, 0xab, 0x53, 0x3c, 0xdc, + 0x61, 0x8a, 0x73, 0x70, 0xc2, 0xe7, 0xea, 0xc5, 0xcc, 0x20, 0xe2, 0x51, 0x3d, 0xbf, 0x05, 0x95, + 0x3a, 0xf5, 0x30, 0x90, 0xef, 0xc7, 0x27, 0xce, 0xca, 0xa3, 0xe8, 0x55, 0x7e, 0x3d, 0x0e, 0x23, + 0xf0, 0x25, 0xa8, 0x38, 0x2e, 0xc6, 0xa3, 0xde, 0x25, 0xb2, 0xcc, 0x4b, 0x4f, 0x3c, 0xa6, 0x3d, + 0x90, 0xb8, 0x72, 0x4c, 0xa8, 0xf3, 0xa6, 0xfa, 0x05, 0x45, 0x74, 0xde, 0x8b, 0x4e, 0xbe, 0x38, + 0x13, 0x1f, 0xad, 0xe8, 0x65, 0x6a, 0x32, 0x24, 0x7c, 0x0a, 0x00, 0xf3, 0x5a, 0xb6, 0xe5, 0x89, + 0xc5, 0xba, 0xd0, 0xa8, 0x74, 0x4e, 0xc2, 0x40, 0xbe, 0xc7, 0x47, 0x46, 0x3e, 0x45, 0x2f, 0x51, + 0x83, 0x2a, 0xb9, 0x95, 0xec, 0x88, 0x55, 0x16, 0x4b, 0x34, 0xee, 0x6c, 0xb5, 0x22, 0xf3, 0x26, + 0x15, 0xbb, 0xd4, 0x82, 0x5d, 0x70, 0x27, 0xf6, 0x46, 0xbc, 0xb6, 0xc9, 0x8c, 0x88, 0x80, 0x86, + 0x4b, 0x61, 0x20, 0x9f, 0x2e, 0x85, 0x27, 0x00, 0x45, 0x7f, 0x9b, 0x65, 0x48, 0x16, 0xe0, 0x08, + 0xdc, 0x4d, 0xbd, 0x49, 0x5b, 0xca, 0xff, 0xda, 0x16, 0x39, 0x6e, 0xcb, 0x59, 0x32, 0x84, 0xe5, + 0x0c, 0x8a, 0x7e, 0x27, 0x5d, 0x8a, 0xdb, 0xb3, 0x10, 0x6e, 0x65, 0x83, 0x70, 0x6b, 0xe0, 0x7e, + 0x96, 0x2c, 0x53, 0xdd, 0xfe, 0x79, 0x98, 0xa1, 0xdb, 0xb6, 0x31, 0x86, 0x9f, 0x83, 0xb7, 0x96, + 0xb5, 0xc7, 0xb4, 0x2b, 0x86, 0x81, 0x5c, 0x4d, 0xf7, 0xc7, 0x4b, 0xae, 0x62, 0xf0, 0x52, 0x33, + 0x80, 0xb4, 0x44, 0xa2, 0x2c, 0x1d, 0x7f, 0x10, 0x06, 0xf2, 0xc3, 0x0c, 0xc2, 0xad, 0x24, 0x16, + 0x79, 0xe7, 0x92, 0x9e, 0xf7, 0xb8, 0x2e, 0x57, 0xaf, 0x82, 0xc2, 0xde, 0x57, 0xc1, 0xaa, 0x0c, + 0x0e, 0x6f, 0x51, 0x06, 0x4d, 0xc0, 0xd8, 0xdd, 0xf3, 0x5c, 0x5f, 0x3c, 0xa2, 0x74, 0xe4, 0x2e, + 0xd1, 0xd4, 0xa5, 0xe8, 0x45, 0xfa, 0x1f, 0xdd, 0xbb, 0xab, 0x1a, 0x38, 0xde, 0x4f, 0x03, 0xc5, + 0x5b, 0xd1, 0x40, 0xe9, 0x7f, 0xd5, 0x00, 0xd8, 0x41, 0x03, 0x6d, 0x63, 0x9c, 0x6a, 0xe0, 0xe7, + 0x03, 0x20, 0xae, 0x01, 0xba, 0xd8, 0x1e, 0x59, 0xee, 0x74, 0x5f, 0x1d, 0xa4, 0x93, 0xeb, 0x1b, + 0x63, 0x4a, 0xfb, 0x8c, 0xc9, 0xf5, 0x8d, 0x71, 0x32, 0xb9, 0x48, 0x79, 0xab, 0x44, 0xca, 0xdf, + 0x22, 0x91, 0x16, 0xcd, 0x2a, 0x6c, 0x68, 0x96, 0x02, 0xea, 0x9b, 0x7a, 0x91, 0x34, 0xec, 0xf1, + 0xdf, 0x79, 0x90, 0x7f, 0x46, 0x4c, 0xf8, 0x03, 0x80, 0x19, 0xef, 0xa8, 0xf3, 0x4d, 0x22, 0xcc, + 0x7c, 0x41, 0x48, 0x1f, 0xef, 0x04, 0x4f, 0xf6, 0x00, 0xbf, 0x07, 0xf7, 0xd6, 0x1f, 0x1b, 0x1f, + 0x6d, 0x9d, 0xeb, 0x85, 0xeb, 0x4b, 0x4f, 0x77, 0x41, 0x6f, 0x2e, 0x1c, 0xcd, 0x6c, 0xfb, 0xc2, + 0x6d, 0x63, 0xbc, 0x43, 0x61, 0x8e, 0xa6, 0xf0, 0x47, 0x01, 0x9c, 0x64, 0x73, 0xf4, 0xd1, 0xd6, + 0xf9, 0xe2, 0x08, 0xe9, 0x93, 0x5d, 0x23, 0x92, 0x5d, 0x74, 0xbe, 0x79, 0x73, 0x5d, 0x13, 0xae, + 0xae, 0x6b, 0xc2, 0x1f, 0xd7, 0x35, 0xe1, 0x97, 0x9b, 0x5a, 0xee, 0xea, 0xa6, 0x96, 0xfb, 0xfd, + 0xa6, 0x96, 0x7b, 0xf9, 0x99, 0x69, 0x79, 0x97, 0xb3, 0x81, 0x6a, 0xe0, 0xa9, 0x66, 0x60, 0x32, + 0xc5, 0x24, 0xfe, 0x9c, 0x93, 0xe1, 0x58, 0x7b, 0xa5, 0xa5, 0x2f, 0xf4, 0x47, 0x4f, 0xce, 0xb9, + 0x47, 0xba, 0xe7, 0x3b, 0x88, 0x0c, 0x8e, 0xe8, 0x8d, 0xfb, 0xe4, 0x9f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xc4, 0x4d, 0xc5, 0x58, 0x53, 0x0c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -663,7 +668,12 @@ func (m *MsgConnectionOpenInit) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.Signer) i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x2a + } + if m.DelayPeriod != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.DelayPeriod)) + i-- + dAtA[i] = 0x20 } if m.Version != nil { { @@ -745,7 +755,7 @@ func (m *MsgConnectionOpenTry) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.Signer) i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) i-- - dAtA[i] = 0x5a + dAtA[i] = 0x62 } { size, err := m.ConsensusHeight.MarshalToSizedBuffer(dAtA[:i]) @@ -756,27 +766,27 @@ func (m *MsgConnectionOpenTry) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x52 + dAtA[i] = 0x5a if len(m.ProofConsensus) > 0 { i -= len(m.ProofConsensus) copy(dAtA[i:], m.ProofConsensus) i = encodeVarintTx(dAtA, i, uint64(len(m.ProofConsensus))) i-- - dAtA[i] = 0x4a + dAtA[i] = 0x52 } if len(m.ProofClient) > 0 { i -= len(m.ProofClient) copy(dAtA[i:], m.ProofClient) i = encodeVarintTx(dAtA, i, uint64(len(m.ProofClient))) i-- - dAtA[i] = 0x42 + dAtA[i] = 0x4a } if len(m.ProofInit) > 0 { i -= len(m.ProofInit) copy(dAtA[i:], m.ProofInit) i = encodeVarintTx(dAtA, i, uint64(len(m.ProofInit))) i-- - dAtA[i] = 0x3a + dAtA[i] = 0x42 } { size, err := m.ProofHeight.MarshalToSizedBuffer(dAtA[:i]) @@ -787,7 +797,7 @@ func (m *MsgConnectionOpenTry) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x32 + dAtA[i] = 0x3a if len(m.CounterpartyVersions) > 0 { for iNdEx := len(m.CounterpartyVersions) - 1; iNdEx >= 0; iNdEx-- { { @@ -799,9 +809,14 @@ func (m *MsgConnectionOpenTry) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x2a + dAtA[i] = 0x32 } } + if m.DelayPeriod != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.DelayPeriod)) + i-- + dAtA[i] = 0x28 + } { size, err := m.Counterparty.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -1100,6 +1115,9 @@ func (m *MsgConnectionOpenInit) Size() (n int) { l = m.Version.Size() n += 1 + l + sovTx(uint64(l)) } + if m.DelayPeriod != 0 { + n += 1 + sovTx(uint64(m.DelayPeriod)) + } l = len(m.Signer) if l > 0 { n += 1 + l + sovTx(uint64(l)) @@ -1136,6 +1154,9 @@ func (m *MsgConnectionOpenTry) Size() (n int) { } l = m.Counterparty.Size() n += 1 + l + sovTx(uint64(l)) + if m.DelayPeriod != 0 { + n += 1 + sovTx(uint64(m.DelayPeriod)) + } if len(m.CounterpartyVersions) > 0 { for _, e := range m.CounterpartyVersions { l = e.Size() @@ -1397,6 +1418,25 @@ func (m *MsgConnectionOpenInit) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DelayPeriod", wireType) + } + m.DelayPeriod = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DelayPeriod |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } @@ -1668,6 +1708,25 @@ func (m *MsgConnectionOpenTry) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DelayPeriod", wireType) + } + m.DelayPeriod = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DelayPeriod |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyVersions", wireType) } @@ -1701,7 +1760,7 @@ func (m *MsgConnectionOpenTry) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 6: + case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofHeight", wireType) } @@ -1734,7 +1793,7 @@ func (m *MsgConnectionOpenTry) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 7: + case 8: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofInit", wireType) } @@ -1768,7 +1827,7 @@ func (m *MsgConnectionOpenTry) Unmarshal(dAtA []byte) error { m.ProofInit = []byte{} } iNdEx = postIndex - case 8: + case 9: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofClient", wireType) } @@ -1802,7 +1861,7 @@ func (m *MsgConnectionOpenTry) Unmarshal(dAtA []byte) error { m.ProofClient = []byte{} } iNdEx = postIndex - case 9: + case 10: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ProofConsensus", wireType) } @@ -1836,7 +1895,7 @@ func (m *MsgConnectionOpenTry) Unmarshal(dAtA []byte) error { m.ProofConsensus = []byte{} } iNdEx = postIndex - case 10: + case 11: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ConsensusHeight", wireType) } @@ -1869,7 +1928,7 @@ func (m *MsgConnectionOpenTry) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 11: + case 12: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } diff --git a/x/ibc/core/exported/client.go b/x/ibc/core/exported/client.go index 67c71526d1e..0fe26d9f55d 100644 --- a/x/ibc/core/exported/client.go +++ b/x/ibc/core/exported/client.go @@ -32,6 +32,14 @@ type ClientState interface { Validate() error GetProofSpecs() []*ics23.ProofSpec + // Initialization function + // Clients must validate the initial consensus state, and may store any client-specific metadata + // necessary for correct light client operation + Initialize(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, ConsensusState) error + + // Genesis function + ExportMetadata(sdk.KVStore) []GenesisMetadata + // Update and Misbehaviour functions CheckHeaderAndUpdateState(sdk.Context, codec.BinaryMarshaler, sdk.KVStore, Header) (ClientState, ConsensusState, error) @@ -102,6 +110,8 @@ type ClientState interface { store sdk.KVStore, cdc codec.BinaryMarshaler, height Height, + currentTimestamp uint64, + delayPeriod uint64, prefix Prefix, proof []byte, portID, @@ -113,6 +123,8 @@ type ClientState interface { store sdk.KVStore, cdc codec.BinaryMarshaler, height Height, + currentTimestamp uint64, + delayPeriod uint64, prefix Prefix, proof []byte, portID, @@ -124,6 +136,8 @@ type ClientState interface { store sdk.KVStore, cdc codec.BinaryMarshaler, height Height, + currentTimestamp uint64, + delayPeriod uint64, prefix Prefix, proof []byte, portID, @@ -134,6 +148,8 @@ type ClientState interface { store sdk.KVStore, cdc codec.BinaryMarshaler, height Height, + currentTimestamp uint64, + delayPeriod uint64, prefix Prefix, proof []byte, portID, @@ -187,3 +203,12 @@ type Height interface { Decrement() (Height, bool) String() string } + +// GenesisMetadata is a wrapper interface over clienttypes.GenesisMetadata +// all clients must use the concrete implementation in types +type GenesisMetadata interface { + // return store key that contains metadata without clientID-prefix + GetKey() []byte + // returns metadata value + GetValue() []byte +} diff --git a/x/ibc/core/exported/connection.go b/x/ibc/core/exported/connection.go index a21c5a53641..8f705daff1a 100644 --- a/x/ibc/core/exported/connection.go +++ b/x/ibc/core/exported/connection.go @@ -6,6 +6,7 @@ type ConnectionI interface { GetState() int32 GetCounterparty() CounterpartyConnectionI GetVersions() []Version + GetDelayPeriod() uint64 ValidateBasic() error } diff --git a/x/ibc/core/genesis_test.go b/x/ibc/core/genesis_test.go index fa0200de79d..c29feef7f8f 100644 --- a/x/ibc/core/genesis_test.go +++ b/x/ibc/core/genesis_test.go @@ -96,13 +96,22 @@ func (suite *IBCTestSuite) TestValidateGenesis() { }, ), }, + []clienttypes.IdentifiedGenesisMetadata{ + clienttypes.NewIdentifiedGenesisMetadata( + clientID, + []clienttypes.GenesisMetadata{ + clienttypes.NewGenesisMetadata([]byte("key1"), []byte("val1")), + clienttypes.NewGenesisMetadata([]byte("key2"), []byte("val2")), + }, + ), + }, clienttypes.NewParams(exported.Tendermint, exported.Localhost), true, 2, ), ConnectionGenesis: connectiontypes.NewGenesisState( []connectiontypes.IdentifiedConnection{ - connectiontypes.NewIdentifiedConnection(connectionID, connectiontypes.NewConnectionEnd(connectiontypes.INIT, clientID, connectiontypes.NewCounterparty(clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))), []*connectiontypes.Version{ibctesting.ConnectionVersion})), + connectiontypes.NewIdentifiedConnection(connectionID, connectiontypes.NewConnectionEnd(connectiontypes.INIT, clientID, connectiontypes.NewCounterparty(clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))), []*connectiontypes.Version{ibctesting.ConnectionVersion}, 0)), }, []connectiontypes.ConnectionPaths{ connectiontypes.NewConnectionPaths(clientID, []string{connectionID}), @@ -154,6 +163,15 @@ func (suite *IBCTestSuite) TestValidateGenesis() { ), }, nil, + []clienttypes.IdentifiedGenesisMetadata{ + clienttypes.NewIdentifiedGenesisMetadata( + clientID, + []clienttypes.GenesisMetadata{ + clienttypes.NewGenesisMetadata([]byte(""), []byte("val1")), + clienttypes.NewGenesisMetadata([]byte("key2"), []byte("")), + }, + ), + }, clienttypes.NewParams(exported.Tendermint), false, 2, @@ -168,7 +186,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { ClientGenesis: clienttypes.DefaultGenesisState(), ConnectionGenesis: connectiontypes.NewGenesisState( []connectiontypes.IdentifiedConnection{ - connectiontypes.NewIdentifiedConnection(connectionID, connectiontypes.NewConnectionEnd(connectiontypes.INIT, "(CLIENTIDONE)", connectiontypes.NewCounterparty(clientID, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))), []*connectiontypes.Version{connectiontypes.NewVersion("1.1", nil)})), + connectiontypes.NewIdentifiedConnection(connectionID, connectiontypes.NewConnectionEnd(connectiontypes.INIT, "(CLIENTIDONE)", connectiontypes.NewCounterparty(clientID, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))), []*connectiontypes.Version{connectiontypes.NewVersion("1.1", nil)}, 0)), }, []connectiontypes.ConnectionPaths{ connectiontypes.NewConnectionPaths(clientID, []string{connectionID}), @@ -240,13 +258,22 @@ func (suite *IBCTestSuite) TestInitGenesis() { }, ), }, + []clienttypes.IdentifiedGenesisMetadata{ + clienttypes.NewIdentifiedGenesisMetadata( + clientID, + []clienttypes.GenesisMetadata{ + clienttypes.NewGenesisMetadata([]byte("key1"), []byte("val1")), + clienttypes.NewGenesisMetadata([]byte("key2"), []byte("val2")), + }, + ), + }, clienttypes.NewParams(exported.Tendermint, exported.Localhost), true, 0, ), ConnectionGenesis: connectiontypes.NewGenesisState( []connectiontypes.IdentifiedConnection{ - connectiontypes.NewIdentifiedConnection(connectionID, connectiontypes.NewConnectionEnd(connectiontypes.INIT, clientID, connectiontypes.NewCounterparty(clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))), []*connectiontypes.Version{ibctesting.ConnectionVersion})), + connectiontypes.NewIdentifiedConnection(connectionID, connectiontypes.NewConnectionEnd(connectiontypes.INIT, clientID, connectiontypes.NewCounterparty(clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))), []*connectiontypes.Version{ibctesting.ConnectionVersion}, 0)), }, []connectiontypes.ConnectionPaths{ connectiontypes.NewConnectionPaths(clientID, []string{connectionID}), diff --git a/x/ibc/core/keeper/msg_server.go b/x/ibc/core/keeper/msg_server.go index 8815a7e45d4..5ea590fea93 100644 --- a/x/ibc/core/keeper/msg_server.go +++ b/x/ibc/core/keeper/msg_server.go @@ -134,7 +134,7 @@ func (k Keeper) SubmitMisbehaviour(goCtx context.Context, msg *clienttypes.MsgSu func (k Keeper) ConnectionOpenInit(goCtx context.Context, msg *connectiontypes.MsgConnectionOpenInit) (*connectiontypes.MsgConnectionOpenInitResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - connectionID, err := k.ConnectionKeeper.ConnOpenInit(ctx, msg.ClientId, msg.Counterparty, msg.Version) + connectionID, err := k.ConnectionKeeper.ConnOpenInit(ctx, msg.ClientId, msg.Counterparty, msg.Version, msg.DelayPeriod) if err != nil { return nil, sdkerrors.Wrap(err, "connection handshake open init failed") } @@ -166,7 +166,7 @@ func (k Keeper) ConnectionOpenTry(goCtx context.Context, msg *connectiontypes.Ms } connectionID, err := k.ConnectionKeeper.ConnOpenTry( - ctx, msg.PreviousConnectionId, msg.Counterparty, msg.ClientId, targetClient, + ctx, msg.PreviousConnectionId, msg.Counterparty, msg.DelayPeriod, msg.ClientId, targetClient, connectiontypes.ProtoVersionsToExported(msg.CounterpartyVersions), msg.ProofInit, msg.ProofClient, msg.ProofConsensus, msg.ProofHeight, msg.ConsensusHeight, ) diff --git a/x/ibc/light-clients/06-solomachine/types/client_state.go b/x/ibc/light-clients/06-solomachine/types/client_state.go index 38004b292b2..24a6582f0f2 100644 --- a/x/ibc/light-clients/06-solomachine/types/client_state.go +++ b/x/ibc/light-clients/06-solomachine/types/client_state.go @@ -1,6 +1,8 @@ package types import ( + "reflect" + ics23 "github.com/confio/ics23/go" "github.com/cosmos/cosmos-sdk/codec" @@ -74,6 +76,20 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState { ) } +// Initialize will check that initial consensus state is equal to the latest consensus state of the initial client. +func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, consState exported.ConsensusState) error { + if !reflect.DeepEqual(cs.ConsensusState, consState) { + return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "consensus state in initial client does not equal initial consensus state. expected: %s, got: %s", + cs.ConsensusState, consState) + } + return nil +} + +// ExportMetadata is a no-op since solomachine does not store any metadata in client store +func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { + return nil +} + // VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades func (cs ClientState) VerifyUpgradeAndUpdateState( _ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, @@ -238,6 +254,8 @@ func (cs ClientState) VerifyPacketCommitment( store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height, + _ uint64, + _ uint64, prefix exported.Prefix, proof []byte, portID, @@ -277,6 +295,8 @@ func (cs ClientState) VerifyPacketAcknowledgement( store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height, + _ uint64, + _ uint64, prefix exported.Prefix, proof []byte, portID, @@ -317,6 +337,8 @@ func (cs ClientState) VerifyPacketReceiptAbsence( store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height, + _ uint64, + _ uint64, prefix exported.Prefix, proof []byte, portID, @@ -355,6 +377,8 @@ func (cs ClientState) VerifyNextSequenceRecv( store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height, + _ uint64, + _ uint64, prefix exported.Prefix, proof []byte, portID, diff --git a/x/ibc/light-clients/06-solomachine/types/client_state_test.go b/x/ibc/light-clients/06-solomachine/types/client_state_test.go index 597adff345d..4f6c195c898 100644 --- a/x/ibc/light-clients/06-solomachine/types/client_state_test.go +++ b/x/ibc/light-clients/06-solomachine/types/client_state_test.go @@ -7,6 +7,7 @@ import ( commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/23-commitment/types" "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types" ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" ) @@ -80,6 +81,55 @@ func (suite *SoloMachineTestSuite) TestClientStateValidateBasic() { } } +func (suite *SoloMachineTestSuite) TestInitialize() { + // test singlesig and multisig public keys + for _, solomachine := range []*ibctesting.Solomachine{suite.solomachine, suite.solomachineMulti} { + malleatedConsensus := solomachine.ClientState().ConsensusState + malleatedConsensus.Timestamp = malleatedConsensus.Timestamp + 10 + + testCases := []struct { + name string + consState exported.ConsensusState + expPass bool + }{ + { + "valid consensus state", + solomachine.ConsensusState(), + true, + }, + { + "nil consensus state", + nil, + false, + }, + { + "invalid consensus state: Tendermint consensus state", + &ibctmtypes.ConsensusState{}, + false, + }, + { + "invalid consensus state: consensus state does not match consensus state in client", + malleatedConsensus, + false, + }, + } + + for _, tc := range testCases { + err := solomachine.ClientState().Initialize( + suite.chainA.GetContext(), suite.chainA.Codec, + suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), "solomachine"), + tc.consState, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid testcase: %s failed", tc.name) + } else { + suite.Require().Error(err, "invalid testcase: %s passed", tc.name) + } + } + } +} + func (suite *SoloMachineTestSuite) TestVerifyClientState() { // create client for tendermint so we can use client state for verification clientA, _ := suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint) @@ -336,7 +386,7 @@ func (suite *SoloMachineTestSuite) TestVerifyClientConsensusState() { func (suite *SoloMachineTestSuite) TestVerifyConnectionState() { counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, prefix) - conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions())) + conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions()), 0) path := suite.solomachine.GetConnectionStatePath(testConnectionID) @@ -587,7 +637,7 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketCommitment() { expSeq := tc.clientState.Sequence + 1 err := tc.clientState.VerifyPacketCommitment( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, commitmentBytes, + suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, commitmentBytes, ) if tc.expPass { @@ -674,7 +724,7 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketAcknowledgement() { expSeq := tc.clientState.Sequence + 1 err := tc.clientState.VerifyPacketAcknowledgement( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, ack, + suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, ack, ) if tc.expPass { @@ -761,7 +811,7 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketReceiptAbsence() { expSeq := tc.clientState.Sequence + 1 err := tc.clientState.VerifyPacketReceiptAbsence( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, + suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, ) if tc.expPass { @@ -848,7 +898,7 @@ func (suite *SoloMachineTestSuite) TestVerifyNextSeqRecv() { expSeq := tc.clientState.Sequence + 1 err := tc.clientState.VerifyNextSequenceRecv( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), tc.prefix, tc.proof, testPortID, testChannelID, nextSeqRecv, + suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, nextSeqRecv, ) if tc.expPass { diff --git a/x/ibc/light-clients/06-solomachine/types/codec_test.go b/x/ibc/light-clients/06-solomachine/types/codec_test.go index eb304bb28d4..70be186a10b 100644 --- a/x/ibc/light-clients/06-solomachine/types/codec_test.go +++ b/x/ibc/light-clients/06-solomachine/types/codec_test.go @@ -68,7 +68,7 @@ func (suite SoloMachineTestSuite) TestUnmarshalDataByType() { { "connection", types.CONNECTION, func() { counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, prefix) - conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions())) + conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions()), 0) path := solomachine.GetConnectionStatePath("connectionID") data, err = types.ConnectionStateDataBytes(cdc, path, conn) @@ -99,7 +99,7 @@ func (suite SoloMachineTestSuite) TestUnmarshalDataByType() { { "bad channel (uses connection data)", types.CHANNEL, func() { counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, prefix) - conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions())) + conn := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions()), 0) path := solomachine.GetConnectionStatePath("connectionID") data, err = types.ConnectionStateDataBytes(cdc, path, conn) diff --git a/x/ibc/light-clients/07-tendermint/types/client_state.go b/x/ibc/light-clients/07-tendermint/types/client_state.go index 10f3bc3baa1..8425b7419bf 100644 --- a/x/ibc/light-clients/07-tendermint/types/client_state.go +++ b/x/ibc/light-clients/07-tendermint/types/client_state.go @@ -140,6 +140,18 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState { } } +// Initialize will check that initial consensus state is a Tendermint consensus state +// and will store ProcessedTime for initial consensus state as ctx.BlockTime() +func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryMarshaler, clientStore sdk.KVStore, consState exported.ConsensusState) error { + if _, ok := consState.(*ConsensusState); !ok { + return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid initial consensus state. expected type: %T, got: %T", + &ConsensusState{}, consState) + } + // set processed time with initial consensus state height equal to initial client state's latest height + SetProcessedTime(clientStore, cs.GetLatestHeight(), uint64(ctx.BlockTime().UnixNano())) + return nil +} + // VerifyClientState verifies a proof of the client state of the running chain // stored on the target machine func (cs ClientState) VerifyClientState( @@ -308,6 +320,8 @@ func (cs ClientState) VerifyPacketCommitment( store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height, + currentTimestamp uint64, + delayPeriod uint64, prefix exported.Prefix, proof []byte, portID, @@ -320,6 +334,11 @@ func (cs ClientState) VerifyPacketCommitment( return err } + // check delay period has passed + if err := verifyDelayPeriodPassed(store, height, currentTimestamp, delayPeriod); err != nil { + return err + } + commitmentPath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, sequence)) path, err := commitmenttypes.ApplyPrefix(prefix, commitmentPath) if err != nil { @@ -339,6 +358,8 @@ func (cs ClientState) VerifyPacketAcknowledgement( store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height, + currentTimestamp uint64, + delayPeriod uint64, prefix exported.Prefix, proof []byte, portID, @@ -351,6 +372,11 @@ func (cs ClientState) VerifyPacketAcknowledgement( return err } + // check delay period has passed + if err := verifyDelayPeriodPassed(store, height, currentTimestamp, delayPeriod); err != nil { + return err + } + ackPath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, sequence)) path, err := commitmenttypes.ApplyPrefix(prefix, ackPath) if err != nil { @@ -371,6 +397,8 @@ func (cs ClientState) VerifyPacketReceiptAbsence( store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height, + currentTimestamp uint64, + delayPeriod uint64, prefix exported.Prefix, proof []byte, portID, @@ -382,6 +410,11 @@ func (cs ClientState) VerifyPacketReceiptAbsence( return err } + // check delay period has passed + if err := verifyDelayPeriodPassed(store, height, currentTimestamp, delayPeriod); err != nil { + return err + } + receiptPath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, sequence)) path, err := commitmenttypes.ApplyPrefix(prefix, receiptPath) if err != nil { @@ -401,6 +434,8 @@ func (cs ClientState) VerifyNextSequenceRecv( store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height, + currentTimestamp uint64, + delayPeriod uint64, prefix exported.Prefix, proof []byte, portID, @@ -412,6 +447,11 @@ func (cs ClientState) VerifyNextSequenceRecv( return err } + // check delay period has passed + if err := verifyDelayPeriodPassed(store, height, currentTimestamp, delayPeriod); err != nil { + return err + } + nextSequenceRecvPath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID)) path, err := commitmenttypes.ApplyPrefix(prefix, nextSequenceRecvPath) if err != nil { @@ -427,6 +467,23 @@ func (cs ClientState) VerifyNextSequenceRecv( return nil } +// verifyDelayPeriodPassed will ensure that at least delayPeriod amount of time has passed since consensus state was submitted +// before allowing verification to continue. +func verifyDelayPeriodPassed(store sdk.KVStore, proofHeight exported.Height, currentTimestamp, delayPeriod uint64) error { + // check that executing chain's timestamp has passed consensusState's processed time + delay period + processedTime, ok := GetProcessedTime(store, proofHeight) + if !ok { + return sdkerrors.Wrapf(ErrProcessedTimeNotFound, "processed time not found for height: %s", proofHeight) + } + validTime := processedTime + delayPeriod + // NOTE: delay period is inclusive, so if currentTimestamp is validTime, then we return no error + if validTime > currentTimestamp { + return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until time: %d, current time: %d", + validTime, currentTimestamp) + } + return nil +} + // produceVerificationArgs perfoms the basic checks on the arguments that are // shared between the verification functions and returns the unmarshalled // merkle proof, the consensus state and an error if one occurred. diff --git a/x/ibc/light-clients/07-tendermint/types/client_state_test.go b/x/ibc/light-clients/07-tendermint/types/client_state_test.go index 80be1472f86..d342c6f7488 100644 --- a/x/ibc/light-clients/07-tendermint/types/client_state_test.go +++ b/x/ibc/light-clients/07-tendermint/types/client_state_test.go @@ -1,6 +1,8 @@ package types_test import ( + "time" + ics23 "github.com/confio/ics23/go" clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types" @@ -98,6 +100,41 @@ func (suite *TendermintTestSuite) TestValidate() { } } +func (suite *TendermintTestSuite) TestInitialize() { + + testCases := []struct { + name string + consensusState exported.ConsensusState + expPass bool + }{ + { + name: "valid consensus", + consensusState: &types.ConsensusState{}, + expPass: true, + }, + { + name: "invalid consensus: consensus state is solomachine consensus", + consensusState: ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2).ConsensusState(), + expPass: false, + }, + } + + clientA, err := suite.coordinator.CreateClient(suite.chainA, suite.chainB, exported.Tendermint) + suite.Require().NoError(err) + + clientState := suite.chainA.GetClientState(clientA) + store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) + + for _, tc := range testCases { + err := clientState.Initialize(suite.chainA.GetContext(), suite.chainA.Codec, store, tc.consensusState) + if tc.expPass { + suite.Require().NoError(err, "valid case returned an error") + } else { + suite.Require().Error(err, "invalid case didn't return an error") + } + } +} + func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { testCases := []struct { name string @@ -335,6 +372,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { var ( clientState *types.ClientState proof []byte + delayPeriod uint64 proofHeight exported.Height prefix commitmenttypes.MerklePrefix ) @@ -347,6 +385,20 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { { "successful verification", func() {}, true, }, + { + name: "delay period has passed", + malleate: func() { + delayPeriod = uint64(time.Second.Nanoseconds()) + }, + expPass: true, + }, + { + name: "delay period has not passed", + malleate: func() { + delayPeriod = uint64(time.Hour.Nanoseconds()) + }, + expPass: false, + }, { "ApplyPrefix failed", func() { prefix = commitmenttypes.MerklePrefix{} @@ -396,9 +448,10 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) + currentTime := uint64(suite.chainA.GetContext().BlockTime().UnixNano()) commitment := channeltypes.CommitPacket(suite.chainA.App.IBCKeeper.Codec(), packet) err = clientState.VerifyPacketCommitment( - store, suite.chainA.Codec, proofHeight, &prefix, proof, + store, suite.chainA.Codec, proofHeight, currentTime, delayPeriod, &prefix, proof, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitment, ) @@ -418,6 +471,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { var ( clientState *types.ClientState proof []byte + delayPeriod uint64 proofHeight exported.Height prefix commitmenttypes.MerklePrefix ) @@ -430,6 +484,20 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { { "successful verification", func() {}, true, }, + { + name: "delay period has passed", + malleate: func() { + delayPeriod = uint64(time.Second.Nanoseconds()) + }, + expPass: true, + }, + { + name: "delay period has not passed", + malleate: func() { + delayPeriod = uint64(time.Hour.Nanoseconds()) + }, + expPass: false, + }, { "ApplyPrefix failed", func() { prefix = commitmenttypes.MerklePrefix{} @@ -485,8 +553,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) + currentTime := uint64(suite.chainA.GetContext().BlockTime().UnixNano()) err = clientState.VerifyPacketAcknowledgement( - store, suite.chainA.Codec, proofHeight, &prefix, proof, + store, suite.chainA.Codec, proofHeight, currentTime, delayPeriod, &prefix, proof, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ibcmock.MockAcknowledgement, ) @@ -506,6 +575,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { var ( clientState *types.ClientState proof []byte + delayPeriod uint64 proofHeight exported.Height prefix commitmenttypes.MerklePrefix ) @@ -518,6 +588,20 @@ func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { { "successful verification", func() {}, true, }, + { + name: "delay period has passed", + malleate: func() { + delayPeriod = uint64(time.Second.Nanoseconds()) + }, + expPass: true, + }, + { + name: "delay period has not passed", + malleate: func() { + delayPeriod = uint64(time.Hour.Nanoseconds()) + }, + expPass: false, + }, { "ApplyPrefix failed", func() { prefix = commitmenttypes.MerklePrefix{} @@ -572,8 +656,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) + currentTime := uint64(suite.chainA.GetContext().BlockTime().UnixNano()) err = clientState.VerifyPacketReceiptAbsence( - store, suite.chainA.Codec, proofHeight, &prefix, proof, + store, suite.chainA.Codec, proofHeight, currentTime, delayPeriod, &prefix, proof, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ) @@ -593,6 +678,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { var ( clientState *types.ClientState proof []byte + delayPeriod uint64 proofHeight exported.Height prefix commitmenttypes.MerklePrefix ) @@ -605,6 +691,20 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { { "successful verification", func() {}, true, }, + { + name: "delay period has passed", + malleate: func() { + delayPeriod = uint64(time.Second.Nanoseconds()) + }, + expPass: true, + }, + { + name: "delay period has not passed", + malleate: func() { + delayPeriod = uint64(time.Hour.Nanoseconds()) + }, + expPass: false, + }, { "ApplyPrefix failed", func() { prefix = commitmenttypes.MerklePrefix{} @@ -663,8 +763,9 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) + currentTime := uint64(suite.chainA.GetContext().BlockTime().UnixNano()) err = clientState.VerifyNextSequenceRecv( - store, suite.chainA.Codec, proofHeight, &prefix, proof, + store, suite.chainA.Codec, proofHeight, currentTime, delayPeriod, &prefix, proof, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()+1, ) diff --git a/x/ibc/light-clients/07-tendermint/types/consensus_state.go b/x/ibc/light-clients/07-tendermint/types/consensus_state.go index d55bc113054..b581983944f 100644 --- a/x/ibc/light-clients/07-tendermint/types/consensus_state.go +++ b/x/ibc/light-clients/07-tendermint/types/consensus_state.go @@ -14,8 +14,7 @@ import ( // NewConsensusState creates a new ConsensusState instance. func NewConsensusState( - timestamp time.Time, root commitmenttypes.MerkleRoot, - nextValsHash tmbytes.HexBytes, + timestamp time.Time, root commitmenttypes.MerkleRoot, nextValsHash tmbytes.HexBytes, ) *ConsensusState { return &ConsensusState{ Timestamp: timestamp, @@ -34,12 +33,14 @@ func (cs ConsensusState) GetRoot() exported.Root { return cs.Root } -// GetTimestamp returns block time in nanoseconds at which the consensus state was stored +// GetTimestamp returns block time in nanoseconds of the header that created consensus state func (cs ConsensusState) GetTimestamp() uint64 { return uint64(cs.Timestamp.UnixNano()) } // ValidateBasic defines a basic validation for the tendermint consensus state. +// NOTE: ProcessedTimestamp may be zero if this is an initial consensus state passed in by relayer +// as opposed to a consensus state constructed by the chain. func (cs ConsensusState) ValidateBasic() error { if cs.Root.Empty() { return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "root cannot be empty") diff --git a/x/ibc/light-clients/07-tendermint/types/errors.go b/x/ibc/light-clients/07-tendermint/types/errors.go index 9683dbf3cfb..276c225b736 100644 --- a/x/ibc/light-clients/07-tendermint/types/errors.go +++ b/x/ibc/light-clients/07-tendermint/types/errors.go @@ -16,8 +16,10 @@ var ( ErrInvalidHeaderHeight = sdkerrors.Register(SubModuleName, 5, "invalid header height") ErrInvalidHeader = sdkerrors.Register(SubModuleName, 6, "invalid header") ErrInvalidMaxClockDrift = sdkerrors.Register(SubModuleName, 7, "invalid max clock drift") - ErrTrustingPeriodExpired = sdkerrors.Register(SubModuleName, 8, "time since latest trusted state has passed the trusting period") - ErrUnbondingPeriodExpired = sdkerrors.Register(SubModuleName, 9, "time since latest trusted state has passed the unbonding period") - ErrInvalidProofSpecs = sdkerrors.Register(SubModuleName, 10, "invalid proof specs") - ErrInvalidValidatorSet = sdkerrors.Register(SubModuleName, 11, "invalid validator set") + ErrProcessedTimeNotFound = sdkerrors.Register(SubModuleName, 8, "processed time not found") + ErrDelayPeriodNotPassed = sdkerrors.Register(SubModuleName, 9, "packet-specified delay period has not been reached") + ErrTrustingPeriodExpired = sdkerrors.Register(SubModuleName, 10, "time since latest trusted state has passed the trusting period") + ErrUnbondingPeriodExpired = sdkerrors.Register(SubModuleName, 11, "time since latest trusted state has passed the unbonding period") + ErrInvalidProofSpecs = sdkerrors.Register(SubModuleName, 12, "invalid proof specs") + ErrInvalidValidatorSet = sdkerrors.Register(SubModuleName, 13, "invalid validator set") ) diff --git a/x/ibc/light-clients/07-tendermint/types/genesis.go b/x/ibc/light-clients/07-tendermint/types/genesis.go new file mode 100644 index 00000000000..7124643b55a --- /dev/null +++ b/x/ibc/light-clients/07-tendermint/types/genesis.go @@ -0,0 +1,21 @@ +package types + +import ( + 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/ibc/core/exported" +) + +// ExportMetadata exports all the processed times in the client store so they can be included in clients genesis +// and imported by a ClientKeeper +func (cs ClientState) ExportMetadata(store sdk.KVStore) []exported.GenesisMetadata { + gm := make([]exported.GenesisMetadata, 0) + IterateProcessedTime(store, func(key, val []byte) bool { + gm = append(gm, clienttypes.NewGenesisMetadata(key, val)) + return false + }) + if len(gm) == 0 { + return nil + } + return gm +} diff --git a/x/ibc/light-clients/07-tendermint/types/genesis_test.go b/x/ibc/light-clients/07-tendermint/types/genesis_test.go new file mode 100644 index 00000000000..5732151e63c --- /dev/null +++ b/x/ibc/light-clients/07-tendermint/types/genesis_test.go @@ -0,0 +1,38 @@ +package types_test + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + 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/light-clients/07-tendermint/types" +) + +func (suite *TendermintTestSuite) TestExportMetadata() { + clientState := types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientState(suite.chainA.GetContext(), "clientA", clientState) + + gm := clientState.ExportMetadata(suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), "clientA")) + suite.Require().Nil(gm, "client with no metadata returned non-nil exported metadata") + + clientStore := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), "clientA") + + // set some processed times + timestamp1 := uint64(time.Now().UnixNano()) + timestamp2 := uint64(time.Now().Add(time.Minute).UnixNano()) + timestampBz1 := sdk.Uint64ToBigEndian(timestamp1) + timestampBz2 := sdk.Uint64ToBigEndian(timestamp2) + types.SetProcessedTime(clientStore, clienttypes.NewHeight(0, 1), timestamp1) + types.SetProcessedTime(clientStore, clienttypes.NewHeight(0, 2), timestamp2) + + gm = clientState.ExportMetadata(suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), "clientA")) + suite.Require().NotNil(gm, "client with metadata returned nil exported metadata") + suite.Require().Len(gm, 2, "exported metadata has unexpected length") + + suite.Require().Equal(types.ProcessedTimeKey(clienttypes.NewHeight(0, 1)), gm[0].GetKey(), "metadata has unexpected key") + suite.Require().Equal(timestampBz1, gm[0].GetValue(), "metadata has unexpected value") + + suite.Require().Equal(types.ProcessedTimeKey(clienttypes.NewHeight(0, 2)), gm[1].GetKey(), "metadata has unexpected key") + suite.Require().Equal(timestampBz2, gm[1].GetValue(), "metadata has unexpected value") +} diff --git a/x/ibc/light-clients/07-tendermint/types/proposal_handle.go b/x/ibc/light-clients/07-tendermint/types/proposal_handle.go index 7e27f543a00..4cd3eb376cb 100644 --- a/x/ibc/light-clients/07-tendermint/types/proposal_handle.go +++ b/x/ibc/light-clients/07-tendermint/types/proposal_handle.go @@ -53,7 +53,7 @@ func (cs ClientState) CheckProposedHeaderAndUpdateState( // if the client is expired we unexpire the client using softer validation, otherwise // full validation on the header is performed. if cs.IsExpired(consensusState.Timestamp, ctx.BlockTime()) { - return cs.unexpireClient(consensusState, tmHeader, ctx.BlockTime()) + return cs.unexpireClient(ctx, clientStore, consensusState, tmHeader, ctx.BlockTime()) } // NOTE: the client may be frozen again since the misbehaviour evidence may @@ -61,7 +61,7 @@ func (cs ClientState) CheckProposedHeaderAndUpdateState( return cs.CheckHeaderAndUpdateState(ctx, cdc, clientStore, header) case cs.AllowUpdateAfterExpiry && cs.IsExpired(consensusState.Timestamp, ctx.BlockTime()): - return cs.unexpireClient(consensusState, tmHeader, ctx.BlockTime()) + return cs.unexpireClient(ctx, clientStore, consensusState, tmHeader, ctx.BlockTime()) default: return nil, nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client cannot be updated with proposal") @@ -72,7 +72,7 @@ func (cs ClientState) CheckProposedHeaderAndUpdateState( // unexpireClient checks if the proposed header is sufficient to update an expired client. // The client is updated if no error occurs. func (cs ClientState) unexpireClient( - consensusState *ConsensusState, header *Header, currentTimestamp time.Time, + ctx sdk.Context, clientStore sdk.KVStore, consensusState *ConsensusState, header *Header, currentTimestamp time.Time, ) (exported.ClientState, exported.ConsensusState, error) { // the client is expired and either AllowUpdateAfterMisbehaviour or AllowUpdateAfterExpiry @@ -81,7 +81,7 @@ func (cs ClientState) unexpireClient( return nil, nil, err } - newClientState, consensusState := update(&cs, header) + newClientState, consensusState := update(ctx, clientStore, &cs, header) return newClientState, consensusState, nil } diff --git a/x/ibc/light-clients/07-tendermint/types/store.go b/x/ibc/light-clients/07-tendermint/types/store.go index 50f8d2a1db2..8b2720c5a99 100644 --- a/x/ibc/light-clients/07-tendermint/types/store.go +++ b/x/ibc/light-clients/07-tendermint/types/store.go @@ -1,6 +1,8 @@ package types import ( + "strings" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -9,6 +11,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" ) +// KeyProcessedTime is appended to consensus state key to store the processed time +var KeyProcessedTime = []byte("/processedTime") + // GetConsensusState retrieves the consensus state from the client prefixed // store. An error is returned if the consensus state does not exist. func GetConsensusState(store sdk.KVStore, cdc codec.BinaryMarshaler, height exported.Height) (*ConsensusState, error) { @@ -35,3 +40,50 @@ func GetConsensusState(store sdk.KVStore, cdc codec.BinaryMarshaler, height expo return consensusState, nil } + +// IterateProcessedTime iterates through the prefix store and applies the callback. +// If the cb returns true, then iterator will close and stop. +func IterateProcessedTime(store sdk.KVStore, cb func(key, val []byte) bool) { + iterator := sdk.KVStorePrefixIterator(store, []byte(host.KeyConsensusStatePrefix)) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + keySplit := strings.Split(string(iterator.Key()), "/") + // processed time key in prefix store has format: "consensusState//processedTime" + if len(keySplit) != 3 || keySplit[2] != "processedTime" { + // ignore all consensus state keys + continue + } + + if cb(iterator.Key(), iterator.Value()) { + break + } + } +} + +// ProcessedTime Store code + +// ProcessedTimeKey returns the key under which the processed time will be stored in the client store. +func ProcessedTimeKey(height exported.Height) []byte { + return append(host.ConsensusStateKey(height), KeyProcessedTime...) +} + +// SetProcessedTime stores the time at which a header was processed and the corresponding consensus state was created. +// This is useful when validating whether a packet has reached the specified delay period in the tendermint client's +// verification functions +func SetProcessedTime(clientStore sdk.KVStore, height exported.Height, timeNs uint64) { + key := ProcessedTimeKey(height) + val := sdk.Uint64ToBigEndian(timeNs) + clientStore.Set(key, val) +} + +// GetProcessedTime gets the time (in nanoseconds) at which this chain received and processed a tendermint header. +// This is used to validate that a received packet has passed the delay period. +func GetProcessedTime(clientStore sdk.KVStore, height exported.Height) (uint64, bool) { + key := ProcessedTimeKey(height) + bz := clientStore.Get(key) + if bz == nil { + return 0, false + } + return sdk.BigEndianToUint64(bz), true +} diff --git a/x/ibc/light-clients/07-tendermint/types/store_test.go b/x/ibc/light-clients/07-tendermint/types/store_test.go index 3bb267b0fc2..b8badc09479 100644 --- a/x/ibc/light-clients/07-tendermint/types/store_test.go +++ b/x/ibc/light-clients/07-tendermint/types/store_test.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" solomachinetypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/types" "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" ) func (suite *TendermintTestSuite) TestGetConsensusState() { @@ -74,3 +75,39 @@ func (suite *TendermintTestSuite) TestGetConsensusState() { }) } } + +func (suite *TendermintTestSuite) TestGetProcessedTime() { + // Verify ProcessedTime on CreateClient + // coordinator increments time before creating client + expectedTime := suite.chainA.CurrentHeader.Time.Add(ibctesting.TimeIncrement) + + clientA, err := suite.coordinator.CreateClient(suite.chainA, suite.chainB, exported.Tendermint) + suite.Require().NoError(err) + + clientState := suite.chainA.GetClientState(clientA) + height := clientState.GetLatestHeight() + + store := suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) + actualTime, ok := types.GetProcessedTime(store, height) + suite.Require().True(ok, "could not retrieve processed time for stored consensus state") + suite.Require().Equal(uint64(expectedTime.UnixNano()), actualTime, "retrieved processed time is not expected value") + + // Verify ProcessedTime on UpdateClient + // coordinator increments time before updating client + expectedTime = suite.chainA.CurrentHeader.Time.Add(ibctesting.TimeIncrement) + + err = suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint) + suite.Require().NoError(err) + + clientState = suite.chainA.GetClientState(clientA) + height = clientState.GetLatestHeight() + + store = suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(suite.chainA.GetContext(), clientA) + actualTime, ok = types.GetProcessedTime(store, height) + suite.Require().True(ok, "could not retrieve processed time for stored consensus state") + suite.Require().Equal(uint64(expectedTime.UnixNano()), actualTime, "retrieved processed time is not expected value") + + // try to get processed time for height that doesn't exist in store + _, ok = types.GetProcessedTime(store, clienttypes.NewHeight(1, 1)) + suite.Require().False(ok, "retrieved processed time for a non-existent consensus state") +} diff --git a/x/ibc/light-clients/07-tendermint/types/update.go b/x/ibc/light-clients/07-tendermint/types/update.go index cee0015a1dc..e692e746686 100644 --- a/x/ibc/light-clients/07-tendermint/types/update.go +++ b/x/ibc/light-clients/07-tendermint/types/update.go @@ -60,7 +60,7 @@ func (cs ClientState) CheckHeaderAndUpdateState( return nil, nil, err } - newClientState, consensusState := update(&cs, tmHeader) + newClientState, consensusState := update(ctx, clientStore, &cs, tmHeader) return newClientState, consensusState, nil } @@ -166,8 +166,8 @@ func checkValidity( return nil } -// update the consensus state from a new header -func update(clientState *ClientState, header *Header) (*ClientState, *ConsensusState) { +// update the consensus state from a new header and set processed time metadata +func update(ctx sdk.Context, clientStore sdk.KVStore, clientState *ClientState, header *Header) (*ClientState, *ConsensusState) { height := header.GetHeight().(clienttypes.Height) if height.GT(clientState.LatestHeight) { clientState.LatestHeight = height @@ -178,5 +178,9 @@ func update(clientState *ClientState, header *Header) (*ClientState, *ConsensusS NextValidatorsHash: header.Header.NextValidatorsHash, } + // set context time as processed time as this is state internal to tendermint client logic. + // client state and consensus state will be set by client keeper + SetProcessedTime(clientStore, header.GetHeight(), uint64(ctx.BlockTime().UnixNano())) + return clientState, consensusState } diff --git a/x/ibc/light-clients/07-tendermint/types/upgrade.go b/x/ibc/light-clients/07-tendermint/types/upgrade.go index e3f230bbbff..074ccc2db8f 100644 --- a/x/ibc/light-clients/07-tendermint/types/upgrade.go +++ b/x/ibc/light-clients/07-tendermint/types/upgrade.go @@ -116,6 +116,8 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( // 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. + // NOTE: We do not set processed time for this consensus state since this consensus state should not be used for packet verification + // as the root is empty. The next consensus state submitted using update will be usable for packet-verification. newConsState := NewConsensusState( tmUpgradeConsState.Timestamp, commitmenttypes.MerkleRoot{}, tmUpgradeConsState.NextValidatorsHash, ) diff --git a/x/ibc/light-clients/09-localhost/types/client_state.go b/x/ibc/light-clients/09-localhost/types/client_state.go index b828aa029a3..e0ba7a2f0b2 100644 --- a/x/ibc/light-clients/09-localhost/types/client_state.go +++ b/x/ibc/light-clients/09-localhost/types/client_state.go @@ -74,6 +74,19 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState { return &cs } +// Initialize ensures that initial consensus state for localhost is nil +func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, consState exported.ConsensusState) error { + if consState != nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.") + } + return nil +} + +// ExportMetadata is a no-op for localhost client +func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { + return nil +} + // CheckHeaderAndUpdateState updates the localhost client. It only needs access to the context func (cs *ClientState) CheckHeaderAndUpdateState( ctx sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, _ exported.Header, @@ -216,6 +229,8 @@ func (cs ClientState) VerifyPacketCommitment( store sdk.KVStore, _ codec.BinaryMarshaler, _ exported.Height, + _ uint64, + _ uint64, _ exported.Prefix, _ []byte, portID, @@ -246,6 +261,8 @@ func (cs ClientState) VerifyPacketAcknowledgement( store sdk.KVStore, _ codec.BinaryMarshaler, _ exported.Height, + _ uint64, + _ uint64, _ exported.Prefix, _ []byte, portID, @@ -277,6 +294,8 @@ func (cs ClientState) VerifyPacketReceiptAbsence( store sdk.KVStore, _ codec.BinaryMarshaler, _ exported.Height, + _ uint64, + _ uint64, _ exported.Prefix, _ []byte, portID, @@ -299,6 +318,8 @@ func (cs ClientState) VerifyNextSequenceRecv( store sdk.KVStore, _ codec.BinaryMarshaler, _ exported.Height, + _ uint64, + _ uint64, _ exported.Prefix, _ []byte, portID, diff --git a/x/ibc/light-clients/09-localhost/types/client_state_test.go b/x/ibc/light-clients/09-localhost/types/client_state_test.go index 17555b9453a..13a1367d5c2 100644 --- a/x/ibc/light-clients/09-localhost/types/client_state_test.go +++ b/x/ibc/light-clients/09-localhost/types/client_state_test.go @@ -7,6 +7,8 @@ import ( channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types" commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/23-commitment/types" host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" + "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/09-localhost/types" ) @@ -50,6 +52,37 @@ func (suite *LocalhostTestSuite) TestValidate() { } } +func (suite *LocalhostTestSuite) TestInitialize() { + testCases := []struct { + name string + consState exported.ConsensusState + expPass bool + }{ + { + "valid initialization", + nil, + true, + }, + { + "invalid consenus state", + &ibctmtypes.ConsensusState{}, + false, + }, + } + + clientState := types.NewClientState("chainID", clienttypes.NewHeight(3, 10)) + + for _, tc := range testCases { + err := clientState.Initialize(suite.ctx, suite.cdc, suite.store, tc.consState) + + if tc.expPass { + suite.Require().NoError(err, "valid testcase: %s failed", tc.name) + } else { + suite.Require().Error(err, "invalid testcase: %s passed", tc.name) + } + } +} + func (suite *LocalhostTestSuite) TestVerifyClientState() { clientState := types.NewClientState("chainID", clientHeight) invalidClient := types.NewClientState("chainID", clienttypes.NewHeight(0, 12)) @@ -145,8 +178,8 @@ func (suite *LocalhostTestSuite) TestProposedHeaderAndUpdateState() { func (suite *LocalhostTestSuite) TestVerifyConnectionState() { counterparty := connectiontypes.NewCounterparty("clientB", testConnectionID, commitmenttypes.NewMerklePrefix([]byte("ibc"))) - conn1 := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, []*connectiontypes.Version{connectiontypes.NewVersion("1", nil)}) - conn2 := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, []*connectiontypes.Version{connectiontypes.NewVersion("2", nil)}) + conn1 := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, []*connectiontypes.Version{connectiontypes.NewVersion("1", nil)}, 0) + conn2 := connectiontypes.NewConnectionEnd(connectiontypes.OPEN, "clientA", counterparty, []*connectiontypes.Version{connectiontypes.NewVersion("2", nil)}, 0) testCases := []struct { name string @@ -336,7 +369,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketCommitment() { tc.malleate() err := tc.clientState.VerifyPacketCommitment( - suite.store, suite.cdc, clientHeight, nil, []byte{}, testPortID, testChannelID, testSequence, tc.commitment, + suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, testSequence, tc.commitment, ) if tc.expPass { @@ -395,7 +428,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgement() { tc.malleate() err := tc.clientState.VerifyPacketAcknowledgement( - suite.store, suite.cdc, clientHeight, nil, []byte{}, testPortID, testChannelID, testSequence, tc.ack, + suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, testSequence, tc.ack, ) if tc.expPass { @@ -411,7 +444,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketReceiptAbsence() { clientState := types.NewClientState("chainID", clientHeight) err := clientState.VerifyPacketReceiptAbsence( - suite.store, suite.cdc, clientHeight, nil, nil, testPortID, testChannelID, testSequence, + suite.store, suite.cdc, clientHeight, 0, 0, nil, nil, testPortID, testChannelID, testSequence, ) suite.Require().NoError(err, "receipt absence failed") @@ -419,7 +452,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketReceiptAbsence() { suite.store.Set(host.PacketReceiptKey(testPortID, testChannelID, testSequence), []byte("receipt")) err = clientState.VerifyPacketReceiptAbsence( - suite.store, suite.cdc, clientHeight, nil, nil, testPortID, testChannelID, testSequence, + suite.store, suite.cdc, clientHeight, 0, 0, nil, nil, testPortID, testChannelID, testSequence, ) suite.Require().Error(err, "receipt exists in store") } @@ -475,7 +508,7 @@ func (suite *LocalhostTestSuite) TestVerifyNextSeqRecv() { tc.malleate() err := tc.clientState.VerifyNextSequenceRecv( - suite.store, suite.cdc, clientHeight, nil, []byte{}, testPortID, testChannelID, nextSeqRecv, + suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, nextSeqRecv, ) if tc.expPass { diff --git a/x/ibc/testing/chain.go b/x/ibc/testing/chain.go index 4dc8ec4f25e..0534066d88d 100644 --- a/x/ibc/testing/chain.go +++ b/x/ibc/testing/chain.go @@ -41,9 +41,10 @@ import ( const ( // Default params constants used to create a TM client - TrustingPeriod time.Duration = time.Hour * 24 * 7 * 2 - UnbondingPeriod time.Duration = time.Hour * 24 * 7 * 3 - MaxClockDrift time.Duration = time.Second * 10 + TrustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + UnbondingPeriod time.Duration = time.Hour * 24 * 7 * 3 + MaxClockDrift time.Duration = time.Second * 10 + DefaultDelayPeriod uint64 = 0 DefaultChannelVersion = ibctransfertypes.Version InvalidID = "IDisInvalid" @@ -643,7 +644,7 @@ func (chain *TestChain) ConnectionOpenInit( msg := connectiontypes.NewMsgConnectionOpenInit( connection.ClientID, connection.CounterpartyClientID, - counterparty.GetPrefix(), DefaultOpenInitVersion, + counterparty.GetPrefix(), DefaultOpenInitVersion, DefaultDelayPeriod, chain.SenderAccount.GetAddress(), ) return chain.sendMsgs(msg) @@ -664,7 +665,7 @@ func (chain *TestChain) ConnectionOpenTry( msg := connectiontypes.NewMsgConnectionOpenTry( "", connection.ClientID, // does not support handshake continuation counterpartyConnection.ID, counterpartyConnection.ClientID, - counterpartyClient, counterparty.GetPrefix(), []*connectiontypes.Version{ConnectionVersion}, + counterpartyClient, counterparty.GetPrefix(), []*connectiontypes.Version{ConnectionVersion}, DefaultDelayPeriod, proofInit, proofClient, proofConsensus, proofHeight, consensusHeight, chain.SenderAccount.GetAddress(), diff --git a/x/ibc/testing/coordinator.go b/x/ibc/testing/coordinator.go index 95b59a1db9b..ade28b4df34 100644 --- a/x/ibc/testing/coordinator.go +++ b/x/ibc/testing/coordinator.go @@ -18,7 +18,7 @@ import ( var ( ChainIDPrefix = "testchain" globalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) - timeIncrement = time.Second * 5 + TimeIncrement = time.Second * 5 ) // Coordinator is a testing struct which contains N TestChain's. It handles keeping all chains @@ -241,6 +241,10 @@ func (coord *Coordinator) RecvPacket( packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) proof, proofHeight := source.QueryProof(packetKey) + // Increment time and commit block so that 5 second delay period passes between send and receive + coord.IncrementTime() + coord.CommitBlock(source, counterparty) + recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, counterparty.SenderAccount.GetAddress()) // receive on counterparty and update source client @@ -280,6 +284,10 @@ func (coord *Coordinator) AcknowledgePacket( packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) proof, proofHeight := counterparty.QueryProof(packetKey) + // Increment time and commit block so that 5 second delay period passes between send and receive + coord.IncrementTime() + coord.CommitBlock(source, counterparty) + ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, source.SenderAccount.GetAddress()) return coord.SendMsgs(source, counterparty, counterpartyClient, []sdk.Msg{ackMsg}) } @@ -291,10 +299,18 @@ func (coord *Coordinator) RelayPacket( sourceClient, counterpartyClient string, packet channeltypes.Packet, ack []byte, ) error { + // Increment time and commit block so that 5 second delay period passes between send and receive + coord.IncrementTime() + coord.CommitBlock(counterparty) + if err := coord.RecvPacket(source, counterparty, sourceClient, packet); err != nil { return err } + // Increment time and commit block so that 5 second delay period passes between send and receive + coord.IncrementTime() + coord.CommitBlock(source) + return coord.AcknowledgePacket(source, counterparty, counterpartyClient, packet, ack) } @@ -304,7 +320,16 @@ func (coord *Coordinator) RelayPacket( // CONTRACT: this function must be called after every commit on any TestChain. func (coord *Coordinator) IncrementTime() { for _, chain := range coord.Chains { - chain.CurrentHeader.Time = chain.CurrentHeader.Time.Add(timeIncrement) + chain.CurrentHeader.Time = chain.CurrentHeader.Time.Add(TimeIncrement) + chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) + } +} + +// IncrementTimeBy iterates through all the TestChain's and increments their current header time +// by specified time. +func (coord *Coordinator) IncrementTimeBy(increment time.Duration) { + for _, chain := range coord.Chains { + chain.CurrentHeader.Time = chain.CurrentHeader.Time.Add(increment) chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) } }