Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reject Redundant Tx Antedecorator #235

Merged
merged 11 commits into from
Jul 19, 2021
3 changes: 3 additions & 0 deletions modules/core/04-channel/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ var (

// ORDERED channel error
ErrPacketSequenceOutOfOrder = sdkerrors.Register(SubModuleName, 21, "packet sequence is out of order")

// Antehandler error
ErrRedundantTx = sdkerrors.Register(SubModuleName, 22, "packet messages are redundant")
)
72 changes: 72 additions & 0 deletions modules/core/ante/ante.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package ante

import (
sdk "github.com/cosmos/cosmos-sdk/types"
clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types"
channelkeeper "github.com/cosmos/ibc-go/modules/core/04-channel/keeper"
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
)

type AnteDecorator struct {
k channelkeeper.Keeper
}

func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator {
return AnteDecorator{k: k}
}

// AnteDecorator returns an error if a multiMsg tx only contains packet messages (Recv, Ack, Timeout) and additional update messages and all packet messages
// are redundant. If the transaction is just a single UpdateClient message, or the multimsg transaction contains some other message type, then the antedecorator returns no error
// and continues processing to ensure these transactions are included.
// This will ensure that relayers do not waste fees on multiMsg transactions when another relayer has already submitted all packets, by rejecting the tx at the mempool layer.
func (ad AnteDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// do not run redundancy check on DeliverTx or simulate
if (ctx.IsCheckTx() || ctx.IsReCheckTx()) && !simulate {
// keep track of total packet messages and number of redundancies across `RecvPacket`, `AcknowledgePacket`, and `TimeoutPacket/OnClose`
redundancies := 0
packetMsgs := 0
for _, m := range tx.GetMsgs() {
switch msg := m.(type) {
case *channeltypes.MsgRecvPacket:
if _, found := ad.k.GetPacketReceipt(ctx, msg.Packet.GetDestPort(), msg.Packet.GetDestChannel(), msg.Packet.GetSequence()); found {
redundancies += 1
}
packetMsgs += 1

case *channeltypes.MsgAcknowledgement:
if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 {
redundancies += 1
}
packetMsgs += 1

case *channeltypes.MsgTimeout:
if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 {
redundancies += 1
}
packetMsgs += 1

case *channeltypes.MsgTimeoutOnClose:
if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 {
redundancies += 1
}
packetMsgs += 1

case *clienttypes.MsgUpdateClient:
// do nothing here, as we want to avoid updating clients if it is batched with only redundant messages

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
// even if they get batched with redundant packet messages.
return next(ctx, tx, simulate)
}

}

// only return error if all packet messages are redundant
if redundancies == packetMsgs && packetMsgs > 0 {
return ctx, channeltypes.ErrRedundantTx
}
}
return next(ctx, tx, simulate)
}
Loading