use crate::{
ids::{MessageId, ProgramId, ReservationId},
memory::Memory,
message::{HandlePacket, InitPacket, MessageContext, Payload, ReplyPacket},
pages::WasmPage,
};
use alloc::collections::BTreeSet;
use core::{fmt::Display, mem};
use gear_core_errors::{ReplyCode, SignalCode};
use gear_wasm_instrument::syscalls::SysCallName;
pub struct PayloadSliceLock {
payload: Payload,
range: (usize, usize),
}
impl PayloadSliceLock {
pub fn try_new((start, end): (u32, u32), msg_ctx: &mut MessageContext) -> Option<Self> {
let payload_len = msg_ctx.payload_mut().inner().len();
if end as usize > payload_len {
return None;
}
Some(Self {
payload: mem::take(msg_ctx.payload_mut()),
range: (start as usize, end as usize),
})
}
fn release(&mut self, msg_ctx: &mut MessageContext) {
mem::swap(msg_ctx.payload_mut(), &mut self.payload);
}
pub fn drop_with<JobErr, Job>(mut self, mut job: Job) -> DropPayloadLockBound<JobErr>
where
Job: FnMut(PayloadSliceAccess<'_>) -> DropPayloadLockBound<JobErr>,
{
let held_range = PayloadSliceAccess(&mut self);
job(held_range)
}
fn in_range(&self) -> &[u8] {
let (start, end) = self.range;
&self.payload.inner()[start..end]
}
}
pub struct PayloadSliceAccess<'a>(&'a mut PayloadSliceLock);
impl<'a> PayloadSliceAccess<'a> {
pub fn as_slice(&self) -> &[u8] {
self.0.in_range()
}
pub fn into_lock(self) -> &'a mut PayloadSliceLock {
self.0
}
}
pub struct DropPayloadLockBound<JobError> {
job_result: Result<(), JobError>,
}
impl<JobErr> DropPayloadLockBound<JobErr> {
pub fn into_inner(self) -> Result<(), JobErr> {
self.job_result
}
}
impl<JobErr> From<(UnlockPayloadBound, Result<(), JobErr>)> for DropPayloadLockBound<JobErr> {
fn from((_token, job_result): (UnlockPayloadBound, Result<(), JobErr>)) -> Self {
DropPayloadLockBound { job_result }
}
}
pub struct UnlockPayloadBound(());
impl From<(&mut MessageContext, &mut PayloadSliceLock)> for UnlockPayloadBound {
fn from((msg_ctx, payload_holder): (&mut MessageContext, &mut PayloadSliceLock)) -> Self {
payload_holder.release(msg_ctx);
UnlockPayloadBound(())
}
}
pub trait Externalities {
type UnrecoverableError;
type FallibleError;
type AllocError: Display;
fn alloc(
&mut self,
pages_num: u32,
mem: &mut impl Memory,
) -> Result<WasmPage, Self::AllocError>;
fn free(&mut self, page: WasmPage) -> Result<(), Self::AllocError>;
fn block_height(&self) -> Result<u32, Self::UnrecoverableError>;
fn block_timestamp(&self) -> Result<u64, Self::UnrecoverableError>;
fn send_init(&mut self) -> Result<u32, Self::FallibleError>;
fn send_push(&mut self, handle: u32, buffer: &[u8]) -> Result<(), Self::FallibleError>;
fn send_commit(
&mut self,
handle: u32,
msg: HandlePacket,
delay: u32,
) -> Result<MessageId, Self::FallibleError>;
fn send(&mut self, msg: HandlePacket, delay: u32) -> Result<MessageId, Self::FallibleError> {
let handle = self.send_init()?;
self.send_commit(handle, msg, delay)
}
fn send_push_input(
&mut self,
handle: u32,
offset: u32,
len: u32,
) -> Result<(), Self::FallibleError>;
fn reservation_send_commit(
&mut self,
id: ReservationId,
handle: u32,
msg: HandlePacket,
delay: u32,
) -> Result<MessageId, Self::FallibleError>;
fn reservation_send(
&mut self,
id: ReservationId,
msg: HandlePacket,
delay: u32,
) -> Result<MessageId, Self::FallibleError> {
let handle = self.send_init()?;
self.reservation_send_commit(id, handle, msg, delay)
}
fn reply_push(&mut self, buffer: &[u8]) -> Result<(), Self::FallibleError>;
fn reply_commit(&mut self, msg: ReplyPacket) -> Result<MessageId, Self::FallibleError>;
fn reservation_reply_commit(
&mut self,
id: ReservationId,
msg: ReplyPacket,
) -> Result<MessageId, Self::FallibleError>;
fn reply(&mut self, msg: ReplyPacket) -> Result<MessageId, Self::FallibleError> {
self.reply_commit(msg)
}
fn reservation_reply(
&mut self,
id: ReservationId,
msg: ReplyPacket,
) -> Result<MessageId, Self::FallibleError> {
self.reservation_reply_commit(id, msg)
}
fn reply_to(&self) -> Result<MessageId, Self::FallibleError>;
fn signal_from(&self) -> Result<MessageId, Self::FallibleError>;
fn reply_push_input(&mut self, offset: u32, len: u32) -> Result<(), Self::FallibleError>;
fn source(&self) -> Result<ProgramId, Self::UnrecoverableError>;
fn reply_code(&self) -> Result<ReplyCode, Self::FallibleError>;
fn signal_code(&self) -> Result<SignalCode, Self::FallibleError>;
fn message_id(&self) -> Result<MessageId, Self::UnrecoverableError>;
fn pay_program_rent(
&mut self,
program_id: ProgramId,
rent: u128,
) -> Result<(u128, u32), Self::FallibleError>;
fn program_id(&self) -> Result<ProgramId, Self::UnrecoverableError>;
fn debug(&self, data: &str) -> Result<(), Self::UnrecoverableError>;
fn lock_payload(&mut self, at: u32, len: u32) -> Result<PayloadSliceLock, Self::FallibleError>;
fn unlock_payload(&mut self, payload_holder: &mut PayloadSliceLock) -> UnlockPayloadBound;
fn size(&self) -> Result<usize, Self::UnrecoverableError>;
fn random(&self) -> Result<(&[u8], u32), Self::UnrecoverableError>;
fn reserve_gas(
&mut self,
amount: u64,
duration: u32,
) -> Result<ReservationId, Self::FallibleError>;
fn unreserve_gas(&mut self, id: ReservationId) -> Result<u64, Self::FallibleError>;
fn system_reserve_gas(&mut self, amount: u64) -> Result<(), Self::FallibleError>;
fn gas_available(&self) -> Result<u64, Self::UnrecoverableError>;
fn value(&self) -> Result<u128, Self::UnrecoverableError>;
fn value_available(&self) -> Result<u128, Self::UnrecoverableError>;
fn wait(&mut self) -> Result<(), Self::UnrecoverableError>;
fn wait_for(&mut self, duration: u32) -> Result<(), Self::UnrecoverableError>;
fn wait_up_to(&mut self, duration: u32) -> Result<bool, Self::UnrecoverableError>;
fn wake(&mut self, waker_id: MessageId, delay: u32) -> Result<(), Self::FallibleError>;
fn create_program(
&mut self,
packet: InitPacket,
delay: u32,
) -> Result<(MessageId, ProgramId), Self::FallibleError>;
fn reply_deposit(
&mut self,
message_id: MessageId,
amount: u64,
) -> Result<(), Self::FallibleError>;
fn forbidden_funcs(&self) -> &BTreeSet<SysCallName>;
}