use crate::{
fs, Arg, AudioMode, InputChunk, InputStreams, OutputStream, PageNum, RangeSet, ServiceMessage,
VideoMode,
};
use alloc::{collections::VecDeque, vec::Vec};
use bytes::Bytes;
use codec::{ConstEncodedLen, Decode, Encode, MaxEncodedLen};
use corevm_types::GuestId;
use jam_types::{
Hash, SegmentBytes, SegmentTreeRoot, ServiceId, SignedGas, VecMap, MEMO_LEN, SEGMENT_LEN,
};
#[derive(Encode, Decode, Debug, Clone)]
pub struct CoreVmPayload {
pub gas: SignedGas,
pub vm_state: VmState,
pub exec_ref: fs::BlockRef,
}
#[derive(Debug, Default, Clone)]
pub struct CoreVmExtrinsics {
pub imported_memory_pages: Vec<SegmentBytes>,
pub incoming_service_messages: VecDeque<(ServiceMessage, Bytes)>,
pub input_chunks: Vec<InputChunk>,
}
impl CoreVmExtrinsics {
#[doc(hidden)]
pub const MAX_COUNT: usize = 3;
}
#[derive(Encode, Decode, Debug)]
pub struct CoreVmOutput {
pub vm_output: VmOutput,
pub vm_state: VmState,
pub old_hash: Hash,
pub new_hash: Hash,
pub touched_imported_pages: VecMap<PageNum, Hash>,
pub updated_pages: VecMap<PageNum, Hash>,
pub exec_ref: fs::BlockRef,
pub processed_service_messages: Vec<ServiceMessage>,
pub outgoing_messages: Vec<(GuestId, Vec<u8>)>,
}
#[derive(Encode, Decode, MaxEncodedLen, Debug)]
pub struct VmOutput {
pub remaining_gas: SignedGas,
pub outcome: Outcome,
pub num_memory_pages: u32,
pub stream_len: [u32; OutputStream::COUNT],
}
impl VmOutput {
pub fn stream_len(&self, i: OutputStream) -> u32 {
self.stream_len[i as usize - 1]
}
pub fn all_streams_len(&self) -> u32 {
self.stream_len.iter().sum()
}
pub fn is_empty(&self) -> bool {
self.stream_len.iter().all(|len| *len == 0)
}
pub fn num_output_segments(&self) -> u32 {
self.stream_len.iter().sum::<u32>().div_ceil(SEGMENT_LEN as u32)
}
pub fn get_stream_range(&self, stream: OutputStream) -> (u32, u32) {
let mut start = 0;
let mut end = 0;
for i in OutputStream::ALL {
let len = self.stream_len[i as usize - 1];
if i == stream {
end = start + len;
break;
}
start += len;
}
let offset = self.num_memory_pages * SEGMENT_LEN as u32;
(offset + start, offset + end)
}
}
#[derive(Encode, Decode, MaxEncodedLen, Debug, PartialEq, Eq, Clone, Copy)]
pub enum Outcome {
Halt,
Panic,
PageFault { page: PageNum, num_pages: u32 },
OutOfGas,
OutputLimitReached,
TimeLimitReached,
WaitingForInput(InputStreams),
InputLimitReached,
}
#[derive(Encode, Decode, Debug, Clone)]
pub struct VmState {
pub regs: [u64; 13],
pub program_counter: u64,
pub step: u32,
pub mapped_heap_pages: RangeSet,
pub resident_pages: RangeSet,
pub kernel: KernelState,
#[doc(hidden)]
pub restart_host_call: Option<u64>,
pub video: Option<VideoMode>,
pub audio: Option<AudioMode>,
}
impl VmState {
pub const fn initial() -> Self {
Self {
regs: [0; 13],
program_counter: 0,
mapped_heap_pages: RangeSet::new(),
resident_pages: RangeSet::new(),
kernel: KernelState { fds: VecMap::new() },
restart_host_call: None,
video: None,
audio: None,
step: 0,
}
}
}
macro_rules! enum_with_count {
(
$(#[$($attr:tt)*])*
pub enum $enum:ident {
$(
$(#[$($variant_attr:tt)*])*
$variant:ident$(($($field:ident),+))?,
)*
}
) => {
$(#[$($attr)*])*
pub enum $enum {
$(
$(#[$($variant_attr)*])*
$variant$(($($field),+))?,
)*
}
impl $enum {
#[doc(hidden)]
pub const COUNT_WITHOUT_PARAMS: usize = {
const fn one(_: &'static str) -> usize { 1 }
const fn one_if_has_params(_: &'static str, num_params: usize) -> usize {
if num_params == 0 { 1 } else { 0 }
}
0
$(
+ one_if_has_params(
stringify!($variant),
0 $(+ one(concat!($(stringify!($field),)+)))?
)
)*
};
}
};
}
enum_with_count! {
#[derive(Encode, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum StorageKey {
Gas,
StateHash,
PageInfo(PageNum),
VmSpec,
VideoMode,
AudioMode,
ExecEnvRef,
Owner,
#[doc(hidden)]
StoredPages,
IncomingServiceMessages,
OutgoingServiceMessages,
OutgoingMessage(u64),
IncomingMessage(ServiceMessage),
}
}
#[derive(Encode, Decode, Debug)]
pub struct PageInfo {
pub hash: Hash,
pub exports_root: SegmentTreeRoot,
pub export_index: u16,
}
#[derive(Encode, Decode, Debug)]
pub struct VmSpec {
pub exports_root: SegmentTreeRoot,
pub output: VmOutput,
pub state: VmState,
}
#[derive(Encode, Decode, Clone, Debug)]
pub struct ExecEnv {
pub program: fs::BlockRef,
pub root_dir: fs::BlockRef,
pub args: Vec<Arg>,
pub env: Vec<Arg>,
pub video_input: Option<VideoMode>,
pub audio_input: Option<AudioMode>,
pub input_key: Option<[u8; 32]>,
}
#[derive(Encode, Decode, Debug)]
pub enum CoreVmInstruction {
Reset {
gas: SignedGas,
exec_ref: fs::BlockRef,
},
SetOwner(ServiceId),
PushServiceMessage(ServiceMessage),
Destroy {
ejector: ServiceId,
},
}
impl MaxEncodedLen for CoreVmInstruction {
fn max_encoded_len() -> usize {
MEMO_LEN
}
}
#[derive(Encode, Decode, Clone, Debug, Default)]
pub struct KernelState {
pub fds: VecMap<u32, KernelFd>,
}
#[derive(Encode, Decode, MaxEncodedLen, Clone, Debug)]
pub struct KernelFd {
pub block_ref: fs::BlockRef,
pub position: u64,
}
impl ConstEncodedLen for KernelFd {}