use crate::{DestroyError, ExecError, Memory, MemoryError, MemoryT, Virt, VirtT};
use sp_wasm_interface::{ExecAction, ExecOutcome, InstanceId, Virtualization};
use std::collections::HashMap;
struct VirtInstance {
virt: Virt,
memory: Memory,
}
pub struct VirtManager {
instances: HashMap<InstanceId, VirtInstance>,
counter: u32,
}
impl Default for VirtManager {
fn default() -> Self {
Self { instances: HashMap::new(), counter: 0 }
}
}
impl Virtualization for VirtManager {
fn instantiate(&mut self, program: &[u8]) -> sp_wasm_interface::Result<Result<InstanceId, u8>> {
let virt = match Virt::instantiate(program) {
Ok(virt) => virt,
Err(err) => return Ok(Err(err.into())),
};
let instance_id = InstanceId({
let old = self.counter;
self.counter = old + 1;
old
});
self.instances.insert(instance_id, VirtInstance { memory: virt.memory(), virt });
Ok(Ok(instance_id))
}
fn run(
&mut self,
instance_id: InstanceId,
gas_left: i64,
action: ExecAction<'_>,
) -> sp_wasm_interface::Result<Result<ExecOutcome, u8>> {
let instance = match self.instances.get_mut(&instance_id) {
Some(instance) => instance,
None => return Ok(Err(ExecError::InvalidInstance.into())),
};
let result = instance.virt.run(gas_left, action);
Ok(result.map_err(|err| err.into()))
}
fn destroy(&mut self, instance_id: InstanceId) -> sp_wasm_interface::Result<Result<(), u8>> {
if self.instances.remove(&instance_id).is_some() {
Ok(Ok(()))
} else {
Ok(Err(DestroyError::InvalidInstance.into()))
}
}
fn read_memory(
&mut self,
instance_id: InstanceId,
offset: u32,
dest: &mut [u8],
) -> sp_wasm_interface::Result<Result<(), u8>> {
let Some(instance) = self.instances.get_mut(&instance_id) else {
return Ok(Err(MemoryError::InvalidInstance.into()));
};
if let Err(err) = instance.memory.read(offset, dest) {
return Ok(Err(err.into()));
}
Ok(Ok(()))
}
fn write_memory(
&mut self,
instance_id: InstanceId,
offset: u32,
src: &[u8],
) -> sp_wasm_interface::Result<Result<(), u8>> {
let Some(instance) = self.instances.get_mut(&instance_id) else {
return Ok(Err(MemoryError::InvalidInstance.into()));
};
if let Err(err) = instance.memory.write(offset, src) {
return Ok(Err(err.into()));
}
Ok(Ok(()))
}
}