gear icon indicating copy to clipboard operation
gear copied to clipboard

Add ability to send scheduled messages

Open shamilsan opened this issue 2 years ago • 7 comments

Problem to Solve

Sometimes we need to send the message after some delay instead of doing it immediately. It might be useful for time scheduled routines, e.g. in DAO, auctions, lotteries.

Possible Solution

Introduce new functions in gstd::msg (all names, parameters, and return types are to be discussed!):

/// `msg` module

/// Add deferred message to the shedule.
fn defer(dest, payload, delay, value) -> Result<MessageId, ...>;
// fn defer_with_gas(...)
// async fn defer_for_reply(...)

/// Allow early sending.
fn allow_shoving(msg_id) -> bool;

/// Cancel sending deferred message.
fn cancel_deferred(msg_id) -> Result<(), ...>;

/// Send deferred message immediately.
fn shove(msg_id) -> Result<(), ...>;
// fn shove_for_reply(...)

Also need to add correspondent functionality to Gear core.

Notes

Using example (DAO):

let msg_id = msg::defer(
    exec::program_id(),
    DaoAction::ProcessProposal(self.proposal_id)),
    exec::blick_timestamp() + self.voting_period,
    0,
)
.expect("Error while deferring message");
msg::allow_shoving(msg_id);

let reply: DaoEvent = 
    exec::shove_as(msg_id).expect("Error while shoving deferred message");

exec::cancel_deferred(msg_id).expect("Error while cancelling deferred message");

let reply: DaoEvent = msg::defer_for_reply_as(
    exec::program_id(),
    DaoAction::ProcessProposal(self.proposal_id),
    exec::block_timestamp() + self.voting_period,
    0,
)
.expect("Error while deferring message")
.await
.expect("Error while processing result");

shamilsan avatar Aug 08 '22 12:08 shamilsan

Defer is an ambiguous name because it is used in several programming languages with a different purpose https://www.educative.io/answers/what-is-the-defer-keyword-in-golang, https://www.hackingwithswift.com/new-syntax-swift-2-defer maybe we can use the word schedule.

puzzle-rusher avatar Aug 08 '22 12:08 puzzle-rusher

allow_shoving can be replaced with allow_forced_execution or allow_forced_firing. Or early execution or something like this. We need to think about the advisability of this method, because it is far from being everywhere at all. We can just execute something and cancel job by messageId

puzzle-rusher avatar Aug 08 '22 12:08 puzzle-rusher

Maybe we should consider argument like is_repeating_task: bool or separate function with the same purpose.

puzzle-rusher avatar Aug 08 '22 13:08 puzzle-rusher

I agree with @puzzle-rusher, schedule is also more appropriate than defer because defer is something planned for an indefinite time, but schedule is for a specific time. And since there will be certain delay in arguments, schedule is more suitable.

I don't think the allow_shoving function is needed because I don't understand where the limiting of early sending can be useful (the current example doesn't clarify this).

Instead shove, I can suggest trigger as an alternative.

fluiderson avatar Aug 08 '22 19:08 fluiderson

In addition to the above, it seems strange to me that we do not use msg_id in order to get a response to a deferred message. I think there should be a function that accepts msg_id only (like cancel_deferred)

DBarinovv avatar Aug 08 '22 19:08 DBarinovv

I like the idea of schedule and trigger. Edited the original comment.

Not sure about triggering allowance. Changed it to deny_triggering. We can omit it if it is not required at all.

Maybe we should consider argument like is_repeating_task: bool or separate function with the same purpose.

I don't like an idea to have too many parameters. A separate function is better in my opinion.

In addition to the above, it seems strange to me that we do not use msg_id in order to get a response to a deferred message. I think there should be a function that accepts msg_id only (like cancel_deferred)

We have an async function schedule_for_reply for getting reply. The API of scheduled sending is to be similar to msg::send et al.

shamilsan avatar Aug 09 '22 11:08 shamilsan

Defer messages sending is 100% must-have-feature, but I'm not sure that other 3 methods are necessary. It also becomes hard to provide such api for the functions: user space should also say on which BN some message id was expected to send

breathx avatar Aug 18 '22 11:08 breathx

what about just wrapping the whole message:

unsafe {
  gstd::config::EXECUTE_MESSAGE_AT =  Some(exec::block_timestamp() + self.voting_period);
}

let reply: DaoEvent = msg::send_for_reply(
    exec::program_id(),
    DaoAction::ProcessProposal(self.proposal_id)),
    0,
)
.expect("Error while deferring message")
.await
.expect("Error while processing result");

// ...

clearloop avatar Sep 09 '22 09:09 clearloop

what about just wrapping the whole message:

I'm afraid this will yield hidden behavior. It's easy to forget about this setting after using and send a scheduled message instead of the immediate one.

shamilsan avatar Sep 09 '22 10:09 shamilsan