Skip to content

Commit

Permalink
Merge tag 'v7.4.1' into HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
inon-man committed Aug 1, 2024
2 parents 58ea260 + 5bf12e6 commit d4f8802
Show file tree
Hide file tree
Showing 8 changed files with 428 additions and 19 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ Ref: https://keepachangelog.com/en/1.0.0/

# Changelog

## [v7.4.1](https://github.com/cosmos/ibc-go/releases/tag/v7.4.1) - 2024-05-22

### Improvements

* (apps/27-interchain-accounts) [\#6144](https://github.com/cosmos/ibc-go/pull/6144) Emit an event signalling that the host submodule is disabled.
* (core/ante) [\#6302](https://github.com/cosmos/ibc-go/pull/6302) Performance: Skip app callbacks during RecvPacket execution in checkTx within the redundant relay ante handler.
* (core/ante) [\#6280](https://github.com/cosmos/ibc-go/pull/6280) Performance: Skip redundant proof checking in RecvPacket execution in reCheckTx within the redundant relay ante handler.
* (core/ante) [\#6306](https://github.com/cosmos/ibc-go/pull/6306) Performance: Skip misbehaviour checks in UpdateClient flow and skip signature checks in reCheckTx mode.

## [v7.4.0](https://github.com/cosmos/ibc-go/releases/tag/v7.4.0) - 2024-04-05

## [v7.3.2](https://github.com/cosmos/ibc-go/releases/tag/v7.3.2) - 2024-01-31
Expand Down
1 change: 1 addition & 0 deletions modules/apps/27-interchain-accounts/host/ibc_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ func (im IBCModule) OnRecvPacket(
_ sdk.AccAddress,
) ibcexported.Acknowledgement {
if !im.keeper.IsHostEnabled(ctx) {
keeper.EmitHostDisabledEvent(ctx, packet)
return channeltypes.NewErrorAcknowledgement(types.ErrHostSubModuleDisabled)
}

Expand Down
15 changes: 15 additions & 0 deletions modules/apps/27-interchain-accounts/host/keeper/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (

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

"github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/host/types"
icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
"github.com/cosmos/ibc-go/v7/modules/core/exported"
)

Expand All @@ -29,3 +31,16 @@ func EmitAcknowledgementEvent(ctx sdk.Context, packet exported.PacketI, ack expo
),
)
}

// EmitHostDisabledEvent emits an event signalling that the host submodule is disabled.
func EmitHostDisabledEvent(ctx sdk.Context, packet channeltypes.Packet) {
ctx.EventManager().EmitEvent(
sdk.NewEvent(
icatypes.EventTypePacket,
sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName),
sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()),
sdk.NewAttribute(icatypes.AttributeKeyAckError, types.ErrHostSubModuleDisabled.Error()),
sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, "false"),
),
)
}
24 changes: 24 additions & 0 deletions modules/core/04-channel/keeper/ante.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package keeper

import (
errorsmod "cosmossdk.io/errors"

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

"github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
)

// RecvPacketReCheckTx applies replay protection ensuring that when relay messages are
// re-executed in ReCheckTx, we can appropriately filter out redundant relay transactions.
func (k *Keeper) RecvPacketReCheckTx(ctx sdk.Context, packet types.Packet) error {
channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel())
if !found {
return errorsmod.Wrap(types.ErrChannelNotFound, packet.GetDestChannel())
}

if err := k.applyReplayProtection(ctx, packet, channel); err != nil {
return err
}

return nil
}
64 changes: 64 additions & 0 deletions modules/core/04-channel/keeper/ante_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package keeper_test

import (
"github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
ibctesting "github.com/cosmos/ibc-go/v7/testing"
)

func (suite *KeeperTestSuite) TestRecvPacketReCheckTx() {
var (
path *ibctesting.Path
packet types.Packet
)

testCases := []struct {
name string
malleate func()
expError error
}{
{
"success",
func() {},
nil,
},
{
"channel not found",
func() {
packet.DestinationPort = "invalid-port" //nolint:goconst
},
types.ErrChannelNotFound,
},
{
"redundant relay",
func() {
err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.RecvPacketReCheckTx(suite.chainB.GetContext(), packet)
suite.Require().NoError(err)
},
types.ErrNoOpMsg,
},
}

for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
suite.SetupTest() // reset
path = ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.Setup(path)

sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
suite.Require().NoError(err)
packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp)

tc.malleate()

err = suite.chainB.App.GetIBCKeeper().ChannelKeeper.RecvPacketReCheckTx(suite.chainB.GetContext(), packet)

expPass := tc.expError == nil
if expPass {
suite.Require().NoError(err)
} else {
suite.Require().ErrorIs(err, tc.expError)
}
})
}
}
36 changes: 23 additions & 13 deletions modules/core/04-channel/keeper/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,29 @@ func (k Keeper) RecvPacket(
return sdkerrors.Wrap(err, "couldn't verify counterparty packet commitment")
}

if err := k.applyReplayProtection(ctx, packet, channel); err != nil {
return err
}

// log that a packet has been received & executed
k.Logger(ctx).Info(
"packet received",
"sequence", strconv.FormatUint(packet.GetSequence(), 10),
"src_port", packet.GetSourcePort(),
"src_channel", packet.GetSourceChannel(),
"dst_port", packet.GetDestPort(),
"dst_channel", packet.GetDestChannel(),
)

// emit an event that the relayer can query for
EmitRecvPacketEvent(ctx, packet, channel)

return nil
}

// applyReplayProtection ensures a packet has not already been received
// and performs the necessary state changes to ensure it cannot be received again.
func (k *Keeper) applyReplayProtection(ctx sdk.Context, packet exported.PacketI, channel types.Channel) error {
switch channel.Ordering {
case types.UNORDERED:
// check if the packet receipt has been received already for unordered channels
Expand Down Expand Up @@ -257,19 +280,6 @@ func (k Keeper) RecvPacket(

}

// log that a packet has been received & executed
k.Logger(ctx).Info(
"packet received",
"sequence", strconv.FormatUint(packet.GetSequence(), 10),
"src_port", packet.GetSourcePort(),
"src_channel", packet.GetSourceChannel(),
"dst_port", packet.GetDestPort(),
"dst_channel", packet.GetDestChannel(),
)

// emit an event that the relayer can query for
EmitRecvPacketEvent(ctx, packet, channel)

return nil
}

Expand Down
110 changes: 107 additions & 3 deletions modules/core/ante/ante.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package ante

import (
errorsmod "cosmossdk.io/errors"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
"github.com/cosmos/ibc-go/v7/modules/core/exported"
"github.com/cosmos/ibc-go/v7/modules/core/keeper"
solomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine"
tendermint "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint"
)

type RedundantRelayDecorator struct {
Expand All @@ -30,10 +36,22 @@ func (rrd RedundantRelayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
for _, m := range tx.GetMsgs() {
switch msg := m.(type) {
case *channeltypes.MsgRecvPacket:
response, err := rrd.k.RecvPacket(sdk.WrapSDKContext(ctx), msg)
var (
response *channeltypes.MsgRecvPacketResponse
err error
)
// when we are in ReCheckTx mode, ctx.IsCheckTx() will also return true
// therefore we must start the if statement on ctx.IsReCheckTx() to correctly
// determine which mode we are in
if ctx.IsReCheckTx() {
response, err = rrd.recvPacketReCheckTx(ctx, msg)
} else {
response, err = rrd.recvPacketCheckTx(ctx, msg)
}
if err != nil {
return ctx, err
}

if response.Result == channeltypes.NOOP {
redundancies++
}
Expand Down Expand Up @@ -70,8 +88,7 @@ func (rrd RedundantRelayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
packetMsgs++

case *clienttypes.MsgUpdateClient:
_, err := rrd.k.UpdateClient(sdk.WrapSDKContext(ctx), msg)
if err != nil {
if err := rrd.updateClientCheckTx(ctx, msg); err != nil {
return ctx, err
}

Expand All @@ -90,3 +107,90 @@ func (rrd RedundantRelayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
}
return next(ctx, tx, simulate)
}

// recvPacketCheckTx runs a subset of ibc recv packet logic to be used specifically within the RedundantRelayDecorator AnteHandler.
// It only performs core IBC receiving logic and skips any application logic.
func (rrd RedundantRelayDecorator) recvPacketCheckTx(ctx sdk.Context, msg *channeltypes.MsgRecvPacket) (*channeltypes.MsgRecvPacketResponse, error) {
// grab channel capability
_, capability, err := rrd.k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel)
if err != nil {
return nil, sdkerrors.Wrap(err, "could not retrieve module from port-id")
}

// If the packet was already received, perform a no-op
// Use a cached context to prevent accidental state changes
cacheCtx, writeFn := ctx.CacheContext()
err = rrd.k.ChannelKeeper.RecvPacket(cacheCtx, capability, msg.Packet, msg.ProofCommitment, msg.ProofHeight)

switch err {
case nil:
writeFn()
case channeltypes.ErrNoOpMsg:
return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.NOOP}, nil
default:
return nil, sdkerrors.Wrap(err, "receive packet verification failed")
}

return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.SUCCESS}, nil
}

// recvPacketReCheckTx runs a subset of ibc recv packet logic to be used specifically within the RedundantRelayDecorator AnteHandler.
// It only performs core IBC receiving logic and skips any application logic.
func (rrd RedundantRelayDecorator) recvPacketReCheckTx(ctx sdk.Context, msg *channeltypes.MsgRecvPacket) (*channeltypes.MsgRecvPacketResponse, error) {
// If the packet was already received, perform a no-op
// Use a cached context to prevent accidental state changes
cacheCtx, writeFn := ctx.CacheContext()
err := rrd.k.ChannelKeeper.RecvPacketReCheckTx(cacheCtx, msg.Packet)

switch err {
case nil:
writeFn()
case channeltypes.ErrNoOpMsg:
return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.NOOP}, nil
default:
return nil, sdkerrors.Wrap(err, "receive packet verification failed")
}

return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.SUCCESS}, nil
}

// updateClientCheckTx runs a subset of ibc client update logic to be used specifically within the RedundantRelayDecorator AnteHandler.
// The following function performs ibc client message verification for CheckTx only and state updates in both CheckTx and ReCheckTx.
// Note that misbehaviour checks are omitted.
func (rrd RedundantRelayDecorator) updateClientCheckTx(ctx sdk.Context, msg *clienttypes.MsgUpdateClient) error {
clientMsg, err := clienttypes.UnpackClientMessage(msg.ClientMessage)
if err != nil {
return err
}

clientState, found := rrd.k.ClientKeeper.GetClientState(ctx, msg.ClientId)
if !found {
return errorsmod.Wrapf(clienttypes.ErrClientNotFound, msg.ClientId)
}

if status := rrd.k.ClientKeeper.GetClientStatus(ctx, clientState, msg.ClientId); status != exported.Active {
return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "cannot update client (%s) with status %s", msg.ClientId, status)
}

clientStore := rrd.k.ClientKeeper.ClientStore(ctx, msg.ClientId)

if !ctx.IsReCheckTx() {
if err := clientState.VerifyClientMessage(ctx, rrd.k.Codec(), clientStore, clientMsg); err != nil {
return err
}
}

// NOTE: the following avoids panics in ante handler client updates for ibc-go v7.4.x
// without state machine breaking changes within light client modules.
switch clientMsg.(type) {
case *solomachine.Misbehaviour:
// ignore solomachine misbehaviour for update state in ante
case *tendermint.Misbehaviour:
// ignore tendermint misbehaviour for update state in ante
default:
heights := clientState.UpdateState(ctx, rrd.k.Codec(), clientStore, clientMsg)
ctx.Logger().With("module", "x/"+exported.ModuleName).Debug("ante ibc client update", "consensusHeights", heights)
}

return nil
}
Loading

0 comments on commit d4f8802

Please sign in to comment.