-
Notifications
You must be signed in to change notification settings - Fork 334
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
Review error handling/rollback when recieve_packet errors (sends ack packet with error) #762
Comments
I have been thinking about this a bit more and followed some general discussion on this issue at cosmos/ibc-go#68 When reflecting more on this, I realized that even if a contract caches it's state internally and only commits writes on success, what if it return a message? And that message errors? The only proper place to handle this would be in the Go app (wasmd). It should make a cached store and execute the task and all messages and all sub-messages and if any errors, then it reverts the local store cache (just inside the wasm handler, not for the ibc handler), and package this error into an "error" acknowledgement message, returning a success with error acknowledgement to the ibc handler. The main issue is creating the error acknowledgement. There is a standardized (but not required) acknowledgement format that is used in ICS20: https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto#L144-L157 (thanks to me). This is currently encoded as JSON in the ics20-1 protocol, but there was some discussion to make this protobuf in the future. I would propose the following mapping in x/wasm (which needs to be well-documented). If a contract returns an error on OnRecvPacket, the Go keeper should revert local state changes, and check the value of the error string to determine the acknowledgement packet (for error):
Open question: should we handle serializing the standard Note: if a protocol requires a specific error ack format and an error may be returned by a message, it must return them as submessages, and if the submessage returns error, the contract can map that to a different custom error format (eg. 0xabcd) before returning that. |
This is a scenario that is possible now but pretty complex to handle in wasmd. IMHO the contract is fully responsible to process or orchestrate the IBC data. We can simply remove |
If Acknowledgement is a binary result or a string error, shouldn't we have an pub enum Acknowledgement {
/// The success case
/// https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto#L154
Result(Binary),
/// The error case
/// https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto#L155
Error(String),
} and use it instead of Binary in both |
That channel acknowledgement is a recommended format for acknowledgements, but not all protocols must use it. (They went overboard on ultra-flexibility in IBC as to make it hard to use). Further, it is unspecified if this is encoded as JSON or Protobuf if it is used (6 months ago they said protobuf, implementation is JSON, this may have something to do with the event system). We could enforce that all contracts use this format and encode it with JSON, but it may then be impossible to provide compatibility with future IBC protocols someone designs. Any idea to provide a simple default, as well as a way to override it? |
Oh, this is MUCH more complex to handle in a contract. With submessages, I already handle the wrapping on the store and reverting if needed. Reverting state in I am happy to implement this in wasmd (simpler than submessages). The main point is some way to allow the contract to potentially be in full control of the acknowledgement (if they want to use a custom format), while providing an easy default (the type linked above, ics20 compatible) |
Unless I understood the issue wrong it does belong to the app level and moving it to wasmd limits the flexibility that dynamic ibc gives us for custom IBC apps. Wasmd must not know anything about the data packages nor do assumptions what an error is. In my understanding the Submessages do not alter state on error. So the contract has to keep track of submessages sent and their responses. It can abort and return an IBC ack error on the first issue or wait for the last submessage to succeed for the final OK ack. But also this is app dependent. Maybe there are scenarios where even a failing submessage does not cause an IBC ack error or different ack states exists.... Maybe we can have some contract framework that helps with the complexity on that level at some point. |
Look at this (common) case:
This is hard because: A. How do I revert the state changes from (1) in another call to the contract? My approach which says, contract returns error in (1) or (3) on failure and error string encodes the (failed) acknowledgement packet makes use of most of the plumbing we already have. We error on any sub-call that returns errors, and just a simple cache wrap and error serialization will let us customize the ack from a failed sub-call. |
I would note that the IBC team plans to support OnRecvPacket callbacks returning error to the IBC handler and manage this state reversion there (in a future IBC version). Meaning, we can be a step ahead with the contract interface using some glue code in tgrade, and then just remove most of the glue code and base on the Cosmos SDK in a future version. I'm not sure how they plan to encode the acknowledgement message on failure, but probably some Go interface on the error. |
Please see cosmos/ibc-go#107 for the new ibc-go approach to revert on error. From 0.43 on, this will be taken care of in the sdk. For now, we have to handle it in wasmd. But we should take a contract interface that works for the future |
I propose a different mechanism to re-write the "error acknoweldgement" (rather than some ad-hoc encoding format in an error string). I would appreciate a review of the description here #885 Once we have agreement on the approach, I will implement it and close this issue. |
Isn't the problem in this use case that the acknowledgement needs to be created in the entry point So what bites us here is no syncronous calls out and no promise system that would allow us to continue processing |
@webmaster128 can you please review #885 where I propose a solution to this? It allows easy extensibility of how to encode the "error acknowledgement" regardless of where the error came from (contract, message, submessage, message of message...). It does assume that all information for a "success acknowledgement" is available at the time of the original contract execution and doesn't depend on any submessages. Let me try to think of a real usecase for that before worrying on a design of that, but it would be good to get feedback on the "error acknowledgement" part and if it looks good and there is need, this can inform the design of the "delayed success acknowledgement" issue |
Okay, on reflection, the success case is also important. In the (vague) ICS27 spec, they define a packet to register a new account, the acknowledgement of that packet should contain the address of the new account. If we implemented this in CosmWasm, the contract would have to return a I would propose a similar method to #885. If a contract needs to do this delayed, it can expose a Unless there are major issues, I will refine this issue and add it to #885 |
This counts as a fail for the contract and we would assume state is rolled back.
But we return what looks like as a success to the ibc callback (which is correct)
Let's ensure this doesn't leave half-written state in
ibc-reflect
andibc-reflect-send
.Note: relevant tracking issue in IBC is cosmos/ibc-go#91 (based on the bug analysis from cosmos/ibc-go#68)
The text was updated successfully, but these errors were encountered: