use std::cell::RefCell;
use wasmi::{
memory_units::Pages, Error as InterpreterError, FuncInstance, FuncRef, MemoryDescriptor,
MemoryInstance, MemoryRef, ModuleImportResolver, Signature, ValueType,
};
use super::{
error::ResolverError, memory_resolver::MemoryResolver, v1_function_index::FunctionIndex,
};
pub(crate) struct RuntimeModuleImportResolver {
memory: RefCell<Option<MemoryRef>>,
max_memory: u32,
}
impl Default for RuntimeModuleImportResolver {
fn default() -> Self {
RuntimeModuleImportResolver {
memory: RefCell::new(None),
max_memory: 64,
}
}
}
impl MemoryResolver for RuntimeModuleImportResolver {
fn memory_ref(&self) -> Result<MemoryRef, ResolverError> {
self.memory
.borrow()
.as_ref()
.map(Clone::clone)
.ok_or(ResolverError::NoImportedMemory)
}
}
impl ModuleImportResolver for RuntimeModuleImportResolver {
fn resolve_func(
&self,
field_name: &str,
_signature: &Signature,
) -> Result<FuncRef, InterpreterError> {
let func_ref = match field_name {
"read_value" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], Some(ValueType::I32)),
FunctionIndex::ReadFuncIndex.into(),
),
"read_value_local" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], Some(ValueType::I32)),
FunctionIndex::ReadLocalFuncIndex.into(),
),
"load_named_keys" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], Some(ValueType::I32)),
FunctionIndex::LoadNamedKeysFuncIndex.into(),
),
"write" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], None),
FunctionIndex::WriteFuncIndex.into(),
),
"write_local" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], None),
FunctionIndex::WriteLocalFuncIndex.into(),
),
"add" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], None),
FunctionIndex::AddFuncIndex.into(),
),
"new_uref" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], None),
FunctionIndex::NewFuncIndex.into(),
),
"ret" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], None),
FunctionIndex::RetFuncIndex.into(),
),
"get_key" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 5][..], Some(ValueType::I32)),
FunctionIndex::GetKeyFuncIndex.into(),
),
"has_key" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], Some(ValueType::I32)),
FunctionIndex::HasKeyFuncIndex.into(),
),
"put_key" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], None),
FunctionIndex::PutKeyFuncIndex.into(),
),
"gas" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 1][..], None),
FunctionIndex::GasFuncIndex.into(),
),
"is_valid_uref" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], Some(ValueType::I32)),
FunctionIndex::IsValidURefFnIndex.into(),
),
"revert" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 1][..], None),
FunctionIndex::RevertFuncIndex.into(),
),
"add_associated_key" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], Some(ValueType::I32)),
FunctionIndex::AddAssociatedKeyFuncIndex.into(),
),
"remove_associated_key" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], Some(ValueType::I32)),
FunctionIndex::RemoveAssociatedKeyFuncIndex.into(),
),
"update_associated_key" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], Some(ValueType::I32)),
FunctionIndex::UpdateAssociatedKeyFuncIndex.into(),
),
"set_action_threshold" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], Some(ValueType::I32)),
FunctionIndex::SetActionThresholdFuncIndex.into(),
),
"remove_key" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], None),
FunctionIndex::RemoveKeyFuncIndex.into(),
),
"get_caller" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 1][..], Some(ValueType::I32)),
FunctionIndex::GetCallerIndex.into(),
),
"get_blocktime" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 1][..], None),
FunctionIndex::GetBlocktimeIndex.into(),
),
"create_purse" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], Some(ValueType::I32)),
FunctionIndex::CreatePurseIndex.into(),
),
"transfer_to_account" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], Some(ValueType::I32)),
FunctionIndex::TransferToAccountIndex.into(),
),
"transfer_from_purse_to_account" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 6][..], Some(ValueType::I32)),
FunctionIndex::TransferFromPurseToAccountIndex.into(),
),
"transfer_from_purse_to_purse" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 6][..], Some(ValueType::I32)),
FunctionIndex::TransferFromPurseToPurseIndex.into(),
),
"get_balance" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], Some(ValueType::I32)),
FunctionIndex::GetBalanceIndex.into(),
),
"get_phase" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 1][..], None),
FunctionIndex::GetPhaseIndex.into(),
),
"get_system_contract" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], Some(ValueType::I32)),
FunctionIndex::GetSystemContractIndex.into(),
),
"get_main_purse" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 1][..], None),
FunctionIndex::GetMainPurseIndex.into(),
),
"read_host_buffer" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], Some(ValueType::I32)),
FunctionIndex::ReadHostBufferIndex.into(),
),
"create_contract_package_at_hash" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], None),
FunctionIndex::CreateContractPackageAtHash.into(),
),
"create_contract_user_group" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 8][..], Some(ValueType::I32)),
FunctionIndex::CreateContractUserGroup.into(),
),
"add_contract_version" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 10][..], Some(ValueType::I32)),
FunctionIndex::AddContractVersion.into(),
),
"disable_contract_version" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], Some(ValueType::I32)),
FunctionIndex::DisableContractVersion.into(),
),
"call_contract" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 7][..], Some(ValueType::I32)),
FunctionIndex::CallContractFuncIndex.into(),
),
"call_versioned_contract" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 9][..], Some(ValueType::I32)),
FunctionIndex::CallVersionedContract.into(),
),
"get_named_arg_size" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 3][..], Some(ValueType::I32)),
FunctionIndex::GetRuntimeArgsizeIndex.into(),
),
"get_named_arg" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], Some(ValueType::I32)),
FunctionIndex::GetRuntimeArgIndex.into(),
),
"remove_contract_user_group" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], Some(ValueType::I32)),
FunctionIndex::RemoveContractUserGroupIndex.into(),
),
"provision_contract_user_group_uref" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 5][..], Some(ValueType::I32)),
FunctionIndex::ExtendContractUserGroupURefsIndex.into(),
),
"remove_contract_user_group_urefs" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 6][..], Some(ValueType::I32)),
FunctionIndex::RemoveContractUserGroupURefsIndex.into(),
),
"blake2b" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 4][..], Some(ValueType::I32)),
FunctionIndex::Blake2b.into(),
),
"record_transfer" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 6][..], Some(ValueType::I32)),
FunctionIndex::RecordTransfer.into(),
),
#[cfg(feature = "test-support")]
"print" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], None),
FunctionIndex::PrintIndex.into(),
),
_ => {
return Err(InterpreterError::Function(format!(
"host module doesn't export function with name {}",
field_name
)));
}
};
Ok(func_ref)
}
fn resolve_memory(
&self,
field_name: &str,
descriptor: &MemoryDescriptor,
) -> Result<MemoryRef, InterpreterError> {
if field_name == "memory" {
let effective_max = descriptor.maximum().unwrap_or(self.max_memory + 1);
if descriptor.initial() > self.max_memory || effective_max > self.max_memory {
Err(InterpreterError::Instantiation(
"Module requested too much memory".to_owned(),
))
} else {
let mem = MemoryInstance::alloc(
Pages(descriptor.initial() as usize),
descriptor.maximum().map(|x| Pages(x as usize)),
)?;
*self.memory.borrow_mut() = Some(mem.clone());
Ok(mem)
}
} else {
Err(InterpreterError::Instantiation(
"Memory imported under unknown name".to_owned(),
))
}
}
}