-
Notifications
You must be signed in to change notification settings - Fork 341
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
Add StdAck #1637
Add StdAck #1637
Conversation
i'm not convinced the ICS-20 format should be standardized. why encoded to base64 if you can just send JSON in the result, for example: https://git.sr.ht/~ekez/ica-secret/tree/main/item/packages/polytone/src/ack.rs#L5 |
it honestly drives me a little insane that the SDK forces you to use the ICS-20 format for error variants by wrapping it up like this: https://github.com/cosmos/ibc-go/blob/main/modules/core/04-channel/types/acknowledgement.go#L35 |
I don't have too much insight here. I copied this from @ethanfrey's code and looked up references for the decisions being made by others in the past. In general I think it's good to have a generic success/error wrapper that does not bother about the application specific sucess data and just uses binary. This allows us to have one layer that works with both ICS-20 and CosmWasm contract acks. |
I understand it is one level of nesting, but we do that often with things like Making a StdAck format is saying "Success if protocol-dependent, a higher level can parse to detect success/error without any protocol knowledge". I agree something like Go's json.RawMessage would be great, but we don't really have a good alternative in our Rust libraries. (There is one in serde-json under a feature flag but it brings in floats). When I see: #[cw_serde]
pub enum Callback {
/// Data returned from the host chain. Index n corresponds to the
/// result of executing the nth message/query.
Success(Vec<Option<Binary>>),
/// The first error that occured while executing the requested
/// messages/queries.
Error(String),
} I see a very specific app-result, which is great, but not the standard. Note, that the Error variant is equivalent to the StdAck one in JSON encoding... so if you just rely on x/wasm handling to auto-encode your errors, then it will be compatible (as x/wasm doesn't auto-encode successes and requires you to properly encode). |
@ethanfrey, thanks for the thoughts. I think nesting base64 is great when the type isn't known at compile time (needs to be an interface => "generic at runtime" => base64). In this case, I think the advantage is that it might normalize the ACK data and make it more compact. The ACK format is known at compile time. For example, you might write: #[cw_serde]
pub enum Ack<T> {
Result(T),
Error(String),
}
pub fn ack_success<T: Serialize>(c: T) -> Binary {
let res = Ack::Result(c);
to_binary(&res).unwrap()
}
// etc.. This is a bit of a bikeshed though, and thinking about it more I don't think there is anything wrong with the base64 approach so fine by me either way. |
Isn't that the same as One thing I was thinking about all the time is how to better separate the JSON serde from the base Ack to get great JSON support but also respect that not all protocols use JSON in the ack success. And looking of the discussion here we can do that plus get better type-safety by using a generic type which can still be StdAck compatible. // A newtype with an extra PhantomData
#[repr(transparent)]
#[serde(transparent)]
pub struct JsonAck<T> {
// private members
ack: StdAck,
marker: PhantomData<*const T>,
}
impl<T: Serialize + DeserializeOwned> JsonAck {
// construct from T
// unwrap into T
// map to Result<T, String>
} |
Okay this So we better just have |
This is just an constructor for the In c588c18 you see how you can prevent the creation of such error acks. This should allow you to use whichever ack type you need. See the rest of that PR for more context why we are working on this. |
f0b95cf
to
a91a35b
Compare
If I return |
Until wasmd 0.31, yes. From 0.32 onwards, panics abort the transaction and no ack is written. See more on that in #1646.
Since in some cases wasmd creates error acks, it has to make those assumptions. #1646 is your friend. Happy to answer questions over there. |
I was thinking about this a bit and came up with JsonAck, implementing whis approach. It's nicer than I originally thought, especially since JsonAck is compatible with the ICS-20 acknowledgement type. See #1657. |
a91a35b
to
a65f505
Compare
a65f505
to
9cc2c89
Compare
9cc2c89
to
2947d94
Compare
Updated the main description and consider this ready now. |
5487d8f
to
94d0eea
Compare
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.
I don't fully understand the whole discussion, but the code looks good to me.
match success { | ||
StdAck::Success(data) => assert_eq!(data, b"foo"), | ||
StdAck::Error(_err) => panic!("must not be an error"), | ||
} |
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.
Not a fan of assert!(matches!(...))
?
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.
Does this allow me to compare the data
value too?
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.
Yes, like this: assert!(matches!(success, StdAck::Success(data) if data == b"foo"))
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.
🧙♂️
Closes #1512
After a bit of back and forth, this is now very minimal and non-opinionated. It ensures compatibility with the standard ack types from ICS-20 and ICS-27 amonst others.
In noislabs/nois-contracts#279 you see how this can be used by projects to avoid the need to have their own ack type. There you can also see that the struct -> binary conversion (JSON serialitzation) is done outside of the ack. I.e. this type does not know or care what kind of bytes you store in the success case.