-
Notifications
You must be signed in to change notification settings - Fork 16
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 semantical replies support #29
Comments
I would see this feature done in two phases
DispatchingLet's start with the reply entry point. I would make it dispatch the message without any parsing. This should be done in some intermediate type to be reused if needed f.e. in overriden entry point. pub fn reply(
deps: sylvia::cw_std::DepsMut<sylvia::cw_std::Empty>,
env: sylvia::cw_std::Env,
msg: sylvia::cw_std::Reply,
) -> Result<sylvia::cw_std::Response<sylvia::cw_std::Empty>, ContractError> {
Contract::new()
.reply((deps, env).into(), msg)
.map_err(Into::into)
} The generated dispatcher has to know about the #[sv::msg(reply)]
fn on_instantiated(...) {}
#[sv::msg(reply)]
fn on_exec_failed(...) {}
pub mod sv {
pub const ON_INSTANTIATE_REPLY_ID: u64 = 1;
pub const ON_EXEC_FAILED_REPLY_ID: u64 = 2;
} Those ids would have to be used by the contract creator. We could automate that process with some sort of With the generated IDs the dispatcher could look something like this. pub fn dispatch(ctx: ReplyCtx, reply: Reply) -> Result<Response, ContractError> {
let contract = CounterContract::new();
match reply.id {
ON_INSTANTIATE_REPLY_ID => contract.on_instantiated(ctx, reply),
ON_EXEC_FAILED_REPLY_ID => contract.on_exec_failed(ctx, reply),
_ => Err(StdError::generic_err(format!(
"Invalid reply id\n Expected one of:{}, {}",
ON_INSTANTIATE_REPLY_ID, ON_EXEC_FAILED_REPLY_ID,
))),
}
} Marking methods with #[msg(reply)]
fn reply_success(
&self,
ctx: ReplyCtx,
events: Vec<Event>,
data: ExpectedData
) -> Result<Response, ContractError>;
#[msg(reply)]
fn reply_success(
&self,
ctx: ReplyCtx,
error: String,
) -> Result<Response, ContractError>;
#[msg(reply)]
fn reply_foo(
&self,
ctx: ReplyCtx,
reply: Result<(Vec<Event>, ExpectedData), String>,
) -> Result<Response, ContractError>; In case of two attributes we treat it as a success, single String param is an error and otherwise we treat it as an I would very like to hear more about the SubMsg constructionIn the
as those are sent to the external The We can consider providing shortcuts for sending messages like Example usage: let submsg = self.remote // Provides the external contract address
.executor()
.call_me() // Constructs WasmMsg
.reply_foo() // Creates `SubMsgBuilder` with the appropriate REPLY_ID
.build(); |
We talked it through, I will leave some notes about the outcomes. Detecting reply variantRefering to:
This might look like API improvement, but we would then struggle with all the edge cases like using type aliases, or some additional variants in the future, this would be not flexible enough. By default the reply handler would be assumed to be the "reply_always" wariant. Such reply handler should have the signature as follows: #[msg(reply)]
fn reply_foo(
&self,
ctx: ReplyCtx,
data: Result<DataT, String>,
arg1: String,
arg2: u64,
) -> Result<Response, ContractError>;
It would be possible to create handler that only handles the success replies: #[msg(reply, reply_on=success)]
fn reply_foo(
&self,
ctx: ReplyCtx,
data: DataT,
arg1: String,
arg2: u64,
) -> Result<Response, ContractError>; Arguments are similar, we expect #[msg(reply, reply_on=failure)]
fn reply_foo(
&self,
ctx: ReplyCtx,
error: String,
arg1: String,
arg2: u64,
) -> Result<Response, ContractError>; Note, that the |
|
Handlers renamingWe want to introduce handlers renaming in the replies. The idea is syntax as follows:
That should generate utility functions in a way, like the function is named
This is supposed to generate two handlers: #[msg(reply=reply_foo, reply_on=success)]
fn reply_foo_success(
&self,
ctx: ReplyCtx,
data: DataT,
arg1: String,
arg2: u64,
) -> Result<Response, ContractError>;
#[msg(reply=reply_foo, reply_on=failure)]
fn reply_foo_failure(
&self,
ctx: ReplyCtx,
err: String
arg1: String,
arg2: u64,
) -> Result<Response, ContractError>; In this situation the This also would allow more use-cases, one of them would be sharing one part of a handler, for example: #[msg(reply, reply_on=success)]
fn reply_foo(
&self,
ctx: ReplyCtx,
data: DataT,
arg1: String,
arg2: u64,
) -> Result<Response, ContractError>;
#[msg(reply, reply_on=success)]
fn reply_bar(
&self,
ctx: ReplyCtx,
data: DataT,
arg1: String,
arg2: u64,
) -> Result<Response, ContractError>;
#[msg(reply=reply_foo|reply_bar, reply_on=failure)]
fn reply_failure(
&self,
ctx: ReplyCtx,
err: String
arg1: String,
arg2: u64,
) -> Result<Response, ContractError>; Here two handlers are generated: |
closed with #418 |
In the vast majority of cases, the reply is handled by assigning the reply id to a specific handling path and matching that in a top-level reply. We can make it easier by incorporating this into Sylvia, leaving a space to pass some custom data with the
id
- just reducing it to 32bits instead of 64.Idea is to treat the lower 32 bits of reply id as some data to pass, and the higher 32 bits as reply handler id. We could then generate a different handler id for all reply functions in Sylvia, and then access them in implementation. Additionally, we can try to improve the arguments there. Here is an example:
To achieve this, we can take advantage of the fact, that we can actually modify the trait attributed with
#[contract]
so we can add an additional functionality. To pass some additional data, it takes u32 argument and ors it with the code id.Then we can go even better - it is an obvious move to just
into_result
the underlying reply structure. But we can also automatically parse the underlyingdata
- I would introduceFromBinary
trait in sylvia, defined as follows:Binary
Deserialize
types forwarding tofrom_binary
This way it would be way more natural to work with data (still being able to use raw
Binary
type here).The last thing is the
on_success
thin on msg - it could be alsoon_failure
. It suggests sylvia that this handler should forward the failure/success implementation to default. Basically,on_success
replies would forward errors if there is any direction, andon_failure
would do nothing on success. Obviously,on_failure
will get just an error string instead ofevents
anddata
.The text was updated successfully, but these errors were encountered: