Skip to content

Commit ef766e3

Browse files
committed
chore: add validation for Ack and plug it in.
1 parent cf82eba commit ef766e3

File tree

8 files changed

+101
-18
lines changed

8 files changed

+101
-18
lines changed

modules/core/04-channel/v2/keeper/msg_server.go

+8
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,21 @@ func (k *Keeper) RecvPacket(ctx context.Context, msg *types.MsgRecvPacket) (*typ
163163
ack.AppAcknowledgements = append(ack.AppAcknowledgements, res.Acknowledgement)
164164
}
165165

166+
if len(ack.AppAcknowledgements) != len(msg.Packet.Payloads) {
167+
return nil, errorsmod.Wrapf(types.ErrInvalidAcknowledgement, "length of app acknowledgement %d does not match length of app payload %d", len(ack.AppAcknowledgements), len(msg.Packet.Payloads))
168+
}
169+
166170
// note this should never happen as the payload would have had to be empty.
167171
if len(ack.AppAcknowledgements) == 0 {
168172
sdkCtx.Logger().Error("receive packet failed", "source-channel", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "invalid acknowledgement results"))
169173
return &types.MsgRecvPacketResponse{Result: types.FAILURE}, errorsmod.Wrapf(err, "receive packet failed source-channel %s invalid acknowledgement results", msg.Packet.SourceChannel)
170174
}
171175

172176
if !isAsync {
177+
// Validate ack before forwarding to WriteAcknowledgement.
178+
if err := ack.Validate(); err != nil {
179+
return nil, err
180+
}
173181
// Set packet acknowledgement only if the acknowledgement is not async.
174182
// NOTE: IBC applications modules may call the WriteAcknowledgement asynchronously if the
175183
// acknowledgement is async.

modules/core/04-channel/v2/keeper/msg_server_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,16 @@ func (suite *KeeperTestSuite) TestMsgRecvPacket() {
290290
},
291291
expError: commitmenttypes.ErrInvalidProof,
292292
},
293+
{
294+
name: "failure: invalid acknowledgement",
295+
malleate: func() {
296+
expRecvRes = types.RecvPacketResult{
297+
Status: types.PacketStatus_Success,
298+
Acknowledgement: []byte(""),
299+
}
300+
},
301+
expError: types.ErrInvalidAcknowledgement,
302+
},
293303
}
294304

295305
for _, tc := range testCases {

modules/core/04-channel/v2/keeper/packet.go

-7
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,6 @@ func (k Keeper) WriteAcknowledgement(
190190
return errorsmod.Wrap(types.ErrInvalidPacket, "receipt not found for packet")
191191
}
192192

193-
// TODO: Validate Acknowledgment more thoroughly here after Issue #7472: https://github.com/cosmos/ibc-go/issues/7472
194-
195-
// TODO: remove this check, maybe pull it up to the handler.
196-
if len(ack.AppAcknowledgements) != len(packet.Payloads) {
197-
return errorsmod.Wrapf(types.ErrInvalidAcknowledgement, "length of app acknowledgement %d does not match length of app payload %d", len(ack.AppAcknowledgements), len(packet.Payloads))
198-
}
199-
200193
// set the acknowledgement so that it can be verified on the other side
201194
k.SetPacketAcknowledgement(
202195
ctx, packet.DestinationChannel, packet.Sequence,

modules/core/04-channel/v2/keeper/packet_test.go

-9
Original file line numberDiff line numberDiff line change
@@ -271,15 +271,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
271271
},
272272
types.ErrAcknowledgementExists,
273273
},
274-
{
275-
"failure: empty ack",
276-
func() {
277-
ack = types.Acknowledgement{
278-
AppAcknowledgements: [][]byte{},
279-
}
280-
},
281-
types.ErrInvalidAcknowledgement,
282-
},
283274
{
284275
"failure: receipt not found for packet",
285276
func() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package types
2+
3+
import (
4+
errorsmod "cosmossdk.io/errors"
5+
)
6+
7+
// NewAcknowledgement creates a new Acknowledgement containing the provided app acknowledgements.
8+
func NewAcknowledgement(appAcknowledgements ...[]byte) Acknowledgement {
9+
return Acknowledgement{AppAcknowledgements: appAcknowledgements}
10+
}
11+
12+
// Validate performs a basic validation of the acknowledgement
13+
func (ack Acknowledgement) Validate() error {
14+
if len(ack.AppAcknowledgements) != 1 {
15+
return errorsmod.Wrap(ErrInvalidAcknowledgement, "app acknowledgements must be of length one")
16+
}
17+
18+
for _, ack := range ack.AppAcknowledgements {
19+
if len(ack) == 0 {
20+
return errorsmod.Wrap(ErrInvalidAcknowledgement, "app acknowledgement cannot be empty")
21+
}
22+
}
23+
24+
return nil
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package types_test
2+
3+
import (
4+
"github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
5+
)
6+
7+
// Test_ValidateAcknowledgement tests the acknowledgements Validate method
8+
func (s *TypesTestSuite) Test_ValidateAcknowledgement() {
9+
testCases := []struct {
10+
name string
11+
ack types.Acknowledgement
12+
expError error
13+
}{
14+
{
15+
"success: valid successful ack",
16+
types.NewAcknowledgement([]byte("appAck1")),
17+
nil,
18+
},
19+
{
20+
"failure: more than one app acknowledgements",
21+
types.NewAcknowledgement([]byte("appAck1"), []byte("appAck2")),
22+
types.ErrInvalidAcknowledgement,
23+
},
24+
{
25+
"failure: app acknowledgement is empty",
26+
types.NewAcknowledgement([]byte("")),
27+
types.ErrInvalidAcknowledgement,
28+
},
29+
}
30+
31+
for _, tc := range testCases {
32+
tc := tc
33+
34+
s.Run(tc.name, func() {
35+
s.SetupTest()
36+
37+
err := tc.ack.Validate()
38+
39+
expPass := tc.expError == nil
40+
if expPass {
41+
s.Require().NoError(err)
42+
} else {
43+
s.Require().ErrorIs(err, tc.expError)
44+
}
45+
})
46+
}
47+
}

modules/core/04-channel/v2/types/msgs.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,9 @@ func (msg *MsgAcknowledgement) ValidateBasic() error {
167167
return errorsmod.Wrap(commitmenttypesv1.ErrInvalidProof, "cannot submit an empty acknowledgement proof")
168168
}
169169

170-
// TODO: Add validation for ack object https://github.com/cosmos/ibc-go/issues/7472
170+
if err := msg.Acknowledgement.Validate(); err != nil {
171+
return err
172+
}
171173

172174
_, err := sdk.AccAddressFromBech32(msg.Signer)
173175
if err != nil {

modules/core/04-channel/v2/types/msgs_test.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -322,12 +322,19 @@ func (s *TypesTestSuite) TestMsgAcknowledge_ValidateBasic() {
322322
},
323323
expError: types.ErrInvalidPacket,
324324
},
325+
{
326+
name: "failure: invalid acknowledgement",
327+
malleate: func() {
328+
msg.Acknowledgement = types.NewAcknowledgement([]byte(""))
329+
},
330+
expError: types.ErrInvalidAcknowledgement,
331+
},
325332
}
326333
for _, tc := range testCases {
327334
s.Run(tc.name, func() {
328335
msg = types.NewMsgAcknowledgement(
329336
types.NewPacket(1, ibctesting.FirstChannelID, ibctesting.SecondChannelID, s.chainA.GetTimeoutTimestamp(), mockv2.NewMockPayload(mockv2.ModuleNameA, mockv2.ModuleNameB)),
330-
types.Acknowledgement{},
337+
types.NewAcknowledgement([]byte("appAck1")),
331338
testProof,
332339
clienttypes.ZeroHeight(),
333340
s.chainA.SenderAccount.GetAddress().String(),

0 commit comments

Comments
 (0)