#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
#[cfg(not(feature = "std"))]
mod forwarder;
#[cfg(not(feature = "std"))]
pub use forwarder::Virt;
#[cfg(feature = "std")]
mod manager;
#[cfg(feature = "std")]
mod native;
#[cfg(feature = "std")]
pub use manager::VirtManager;
#[cfg(feature = "std")]
pub use native::Virt;
mod host_functions;
mod tests;
pub use crate::tests::run as run_tests;
pub use crate::host_functions::virtualization as host_fn;
use codec::{Decode, Encode};
use core::mem;
use num_enum::{IntoPrimitive, TryFromPrimitive};
pub type Memory = <Virt as VirtT>::Memory;
pub const LOG_TARGET: &str = "virtualization";
pub use sp_wasm_interface::{ExecAction, ExecOutcome};
#[derive(Debug, Default)]
#[repr(C)]
pub struct ExecBuffer {
pub gas_left: i64,
pub syscall_no: u32,
pub _pad: u32,
pub a0: u64,
pub a1: u64,
pub a2: u64,
pub a3: u64,
pub a4: u64,
pub a5: u64,
}
pub const EXEC_BUFFER_SIZE: usize = mem::size_of::<ExecBuffer>();
impl AsRef<[u8]> for ExecBuffer {
fn as_ref(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, EXEC_BUFFER_SIZE) }
}
}
impl AsMut<[u8]> for ExecBuffer {
fn as_mut(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self as *mut Self as *mut u8, EXEC_BUFFER_SIZE) }
}
}
impl ExecBuffer {
pub fn from_outcome(outcome: &ExecOutcome) -> Self {
match *outcome {
ExecOutcome::Finished { gas_left } => Self { gas_left, ..Default::default() },
ExecOutcome::Syscall { gas_left, syscall_no, a0, a1, a2, a3, a4, a5 } => {
Self { gas_left, syscall_no, _pad: 0, a0, a1, a2, a3, a4, a5 }
},
}
}
pub fn into_outcome(self, status: ExecStatus) -> ExecOutcome {
match status {
ExecStatus::Finished => ExecOutcome::Finished { gas_left: self.gas_left },
ExecStatus::Syscall => ExecOutcome::Syscall {
gas_left: self.gas_left,
syscall_no: self.syscall_no,
a0: self.a0,
a1: self.a1,
a2: self.a2,
a3: self.a3,
a4: self.a4,
a5: self.a5,
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum ExecStatus {
Finished = 0,
Syscall = 1,
}
impl ExecStatus {
pub fn from_outcome(outcome: &ExecOutcome) -> Self {
match outcome {
ExecOutcome::Finished { .. } => Self::Finished,
ExecOutcome::Syscall { .. } => Self::Syscall,
}
}
}
pub trait VirtT: Sized {
type Memory: MemoryT;
fn instantiate(program: &[u8]) -> Result<Self, InstantiateError>;
fn run(&mut self, gas_left: i64, action: ExecAction<'_>) -> Result<ExecOutcome, ExecError>;
fn memory(&self) -> Self::Memory;
}
pub trait MemoryT {
fn read(&mut self, offset: u32, dest: &mut [u8]) -> Result<(), MemoryError>;
fn write(&mut self, offset: u32, src: &[u8]) -> Result<(), MemoryError>;
}
#[derive(Encode, Decode, TryFromPrimitive, IntoPrimitive, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum InstantiateError {
InvalidImage = 1,
}
#[derive(Encode, Decode, TryFromPrimitive, IntoPrimitive, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum ExecError {
InvalidInstance = 1,
InvalidImage = 2,
OutOfGas = 3,
Trap = 4,
}
#[derive(Encode, Decode, TryFromPrimitive, IntoPrimitive, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum MemoryError {
InvalidInstance = 1,
OutOfBounds = 2,
}
#[derive(Encode, Decode, TryFromPrimitive, IntoPrimitive, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum DestroyError {
InvalidInstance = 1,
}