Skip to content

Commit

Permalink
chore: add redundancy checks for V2 Msgs (#7509)
Browse files Browse the repository at this point in the history
* chore: add redundant checks for V2 Msgs

* reintroduce tests
  • Loading branch information
bznein authored Nov 4, 2024
1 parent 4e5b07c commit 870e830
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
31 changes: 31 additions & 0 deletions modules/core/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types"
channeltypesv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
"github.com/cosmos/ibc-go/v9/modules/core/exported"
"github.com/cosmos/ibc-go/v9/modules/core/keeper"
)
Expand Down Expand Up @@ -89,6 +90,36 @@ func (rrd RedundantRelayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
return ctx, err
}

case *channeltypesv2.MsgTimeout:
response, err := rrd.k.ChannelKeeperV2.Timeout(ctx, msg)
if err != nil {
return ctx, err
}

if response.Result == channeltypes.NOOP {
redundancies++
}
packetMsgs++
case *channeltypesv2.MsgAcknowledgement:
response, err := rrd.k.ChannelKeeperV2.Acknowledgement(ctx, msg)
if err != nil {
return ctx, err
}

if response.Result == channeltypes.NOOP {
redundancies++
}
packetMsgs++
case *channeltypesv2.MsgRecvPacket:
response, err := rrd.k.ChannelKeeperV2.RecvPacket(ctx, msg)
if err != nil {
return ctx, err
}

if response.Result == channeltypes.NOOP {
redundancies++
}
packetMsgs++
default:
// if the multiMsg tx has a msg that is not a packet msg or update msg, then we will not return error
// regardless of if all packet messages are redundant. This ensures that non-packet messages get processed
Expand Down
123 changes: 123 additions & 0 deletions modules/core/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"testing"
"time"

"github.com/stretchr/testify/require"
testifysuite "github.com/stretchr/testify/suite"
Expand All @@ -13,12 +14,15 @@ import (

clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types"
channeltypesv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
commitmenttypes "github.com/cosmos/ibc-go/v9/modules/core/23-commitment/types"
host "github.com/cosmos/ibc-go/v9/modules/core/24-host"
hostv2 "github.com/cosmos/ibc-go/v9/modules/core/24-host/v2"
"github.com/cosmos/ibc-go/v9/modules/core/ante"
"github.com/cosmos/ibc-go/v9/modules/core/exported"
ibctm "github.com/cosmos/ibc-go/v9/modules/light-clients/07-tendermint"
ibctesting "github.com/cosmos/ibc-go/v9/testing"
"github.com/cosmos/ibc-go/v9/testing/mock/v2"
)

type AnteTestSuite struct {
Expand Down Expand Up @@ -74,6 +78,25 @@ func (suite *AnteTestSuite) createRecvPacketMessage(isRedundant bool) *channelty
return channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
}

// createRecvPacketMessageV2 creates a V2 RecvPacket message for a packet sent from chain A to chain B.
func (suite *AnteTestSuite) createRecvPacketMessageV2(isRedundant bool) *channeltypesv2.MsgRecvPacket {
packet, err := suite.path.EndpointA.MsgSendPacket(suite.chainA.GetTimeoutTimestamp(), mock.NewMockPayload(mock.ModuleNameA, mock.ModuleNameB))
suite.Require().NoError(err)

if isRedundant {
err = suite.path.EndpointB.MsgRecvPacket(packet)
suite.Require().NoError(err)
}

err = suite.path.EndpointB.UpdateClient()
suite.Require().NoError(err)

packetKey := hostv2.PacketCommitmentKey(packet.SourceChannel, packet.Sequence)
proof, proofHeight := suite.chainA.QueryProof(packetKey)

return channeltypesv2.NewMsgRecvPacket(packet, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
}

// createAcknowledgementMessage creates an Acknowledgement message for a packet sent from chain B to chain A.
func (suite *AnteTestSuite) createAcknowledgementMessage(isRedundant bool) sdk.Msg {
sequence, err := suite.path.EndpointB.SendPacket(clienttypes.NewHeight(2, 0), 0, ibctesting.MockPacketData)
Expand All @@ -97,6 +120,33 @@ func (suite *AnteTestSuite) createAcknowledgementMessage(isRedundant bool) sdk.M
return channeltypes.NewMsgAcknowledgement(packet, ibctesting.MockAcknowledgement, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
}

// createAcknowledgementMessageV2 creates a V2 Acknowledgement message for a packet sent from chain B to chain A.
func (suite *AnteTestSuite) createAcknowledgementMessageV2(isRedundant bool) *channeltypesv2.MsgAcknowledgement {
packet, err := suite.path.EndpointB.MsgSendPacket(suite.chainB.GetTimeoutTimestamp(), mock.NewMockPayload(mock.ModuleNameA, mock.ModuleNameB))
suite.Require().NoError(err)

err = suite.path.EndpointA.MsgRecvPacket(packet)
suite.Require().NoError(err)

ack := channeltypesv2.Acknowledgement{
AcknowledgementResults: []channeltypesv2.AcknowledgementResult{
{
AppName: mock.ModuleNameB,
RecvPacketResult: mock.MockRecvPacketResult,
},
},
}
if isRedundant {
err = suite.path.EndpointB.MsgAcknowledgePacket(packet, ack)
suite.Require().NoError(err)
}

packetKey := hostv2.PacketAcknowledgementKey(packet.DestinationChannel, packet.Sequence)
proof, proofHeight := suite.chainA.QueryProof(packetKey)

return channeltypesv2.NewMsgAcknowledgement(packet, ack, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
}

// createTimeoutMessage creates an Timeout message for a packet sent from chain B to chain A.
func (suite *AnteTestSuite) createTimeoutMessage(isRedundant bool) sdk.Msg {
height := suite.chainA.LatestCommittedHeader.GetHeight()
Expand Down Expand Up @@ -126,6 +176,27 @@ func (suite *AnteTestSuite) createTimeoutMessage(isRedundant bool) sdk.Msg {
return channeltypes.NewMsgTimeout(packet, sequence, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
}

// createTimeoutMessageV2 creates a V2 Timeout message for a packet sent from chain B to chain A.
func (suite *AnteTestSuite) createTimeoutMessageV2(isRedundant bool) *channeltypesv2.MsgTimeout {
timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().Unix())
packet, err := suite.path.EndpointB.MsgSendPacket(timeoutTimestamp, mock.NewMockPayload(mock.ModuleNameA, mock.ModuleNameB))
suite.Require().NoError(err)

suite.coordinator.IncrementTimeBy(time.Hour)
err = suite.path.EndpointB.UpdateClient()
suite.Require().NoError(err)

if isRedundant {
err = suite.path.EndpointB.MsgTimeoutPacket(packet)
suite.Require().NoError(err)
}

packetKey := hostv2.PacketReceiptKey(packet.SourceChannel, packet.Sequence)
proof, proofHeight := suite.chainA.QueryProof(packetKey)

return channeltypesv2.NewMsgTimeout(packet, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String())
}

// createTimeoutOnCloseMessage creates an TimeoutOnClose message for a packet sent from chain B to chain A.
func (suite *AnteTestSuite) createTimeoutOnCloseMessage(isRedundant bool) sdk.Msg {
height := suite.chainA.LatestCommittedHeader.GetHeight()
Expand Down Expand Up @@ -193,6 +264,15 @@ func (suite *AnteTestSuite) TestAnteDecoratorCheckTx() {
},
nil,
},
{
"success on one new V2 RecvPacket message",
func(suite *AnteTestSuite) []sdk.Msg {
suite.path.SetupV2()
// the RecvPacket message has not been submitted to the chain yet, so it will succeed
return []sdk.Msg{suite.createRecvPacketMessageV2(false)}
},
nil,
},
{
"success on one new Acknowledgement message",
func(suite *AnteTestSuite) []sdk.Msg {
Expand All @@ -201,6 +281,15 @@ func (suite *AnteTestSuite) TestAnteDecoratorCheckTx() {
},
nil,
},
{
"success on one new V2 Acknowledgement message",
func(suite *AnteTestSuite) []sdk.Msg {
suite.path.SetupV2()
// the Acknowledgement message has not been submitted to the chain yet, so it will succeed
return []sdk.Msg{suite.createAcknowledgementMessageV2(false)}
},
nil,
},
{
"success on one new Timeout message",
func(suite *AnteTestSuite) []sdk.Msg {
Expand All @@ -209,6 +298,15 @@ func (suite *AnteTestSuite) TestAnteDecoratorCheckTx() {
},
nil,
},
{
"success on one new Timeout V2 message",
func(suite *AnteTestSuite) []sdk.Msg {
suite.path.SetupV2()
// the Timeout message has not been submitted to the chain yet, so it will succeed
return []sdk.Msg{suite.createTimeoutMessageV2(false)}
},
nil,
},
{
"success on one new TimeoutOnClose message",
func(suite *AnteTestSuite) []sdk.Msg {
Expand Down Expand Up @@ -368,6 +466,14 @@ func (suite *AnteTestSuite) TestAnteDecoratorCheckTx() {
},
channeltypes.ErrRedundantTx,
},
{
"no success on one redundant V2 RecvPacket message",
func(suite *AnteTestSuite) []sdk.Msg {
suite.path.SetupV2()
return []sdk.Msg{suite.createRecvPacketMessageV2(true)}
},
channeltypes.ErrRedundantTx,
},
{
"no success on three redundant messages of each type",
func(suite *AnteTestSuite) []sdk.Msg {
Expand Down Expand Up @@ -555,6 +661,15 @@ func (suite *AnteTestSuite) TestAnteDecoratorReCheckTx() {
},
nil,
},
{
"success on one new V2 RecvPacket message",
func(suite *AnteTestSuite) []sdk.Msg {
suite.path.SetupV2()
// the RecvPacket message has not been submitted to the chain yet, so it will succeed
return []sdk.Msg{suite.createRecvPacketMessageV2(false)}
},
nil,
},
{
"success on one redundant and one new RecvPacket message",
func(suite *AnteTestSuite) []sdk.Msg {
Expand Down Expand Up @@ -595,6 +710,14 @@ func (suite *AnteTestSuite) TestAnteDecoratorReCheckTx() {
},
channeltypes.ErrRedundantTx,
},
{
"no success on one redundant V2 RecvPacket message",
func(suite *AnteTestSuite) []sdk.Msg {
suite.path.SetupV2()
return []sdk.Msg{suite.createRecvPacketMessageV2(true)}
},
channeltypes.ErrRedundantTx,
},
}

for _, tc := range testCases {
Expand Down

0 comments on commit 870e830

Please sign in to comment.