diff --git a/CHANGELOG.md b/CHANGELOG.md index 8119e1019a7..e05d119b1fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/light-clients/07-tendermint) [\#141](https://github.com/cosmos/ibc-go/pull/141) Freeze the client if there's a conflicting header submitted for an existing consensus state. * (modules/core/02-client) [\#8405](https://github.com/cosmos/cosmos-sdk/pull/8405) Refactor IBC client update governance proposals to use a substitute client to update a frozen or expired client. * (modules/core/02-client) [\#8673](https://github.com/cosmos/cosmos-sdk/pull/8673) IBC upgrade logic moved to 02-client and an IBC UpgradeProposal is added. +* (modules/core/03-connection) [\#171](https://github.com/cosmos/ibc-go/pull/171) Introduces a new parameter `MaxExpectedTimePerBlock` to allow connections to calculate and enforce a block delay that is proportional to time delay set by connection. ### Improvements diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 67c1741efed..b098c732179 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -155,6 +155,7 @@ - [ConnectionPaths](#ibc.core.connection.v1.ConnectionPaths) - [Counterparty](#ibc.core.connection.v1.Counterparty) - [IdentifiedConnection](#ibc.core.connection.v1.IdentifiedConnection) + - [Params](#ibc.core.connection.v1.Params) - [Version](#ibc.core.connection.v1.Version) - [State](#ibc.core.connection.v1.State) @@ -2399,6 +2400,21 @@ identifier field. + + +### Params +Params defines the set of Connection parameters. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `max_expected_time_per_block` | [uint64](#uint64) | | maximum expected time per block, used to enforce block delay. This parameter should reflect the largest amount of time that the chain might reasonably take to produce the next block under normal operating conditions. A safe choice is 3-5x the expected time per block. | + + + + + + ### Version @@ -2458,6 +2474,7 @@ GenesisState defines the ibc connection submodule's genesis state. | `connections` | [IdentifiedConnection](#ibc.core.connection.v1.IdentifiedConnection) | repeated | | | `client_connection_paths` | [ConnectionPaths](#ibc.core.connection.v1.ConnectionPaths) | repeated | | | `next_connection_sequence` | [uint64](#uint64) | | the sequence for the next generated connection identifier | +| `params` | [Params](#ibc.core.connection.v1.Params) | | | diff --git a/go.mod b/go.mod index f4100fcb9c5..233f26b718e 100644 --- a/go.mod +++ b/go.mod @@ -22,5 +22,4 @@ require ( github.com/tendermint/tm-db v0.6.4 google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f google.golang.org/grpc v1.37.0 - google.golang.org/protobuf v1.26.0 ) diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index a2531c4dd62..f066b05b822 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -144,7 +144,7 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { expClientStates = types.IdentifiedClientStates{idcs, idcs2}.Sort() req = &types.QueryClientStatesRequest{ Pagination: &query.PageRequest{ - Limit: 7, + Limit: 20, CountTotal: true, }, } @@ -159,7 +159,6 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { expClientStates = nil tc.malleate() - // always add localhost which is created by default in init genesis localhostClientState := suite.chainA.GetClientState(exported.Localhost) identifiedLocalhost := types.NewIdentifiedClientState(exported.Localhost, localhostClientState) diff --git a/modules/core/02-client/keeper/params.go b/modules/core/02-client/keeper/params.go index c9b88acd371..2addf95d0df 100644 --- a/modules/core/02-client/keeper/params.go +++ b/modules/core/02-client/keeper/params.go @@ -5,19 +5,19 @@ import ( "github.com/cosmos/ibc-go/modules/core/02-client/types" ) -// GetAllowedClients retrieves the receive enabled boolean from the paramstore +// GetAllowedClients retrieves the allowed clients from the paramstore func (k Keeper) GetAllowedClients(ctx sdk.Context) []string { var res []string k.paramSpace.Get(ctx, types.KeyAllowedClients, &res) return res } -// GetParams returns the total set of ibc-transfer parameters. +// GetParams returns the total set of ibc-client parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { return types.NewParams(k.GetAllowedClients(ctx)...) } -// SetParams sets the total set of ibc-transfer parameters. +// SetParams sets the total set of ibc-client parameters. func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramSpace.SetParamSet(ctx, ¶ms) } diff --git a/modules/core/02-client/types/params.go b/modules/core/02-client/types/params.go index f9c50f15f1a..6460a3fcde5 100644 --- a/modules/core/02-client/types/params.go +++ b/modules/core/02-client/types/params.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" - "github.com/cosmos/ibc-go/modules/core/exported" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/ibc-go/modules/core/exported" ) var ( @@ -21,19 +21,19 @@ func ParamKeyTable() paramtypes.KeyTable { return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) } -// NewParams creates a new parameter configuration for the ibc transfer module +// NewParams creates a new parameter configuration for the ibc client module func NewParams(allowedClients ...string) Params { return Params{ AllowedClients: allowedClients, } } -// DefaultParams is the default parameter configuration for the ibc-transfer module +// DefaultParams is the default parameter configuration for the ibc-client module func DefaultParams() Params { return NewParams(DefaultAllowedClients...) } -// Validate all ibc-transfer module parameters +// Validate all ibc-client module parameters func (p Params) Validate() error { return validateClients(p.AllowedClients) } diff --git a/modules/core/03-connection/genesis.go b/modules/core/03-connection/genesis.go index ca2d9e7e90b..af46c8ba694 100644 --- a/modules/core/03-connection/genesis.go +++ b/modules/core/03-connection/genesis.go @@ -17,6 +17,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) { k.SetClientConnectionPaths(ctx, connPaths.ClientId, connPaths.Paths) } k.SetNextConnectionSequence(ctx, gs.NextConnectionSequence) + k.SetParams(ctx, gs.Params) } // ExportGenesis returns the ibc connection submodule's exported genesis. diff --git a/modules/core/03-connection/keeper/keeper.go b/modules/core/03-connection/keeper/keeper.go index 49747b56704..3ce029168ac 100644 --- a/modules/core/03-connection/keeper/keeper.go +++ b/modules/core/03-connection/keeper/keeper.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" "github.com/cosmos/ibc-go/modules/core/03-connection/types" commitmenttypes "github.com/cosmos/ibc-go/modules/core/23-commitment/types" @@ -19,15 +20,22 @@ type Keeper struct { types.QueryServer storeKey sdk.StoreKey + paramSpace paramtypes.Subspace cdc codec.BinaryCodec clientKeeper types.ClientKeeper } // NewKeeper creates a new IBC connection Keeper instance -func NewKeeper(cdc codec.BinaryCodec, key sdk.StoreKey, ck types.ClientKeeper) Keeper { +func NewKeeper(cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, ck types.ClientKeeper) Keeper { + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ storeKey: key, cdc: cdc, + paramSpace: paramSpace, clientKeeper: ck, } } diff --git a/modules/core/03-connection/keeper/params.go b/modules/core/03-connection/keeper/params.go new file mode 100644 index 00000000000..df057f9d093 --- /dev/null +++ b/modules/core/03-connection/keeper/params.go @@ -0,0 +1,23 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/modules/core/03-connection/types" +) + +// GetMaxExpectedTimePerBlock retrieves the maximum expected time per block from the paramstore +func (k Keeper) GetMaxExpectedTimePerBlock(ctx sdk.Context) uint64 { + var res uint64 + k.paramSpace.Get(ctx, types.KeyMaxExpectedTimePerBlock, &res) + return res +} + +// GetParams returns the total set of ibc-connection parameters. +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + return types.NewParams(k.GetMaxExpectedTimePerBlock(ctx)) +} + +// SetParams sets the total set of ibc-connection parameters. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} diff --git a/modules/core/03-connection/keeper/params_test.go b/modules/core/03-connection/keeper/params_test.go new file mode 100644 index 00000000000..53ab160c9dc --- /dev/null +++ b/modules/core/03-connection/keeper/params_test.go @@ -0,0 +1,17 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-go/modules/core/03-connection/types" +) + +func (suite *KeeperTestSuite) TestParams() { + expParams := types.DefaultParams() + + params := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(expParams, params) + + expParams.MaxExpectedTimePerBlock = 10 + suite.chainA.App.GetIBCKeeper().ConnectionKeeper.SetParams(suite.chainA.GetContext(), expParams) + params = suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetParams(suite.chainA.GetContext()) + suite.Require().Equal(uint64(10), expParams.MaxExpectedTimePerBlock) +} diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index 38722f98958..510039740ee 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -1,6 +1,8 @@ package keeper import ( + "math" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" @@ -159,9 +161,13 @@ func (k Keeper) VerifyPacketCommitment( return sdkerrors.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } + // get time and block delays + timeDelay := connection.GetDelayPeriod() + blockDelay := k.getBlockDelay(ctx, connection) + if err := clientState.VerifyPacketCommitment( - clientStore, k.cdc, height, - uint64(ctx.BlockTime().UnixNano()), connection.GetDelayPeriod(), + ctx, clientStore, k.cdc, height, + timeDelay, blockDelay, connection.GetCounterparty().GetPrefix(), proof, portID, channelID, sequence, commitmentBytes, ); err != nil { @@ -195,9 +201,13 @@ func (k Keeper) VerifyPacketAcknowledgement( return sdkerrors.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } + // get time and block delays + timeDelay := connection.GetDelayPeriod() + blockDelay := k.getBlockDelay(ctx, connection) + if err := clientState.VerifyPacketAcknowledgement( - clientStore, k.cdc, height, - uint64(ctx.BlockTime().UnixNano()), connection.GetDelayPeriod(), + ctx, clientStore, k.cdc, height, + timeDelay, blockDelay, connection.GetCounterparty().GetPrefix(), proof, portID, channelID, sequence, acknowledgement, ); err != nil { @@ -231,9 +241,13 @@ func (k Keeper) VerifyPacketReceiptAbsence( return sdkerrors.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } + // get time and block delays + timeDelay := connection.GetDelayPeriod() + blockDelay := k.getBlockDelay(ctx, connection) + if err := clientState.VerifyPacketReceiptAbsence( - clientStore, k.cdc, height, - uint64(ctx.BlockTime().UnixNano()), connection.GetDelayPeriod(), + ctx, clientStore, k.cdc, height, + timeDelay, blockDelay, connection.GetCounterparty().GetPrefix(), proof, portID, channelID, sequence, ); err != nil { @@ -266,9 +280,13 @@ func (k Keeper) VerifyNextSequenceRecv( return sdkerrors.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } + // get time and block delays + timeDelay := connection.GetDelayPeriod() + blockDelay := k.getBlockDelay(ctx, connection) + if err := clientState.VerifyNextSequenceRecv( - clientStore, k.cdc, height, - uint64(ctx.BlockTime().UnixNano()), connection.GetDelayPeriod(), + ctx, clientStore, k.cdc, height, + timeDelay, blockDelay, connection.GetCounterparty().GetPrefix(), proof, portID, channelID, nextSequenceRecv, ); err != nil { @@ -277,3 +295,18 @@ func (k Keeper) VerifyNextSequenceRecv( return nil } + +// getBlockDelay calculates the block delay period from the time delay of the connection +// and the maximum expected time per block. +func (k Keeper) getBlockDelay(ctx sdk.Context, connection exported.ConnectionI) uint64 { + // expectedTimePerBlock should never be zero, however if it is then return a 0 blcok delay for safety + // as the expectedTimePerBlock parameter was not set. + expectedTimePerBlock := k.GetMaxExpectedTimePerBlock(ctx) + if expectedTimePerBlock == 0 { + return 0 + } + // calculate minimum block delay by dividing time delay period + // by the expected time per block. Round up the block delay. + timeDelay := connection.GetDelayPeriod() + return uint64(math.Ceil(float64(timeDelay) / float64(expectedTimePerBlock))) +} diff --git a/modules/core/03-connection/keeper/verify_test.go b/modules/core/03-connection/keeper/verify_test.go index f57953feff6..620f4425e5f 100644 --- a/modules/core/03-connection/keeper/verify_test.go +++ b/modules/core/03-connection/keeper/verify_test.go @@ -290,10 +290,11 @@ func (suite *KeeperTestSuite) TestVerifyChannelState() { // packet is sent from chainA to chainB, but has not been received. func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { var ( - path *ibctesting.Path - packet channeltypes.Packet - heightDiff uint64 - delayPeriod uint64 + path *ibctesting.Path + packet channeltypes.Packet + heightDiff uint64 + delayTimePeriod uint64 + timePerBlock uint64 ) cases := []struct { name string @@ -302,10 +303,16 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { }{ {"verification success", func() {}, true}, {"verification success: delay period passed", func() { - delayPeriod = uint64(1 * time.Second.Nanoseconds()) + delayTimePeriod = uint64(1 * time.Second.Nanoseconds()) }, true}, - {"delay period has not passed", func() { - delayPeriod = uint64(1 * time.Hour.Nanoseconds()) + {"delay time period has not passed", func() { + delayTimePeriod = uint64(1 * time.Hour.Nanoseconds()) + }, false}, + {"delay block period has not passed", func() { + // make timePerBlock 1 nanosecond so that block delay is not passed. + // must also set a non-zero time delay to ensure block delay is enforced. + delayTimePeriod = uint64(1 * time.Second.Nanoseconds()) + timePerBlock = 1 }, false}, {"client state not found- changed client ID", func() { connection := path.EndpointB.GetConnection() @@ -338,13 +345,22 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { err := path.EndpointA.SendPacket(packet) suite.Require().NoError(err) + // reset variables + heightDiff = 0 + delayTimePeriod = 0 + timePerBlock = 0 tc.malleate() connection := path.EndpointB.GetConnection() - connection.DelayPeriod = delayPeriod + connection.DelayPeriod = delayTimePeriod commitmentKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) proof, proofHeight := suite.chainA.QueryProof(commitmentKey) + // set time per block param + if timePerBlock != 0 { + suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(timePerBlock)) + } + commitment := channeltypes.CommitPacket(suite.chainB.App.GetIBCKeeper().Codec(), packet) err = suite.chainB.App.GetIBCKeeper().ConnectionKeeper.VerifyPacketCommitment( suite.chainB.GetContext(), connection, malleateHeight(proofHeight, heightDiff), proof, @@ -365,10 +381,11 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { // is sent from chainA to chainB and received. func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { var ( - path *ibctesting.Path - ack exported.Acknowledgement - heightDiff uint64 - delayPeriod uint64 + path *ibctesting.Path + ack exported.Acknowledgement + heightDiff uint64 + delayTimePeriod uint64 + timePerBlock uint64 ) cases := []struct { @@ -378,10 +395,16 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { }{ {"verification success", func() {}, true}, {"verification success: delay period passed", func() { - delayPeriod = uint64(1 * time.Second.Nanoseconds()) + delayTimePeriod = uint64(1 * time.Second.Nanoseconds()) }, true}, - {"delay period has not passed", func() { - delayPeriod = uint64(1 * time.Hour.Nanoseconds()) + {"delay time period has not passed", func() { + delayTimePeriod = uint64(1 * time.Hour.Nanoseconds()) + }, false}, + {"delay block period has not passed", func() { + // make timePerBlock 1 nanosecond so that block delay is not passed. + // must also set a non-zero time delay to ensure block delay is enforced. + delayTimePeriod = uint64(1 * time.Second.Nanoseconds()) + timePerBlock = 1 }, false}, {"client state not found- changed client ID", func() { connection := path.EndpointA.GetConnection() @@ -426,10 +449,19 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { packetAckKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) proof, proofHeight := suite.chainB.QueryProof(packetAckKey) + // reset variables + heightDiff = 0 + delayTimePeriod = 0 + timePerBlock = 0 tc.malleate() connection := path.EndpointA.GetConnection() - connection.DelayPeriod = delayPeriod + connection.DelayPeriod = delayTimePeriod + + // set time per block param + if timePerBlock != 0 { + suite.chainA.App.GetIBCKeeper().ConnectionKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(timePerBlock)) + } err = suite.chainA.App.GetIBCKeeper().ConnectionKeeper.VerifyPacketAcknowledgement( suite.chainA.GetContext(), connection, malleateHeight(proofHeight, heightDiff), proof, @@ -450,10 +482,11 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { // a packet is sent from chainA to chainB and not received. func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { var ( - path *ibctesting.Path - packet channeltypes.Packet - heightDiff uint64 - delayPeriod uint64 + path *ibctesting.Path + packet channeltypes.Packet + heightDiff uint64 + delayTimePeriod uint64 + timePerBlock uint64 ) cases := []struct { @@ -463,10 +496,16 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { }{ {"verification success", func() {}, true}, {"verification success: delay period passed", func() { - delayPeriod = uint64(1 * time.Second.Nanoseconds()) + delayTimePeriod = uint64(1 * time.Second.Nanoseconds()) }, true}, - {"delay period has not passed", func() { - delayPeriod = uint64(1 * time.Hour.Nanoseconds()) + {"delay time period has not passed", func() { + delayTimePeriod = uint64(1 * time.Hour.Nanoseconds()) + }, false}, + {"delay block period has not passed", func() { + // make timePerBlock 1 nanosecond so that block delay is not passed. + // must also set a non-zero time delay to ensure block delay is enforced. + delayTimePeriod = uint64(1 * time.Second.Nanoseconds()) + timePerBlock = 1 }, false}, {"client state not found - changed client ID", func() { connection := path.EndpointA.GetConnection() @@ -505,10 +544,14 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { err := path.EndpointA.SendPacket(packet) suite.Require().NoError(err) + // reset variables + heightDiff = 0 + delayTimePeriod = 0 + timePerBlock = 0 tc.malleate() connection := path.EndpointA.GetConnection() - connection.DelayPeriod = delayPeriod + connection.DelayPeriod = delayTimePeriod clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState) if clientState.FrozenHeight.IsZero() { @@ -520,6 +563,11 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { packetReceiptKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) proof, proofHeight := suite.chainB.QueryProof(packetReceiptKey) + // set time per block param + if timePerBlock != 0 { + suite.chainA.App.GetIBCKeeper().ConnectionKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(timePerBlock)) + } + err = suite.chainA.App.GetIBCKeeper().ConnectionKeeper.VerifyPacketReceiptAbsence( suite.chainA.GetContext(), connection, malleateHeight(proofHeight, heightDiff), proof, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), @@ -539,10 +587,11 @@ func (suite *KeeperTestSuite) TestVerifyPacketReceiptAbsence() { // is sent from chainA to chainB and received. func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { var ( - path *ibctesting.Path - heightDiff uint64 - delayPeriod uint64 - offsetSeq uint64 + path *ibctesting.Path + heightDiff uint64 + delayTimePeriod uint64 + timePerBlock uint64 + offsetSeq uint64 ) cases := []struct { @@ -552,10 +601,16 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { }{ {"verification success", func() {}, true}, {"verification success: delay period passed", func() { - delayPeriod = uint64(1 * time.Second.Nanoseconds()) + delayTimePeriod = uint64(1 * time.Second.Nanoseconds()) }, true}, - {"delay period has not passed", func() { - delayPeriod = uint64(1 * time.Hour.Nanoseconds()) + {"delay time period has not passed", func() { + delayTimePeriod = uint64(1 * time.Hour.Nanoseconds()) + }, false}, + {"delay block period has not passed", func() { + // make timePerBlock 1 nanosecond so that block delay is not passed. + // must also set a non-zero time delay to ensure block delay is enforced. + delayTimePeriod = uint64(1 * time.Second.Nanoseconds()) + timePerBlock = 1 }, false}, {"client state not found- changed client ID", func() { connection := path.EndpointA.GetConnection() @@ -599,10 +654,19 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { nextSeqRecvKey := host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) proof, proofHeight := suite.chainB.QueryProof(nextSeqRecvKey) + // reset variables + heightDiff = 0 + delayTimePeriod = 0 + timePerBlock = 0 tc.malleate() + // set time per block param + if timePerBlock != 0 { + suite.chainA.App.GetIBCKeeper().ConnectionKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(timePerBlock)) + } + connection := path.EndpointA.GetConnection() - connection.DelayPeriod = delayPeriod + connection.DelayPeriod = delayTimePeriod err = suite.chainA.App.GetIBCKeeper().ConnectionKeeper.VerifyNextSequenceRecv( suite.chainA.GetContext(), connection, malleateHeight(proofHeight, heightDiff), proof, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()+offsetSeq, diff --git a/modules/core/03-connection/types/connection.pb.go b/modules/core/03-connection/types/connection.pb.go index 163897783e4..07577489103 100644 --- a/modules/core/03-connection/types/connection.pb.go +++ b/modules/core/03-connection/types/connection.pb.go @@ -354,6 +354,54 @@ func (m *Version) XXX_DiscardUnknown() { var xxx_messageInfo_Version proto.InternalMessageInfo +// Params defines the set of Connection parameters. +type Params struct { + // maximum expected time per block, used to enforce block delay. This parameter should reflect the largest amount of + // time that the chain might reasonably take to produce the next block under normal operating conditions. A safe + // choice is 3-5x the expected time per block. + MaxExpectedTimePerBlock uint64 `protobuf:"varint,1,opt,name=max_expected_time_per_block,json=maxExpectedTimePerBlock,proto3" json:"max_expected_time_per_block,omitempty" yaml:"max_expected_time_per_block"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_90572467c054e43a, []int{6} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetMaxExpectedTimePerBlock() uint64 { + if m != nil { + return m.MaxExpectedTimePerBlock + } + return 0 +} + func init() { proto.RegisterEnum("ibc.core.connection.v1.State", State_name, State_value) proto.RegisterType((*ConnectionEnd)(nil), "ibc.core.connection.v1.ConnectionEnd") @@ -362,6 +410,7 @@ func init() { proto.RegisterType((*ClientPaths)(nil), "ibc.core.connection.v1.ClientPaths") proto.RegisterType((*ConnectionPaths)(nil), "ibc.core.connection.v1.ConnectionPaths") proto.RegisterType((*Version)(nil), "ibc.core.connection.v1.Version") + proto.RegisterType((*Params)(nil), "ibc.core.connection.v1.Params") } func init() { @@ -369,49 +418,52 @@ func init() { } var fileDescriptor_90572467c054e43a = []byte{ - // 658 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, 0x0a, 0x4d, 0xe9, 0x21, 0x76, 0x5c, 0x10, 0x6d, 0x5d, 0x23, 0x3b, - 0x85, 0xe6, 0x62, 0x6c, 0x69, 0xe3, 0x2c, 0xb5, 0xb5, 0x46, 0x5a, 0x9b, 0xfa, 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, 0xbd, 0xbd, 0xd9, 0x37, 0x33, 0xde, 0x37, - 0x7e, 0x5a, 0xf0, 0x08, 0xf7, 0x6c, 0xc3, 0x26, 0x1e, 0x32, 0x6c, 0xe2, 0xba, 0xc8, 0xa6, 0x98, - 0xb8, 0xc6, 0xa4, 0x92, 0x40, 0xe5, 0x91, 0x47, 0x28, 0x81, 0xf7, 0x70, 0xcf, 0x2e, 0x07, 0xc4, - 0x72, 0xa2, 0x35, 0xa9, 0xc8, 0xc5, 0x3e, 0xe9, 0x93, 0x90, 0x62, 0x04, 0x15, 0x63, 0xcb, 0x49, - 0xdb, 0xe1, 0x10, 0xd3, 0x21, 0x72, 0x29, 0xb3, 0x5d, 0x20, 0x46, 0xd4, 0xbf, 0x09, 0x20, 0x5f, - 0x8b, 0x0d, 0xeb, 0xae, 0x03, 0x2b, 0x20, 0x6b, 0x0f, 0x30, 0x72, 0x69, 0x07, 0x3b, 0x12, 0xaf, - 0xf1, 0xa5, 0x6c, 0xb5, 0x38, 0x9f, 0xa9, 0x85, 0x69, 0x77, 0x38, 0xd8, 0xd6, 0xe3, 0x96, 0x6e, - 0x65, 0x58, 0x6d, 0x3a, 0xf0, 0x39, 0xc8, 0x4c, 0x90, 0xe7, 0x63, 0xe2, 0xfa, 0x92, 0xa0, 0xa5, - 0x4a, 0xb9, 0x4d, 0xb5, 0xfc, 0xe7, 0xeb, 0x96, 0xdf, 0x31, 0x9e, 0x15, 0x0b, 0xe0, 0x16, 0x48, - 0xfb, 0xb4, 0x4b, 0x91, 0x94, 0xd2, 0xf8, 0xd2, 0x7f, 0x9b, 0xeb, 0xd7, 0x29, 0x5b, 0x01, 0xc9, - 0x62, 0x5c, 0xd8, 0x00, 0x6b, 0x36, 0x19, 0xbb, 0x14, 0x79, 0xa3, 0xae, 0x47, 0xa7, 0x92, 0xa8, - 0xf1, 0xa5, 0xdc, 0xe6, 0xc3, 0xeb, 0xb4, 0xb5, 0x04, 0xb7, 0x2a, 0x9e, 0xce, 0x54, 0xce, 0xba, - 0xa4, 0x87, 0xdb, 0x60, 0xcd, 0x41, 0x83, 0xee, 0xb4, 0x33, 0x42, 0x1e, 0x26, 0x8e, 0x94, 0xd6, - 0xf8, 0x92, 0x58, 0xbd, 0x3f, 0x9f, 0xa9, 0x77, 0xd9, 0xdc, 0xc9, 0xae, 0x6e, 0xe5, 0x42, 0xd8, - 0x0c, 0xd1, 0xb6, 0x78, 0xf4, 0x45, 0xe5, 0xf4, 0x5f, 0x02, 0x28, 0x9a, 0x0e, 0x72, 0x29, 0x3e, - 0xc0, 0xc8, 0x59, 0x46, 0x0a, 0xd7, 0x81, 0x10, 0x07, 0x99, 0x9f, 0xcf, 0xd4, 0x2c, 0x33, 0x0c, - 0x12, 0x14, 0xf0, 0x95, 0xb8, 0x85, 0x1b, 0xc7, 0x9d, 0xba, 0x75, 0xdc, 0xe2, 0x5f, 0xc4, 0x9d, - 0xfe, 0xc7, 0x71, 0xaf, 0xdc, 0x38, 0xee, 0xef, 0x3c, 0x58, 0x4b, 0xfe, 0xcc, 0x6d, 0xd6, 0xf6, - 0x05, 0xc8, 0x2f, 0xef, 0xbd, 0x8c, 0x5f, 0x9a, 0xcf, 0xd4, 0x62, 0x24, 0x4b, 0xb6, 0xf5, 0x60, - 0x88, 0x05, 0x36, 0x1d, 0x58, 0x05, 0x2b, 0x23, 0x0f, 0x1d, 0xe0, 0x8f, 0xe1, 0xe6, 0x5e, 0x89, - 0x23, 0xfe, 0xcc, 0x26, 0x95, 0xf2, 0x1b, 0xe4, 0x7d, 0x18, 0xa0, 0x66, 0xc8, 0x8d, 0xe2, 0x88, - 0x94, 0xd1, 0x30, 0x0f, 0x40, 0xae, 0x16, 0x5e, 0xaa, 0xd9, 0xa5, 0x87, 0x3e, 0x2c, 0x82, 0xf4, - 0x28, 0x28, 0x24, 0x5e, 0x4b, 0x95, 0xb2, 0x16, 0x03, 0xfa, 0x3e, 0xf8, 0x7f, 0xb9, 0x55, 0x8c, - 0x78, 0x8b, 0x99, 0x63, 0x6f, 0x21, 0xe9, 0xfd, 0x0a, 0xac, 0x46, 0x9b, 0x02, 0x15, 0x00, 0xf0, - 0x62, 0x8d, 0x3d, 0x66, 0x6a, 0x25, 0x4e, 0xa0, 0x0c, 0x32, 0x07, 0xa8, 0x4b, 0xc7, 0x1e, 0x5a, - 0x78, 0xc4, 0x98, 0x4d, 0xf3, 0xf8, 0x33, 0x0f, 0xd2, 0xe1, 0xf6, 0xc0, 0xa7, 0x40, 0x6d, 0xb5, - 0x77, 0xda, 0xf5, 0xce, 0x5e, 0xc3, 0x6c, 0x98, 0x6d, 0x73, 0xe7, 0xb5, 0xb9, 0x5f, 0xdf, 0xed, - 0xec, 0x35, 0x5a, 0xcd, 0x7a, 0xcd, 0x7c, 0x69, 0xd6, 0x77, 0x0b, 0x9c, 0x7c, 0xe7, 0xf8, 0x44, - 0xcb, 0x5f, 0x22, 0x40, 0x09, 0x00, 0xa6, 0x0b, 0x0e, 0x0b, 0xbc, 0x9c, 0x39, 0x3e, 0xd1, 0xc4, - 0xa0, 0x86, 0x0a, 0xc8, 0xb3, 0x4e, 0xdb, 0x7a, 0xff, 0xb6, 0x59, 0x6f, 0x14, 0x04, 0x39, 0x77, - 0x7c, 0xa2, 0xad, 0x46, 0x70, 0xa9, 0x0c, 0x9b, 0x29, 0xa6, 0x0c, 0x6a, 0x59, 0x3c, 0xfa, 0xaa, - 0x70, 0xd5, 0xd6, 0xe9, 0xb9, 0xc2, 0x9f, 0x9d, 0x2b, 0xfc, 0xcf, 0x73, 0x85, 0xff, 0x74, 0xa1, - 0x70, 0x67, 0x17, 0x0a, 0xf7, 0xe3, 0x42, 0xe1, 0xf6, 0x9f, 0xf5, 0x31, 0x3d, 0x1c, 0xf7, 0x82, - 0xbf, 0xce, 0xb0, 0x89, 0x3f, 0x24, 0xbe, 0x81, 0x7b, 0xf6, 0x46, 0x9f, 0x18, 0x43, 0xe2, 0x8c, - 0x07, 0xc8, 0x67, 0xcf, 0xe9, 0x93, 0xad, 0x8d, 0xc4, 0x43, 0x4d, 0xa7, 0x23, 0xe4, 0xf7, 0x56, - 0xc2, 0xa7, 0x74, 0xeb, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7b, 0x1f, 0x87, 0x8e, 0xcc, 0x05, - 0x00, 0x00, + // 717 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x5f, 0x6b, 0xda, 0x5c, + 0x18, 0x37, 0x31, 0x5a, 0x3d, 0xd6, 0xf7, 0xf5, 0x3d, 0xaf, 0xbc, 0x0d, 0xbe, 0x34, 0x09, 0xd9, + 0xd8, 0x64, 0x50, 0x9d, 0x2d, 0x0c, 0xd6, 0xb1, 0x8b, 0x6a, 0x1d, 0x84, 0x6d, 0x4e, 0xa2, 0x1d, + 0xac, 0x37, 0x12, 0x93, 0x53, 0x7b, 0xa8, 0xc9, 0x91, 0xe4, 0x28, 0xfa, 0x0d, 0x4a, 0xaf, 0x76, + 0xbb, 0x8b, 0xc2, 0x60, 0xdf, 0x65, 0x94, 0x5d, 0xf5, 0x72, 0x57, 0x32, 0xda, 0xdb, 0x5d, 0xf9, + 0x09, 0x46, 0x72, 0xa2, 0xa6, 0x65, 0x1d, 0xb4, 0xdb, 0xdd, 0xf3, 0xe4, 0xf7, 0xc7, 0xe7, 0xf9, + 0xf9, 0x18, 0xc1, 0x43, 0xdc, 0x35, 0xcb, 0x26, 0x71, 0x51, 0xd9, 0x24, 0x8e, 0x83, 0x4c, 0x8a, + 0x89, 0x53, 0x1e, 0x55, 0x22, 0x5d, 0x69, 0xe0, 0x12, 0x4a, 0xe0, 0x7f, 0xb8, 0x6b, 0x96, 0x7c, + 0x62, 0x29, 0x02, 0x8d, 0x2a, 0x85, 0x7c, 0x8f, 0xf4, 0x48, 0x40, 0x29, 0xfb, 0x15, 0x63, 0x17, + 0xa2, 0xb6, 0xb6, 0x8d, 0xa9, 0x8d, 0x1c, 0xca, 0x6c, 0xe7, 0x1d, 0x23, 0xaa, 0x9f, 0x79, 0x90, + 0xad, 0x2d, 0x0c, 0xeb, 0x8e, 0x05, 0x2b, 0x20, 0x6d, 0xf6, 0x31, 0x72, 0x68, 0x07, 0x5b, 0x22, + 0xa7, 0x70, 0xc5, 0x74, 0x35, 0x3f, 0x9b, 0xca, 0xb9, 0x89, 0x61, 0xf7, 0xb7, 0xd5, 0x05, 0xa4, + 0xea, 0x29, 0x56, 0x6b, 0x16, 0x7c, 0x06, 0x52, 0x23, 0xe4, 0x7a, 0x98, 0x38, 0x9e, 0xc8, 0x2b, + 0xf1, 0x62, 0x66, 0x53, 0x2e, 0xfd, 0x7c, 0xdc, 0xd2, 0x5b, 0xc6, 0xd3, 0x17, 0x02, 0xb8, 0x05, + 0x12, 0x1e, 0x35, 0x28, 0x12, 0xe3, 0x0a, 0x57, 0xfc, 0x6b, 0x73, 0xfd, 0x26, 0x65, 0xcb, 0x27, + 0xe9, 0x8c, 0x0b, 0x1b, 0x60, 0xd5, 0x24, 0x43, 0x87, 0x22, 0x77, 0x60, 0xb8, 0x74, 0x22, 0x0a, + 0x0a, 0x57, 0xcc, 0x6c, 0xde, 0xbf, 0x49, 0x5b, 0x8b, 0x70, 0xab, 0xc2, 0xd9, 0x54, 0x8e, 0xe9, + 0x57, 0xf4, 0x70, 0x1b, 0xac, 0x5a, 0xa8, 0x6f, 0x4c, 0x3a, 0x03, 0xe4, 0x62, 0x62, 0x89, 0x09, + 0x85, 0x2b, 0x0a, 0xd5, 0xb5, 0xd9, 0x54, 0xfe, 0x97, 0xed, 0x1d, 0x45, 0x55, 0x3d, 0x13, 0xb4, + 0xcd, 0xa0, 0xdb, 0x16, 0x8e, 0x3f, 0xca, 0x31, 0xf5, 0x3b, 0x0f, 0xf2, 0x9a, 0x85, 0x1c, 0x8a, + 0x0f, 0x30, 0xb2, 0x96, 0x91, 0xc2, 0x75, 0xc0, 0x2f, 0x82, 0xcc, 0xce, 0xa6, 0x72, 0x9a, 0x19, + 0xfa, 0x09, 0xf2, 0xf8, 0x5a, 0xdc, 0xfc, 0xad, 0xe3, 0x8e, 0xdf, 0x39, 0x6e, 0xe1, 0x37, 0xe2, + 0x4e, 0xfc, 0xe1, 0xb8, 0x93, 0xb7, 0x8e, 0xfb, 0x0b, 0x07, 0x56, 0xa3, 0x1f, 0x73, 0x97, 0xb3, + 0x7d, 0x0e, 0xb2, 0xcb, 0xb9, 0x97, 0xf1, 0x8b, 0xb3, 0xa9, 0x9c, 0x0f, 0x65, 0x51, 0x58, 0xf5, + 0x97, 0x98, 0xf7, 0x9a, 0x05, 0xab, 0x20, 0x39, 0x70, 0xd1, 0x01, 0x1e, 0x07, 0x97, 0x7b, 0x2d, + 0x8e, 0xc5, 0xcf, 0x6c, 0x54, 0x29, 0xbd, 0x46, 0xee, 0x51, 0x1f, 0x35, 0x03, 0x6e, 0x18, 0x47, + 0xa8, 0x0c, 0x97, 0xb9, 0x07, 0x32, 0xb5, 0x60, 0xa8, 0xa6, 0x41, 0x0f, 0x3d, 0x98, 0x07, 0x89, + 0x81, 0x5f, 0x88, 0x9c, 0x12, 0x2f, 0xa6, 0x75, 0xd6, 0xa8, 0xfb, 0xe0, 0xef, 0xe5, 0x55, 0x31, + 0xe2, 0x1d, 0x76, 0x5e, 0x78, 0xf3, 0x51, 0xef, 0x97, 0x60, 0x25, 0xbc, 0x14, 0x28, 0x01, 0x80, + 0xe7, 0x67, 0xec, 0x32, 0x53, 0x3d, 0xf2, 0x04, 0x16, 0x40, 0xea, 0x00, 0x19, 0x74, 0xe8, 0xa2, + 0xb9, 0xc7, 0xa2, 0x0f, 0xb7, 0x71, 0x40, 0xb2, 0x69, 0xb8, 0x86, 0xed, 0x41, 0x0b, 0xfc, 0x6f, + 0x1b, 0xe3, 0x0e, 0x1a, 0x0f, 0x90, 0x49, 0x91, 0xd5, 0xa1, 0xd8, 0x46, 0xfe, 0x97, 0xda, 0xe9, + 0xf6, 0x89, 0x79, 0x14, 0x98, 0x0b, 0xd5, 0x07, 0xb3, 0xa9, 0xac, 0xb2, 0x89, 0x7f, 0x41, 0x56, + 0xf5, 0x35, 0xdb, 0x18, 0xd7, 0x43, 0xb0, 0x8d, 0x6d, 0xd4, 0x44, 0x6e, 0xd5, 0x47, 0x1e, 0x7d, + 0xe0, 0x40, 0x22, 0xb8, 0x56, 0xf8, 0x04, 0xc8, 0xad, 0xf6, 0x4e, 0xbb, 0xde, 0xd9, 0x6b, 0x68, + 0x0d, 0xad, 0xad, 0xed, 0xbc, 0xd2, 0xf6, 0xeb, 0xbb, 0x9d, 0xbd, 0x46, 0xab, 0x59, 0xaf, 0x69, + 0x2f, 0xb4, 0xfa, 0x6e, 0x2e, 0x56, 0xf8, 0xe7, 0xe4, 0x54, 0xc9, 0x5e, 0x21, 0x40, 0x11, 0x00, + 0xa6, 0xf3, 0x1f, 0xe6, 0xb8, 0x42, 0xea, 0xe4, 0x54, 0x11, 0xfc, 0x1a, 0x4a, 0x20, 0xcb, 0x90, + 0xb6, 0xfe, 0xee, 0x4d, 0xb3, 0xde, 0xc8, 0xf1, 0x85, 0xcc, 0xc9, 0xa9, 0xb2, 0x12, 0xb6, 0x4b, + 0x65, 0x00, 0xc6, 0x99, 0xd2, 0xaf, 0x0b, 0xc2, 0xf1, 0x27, 0x29, 0x56, 0x6d, 0x9d, 0x5d, 0x48, + 0xdc, 0xf9, 0x85, 0xc4, 0x7d, 0xbb, 0x90, 0xb8, 0xf7, 0x97, 0x52, 0xec, 0xfc, 0x52, 0x8a, 0x7d, + 0xbd, 0x94, 0x62, 0xfb, 0x4f, 0x7b, 0x98, 0x1e, 0x0e, 0xbb, 0xfe, 0xa9, 0x94, 0x4d, 0xe2, 0xd9, + 0xc4, 0x2b, 0xe3, 0xae, 0xb9, 0xd1, 0x23, 0x65, 0x9b, 0x58, 0xc3, 0x3e, 0xf2, 0xd8, 0xeb, 0xfb, + 0xf1, 0xd6, 0x46, 0xe4, 0x8f, 0x81, 0x4e, 0x06, 0xc8, 0xeb, 0x26, 0x83, 0x57, 0xf7, 0xd6, 0x8f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xb4, 0x83, 0x45, 0x2b, 0x3c, 0x06, 0x00, 0x00, } func (m *ConnectionEnd) Marshal() (dAtA []byte, err error) { @@ -706,6 +758,34 @@ func (m *Version) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MaxExpectedTimePerBlock != 0 { + i = encodeVarintConnection(dAtA, i, uint64(m.MaxExpectedTimePerBlock)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintConnection(dAtA []byte, offset int, v uint64) int { offset -= sovConnection(v) base := offset @@ -847,6 +927,18 @@ func (m *Version) Size() (n int) { return n } +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MaxExpectedTimePerBlock != 0 { + n += 1 + sovConnection(uint64(m.MaxExpectedTimePerBlock)) + } + return n +} + func sovConnection(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1716,6 +1808,75 @@ func (m *Version) Unmarshal(dAtA []byte) error { } return nil } +func (m *Params) 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 ErrIntOverflowConnection + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxExpectedTimePerBlock", wireType) + } + m.MaxExpectedTimePerBlock = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConnection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxExpectedTimePerBlock |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipConnection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthConnection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipConnection(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/core/03-connection/types/genesis.go b/modules/core/03-connection/types/genesis.go index 8eb441c5235..313782184cd 100644 --- a/modules/core/03-connection/types/genesis.go +++ b/modules/core/03-connection/types/genesis.go @@ -17,12 +17,13 @@ func NewConnectionPaths(id string, paths []string) ConnectionPaths { // NewGenesisState creates a GenesisState instance. func NewGenesisState( connections []IdentifiedConnection, connPaths []ConnectionPaths, - nextConnectionSequence uint64, + nextConnectionSequence uint64, params Params, ) GenesisState { return GenesisState{ Connections: connections, ClientConnectionPaths: connPaths, NextConnectionSequence: nextConnectionSequence, + Params: params, } } @@ -32,6 +33,7 @@ func DefaultGenesisState() GenesisState { Connections: []IdentifiedConnection{}, ClientConnectionPaths: []ConnectionPaths{}, NextConnectionSequence: 0, + Params: DefaultParams(), } } @@ -72,5 +74,9 @@ func (gs GenesisState) Validate() error { return fmt.Errorf("next connection sequence %d must be greater than maximum sequence used in connection identifier %d", gs.NextConnectionSequence, maxSequence) } + if err := gs.Params.Validate(); err != nil { + return err + } + return nil } diff --git a/modules/core/03-connection/types/genesis.pb.go b/modules/core/03-connection/types/genesis.pb.go index c538d3e3536..2efa4395200 100644 --- a/modules/core/03-connection/types/genesis.pb.go +++ b/modules/core/03-connection/types/genesis.pb.go @@ -29,6 +29,7 @@ type GenesisState struct { ClientConnectionPaths []ConnectionPaths `protobuf:"bytes,2,rep,name=client_connection_paths,json=clientConnectionPaths,proto3" json:"client_connection_paths" yaml:"client_connection_paths"` // the sequence for the next generated connection identifier NextConnectionSequence uint64 `protobuf:"varint,3,opt,name=next_connection_sequence,json=nextConnectionSequence,proto3" json:"next_connection_sequence,omitempty" yaml:"next_connection_sequence"` + Params Params `protobuf:"bytes,4,opt,name=params,proto3" json:"params"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -85,6 +86,13 @@ func (m *GenesisState) GetNextConnectionSequence() uint64 { return 0 } +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + func init() { proto.RegisterType((*GenesisState)(nil), "ibc.core.connection.v1.GenesisState") } @@ -94,28 +102,29 @@ func init() { } var fileDescriptor_1879d34bc6ac3cd7 = []byte{ - // 327 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x31, 0x4f, 0xc2, 0x40, - 0x18, 0x86, 0x5b, 0x20, 0x0e, 0xc5, 0xa9, 0x51, 0x6c, 0x18, 0xae, 0xa4, 0x1a, 0x61, 0x90, 0x3b, - 0x91, 0x49, 0xc7, 0x3a, 0x18, 0x37, 0x03, 0x4e, 0x26, 0x86, 0xd0, 0xe3, 0xb3, 0x5c, 0x42, 0xef, - 0x43, 0xee, 0x20, 0xf2, 0x0b, 0x5c, 0xfd, 0x59, 0x2c, 0x26, 0x8c, 0x4e, 0xc4, 0xc0, 0x3f, 0xe0, - 0x17, 0x98, 0xb6, 0xc6, 0xa2, 0xb1, 0xdb, 0xe5, 0xbe, 0xe7, 0x7d, 0xde, 0xe1, 0xb5, 0x4e, 0x44, - 0xc0, 0x19, 0xc7, 0x09, 0x30, 0x8e, 0x52, 0x02, 0xd7, 0x02, 0x25, 0x9b, 0xb5, 0x58, 0x08, 0x12, - 0x94, 0x50, 0x74, 0x3c, 0x41, 0x8d, 0x76, 0x45, 0x04, 0x9c, 0xc6, 0x14, 0xcd, 0x28, 0x3a, 0x6b, - 0x55, 0x0f, 0x42, 0x0c, 0x31, 0x41, 0x58, 0xfc, 0x4a, 0xe9, 0x6a, 0x3d, 0xc7, 0xb9, 0x93, 0x4d, - 0x40, 0xef, 0xbd, 0x60, 0xed, 0xdf, 0xa4, 0x45, 0x5d, 0xdd, 0xd7, 0x60, 0xdf, 0x5b, 0xe5, 0x0c, - 0x52, 0x8e, 0x59, 0x2b, 0x36, 0xca, 0x17, 0x67, 0xf4, 0xff, 0x76, 0x7a, 0x3b, 0x00, 0xa9, 0xc5, - 0x93, 0x80, 0xc1, 0xf5, 0xcf, 0xbf, 0x5f, 0x5a, 0xac, 0x5c, 0xa3, 0xb3, 0xab, 0xb1, 0x5f, 0x4d, - 0xeb, 0x88, 0x8f, 0x04, 0x48, 0xdd, 0xcb, 0xbe, 0x7b, 0xe3, 0xbe, 0x1e, 0x2a, 0xa7, 0x90, 0x54, - 0xd4, 0xf3, 0x2a, 0x32, 0xf1, 0x5d, 0x8c, 0xfb, 0xa7, 0xb1, 0x7d, 0xbb, 0x72, 0xc9, 0xbc, 0x1f, - 0x8d, 0xae, 0xbc, 0x1c, 0xab, 0xd7, 0x39, 0x4c, 0x2f, 0x7f, 0xe2, 0xf6, 0xa3, 0xe5, 0x48, 0x78, - 0xf9, 0x15, 0x50, 0xf0, 0x3c, 0x05, 0xc9, 0xc1, 0x29, 0xd6, 0xcc, 0x46, 0xc9, 0x3f, 0xde, 0xae, - 0x5c, 0x37, 0x95, 0xe7, 0x91, 0x5e, 0xa7, 0x12, 0x9f, 0x32, 0x77, 0xf7, 0xfb, 0xe0, 0x77, 0x17, - 0x6b, 0x62, 0x2e, 0xd7, 0xc4, 0xfc, 0x5c, 0x13, 0xf3, 0x6d, 0x43, 0x8c, 0xe5, 0x86, 0x18, 0x1f, - 0x1b, 0x62, 0x3c, 0x5c, 0x86, 0x42, 0x0f, 0xa7, 0x01, 0xe5, 0x18, 0x31, 0x8e, 0x2a, 0x42, 0xc5, - 0x44, 0xc0, 0x9b, 0x21, 0xb2, 0x08, 0x07, 0xd3, 0x11, 0xa8, 0x74, 0xaf, 0xf3, 0x76, 0x73, 0x67, - 0x32, 0x3d, 0x1f, 0x83, 0x0a, 0xf6, 0x92, 0xad, 0xda, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x85, - 0x66, 0x6f, 0x29, 0x2a, 0x02, 0x00, 0x00, + // 352 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xb1, 0x4e, 0xc2, 0x40, + 0x18, 0xc7, 0x5b, 0x21, 0x0c, 0xc5, 0xa9, 0x51, 0x6c, 0x18, 0xae, 0xa4, 0x1a, 0x61, 0x90, 0x3b, + 0x81, 0x49, 0xe3, 0x54, 0x07, 0xe3, 0x46, 0xc0, 0xc9, 0xc4, 0x90, 0xf6, 0xf8, 0x2c, 0x97, 0xd0, + 0xbb, 0xca, 0x1d, 0x44, 0x9e, 0xc0, 0xc1, 0xc5, 0xc7, 0x62, 0x64, 0x74, 0x22, 0x06, 0xde, 0x80, + 0x27, 0x30, 0x6d, 0x89, 0x45, 0x63, 0xb7, 0xe6, 0xfb, 0x7e, 0xff, 0xdf, 0x3f, 0xbd, 0xcf, 0x38, + 0x63, 0x3e, 0x25, 0x54, 0x4c, 0x80, 0x50, 0xc1, 0x39, 0x50, 0xc5, 0x04, 0x27, 0xb3, 0x16, 0x09, + 0x80, 0x83, 0x64, 0x12, 0x47, 0x13, 0xa1, 0x84, 0x59, 0x61, 0x3e, 0xc5, 0x31, 0x85, 0x33, 0x0a, + 0xcf, 0x5a, 0xd5, 0xa3, 0x40, 0x04, 0x22, 0x41, 0x48, 0xfc, 0x95, 0xd2, 0xd5, 0x7a, 0x8e, 0x73, + 0x2f, 0x9b, 0x80, 0xce, 0x7b, 0xc1, 0x38, 0xbc, 0x4b, 0x8b, 0xfa, 0xca, 0x53, 0x60, 0x3e, 0x18, + 0xe5, 0x0c, 0x92, 0x96, 0x5e, 0x2b, 0x34, 0xca, 0xed, 0x0b, 0xfc, 0x7f, 0x3b, 0xbe, 0x1f, 0x02, + 0x57, 0xec, 0x99, 0xc1, 0xf0, 0xf6, 0x67, 0xee, 0x16, 0x17, 0x2b, 0x5b, 0xeb, 0xed, 0x6b, 0xcc, + 0x37, 0xdd, 0x38, 0xa1, 0x63, 0x06, 0x5c, 0x0d, 0xb2, 0xf1, 0x20, 0xf2, 0xd4, 0x48, 0x5a, 0x07, + 0x49, 0x45, 0x3d, 0xaf, 0x22, 0x13, 0x77, 0x63, 0xdc, 0x3d, 0x8f, 0xed, 0xdb, 0x95, 0x8d, 0xe6, + 0x5e, 0x38, 0xbe, 0x76, 0x72, 0xac, 0x4e, 0xef, 0x38, 0xdd, 0xfc, 0x89, 0x9b, 0x4f, 0x86, 0xc5, + 0xe1, 0xf5, 0x57, 0x40, 0xc2, 0xcb, 0x14, 0x38, 0x05, 0xab, 0x50, 0xd3, 0x1b, 0x45, 0xf7, 0x74, + 0xbb, 0xb2, 0xed, 0x54, 0x9e, 0x47, 0x3a, 0xbd, 0x4a, 0xbc, 0xca, 0xdc, 0xfd, 0xdd, 0xc2, 0xbc, + 0x31, 0x4a, 0x91, 0x37, 0xf1, 0x42, 0x69, 0x15, 0x6b, 0x7a, 0xa3, 0xdc, 0x46, 0x79, 0xbf, 0xd5, + 0x4d, 0xa8, 0xdd, 0x5b, 0xed, 0x32, 0x6e, 0x7f, 0xb1, 0x46, 0xfa, 0x72, 0x8d, 0xf4, 0xaf, 0x35, + 0xd2, 0x3f, 0x36, 0x48, 0x5b, 0x6e, 0x90, 0xf6, 0xb9, 0x41, 0xda, 0xe3, 0x55, 0xc0, 0xd4, 0x68, + 0xea, 0x63, 0x2a, 0x42, 0x42, 0x85, 0x0c, 0x85, 0x24, 0xcc, 0xa7, 0xcd, 0x40, 0x90, 0x50, 0x0c, + 0xa7, 0x63, 0x90, 0xe9, 0xb5, 0x2f, 0x3b, 0xcd, 0xbd, 0x83, 0xab, 0x79, 0x04, 0xd2, 0x2f, 0x25, + 0x97, 0xee, 0x7c, 0x07, 0x00, 0x00, 0xff, 0xff, 0x5a, 0x52, 0xa6, 0xc4, 0x68, 0x02, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -138,6 +147,16 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 if m.NextConnectionSequence != 0 { i = encodeVarintGenesis(dAtA, i, uint64(m.NextConnectionSequence)) i-- @@ -206,6 +225,8 @@ func (m *GenesisState) Size() (n int) { if m.NextConnectionSequence != 0 { n += 1 + sovGenesis(uint64(m.NextConnectionSequence)) } + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -331,6 +352,39 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", 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 + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/modules/core/03-connection/types/genesis_test.go b/modules/core/03-connection/types/genesis_test.go index 562890ddd15..9a64c86b499 100644 --- a/modules/core/03-connection/types/genesis_test.go +++ b/modules/core/03-connection/types/genesis_test.go @@ -32,6 +32,7 @@ func TestValidateGenesis(t *testing.T) { {clientID, []string{connectionID}}, }, 0, + types.DefaultParams(), ), expPass: true, }, @@ -45,6 +46,7 @@ func TestValidateGenesis(t *testing.T) { {clientID, []string{connectionID}}, }, 0, + types.DefaultParams(), ), expPass: false, }, @@ -58,6 +60,7 @@ func TestValidateGenesis(t *testing.T) { {"(CLIENTIDONE)", []string{connectionID}}, }, 0, + types.DefaultParams(), ), expPass: false, }, @@ -71,6 +74,7 @@ func TestValidateGenesis(t *testing.T) { {clientID, []string{invalidConnectionID}}, }, 0, + types.DefaultParams(), ), expPass: false, }, @@ -84,6 +88,7 @@ func TestValidateGenesis(t *testing.T) { {clientID, []string{connectionID}}, }, 0, + types.DefaultParams(), ), expPass: false, }, @@ -97,6 +102,21 @@ func TestValidateGenesis(t *testing.T) { {clientID, []string{connectionID}}, }, 0, + types.DefaultParams(), + ), + expPass: false, + }, + { + name: "invalid params", + 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}, 500)), + }, + []types.ConnectionPaths{ + {clientID, []string{connectionID}}, + }, + 0, + types.Params{}, ), expPass: false, }, diff --git a/modules/core/03-connection/types/params.go b/modules/core/03-connection/types/params.go new file mode 100644 index 00000000000..904bde60415 --- /dev/null +++ b/modules/core/03-connection/types/params.go @@ -0,0 +1,54 @@ +package types + +import ( + "fmt" + "time" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +// DefaultTimePerBlock is the default value for maximum expected time per block. +const DefaultTimePerBlock = 30 * time.Second + +// KeyMaxExpectedTimePerBlock is store's key for MaxExpectedTimePerBlock parameter +var KeyMaxExpectedTimePerBlock = []byte("MaxExpectedTimePerBlock") + +// ParamKeyTable type declaration for parameters +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new parameter configuration for the ibc connection module +func NewParams(timePerBlock uint64) Params { + return Params{ + MaxExpectedTimePerBlock: timePerBlock, + } +} + +// DefaultParams is the default parameter configuration for the ibc connection module +func DefaultParams() Params { + return NewParams(uint64(DefaultTimePerBlock)) +} + +// Validate ensures MaxExpectedTimePerBlock is non-zero +func (p Params) Validate() error { + if p.MaxExpectedTimePerBlock == 0 { + return fmt.Errorf("MaxExpectedTimePerBlock cannot be zero") + } + return nil +} + +// ParamSetPairs implements params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyMaxExpectedTimePerBlock, p.MaxExpectedTimePerBlock, validateParams), + } +} + +func validateParams(i interface{}) error { + _, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter. expected %T, got type: %T", uint64(1), i) + } + return nil +} diff --git a/modules/core/03-connection/types/params_test.go b/modules/core/03-connection/types/params_test.go new file mode 100644 index 00000000000..0a04ed34a4b --- /dev/null +++ b/modules/core/03-connection/types/params_test.go @@ -0,0 +1,29 @@ +package types_test + +import ( + "testing" + + "github.com/cosmos/ibc-go/modules/core/03-connection/types" + "github.com/stretchr/testify/require" +) + +func TestValidateParams(t *testing.T) { + testCases := []struct { + name string + params types.Params + expPass bool + }{ + {"default params", types.DefaultParams(), true}, + {"custom params", types.NewParams(10), true}, + {"blank client", types.NewParams(0), false}, + } + + for _, tc := range testCases { + err := tc.params.Validate() + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + } +} diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 77268b1b350..8de7976c14c 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -126,11 +126,12 @@ type ClientState interface { channel ChannelI, ) error VerifyPacketCommitment( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height Height, - currentTimestamp uint64, - delayPeriod uint64, + delayTimePeriod uint64, + delayBlockPeriod uint64, prefix Prefix, proof []byte, portID, @@ -139,11 +140,12 @@ type ClientState interface { commitmentBytes []byte, ) error VerifyPacketAcknowledgement( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height Height, - currentTimestamp uint64, - delayPeriod uint64, + delayTimePeriod uint64, + delayBlockPeriod uint64, prefix Prefix, proof []byte, portID, @@ -152,11 +154,12 @@ type ClientState interface { acknowledgement []byte, ) error VerifyPacketReceiptAbsence( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height Height, - currentTimestamp uint64, - delayPeriod uint64, + delayTimePeriod uint64, + delayBlockPeriod uint64, prefix Prefix, proof []byte, portID, @@ -164,11 +167,12 @@ type ClientState interface { sequence uint64, ) error VerifyNextSequenceRecv( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height Height, - currentTimestamp uint64, - delayPeriod uint64, + delayTimePeriod uint64, + delayBlockPeriod uint64, prefix Prefix, proof []byte, portID, diff --git a/modules/core/genesis_test.go b/modules/core/genesis_test.go index 924fb42e2d3..5873440dc4b 100644 --- a/modules/core/genesis_test.go +++ b/modules/core/genesis_test.go @@ -117,6 +117,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { connectiontypes.NewConnectionPaths(clientID, []string{connectionID}), }, 0, + connectiontypes.NewParams(10), ), ChannelGenesis: channeltypes.NewGenesisState( []channeltypes.IdentifiedChannel{ @@ -192,6 +193,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { connectiontypes.NewConnectionPaths(clientID, []string{connectionID}), }, 0, + connectiontypes.Params{}, ), }, expPass: false, @@ -279,6 +281,7 @@ func (suite *IBCTestSuite) TestInitGenesis() { connectiontypes.NewConnectionPaths(clientID, []string{connectionID}), }, 0, + connectiontypes.NewParams(10), ), ChannelGenesis: channeltypes.NewGenesisState( []channeltypes.IdentifiedChannel{ diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 0320bb467ee..164fecfcd23 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -4,14 +4,15 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" clientkeeper "github.com/cosmos/ibc-go/modules/core/02-client/keeper" clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" connectionkeeper "github.com/cosmos/ibc-go/modules/core/03-connection/keeper" + connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" channelkeeper "github.com/cosmos/ibc-go/modules/core/04-channel/keeper" portkeeper "github.com/cosmos/ibc-go/modules/core/05-port/keeper" porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types" "github.com/cosmos/ibc-go/modules/core/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) var _ types.QueryServer = (*Keeper)(nil) @@ -36,8 +37,16 @@ func NewKeeper( stakingKeeper clienttypes.StakingKeeper, upgradeKeeper clienttypes.UpgradeKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, ) *Keeper { + // register paramSpace at top level keeper + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + keyTable := clienttypes.ParamKeyTable() + keyTable.RegisterParamSet(&connectiontypes.Params{}) + paramSpace = paramSpace.WithKeyTable(keyTable) + } + clientKeeper := clientkeeper.NewKeeper(cdc, key, paramSpace, stakingKeeper, upgradeKeeper) - connectionKeeper := connectionkeeper.NewKeeper(cdc, key, clientKeeper) + connectionKeeper := connectionkeeper.NewKeeper(cdc, key, paramSpace, clientKeeper) portKeeper := portkeeper.NewKeeper(scopedKeeper) channelKeeper := channelkeeper.NewKeeper(cdc, key, clientKeeper, connectionKeeper, portKeeper, scopedKeeper) diff --git a/modules/light-clients/06-solomachine/types/client_state.go b/modules/light-clients/06-solomachine/types/client_state.go index dd07273ec9c..b4fcf710cf7 100644 --- a/modules/light-clients/06-solomachine/types/client_state.go +++ b/modules/light-clients/06-solomachine/types/client_state.go @@ -257,6 +257,7 @@ func (cs *ClientState) VerifyChannelState( // VerifyPacketCommitment verifies a proof of an outgoing packet commitment at // the specified port, specified channel, and specified sequence. func (cs *ClientState) VerifyPacketCommitment( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, @@ -298,6 +299,7 @@ func (cs *ClientState) VerifyPacketCommitment( // VerifyPacketAcknowledgement verifies a proof of an incoming packet // acknowledgement at the specified port, specified channel, and specified sequence. func (cs *ClientState) VerifyPacketAcknowledgement( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, @@ -340,6 +342,7 @@ func (cs *ClientState) VerifyPacketAcknowledgement( // incoming packet receipt at the specified port, specified channel, and // specified sequence. func (cs *ClientState) VerifyPacketReceiptAbsence( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, @@ -380,6 +383,7 @@ func (cs *ClientState) VerifyPacketReceiptAbsence( // VerifyNextSequenceRecv verifies a proof of the next sequence number to be // received of the specified channel at the specified port. func (cs *ClientState) VerifyNextSequenceRecv( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, diff --git a/modules/light-clients/06-solomachine/types/client_state_test.go b/modules/light-clients/06-solomachine/types/client_state_test.go index 82b9ac57b12..34344622648 100644 --- a/modules/light-clients/06-solomachine/types/client_state_test.go +++ b/modules/light-clients/06-solomachine/types/client_state_test.go @@ -601,9 +601,10 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketCommitment() { tc := tc expSeq := tc.clientState.Sequence + 1 + ctx := suite.chainA.GetContext() err := tc.clientState.VerifyPacketCommitment( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, commitmentBytes, + ctx, suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, commitmentBytes, ) if tc.expPass { @@ -676,9 +677,10 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketAcknowledgement() { tc := tc expSeq := tc.clientState.Sequence + 1 + ctx := suite.chainA.GetContext() err := tc.clientState.VerifyPacketAcknowledgement( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, ack, + ctx, suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, ack, ) if tc.expPass { @@ -751,9 +753,10 @@ func (suite *SoloMachineTestSuite) TestVerifyPacketReceiptAbsence() { tc := tc expSeq := tc.clientState.Sequence + 1 + ctx := suite.chainA.GetContext() err := tc.clientState.VerifyPacketReceiptAbsence( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, + ctx, suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, solomachine.Sequence, ) if tc.expPass { @@ -826,9 +829,10 @@ func (suite *SoloMachineTestSuite) TestVerifyNextSeqRecv() { tc := tc expSeq := tc.clientState.Sequence + 1 + ctx := suite.chainA.GetContext() err := tc.clientState.VerifyNextSequenceRecv( - suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, nextSeqRecv, + ctx, suite.store, suite.chainA.Codec, solomachine.GetHeight(), 0, 0, tc.prefix, tc.proof, testPortID, testChannelID, nextSeqRecv, ) if tc.expPass { diff --git a/modules/light-clients/07-tendermint/types/client_state.go b/modules/light-clients/07-tendermint/types/client_state.go index 4928a6819aa..bf93cdbf7d5 100644 --- a/modules/light-clients/07-tendermint/types/client_state.go +++ b/modules/light-clients/07-tendermint/types/client_state.go @@ -171,8 +171,8 @@ func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientSto 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())) + // set metadata for initial consensus state. + setConsensusMetadata(ctx, clientStore, cs.GetLatestHeight()) return nil } @@ -341,11 +341,12 @@ func (cs ClientState) VerifyChannelState( // VerifyPacketCommitment verifies a proof of an outgoing packet commitment at // the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketCommitment( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, - currentTimestamp uint64, - delayPeriod uint64, + delayTimePeriod uint64, + delayBlockPeriod uint64, prefix exported.Prefix, proof []byte, portID, @@ -359,7 +360,7 @@ func (cs ClientState) VerifyPacketCommitment( } // check delay period has passed - if err := verifyDelayPeriodPassed(store, height, currentTimestamp, delayPeriod); err != nil { + if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { return err } @@ -379,11 +380,12 @@ func (cs ClientState) VerifyPacketCommitment( // VerifyPacketAcknowledgement verifies a proof of an incoming packet // acknowledgement at the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketAcknowledgement( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, - currentTimestamp uint64, - delayPeriod uint64, + delayTimePeriod uint64, + delayBlockPeriod uint64, prefix exported.Prefix, proof []byte, portID, @@ -397,7 +399,7 @@ func (cs ClientState) VerifyPacketAcknowledgement( } // check delay period has passed - if err := verifyDelayPeriodPassed(store, height, currentTimestamp, delayPeriod); err != nil { + if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { return err } @@ -418,11 +420,12 @@ func (cs ClientState) VerifyPacketAcknowledgement( // incoming packet receipt at the specified port, specified channel, and // specified sequence. func (cs ClientState) VerifyPacketReceiptAbsence( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, - currentTimestamp uint64, - delayPeriod uint64, + delayTimePeriod uint64, + delayBlockPeriod uint64, prefix exported.Prefix, proof []byte, portID, @@ -435,7 +438,7 @@ func (cs ClientState) VerifyPacketReceiptAbsence( } // check delay period has passed - if err := verifyDelayPeriodPassed(store, height, currentTimestamp, delayPeriod); err != nil { + if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { return err } @@ -455,11 +458,12 @@ func (cs ClientState) VerifyPacketReceiptAbsence( // VerifyNextSequenceRecv verifies a proof of the next sequence number to be // received of the specified channel at the specified port. func (cs ClientState) VerifyNextSequenceRecv( + ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, - currentTimestamp uint64, - delayPeriod uint64, + delayTimePeriod uint64, + delayBlockPeriod uint64, prefix exported.Prefix, proof []byte, portID, @@ -472,7 +476,7 @@ func (cs ClientState) VerifyNextSequenceRecv( } // check delay period has passed - if err := verifyDelayPeriodPassed(store, height, currentTimestamp, delayPeriod); err != nil { + if err := verifyDelayPeriodPassed(ctx, store, height, delayTimePeriod, delayBlockPeriod); err != nil { return err } @@ -491,20 +495,33 @@ 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 +// verifyDelayPeriodPassed will ensure that at least delayTimePeriod amount of time and delayBlockPeriod number of blocks have passed +// since consensus state was submitted before allowing verification to continue. +func verifyDelayPeriodPassed(ctx sdk.Context, store sdk.KVStore, proofHeight exported.Height, delayTimePeriod, delayBlockPeriod uint64) error { + // check that executing chain's timestamp has passed consensusState's processed time + delay time 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 { + currentTimestamp := uint64(ctx.BlockTime().UnixNano()) + validTime := processedTime + delayTimePeriod + // NOTE: delay time period is inclusive, so if currentTimestamp is validTime, then we return no error + if currentTimestamp < validTime { return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until time: %d, current time: %d", validTime, currentTimestamp) } + // check that executing chain's height has passed consensusState's processed height + delay block period + processedHeight, ok := GetProcessedHeight(store, proofHeight) + if !ok { + return sdkerrors.Wrapf(ErrProcessedHeightNotFound, "processed height not found for height: %s", proofHeight) + } + currentHeight := clienttypes.GetSelfHeight(ctx) + validHeight := clienttypes.NewHeight(processedHeight.GetRevisionNumber(), processedHeight.GetRevisionHeight()+delayBlockPeriod) + // NOTE: delay block period is inclusive, so if currentHeight is validHeight, then we return no error + if currentHeight.LT(validHeight) { + return sdkerrors.Wrapf(ErrDelayPeriodNotPassed, "cannot verify packet until height: %s, current height: %s", + validHeight, currentHeight) + } return nil } diff --git a/modules/light-clients/07-tendermint/types/client_state_test.go b/modules/light-clients/07-tendermint/types/client_state_test.go index e6b62ddc76a..93125c04268 100644 --- a/modules/light-clients/07-tendermint/types/client_state_test.go +++ b/modules/light-clients/07-tendermint/types/client_state_test.go @@ -400,11 +400,12 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { // in the light client on chainA. A send from chainB to chainA is simulated. func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { var ( - clientState *types.ClientState - proof []byte - delayPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix + clientState *types.ClientState + proof []byte + delayTimePeriod uint64 + delayBlockPeriod uint64 + proofHeight exported.Height + prefix commitmenttypes.MerklePrefix ) testCases := []struct { @@ -416,19 +417,34 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { "successful verification", func() {}, true, }, { - name: "delay period has passed", + name: "delay time period has passed", + malleate: func() { + delayTimePeriod = uint64(time.Second.Nanoseconds()) + }, + expPass: true, + }, + { + name: "delay time period has not passed", + malleate: func() { + delayTimePeriod = uint64(time.Hour.Nanoseconds()) + }, + expPass: false, + }, + { + name: "delay block period has passed", malleate: func() { - delayPeriod = uint64(time.Second.Nanoseconds()) + delayBlockPeriod = 1 }, expPass: true, }, { - name: "delay period has not passed", + name: "delay block period has not passed", malleate: func() { - delayPeriod = uint64(time.Hour.Nanoseconds()) + delayBlockPeriod = 1000 }, expPass: false, }, + { "ApplyPrefix failed", func() { prefix = commitmenttypes.MerklePrefix{} @@ -470,14 +486,17 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) proof, proofHeight = path.EndpointB.QueryProof(packetKey) + // reset time and block delays to 0, malleate may change to a specific non-zero value. + delayTimePeriod = 0 + delayBlockPeriod = 0 tc.malleate() // make changes as necessary - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + ctx := suite.chainA.GetContext() + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - currentTime := uint64(suite.chainA.GetContext().BlockTime().UnixNano()) commitment := channeltypes.CommitPacket(suite.chainA.App.GetIBCKeeper().Codec(), packet) err = clientState.VerifyPacketCommitment( - store, suite.chainA.Codec, proofHeight, currentTime, delayPeriod, &prefix, proof, + ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), commitment, ) @@ -495,11 +514,12 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { // is simulated. func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { var ( - clientState *types.ClientState - proof []byte - delayPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix + clientState *types.ClientState + proof []byte + delayTimePeriod uint64 + delayBlockPeriod uint64 + proofHeight exported.Height + prefix commitmenttypes.MerklePrefix ) testCases := []struct { @@ -511,19 +531,34 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { "successful verification", func() {}, true, }, { - name: "delay period has passed", + name: "delay time period has passed", + malleate: func() { + delayTimePeriod = uint64(time.Second.Nanoseconds()) + }, + expPass: true, + }, + { + name: "delay time period has not passed", + malleate: func() { + delayTimePeriod = uint64(time.Hour.Nanoseconds()) + }, + expPass: false, + }, + { + name: "delay block period has passed", malleate: func() { - delayPeriod = uint64(time.Second.Nanoseconds()) + delayBlockPeriod = 1 }, expPass: true, }, { - name: "delay period has not passed", + name: "delay block period has not passed", malleate: func() { - delayPeriod = uint64(time.Hour.Nanoseconds()) + delayBlockPeriod = 10 }, expPass: false, }, + { "ApplyPrefix failed", func() { prefix = commitmenttypes.MerklePrefix{} @@ -571,13 +606,16 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { acknowledgementKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) proof, proofHeight = suite.chainB.QueryProof(acknowledgementKey) + // reset time and block delays to 0, malleate may change to a specific non-zero value. + delayTimePeriod = 0 + delayBlockPeriod = 0 tc.malleate() // make changes as necessary - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + ctx := suite.chainA.GetContext() + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - currentTime := uint64(suite.chainA.GetContext().BlockTime().UnixNano()) err = clientState.VerifyPacketAcknowledgement( - store, suite.chainA.Codec, proofHeight, currentTime, delayPeriod, &prefix, proof, + ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ibcmock.MockAcknowledgement.Acknowledgement(), ) @@ -595,11 +633,12 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { // no receive. func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { var ( - clientState *types.ClientState - proof []byte - delayPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix + clientState *types.ClientState + proof []byte + delayTimePeriod uint64 + delayBlockPeriod uint64 + proofHeight exported.Height + prefix commitmenttypes.MerklePrefix ) testCases := []struct { @@ -611,19 +650,34 @@ func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { "successful verification", func() {}, true, }, { - name: "delay period has passed", + name: "delay time period has passed", + malleate: func() { + delayTimePeriod = uint64(time.Second.Nanoseconds()) + }, + expPass: true, + }, + { + name: "delay time period has not passed", + malleate: func() { + delayTimePeriod = uint64(time.Hour.Nanoseconds()) + }, + expPass: false, + }, + { + name: "delay block period has passed", malleate: func() { - delayPeriod = uint64(time.Second.Nanoseconds()) + delayBlockPeriod = 1 }, expPass: true, }, { - name: "delay period has not passed", + name: "delay block period has not passed", malleate: func() { - delayPeriod = uint64(time.Hour.Nanoseconds()) + delayBlockPeriod = 10 }, expPass: false, }, + { "ApplyPrefix failed", func() { prefix = commitmenttypes.MerklePrefix{} @@ -667,13 +721,16 @@ func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { receiptKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) proof, proofHeight = path.EndpointB.QueryProof(receiptKey) + // reset time and block delays to 0, malleate may change to a specific non-zero value. + delayTimePeriod = 0 + delayBlockPeriod = 0 tc.malleate() // make changes as necessary - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + ctx := suite.chainA.GetContext() + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - currentTime := uint64(suite.chainA.GetContext().BlockTime().UnixNano()) err = clientState.VerifyPacketReceiptAbsence( - store, suite.chainA.Codec, proofHeight, currentTime, delayPeriod, &prefix, proof, + ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ) @@ -691,11 +748,12 @@ func (suite *TendermintTestSuite) TestVerifyPacketReceiptAbsence() { // simulated. func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { var ( - clientState *types.ClientState - proof []byte - delayPeriod uint64 - proofHeight exported.Height - prefix commitmenttypes.MerklePrefix + clientState *types.ClientState + proof []byte + delayTimePeriod uint64 + delayBlockPeriod uint64 + proofHeight exported.Height + prefix commitmenttypes.MerklePrefix ) testCases := []struct { @@ -707,19 +765,34 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { "successful verification", func() {}, true, }, { - name: "delay period has passed", + name: "delay time period has passed", + malleate: func() { + delayTimePeriod = uint64(time.Second.Nanoseconds()) + }, + expPass: true, + }, + { + name: "delay time period has not passed", + malleate: func() { + delayTimePeriod = uint64(time.Hour.Nanoseconds()) + }, + expPass: false, + }, + { + name: "delay block period has passed", malleate: func() { - delayPeriod = uint64(time.Second.Nanoseconds()) + delayBlockPeriod = 1 }, expPass: true, }, { - name: "delay period has not passed", + name: "delay block period has not passed", malleate: func() { - delayPeriod = uint64(time.Hour.Nanoseconds()) + delayBlockPeriod = 10 }, expPass: false, }, + { "ApplyPrefix failed", func() { prefix = commitmenttypes.MerklePrefix{} @@ -768,13 +841,16 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { nextSeqRecvKey := host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) proof, proofHeight = suite.chainB.QueryProof(nextSeqRecvKey) + // reset time and block delays to 0, malleate may change to a specific non-zero value. + delayTimePeriod = 0 + delayBlockPeriod = 0 tc.malleate() // make changes as necessary - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + ctx := suite.chainA.GetContext() + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) - currentTime := uint64(suite.chainA.GetContext().BlockTime().UnixNano()) err = clientState.VerifyNextSequenceRecv( - store, suite.chainA.Codec, proofHeight, currentTime, delayPeriod, &prefix, proof, + ctx, store, suite.chainA.Codec, proofHeight, delayTimePeriod, delayBlockPeriod, &prefix, proof, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()+1, ) diff --git a/modules/light-clients/07-tendermint/types/errors.go b/modules/light-clients/07-tendermint/types/errors.go index 276c225b736..7b087e41af5 100644 --- a/modules/light-clients/07-tendermint/types/errors.go +++ b/modules/light-clients/07-tendermint/types/errors.go @@ -10,16 +10,17 @@ const ( // IBC tendermint client sentinel errors var ( - ErrInvalidChainID = sdkerrors.Register(SubModuleName, 2, "invalid chain-id") - ErrInvalidTrustingPeriod = sdkerrors.Register(SubModuleName, 3, "invalid trusting period") - ErrInvalidUnbondingPeriod = sdkerrors.Register(SubModuleName, 4, "invalid unbonding period") - ErrInvalidHeaderHeight = sdkerrors.Register(SubModuleName, 5, "invalid header height") - ErrInvalidHeader = sdkerrors.Register(SubModuleName, 6, "invalid header") - ErrInvalidMaxClockDrift = sdkerrors.Register(SubModuleName, 7, "invalid max clock drift") - 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") + ErrInvalidChainID = sdkerrors.Register(SubModuleName, 2, "invalid chain-id") + ErrInvalidTrustingPeriod = sdkerrors.Register(SubModuleName, 3, "invalid trusting period") + ErrInvalidUnbondingPeriod = sdkerrors.Register(SubModuleName, 4, "invalid unbonding period") + ErrInvalidHeaderHeight = sdkerrors.Register(SubModuleName, 5, "invalid header height") + ErrInvalidHeader = sdkerrors.Register(SubModuleName, 6, "invalid header") + ErrInvalidMaxClockDrift = sdkerrors.Register(SubModuleName, 7, "invalid max clock drift") + ErrProcessedTimeNotFound = sdkerrors.Register(SubModuleName, 8, "processed time not found") + ErrProcessedHeightNotFound = sdkerrors.Register(SubModuleName, 9, "processed height not found") + ErrDelayPeriodNotPassed = sdkerrors.Register(SubModuleName, 10, "packet-specified delay period has not been reached") + ErrTrustingPeriodExpired = sdkerrors.Register(SubModuleName, 11, "time since latest trusted state has passed the trusting period") + ErrUnbondingPeriodExpired = sdkerrors.Register(SubModuleName, 12, "time since latest trusted state has passed the unbonding period") + ErrInvalidProofSpecs = sdkerrors.Register(SubModuleName, 13, "invalid proof specs") + ErrInvalidValidatorSet = sdkerrors.Register(SubModuleName, 14, "invalid validator set") ) diff --git a/modules/light-clients/07-tendermint/types/proposal_handle.go b/modules/light-clients/07-tendermint/types/proposal_handle.go index 55c00d0f9d5..780ffdf9ff4 100644 --- a/modules/light-clients/07-tendermint/types/proposal_handle.go +++ b/modules/light-clients/07-tendermint/types/proposal_handle.go @@ -90,12 +90,8 @@ func (cs ClientState) CheckSubstituteAndUpdateState( } SetConsensusState(subjectClientStore, cdc, consensusState, height) - processedTime, found := GetProcessedTime(substituteClientStore, height) - if !found { - continue - } - SetProcessedTime(subjectClientStore, height, processedTime) - + // set metadata for this consensus state + setConsensusMetadata(ctx, subjectClientStore, height) } cs.LatestHeight = substituteClientState.LatestHeight diff --git a/modules/light-clients/07-tendermint/types/store.go b/modules/light-clients/07-tendermint/types/store.go index f261f4dc146..ba21e81ba80 100644 --- a/modules/light-clients/07-tendermint/types/store.go +++ b/modules/light-clients/07-tendermint/types/store.go @@ -36,7 +36,10 @@ const KeyIterateConsensusStatePrefix = "iterateConsensusStates" var ( // KeyProcessedTime is appended to consensus state key to store the processed time KeyProcessedTime = []byte("/processedTime") - KeyIteration = []byte("/iterationKey") + // KeyProcessedHeight is appended to consensus state key to store the processed height + KeyProcessedHeight = []byte("/processedHeight") + // KeyIteration stores the key mapping to consensus state key for efficient iteration + KeyIteration = []byte("/iterationKey") ) // SetConsensusState stores the consensus state at the given height. @@ -99,15 +102,13 @@ func IterateProcessedTime(store sdk.KVStore, cb func(key, val []byte) bool) { } } -// 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 +// This is useful when validating whether a packet has reached the time specified delay period in the tendermint client's // verification functions func SetProcessedTime(clientStore sdk.KVStore, height exported.Height, timeNs uint64) { key := ProcessedTimeKey(height) @@ -116,7 +117,7 @@ func SetProcessedTime(clientStore sdk.KVStore, height exported.Height, timeNs ui } // 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. +// This is used to validate that a received packet has passed the time delay period. func GetProcessedTime(clientStore sdk.KVStore, height exported.Height) (uint64, bool) { key := ProcessedTimeKey(height) bz := clientStore.Get(key) @@ -132,7 +133,40 @@ func deleteProcessedTime(clientStore sdk.KVStore, height exported.Height) { clientStore.Delete(key) } -// Iteration Code +// ProcessedHeightKey returns the key under which the processed height will be stored in the client store. +func ProcessedHeightKey(height exported.Height) []byte { + return append(host.ConsensusStateKey(height), KeyProcessedHeight...) +} + +// SetProcessedHeight stores the height 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 block delay period in the tendermint client's +// verification functions +func SetProcessedHeight(clientStore sdk.KVStore, consHeight, processedHeight exported.Height) { + key := ProcessedHeightKey(consHeight) + val := []byte(processedHeight.String()) + clientStore.Set(key, val) +} + +// GetProcessedHeight gets the height at which this chain received and processed a tendermint header. +// This is used to validate that a received packet has passed the block delay period. +func GetProcessedHeight(clientStore sdk.KVStore, height exported.Height) (exported.Height, bool) { + key := ProcessedHeightKey(height) + bz := clientStore.Get(key) + if bz == nil { + return nil, false + } + processedHeight, err := clienttypes.ParseHeight(string(bz)) + if err != nil { + return nil, false + } + return processedHeight, true +} + +// deleteProcessedHeight deletes the processedHeight for a given height +func deleteProcessedHeight(clientStore sdk.KVStore, height exported.Height) { + key := ProcessedHeightKey(height) + clientStore.Delete(key) +} // IterationKey returns the key under which the consensus state key will be stored. // The iteration key is a BigEndian representation of the consensus state key to support efficient iteration. @@ -255,3 +289,20 @@ func bigEndianHeightBytes(height exported.Height) []byte { binary.BigEndian.PutUint64(heightBytes[8:], height.GetRevisionHeight()) return heightBytes } + +// setConsensusMetadata sets context time as processed time and set context height as processed height +// as this is internal tendermint light client logic. +// client state and consensus state will be set by client keeper +// set iteration key to provide ability for efficient ordered iteration of consensus states. +func setConsensusMetadata(ctx sdk.Context, clientStore sdk.KVStore, height exported.Height) { + SetProcessedTime(clientStore, height, uint64(ctx.BlockTime().UnixNano())) + SetProcessedHeight(clientStore, height, clienttypes.GetSelfHeight(ctx)) + SetIterationKey(clientStore, height) +} + +// deleteConsensusMetadata deletes the metadata stored for a particular consensus state. +func deleteConsensusMetadata(clientStore sdk.KVStore, height exported.Height) { + deleteProcessedTime(clientStore, height) + deleteProcessedHeight(clientStore, height) + deleteIterationKey(clientStore, height) +} diff --git a/modules/light-clients/07-tendermint/types/tendermint.pb.go b/modules/light-clients/07-tendermint/types/tendermint.pb.go index 9a0645a4462..84a79b66668 100644 --- a/modules/light-clients/07-tendermint/types/tendermint.pb.go +++ b/modules/light-clients/07-tendermint/types/tendermint.pb.go @@ -11,10 +11,10 @@ import ( _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + _ "github.com/golang/protobuf/ptypes/duration" + _ "github.com/golang/protobuf/ptypes/timestamp" github_com_tendermint_tendermint_libs_bytes "github.com/tendermint/tendermint/libs/bytes" types2 "github.com/tendermint/tendermint/proto/tendermint/types" - _ "google.golang.org/protobuf/types/known/durationpb" - _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" math_bits "math/bits" diff --git a/modules/light-clients/07-tendermint/types/update.go b/modules/light-clients/07-tendermint/types/update.go index e1104e8d54b..c70746b4f74 100644 --- a/modules/light-clients/07-tendermint/types/update.go +++ b/modules/light-clients/07-tendermint/types/update.go @@ -134,9 +134,9 @@ func (cs ClientState) CheckHeaderAndUpdateState( } // if pruneHeight is set, delete consensus state and metadata if pruneHeight != nil { + deleteConsensusState(clientStore, pruneHeight) - deleteProcessedTime(clientStore, pruneHeight) - deleteIterationKey(clientStore, pruneHeight) + deleteConsensusMetadata(clientStore, pruneHeight) } newClientState, consensusState := update(ctx, clientStore, &cs, tmHeader) @@ -257,11 +257,8 @@ func update(ctx sdk.Context, clientStore sdk.KVStore, clientState *ClientState, 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 - // set iteration key to provide ability for efficient ordered iteration of consensus states. - SetProcessedTime(clientStore, header.GetHeight(), uint64(ctx.BlockTime().UnixNano())) - SetIterationKey(clientStore, header.GetHeight()) + // set metadata for this consensus state + setConsensusMetadata(ctx, clientStore, header.GetHeight()) return clientState, consensusState } diff --git a/modules/light-clients/07-tendermint/types/update_test.go b/modules/light-clients/07-tendermint/types/update_test.go index 95a159ef97c..b93168b5166 100644 --- a/modules/light-clients/07-tendermint/types/update_test.go +++ b/modules/light-clients/07-tendermint/types/update_test.go @@ -8,6 +8,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/modules/core/exported" types "github.com/cosmos/ibc-go/modules/light-clients/07-tendermint/types" ibctesting "github.com/cosmos/ibc-go/testing" ibctestingmock "github.com/cosmos/ibc-go/testing/mock" @@ -377,10 +378,16 @@ func (suite *TendermintTestSuite) TestPruneConsensusState() { path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) - // call update client twice. When pruning occurs, only first consensus state should be pruned. - // this height will be pruned - path.EndpointA.UpdateClient() - pruneHeight := path.EndpointA.GetClientState().GetLatestHeight() + // get the first height as it will be pruned first. + var pruneHeight exported.Height + getFirstHeightCb := func(height exported.Height) bool { + pruneHeight = height + return true + } + ctx := path.EndpointA.Chain.GetContext() + clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) + err := types.IterateConsensusStateAscending(clientStore, getFirstHeightCb) + suite.Require().Nil(err) // this height will be expired but not pruned path.EndpointA.UpdateClient() @@ -389,8 +396,8 @@ func (suite *TendermintTestSuite) TestPruneConsensusState() { // expected values that must still remain in store after pruning expectedConsState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, expiredHeight) suite.Require().True(ok) - ctx := path.EndpointA.Chain.GetContext() - clientStore := path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) + ctx = path.EndpointA.Chain.GetContext() + clientStore = path.EndpointA.Chain.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, path.EndpointA.ClientID) expectedProcessTime, ok := types.GetProcessedTime(clientStore, expiredHeight) suite.Require().True(ok) expectedConsKey := types.GetIterationKey(clientStore, expiredHeight) diff --git a/modules/light-clients/07-tendermint/types/upgrade.go b/modules/light-clients/07-tendermint/types/upgrade.go index ab5ebcf4148..b70cbd4879d 100644 --- a/modules/light-clients/07-tendermint/types/upgrade.go +++ b/modules/light-clients/07-tendermint/types/upgrade.go @@ -6,10 +6,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/modules/core/exported" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) // VerifyUpgradeAndUpdateState checks if the upgraded client has been committed by the current client @@ -122,6 +122,9 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( tmUpgradeConsState.Timestamp, commitmenttypes.MerkleRoot{}, tmUpgradeConsState.NextValidatorsHash, ) + // set metadata for this consensus state + setConsensusMetadata(ctx, clientStore, tmUpgradeClient.LatestHeight) + return newClientState, newConsState, nil } diff --git a/modules/light-clients/09-localhost/types/client_state.go b/modules/light-clients/09-localhost/types/client_state.go index 294ee4d9d48..a0615b8fda9 100644 --- a/modules/light-clients/09-localhost/types/client_state.go +++ b/modules/light-clients/09-localhost/types/client_state.go @@ -223,6 +223,7 @@ func (cs ClientState) VerifyChannelState( // VerifyPacketCommitment verifies a proof of an outgoing packet commitment at // the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketCommitment( + ctx sdk.Context, store sdk.KVStore, _ codec.BinaryCodec, _ exported.Height, @@ -255,6 +256,7 @@ func (cs ClientState) VerifyPacketCommitment( // VerifyPacketAcknowledgement verifies a proof of an incoming packet // acknowledgement at the specified port, specified channel, and specified sequence. func (cs ClientState) VerifyPacketAcknowledgement( + ctx sdk.Context, store sdk.KVStore, _ codec.BinaryCodec, _ exported.Height, @@ -288,6 +290,7 @@ func (cs ClientState) VerifyPacketAcknowledgement( // incoming packet receipt at the specified port, specified channel, and // specified sequence. func (cs ClientState) VerifyPacketReceiptAbsence( + ctx sdk.Context, store sdk.KVStore, _ codec.BinaryCodec, _ exported.Height, @@ -312,6 +315,7 @@ func (cs ClientState) VerifyPacketReceiptAbsence( // VerifyNextSequenceRecv verifies a proof of the next sequence number to be // received of the specified channel at the specified port. func (cs ClientState) VerifyNextSequenceRecv( + ctx sdk.Context, store sdk.KVStore, _ codec.BinaryCodec, _ exported.Height, diff --git a/modules/light-clients/09-localhost/types/client_state_test.go b/modules/light-clients/09-localhost/types/client_state_test.go index 358ac294170..e2dbe89b78b 100644 --- a/modules/light-clients/09-localhost/types/client_state_test.go +++ b/modules/light-clients/09-localhost/types/client_state_test.go @@ -376,7 +376,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketCommitment() { tc.malleate() err := tc.clientState.VerifyPacketCommitment( - suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, testSequence, tc.commitment, + suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, testSequence, tc.commitment, ) if tc.expPass { @@ -435,7 +435,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgement() { tc.malleate() err := tc.clientState.VerifyPacketAcknowledgement( - suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, testSequence, tc.ack, + suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, testSequence, tc.ack, ) if tc.expPass { @@ -451,7 +451,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketReceiptAbsence() { clientState := types.NewClientState("chainID", clientHeight) err := clientState.VerifyPacketReceiptAbsence( - suite.store, suite.cdc, clientHeight, 0, 0, nil, nil, testPortID, testChannelID, testSequence, + suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, nil, testPortID, testChannelID, testSequence, ) suite.Require().NoError(err, "receipt absence failed") @@ -459,7 +459,7 @@ func (suite *LocalhostTestSuite) TestVerifyPacketReceiptAbsence() { suite.store.Set(host.PacketReceiptKey(testPortID, testChannelID, testSequence), []byte("receipt")) err = clientState.VerifyPacketReceiptAbsence( - suite.store, suite.cdc, clientHeight, 0, 0, nil, nil, testPortID, testChannelID, testSequence, + suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, nil, testPortID, testChannelID, testSequence, ) suite.Require().Error(err, "receipt exists in store") } @@ -515,7 +515,7 @@ func (suite *LocalhostTestSuite) TestVerifyNextSeqRecv() { tc.malleate() err := tc.clientState.VerifyNextSequenceRecv( - suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, nextSeqRecv, + suite.ctx, suite.store, suite.cdc, clientHeight, 0, 0, nil, []byte{}, testPortID, testChannelID, nextSeqRecv, ) if tc.expPass { diff --git a/proto/ibc/core/connection/v1/connection.proto b/proto/ibc/core/connection/v1/connection.proto index 5b4e32bf856..e09f1529d92 100644 --- a/proto/ibc/core/connection/v1/connection.proto +++ b/proto/ibc/core/connection/v1/connection.proto @@ -104,3 +104,11 @@ message Version { // list of features compatible with the specified identifier repeated string features = 2; } + +// Params defines the set of Connection parameters. +message Params { + // maximum expected time per block, used to enforce block delay. This parameter should reflect the largest amount of + // time that the chain might reasonably take to produce the next block under normal operating conditions. A safe + // choice is 3-5x the expected time per block. + uint64 max_expected_time_per_block = 1 [(gogoproto.moretags) = "yaml:\"max_expected_time_per_block\""]; +} diff --git a/proto/ibc/core/connection/v1/genesis.proto b/proto/ibc/core/connection/v1/genesis.proto index 62296e1e6dd..64f2e026aca 100644 --- a/proto/ibc/core/connection/v1/genesis.proto +++ b/proto/ibc/core/connection/v1/genesis.proto @@ -14,4 +14,5 @@ message GenesisState { [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_connection_paths\""]; // the sequence for the next generated connection identifier uint64 next_connection_sequence = 3 [(gogoproto.moretags) = "yaml:\"next_connection_sequence\""]; + Params params = 4 [(gogoproto.nullable) = false]; }