Skip to content

Commit ffdb9d0

Browse files
authored
Simplify WriteAck API for async acks (#7869)
* simplify writeack api * fix tests
1 parent ddce441 commit ffdb9d0

File tree

5 files changed

+92
-6
lines changed

5 files changed

+92
-6
lines changed

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

+32
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,35 @@ func (k *Keeper) SetNextSequenceSend(ctx context.Context, clientID string, seque
162162
panic(err)
163163
}
164164
}
165+
166+
// SetAsyncPacket writes the packet under the async path
167+
func (k *Keeper) SetAsyncPacket(ctx context.Context, clientID string, sequence uint64, packet types.Packet) {
168+
store := k.KVStoreService.OpenKVStore(ctx)
169+
bz := k.cdc.MustMarshal(&packet)
170+
if err := store.Set(types.AsyncPacketKey(clientID, sequence), bz); err != nil {
171+
panic(err)
172+
}
173+
}
174+
175+
// GetAsyncPacket fetches the packet from the async path
176+
func (k *Keeper) GetAsyncPacket(ctx context.Context, clientID string, sequence uint64) (types.Packet, bool) {
177+
store := k.KVStoreService.OpenKVStore(ctx)
178+
bz, err := store.Get(types.AsyncPacketKey(clientID, sequence))
179+
if err != nil {
180+
panic(err)
181+
}
182+
if len(bz) == 0 {
183+
return types.Packet{}, false
184+
}
185+
var packet types.Packet
186+
k.cdc.MustUnmarshal(bz, &packet)
187+
return packet, true
188+
}
189+
190+
// DeleteAsyncPacket deletes the packet from the async path
191+
func (k *Keeper) DeleteAsyncPacket(ctx context.Context, clientID string, sequence uint64) {
192+
store := k.KVStoreService.OpenKVStore(ctx)
193+
if err := store.Delete(types.AsyncPacketKey(clientID, sequence)); err != nil {
194+
panic(err)
195+
}
196+
}

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,12 @@ func (k *Keeper) RecvPacket(ctx context.Context, msg *types.MsgRecvPacket) (*typ
135135
// Set packet acknowledgement only if the acknowledgement is not async.
136136
// NOTE: IBC applications modules may call the WriteAcknowledgement asynchronously if the
137137
// acknowledgement is async.
138-
if err := k.WriteAcknowledgement(ctx, msg.Packet, ack); err != nil {
138+
if err := k.writeAcknowledgement(ctx, msg.Packet, ack); err != nil {
139139
return nil, err
140140
}
141+
} else {
142+
// store the packet temporarily until the application returns an acknowledgement
143+
k.SetAsyncPacket(ctx, msg.Packet.DestinationClient, msg.Packet.Sequence, msg.Packet)
141144
}
142145

143146
// TODO: store the packet for async applications to access if required.

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

+30-4
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ func (k *Keeper) recvPacket(
146146
return nil
147147
}
148148

149-
// WriteAcknowledgement writes the acknowledgement to the store.
150-
// TODO: change this function to accept destPort, destChannel, sequence, ack
151-
func (k Keeper) WriteAcknowledgement(
149+
// writeAcknowledgement writes the acknowledgement to the store and emits the packet and acknowledgement
150+
// for relayers to relay the acknowledgement to the counterparty chain.
151+
func (k Keeper) writeAcknowledgement(
152152
ctx context.Context,
153153
packet types.Packet,
154154
ack types.Acknowledgement,
@@ -184,7 +184,33 @@ func (k Keeper) WriteAcknowledgement(
184184

185185
emitWriteAcknowledgementEvents(ctx, packet, ack)
186186

187-
// TODO: delete the packet that has been stored in ibc-core.
187+
return nil
188+
}
189+
190+
// WriteAcknowledgement writes the acknowledgement and emits events for asynchronous acknowledgements
191+
// this is the method to be called by external apps when they want to write an acknowledgement asyncrhonously
192+
func (k *Keeper) WriteAcknowledgement(ctx context.Context, clientID string, sequence uint64, ack types.Acknowledgement) error {
193+
sdkCtx := sdk.UnwrapSDKContext(ctx)
194+
195+
// Validate the acknowledgement
196+
if err := ack.Validate(); err != nil {
197+
sdkCtx.Logger().Error("write acknowledgement failed", "error", errorsmod.Wrap(err, "invalid acknowledgement"))
198+
return errorsmod.Wrap(err, "invalid acknowledgement")
199+
}
200+
201+
packet, ok := k.GetAsyncPacket(ctx, clientID, sequence)
202+
if !ok {
203+
return errorsmod.Wrapf(types.ErrInvalidAcknowledgement, "packet with clientID (%s) and sequence (%d) not found for async acknowledgement", clientID, sequence)
204+
}
205+
206+
// Write the acknowledgement to the store
207+
if err := k.writeAcknowledgement(ctx, packet, ack); err != nil {
208+
sdkCtx.Logger().Error("write acknowledgement failed", "error", errorsmod.Wrap(err, "write acknowledgement failed"))
209+
return errorsmod.Wrap(err, "write acknowledgement failed")
210+
}
211+
212+
// Delete the packet from the async store
213+
k.DeleteAsyncPacket(ctx, clientID, sequence)
188214

189215
return nil
190216
}

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,17 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
253253
"failure: client not found",
254254
func() {
255255
packet.DestinationClient = ibctesting.InvalidID
256+
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetPacketReceipt(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence)
257+
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetAsyncPacket(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence, packet)
256258
},
257259
clienttypes.ErrCounterpartyNotFound,
258260
},
259261
{
260262
"failure: counterparty client identifier different than source client",
261263
func() {
262264
packet.SourceClient = unusedChannel
265+
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetPacketReceipt(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence)
266+
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetAsyncPacket(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence, packet)
263267
},
264268
clienttypes.ErrInvalidCounterparty,
265269
},
@@ -275,9 +279,17 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
275279
"failure: receipt not found for packet",
276280
func() {
277281
packet.Sequence = 2
282+
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetAsyncPacket(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence, packet)
278283
},
279284
types.ErrInvalidPacket,
280285
},
286+
{
287+
"failure: async packet not found",
288+
func() {
289+
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.DeleteAsyncPacket(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence)
290+
},
291+
types.ErrInvalidAcknowledgement,
292+
},
281293
}
282294

283295
for _, tc := range testCases {
@@ -301,11 +313,13 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() {
301313
AppAcknowledgements: [][]byte{mockv2.MockRecvPacketResult.Acknowledgement},
302314
}
303315

316+
// mock receive with async acknowledgement
304317
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetPacketReceipt(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence)
318+
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetAsyncPacket(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence, packet)
305319

306320
tc.malleate()
307321

308-
err := suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack)
322+
err := suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.WriteAcknowledgement(suite.chainB.GetContext(), packet.DestinationClient, packet.Sequence, ack)
309323

310324
expPass := tc.expError == nil
311325
if expPass {
+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
package types
22

3+
import "fmt"
4+
35
const (
46
// SubModuleName defines the channelv2 module name.
57
SubModuleName = "channelv2"
8+
9+
// KeyAsyncPacket defines the key to store the async packet.
10+
KeyAsyncPacket = "async_packet"
611
)
12+
13+
// AsyncPacketKey returns the key under which the packet is stored
14+
// if the receiving application returns an async acknowledgement.
15+
func AsyncPacketKey(clientID string, sequence uint64) []byte {
16+
return []byte(fmt.Sprintf("%s/%s/%d", KeyAsyncPacket, clientID, sequence))
17+
}

0 commit comments

Comments
 (0)