use crate::RuntimeInterface;
use alloc::collections::btree_set::BTreeSet;
use gear_core::{
buffer::PayloadSlice,
costs::{CostToken, LazyPagesCosts},
env::Externalities,
env_vars::EnvVars,
gas::{ChargeError, CounterType, CountersOwner, GasAmount, GasLeft},
memory::{Memory, MemoryError, MemoryInterval},
message::{HandlePacket, InitPacket, MessageContext, ReplyPacket},
pages::WasmPage,
program::MemoryInfix,
};
use gear_core_backend::BackendExternalities;
use gear_core_errors::{ExtError, ReplyCode};
use gear_core_processor::{
Ext as CoreExt, ExtInfo, FallibleExtError, ProcessorContext, ProcessorExternalities,
configs::SyscallName,
};
use gear_lazy_pages_common::{GlobalsAccessConfig, ProcessAccessError};
use gprimitives::{ActorId, MessageId, ReservationId};
pub struct Ext<RI: RuntimeInterface> {
core: CoreExt<RI::LazyPages>,
}
impl<RI: RuntimeInterface> ProcessorExternalities for Ext<RI> {
fn new(context: ProcessorContext) -> Self {
Self {
core: CoreExt::<RI::LazyPages>::new(context),
}
}
fn lazy_pages_init_for_program<Context>(
ctx: &mut Context,
mem: &mut impl Memory<Context>,
prog_id: ActorId,
memory_infix: MemoryInfix,
stack_end: Option<WasmPage>,
globals_config: GlobalsAccessConfig,
lazy_pages_costs: LazyPagesCosts,
) {
CoreExt::<RI::LazyPages>::lazy_pages_init_for_program(
ctx,
mem,
prog_id,
memory_infix,
stack_end,
globals_config,
lazy_pages_costs,
)
}
fn lazy_pages_post_execution_actions<Context>(
ctx: &mut Context,
mem: &mut impl Memory<Context>,
) {
CoreExt::<RI::LazyPages>::lazy_pages_post_execution_actions(ctx, mem)
}
fn lazy_pages_status() -> gear_lazy_pages_common::Status {
CoreExt::<RI::LazyPages>::lazy_pages_status()
}
delegate::delegate! {
to self.core {
fn into_ext_info<Context>(
self,
ctx: &mut Context,
memory: &impl Memory<Context>,
) -> Result<ExtInfo, MemoryError>;
}
}
}
impl<RI: RuntimeInterface> Externalities for Ext<RI> {
type UnrecoverableError = <CoreExt<RI::LazyPages> as Externalities>::UnrecoverableError;
type FallibleError = <CoreExt<RI::LazyPages> as Externalities>::FallibleError;
type AllocError = <CoreExt<RI::LazyPages> as Externalities>::AllocError;
delegate::delegate! {
to self.core {
fn alloc<Context>(&mut self, ctx: &mut Context, mem: &mut impl Memory<Context>, pages_num: u32) -> Result<WasmPage, Self::AllocError>;
fn free(&mut self, page: WasmPage) -> Result<(), Self::AllocError>;
fn free_range(&mut self, start: WasmPage, end: WasmPage) -> Result<(), Self::AllocError>;
fn env_vars(&self, version: u32) -> Result<EnvVars, Self::UnrecoverableError>;
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_push_input(&mut self, handle: u32, offset: u32, len: u32) -> Result<(), Self::FallibleError>;
fn reply_push(&mut self, buffer: &[u8]) -> Result<(), Self::FallibleError>;
fn reply_commit(&mut self, msg: ReplyPacket) -> Result<MessageId, Self::FallibleError>;
fn reply_to(&self) -> Result<MessageId, Self::FallibleError>;
fn reply_push_input(&mut self, offset: u32, len: u32) -> Result<(), Self::FallibleError>;
fn source(&self) -> Result<ActorId, Self::UnrecoverableError>;
fn reply_code(&self) -> Result<ReplyCode, Self::FallibleError>;
fn message_id(&self) -> Result<MessageId, Self::UnrecoverableError>;
fn program_id(&self) -> Result<ActorId, Self::UnrecoverableError>;
fn debug(&self, data: &str) -> Result<(), Self::UnrecoverableError>;
fn payload_slice(&mut self, at: u32, len: u32) -> Result<PayloadSlice, Self::FallibleError>;
fn size(&self) -> Result<usize, Self::UnrecoverableError>;
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_for(&mut self, duration: u32) -> Result<(), Self::UnrecoverableError>;
fn wait_up_to(&mut self, duration: u32) -> Result<bool, Self::UnrecoverableError>;
fn forbidden_funcs(&self) -> &BTreeSet<SyscallName>;
fn msg_ctx(&self) -> &MessageContext;
}
}
fn wake(&mut self, waker_id: MessageId, delay: u32) -> Result<(), Self::FallibleError> {
if delay != 0 {
Err(FallibleExtError::Core(ExtError::Unsupported))
} else {
self.core.wake(waker_id, delay)
}
}
fn reservation_send_commit(
&mut self,
_: ReservationId,
_: u32,
_: HandlePacket,
_: u32,
) -> Result<MessageId, Self::FallibleError> {
unreachable!("reservation_send_commit syscall is forbidden in ethexe runtime")
}
fn reservation_reply_commit(
&mut self,
_: ReservationId,
_: ReplyPacket,
) -> Result<MessageId, Self::FallibleError> {
unreachable!("reservation_reply_commit syscall is forbidden in ethexe runtime")
}
fn signal_from(&self) -> Result<MessageId, Self::FallibleError> {
unreachable!("signal_from syscall is forbidden in ethexe runtime")
}
fn signal_code(&self) -> Result<gear_core_errors::SignalCode, Self::FallibleError> {
unreachable!("signal_code syscall is forbidden in ethexe runtime")
}
fn wait(&mut self) -> Result<(), Self::UnrecoverableError> {
unreachable!("wait syscall is forbidden in ethexe runtime")
}
fn random(&self) -> Result<(&[u8], u32), Self::UnrecoverableError> {
unreachable!("random syscall is forbidden in ethexe runtime")
}
fn create_program(
&mut self,
_: InitPacket,
_: u32,
) -> Result<(MessageId, ActorId), Self::FallibleError> {
unreachable!("create_program syscall is forbidden in ethexe runtime")
}
fn reply_deposit(&mut self, _: MessageId, _: u64) -> Result<(), Self::FallibleError> {
unreachable!("reply_deposit syscall is forbidden in ethexe runtime")
}
fn reserve_gas(&mut self, _: u64, _: u32) -> Result<ReservationId, Self::FallibleError> {
unreachable!("reserve_gas syscall is forbidden in ethexe runtime")
}
fn unreserve_gas(&mut self, _: ReservationId) -> Result<u64, Self::FallibleError> {
unreachable!("unreserve_gas syscall is forbidden in ethexe runtime")
}
fn system_reserve_gas(&mut self, _: u64) -> Result<(), Self::FallibleError> {
unreachable!("system_reserve_gas syscall is forbidden in ethexe runtime")
}
}
impl<RI: RuntimeInterface> CountersOwner for Ext<RI> {
delegate::delegate! {
to self.core {
fn charge_gas_for_token(&mut self, token: CostToken) -> Result<(), ChargeError>;
fn charge_gas_if_enough(&mut self, amount: u64) -> Result<(), ChargeError>;
fn gas_left(&self) -> GasLeft;
fn current_counter_type(&self) -> CounterType;
fn decrease_current_counter_to(&mut self, amount: u64);
fn define_current_counter(&mut self) -> u64;
}
}
}
impl<RI: RuntimeInterface> BackendExternalities for Ext<RI> {
delegate::delegate! {
to self.core {
fn gas_amount(&self) -> GasAmount;
fn pre_process_memory_accesses(&mut self, reads: &[MemoryInterval], writes: &[MemoryInterval], gas_counter: &mut u64) -> Result<(), ProcessAccessError>;
}
}
}