casper-execution-engine 0.1.0

CasperLabs execution engine crates.
Documentation
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 {
                // Note: each "page" is 64 KiB
                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(),
            ))
        }
    }
}