-
Notifications
You must be signed in to change notification settings - Fork 672
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
Revert application state changes on failed acknowledgements #107
Changes from all commits
5849d5a
c4ea50f
00abadc
1149f3c
0ba44bc
bbd1e38
f97e6f4
b0ed09a
9da6a16
2b00c1b
3111c1d
34e6d63
2ab95f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -295,49 +295,46 @@ invoked by the IBC module after the packet has been proved valid and correctly p | |||||
keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state | ||||||
changes given the packet data without worrying about whether the packet is valid or not. | ||||||
|
||||||
Modules may return an acknowledgement as a byte string and return it to the IBC handler. | ||||||
Modules may return to the IBC handler an acknowledgement which implements the Acknowledgement interface. | ||||||
The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the | ||||||
acknowledgement back to the sender module. | ||||||
|
||||||
The state changes that occurred during this callback will only be written if: | ||||||
- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement | ||||||
- if the acknowledgement returned is nil indicating that an asynchronous process is occurring | ||||||
|
||||||
NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes | ||||||
when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written | ||||||
for asynchronous acknowledgements. | ||||||
|
||||||
```go | ||||||
OnRecvPacket( | ||||||
ctx sdk.Context, | ||||||
packet channeltypes.Packet, | ||||||
) (res *sdk.Result, ack []byte, abort error) { | ||||||
) ibcexported.Acknowledgement { | ||||||
// Decode the packet data | ||||||
packetData := DecodePacketData(packet.Data) | ||||||
|
||||||
// do application state changes based on packet data | ||||||
// and return result, acknowledgement and abortErr | ||||||
// Note: abortErr is only not nil if we need to abort the entire receive packet, and allow a replay of the receive. | ||||||
// If the application state change failed but we do not want to replay the packet, | ||||||
// simply encode this failure with relevant information in ack and return nil error | ||||||
res, ack, abortErr := processPacket(ctx, packet, packetData) | ||||||
|
||||||
// if we need to abort the entire receive packet, return error | ||||||
if abortErr != nil { | ||||||
return nil, nil, abortErr | ||||||
} | ||||||
|
||||||
// Encode the ack since IBC expects acknowledgement bytes | ||||||
ackBytes := EncodeAcknowledgement(ack) | ||||||
// do application state changes based on packet data and return the acknowledgement | ||||||
// NOTE: The acknowledgement will indicate to the IBC handler if the application | ||||||
// state changes should be written via the `Success()` function. Application state | ||||||
// changes are only written if the acknowledgement is successful or the acknowledgement | ||||||
// returned is nil indicating that an asynchronous acknowledgement will occur. | ||||||
ack := processPacket(ctx, packet, packetData) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
It's a bit confusing to have both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is useful to show the app developer they need to decode the packet data, as shown by the line above this one Going to leave as is since it matches ICS 20 |
||||||
|
||||||
return res, ackBytes, nil | ||||||
return ack | ||||||
} | ||||||
``` | ||||||
|
||||||
::: warning | ||||||
`OnRecvPacket` should **only** return an error if we want the entire receive packet execution | ||||||
(including the IBC handling) to be reverted. This will allow the packet to be replayed in the case | ||||||
that some mistake in the relaying caused the packet processing to fail. | ||||||
|
||||||
If some application-level error happened while processing the packet data, in most cases, we will | ||||||
not want the packet processing to revert. Instead, we may want to encode this failure into the | ||||||
acknowledgement and finish processing the packet. This will ensure the packet cannot be replayed, | ||||||
and will also allow the sender module to potentially remediate the situation upon receiving the | ||||||
acknowledgement. An example of this technique is in the `ibc-transfer` module's | ||||||
[`OnRecvPacket`](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go). | ||||||
::: | ||||||
The Acknowledgement interface: | ||||||
```go | ||||||
// Acknowledgement defines the interface used to return | ||||||
// acknowledgements in the OnRecvPacket callback. | ||||||
type Acknowledgement interface { | ||||||
Success() bool | ||||||
Acknowledgement() []byte | ||||||
} | ||||||
``` | ||||||
|
||||||
### Acknowledgements | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,3 +91,11 @@ REST routes are not supported for these proposals. | |
## Proto file changes | ||
|
||
The gRPC querier service endpoints have changed slightly. The previous files used `v1beta1`, this has been updated to `v1`. | ||
|
||
## IBC callback changes | ||
|
||
### OnRecvPacket | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Big fan of this doc 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Me too! We should continue this for future major version releases |
||
|
||
Application developers need to update their `OnRecvPacket` callback logic. | ||
|
||
The `OnRecvPacket` callback has been modified to only return the acknowledgement. The acknowledgement returned must implement the `Acknowledgement` interface. The acknowledgement should indicate if it represents a successful processing of a packet by returning true on `Success()` and false in all other cases. A return value of false on `Success()` will result in all state changes which occurred in the callback being discarded. More information can be found in the [documentation](https://github.com/cosmos/ibc-go/blob/main/docs/custom.md#receiving-packets). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So anyone using async acks will have to take care to revert state themselves. This should be documented
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a note. Going to merge this pr, feel free to open an issue or comment here if you think it could use more information