use super::*;
impl ExtManager {
pub(crate) fn wait_dispatch_impl(
&mut self,
dispatch: StoredDispatch,
duration: Option<BlockNumber>,
reason: MessageWaitedReason,
) {
use MessageWaitedRuntimeReason::*;
let hold_builder = HoldBoundBuilder::new(StorageType::Waitlist);
let maximal_hold = hold_builder.maximum_for_message(self, dispatch.id());
let hold = if let Some(duration) = duration {
hold_builder.duration(self, duration).min(maximal_hold)
} else {
maximal_hold
};
let message_id = dispatch.id();
let destination = dispatch.destination();
if hold.expected_duration(self).is_zero() {
let gas_limit = self.gas_tree.get_limit(dispatch.id()).unwrap_or_else(|e| {
let err_msg = format!(
"wait_dispatch: failed getting message gas limit. Message id - {message_id}. \
Got error - {e:?}",
message_id = dispatch.id()
);
unreachable!("{err_msg}");
});
let err_msg = format!(
"wait_dispatch: message got zero duration hold bound for waitlist. \
Requested duration - {duration:?}, gas limit - {gas_limit}, \
wait reason - {reason:?}, message id - {}.",
dispatch.id(),
);
unreachable!("{err_msg}");
}
let lock_id = hold.lock_id().unwrap_or_else(|| {
let err_msg = "wait_dispatch: No associated lock id for the waitlist storage";
unreachable!("{err_msg}");
});
self.gas_tree
.lock(message_id, lock_id, hold.lock_amount(self))
.unwrap_or_else(|e| {
let err_msg = format!(
"wait_dispatch: failed locking gas for the waitlist hold. \
Message id - {message_id}, lock amount - {lock}. Got error - {e:?}",
lock = hold.lock_amount(self)
);
unreachable!("{err_msg}");
});
match reason {
MessageWaitedReason::Runtime(WaitForCalled | WaitUpToCalledFull) => {
let expected = hold.expected();
let task = ScheduledTask::WakeMessage(destination, message_id);
if !self.task_pool.contains(&expected, &task) {
self.task_pool.add(expected, task).unwrap_or_else(|e| {
let err_msg = format!(
"wait_dispatch: failed adding task for waking message. \
Expected bn - {expected:?}, program id - {destination}, message id - {message_id}. Got error - {e:?}",
);
unreachable!("{err_msg}");
});
self.on_task_pool_change();
}
}
MessageWaitedReason::Runtime(WaitCalled | WaitUpToCalled) => {
self.task_pool.add(
hold.expected(),
ScheduledTask::RemoveFromWaitlist(dispatch.destination(), dispatch.id()),
)
.unwrap_or_else(|e| {
let err_msg = format!(
"wait_dispatch: failed adding task for removing message from waitlist. \
Expected bn - {bn:?}, program id - {destination}, message id - {message_id}. Got error - {e:?}",
bn = hold.expected(),
);
unreachable!("{err_msg}");
});
self.on_task_pool_change();
}
MessageWaitedReason::System(reason) => match reason {},
}
self.waitlist.insert(dispatch, hold.expected())
.unwrap_or_else(|e| {
let err_msg = format!(
"wait_dispatch: failed inserting message to the wailist. \
Expected bn - {bn:?}, program id - {destination}, message id - {message_id}. Got error - {e:?}",
bn = hold.expected(),
);
unreachable!("{err_msg}");
});
}
pub(crate) fn wake_dispatch_impl(
&mut self,
program_id: ProgramId,
message_id: MessageId,
) -> Result<StoredDispatch, WaitlistErrorImpl> {
self.waitlist
.remove(program_id, message_id)
.map(|waitlisted_message| self.wake_dispatch_requirements(waitlisted_message))
}
pub(crate) fn wake_dispatch_requirements(
&mut self,
(waitlisted, hold_interval): (StoredDispatch, Interval<BlockNumber>),
) -> StoredDispatch {
let expected = hold_interval.finish;
self.charge_for_hold(waitlisted.id(), hold_interval, StorageType::Waitlist);
let _ = self
.task_pool
.delete(
expected,
ScheduledTask::RemoveFromWaitlist(waitlisted.destination(), waitlisted.id()),
)
.map(|_| {
self.on_task_pool_change();
});
waitlisted
}
}