mirror of
https://github.com/fluencelabs/wasm-utils
synced 2025-03-16 03:20:50 +00:00
refactor to native env initial
This commit is contained in:
parent
2f691bb360
commit
b9acb877bc
@ -12,12 +12,12 @@ fn write_u32(dst: &mut [u8], val: u32) {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Allocator(alloc::Error),
|
||||
Allocator(runtime::ErrorAlloc),
|
||||
Interpreter(interpreter::Error),
|
||||
}
|
||||
|
||||
impl From<alloc::Error> for Error {
|
||||
fn from(err: alloc::Error) -> Self {
|
||||
impl From<runtime::ErrorAlloc> for Error {
|
||||
fn from(err: alloc::ErrorAlloc) -> Self {
|
||||
Error::Allocator(err)
|
||||
}
|
||||
}
|
||||
@ -29,22 +29,20 @@ impl From<interpreter::Error> for Error {
|
||||
}
|
||||
|
||||
pub fn init(
|
||||
env: &interpreter::ModuleInstanceInterface,
|
||||
runtime: &runtime::Runtime,
|
||||
memory: &interpreter::Memory,
|
||||
runtime: &mut runtime::Runtime,
|
||||
input: &[u8],
|
||||
) -> Result<WasmMemoryPtr, Error> {
|
||||
let mut input_ptr_slc = [0u8; 4];
|
||||
let mut input_length = [0u8; 4];
|
||||
|
||||
let allocator = runtime.allocator();
|
||||
|
||||
let descriptor_ptr = allocator.alloc(16)?;
|
||||
let descriptor_ptr = runtime.alloc(16)?;
|
||||
|
||||
println!("descriptor_ptr: {}", descriptor_ptr);
|
||||
let memory = env.memory(DEFAULT_MEMORY_INDEX)?;
|
||||
|
||||
if input.len() > 0 {
|
||||
let input_ptr = allocator.alloc(input.len() as u32)?;
|
||||
let input_ptr = runtime.alloc(input.len() as u32)?;
|
||||
write_u32(&mut input_ptr_slc, input_ptr);
|
||||
write_u32(&mut input_length, input.len() as u32);
|
||||
memory.set(input_ptr, input)?;
|
||||
@ -69,14 +67,4 @@ pub fn init(
|
||||
fn read_u32(slc: &[u8]) -> u32 {
|
||||
use std::ops::Shl;
|
||||
(slc[0] as u32) + (slc[1] as u32).shl(8) + (slc[2] as u32).shl(16) + (slc[3] as u32).shl(24)
|
||||
}
|
||||
|
||||
// pub fn retrieve(env:
|
||||
// env: &interpreter::ModuleInstanceInterface,
|
||||
// runtime: &runtime::Runtime,
|
||||
// descriptor_ptr: u32,
|
||||
// result_ptr: u32,
|
||||
// ) -> Result<Vec<u8>, Error> {
|
||||
// let memory = env.memory(DEFAULT_MEMORY_INDEX)?;
|
||||
|
||||
// }
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
use parity_wasm::interpreter::{self, ModuleInstance};
|
||||
use runtime::Runtime;
|
||||
|
||||
pub struct GasCounter {
|
||||
pub runtime: Runtime,
|
||||
}
|
||||
|
||||
impl interpreter::UserFunctionInterface for GasCounter {
|
||||
fn call(&mut self, _module: &ModuleInstance, context: interpreter::CallerContext) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
|
||||
let prev = self.runtime.env().gas_counter.get();
|
||||
let update = context.value_stack.pop_as::<i32>()? as u64;
|
||||
if prev + update > self.runtime.env().gas_limit {
|
||||
// exceeds gas
|
||||
Err(interpreter::Error::Trap(format!("Gas exceeds limits of {}", self.runtime.env().gas_limit)))
|
||||
} else {
|
||||
self.runtime.env().gas_counter.set(prev + update);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
@ -5,88 +5,107 @@ use std::collections::HashMap;
|
||||
use parity_wasm::{interpreter, elements};
|
||||
use {alloc, gas_counter, storage};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RuntimeEnv {
|
||||
pub gas_counter: Cell<u64>,
|
||||
pub gas_limit: u64,
|
||||
pub dynamic_top: Cell<u32>,
|
||||
pub storage: RefCell<HashMap<storage::StorageKey, storage::StorageValue>>,
|
||||
#[derive(Hash, PartialEq, Eq, Debug)]
|
||||
pub struct StorageKey([u8; 32]);
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct StorageValue([u8; 32]);
|
||||
|
||||
pub struct Runtime {
|
||||
gas_counter: u64,
|
||||
gas_limit: u64,
|
||||
dynamic_top: u32,
|
||||
storage: HashMap<storage::StorageKey, storage::StorageValue>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Runtime(Arc<RuntimeEnv>);
|
||||
#[derive(Debug)]
|
||||
struct ErrorAlloc;
|
||||
|
||||
impl Runtime {
|
||||
pub fn with_params(stack_space: u32, gas_limit: u64) -> Runtime {
|
||||
Runtime(Arc::new(RuntimeEnv {
|
||||
gas_counter: Cell::new(0),
|
||||
gas_counter: 0,
|
||||
gas_limit: gas_limit,
|
||||
dynamic_top: Cell::new(stack_space),
|
||||
storage: RefCell::new(HashMap::new()),
|
||||
dynamic_top: stack_space,
|
||||
storage: HashMap::new(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn allocator(&self) -> alloc::Arena {
|
||||
alloc::Arena {
|
||||
runtime: self.clone(),
|
||||
pub fn storage_write(&mut self, memory: Arc<interpreter::Memory>, context: interpreter::CallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||
{
|
||||
let val_ptr = context.value_stack.pop_as::<i32>()?;
|
||||
let key_ptr = context.value_stack.pop_as::<i32>()?;
|
||||
|
||||
let key = StorageKey::from_mem(memory.get(key_ptr as u32, 32)?)
|
||||
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||
let val = StorageValue::from_mem(memory.get(val_ptr as u32, 32)?)
|
||||
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||
|
||||
self.storage.insert(key, val);
|
||||
|
||||
Ok(0.into())
|
||||
}
|
||||
|
||||
pub fn storage_write(&mut self, memory: Arc<interpreter::Memory>, context: interpreter::CallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||
{
|
||||
// arguments passed are in backward order (since it is stack)
|
||||
let val_ptr = context.value_stack.pop_as::<i32>()?;
|
||||
let key_ptr = context.value_stack.pop_as::<i32>()?;
|
||||
|
||||
let key = StorageKey::from_mem(memory.get(key_ptr as u32, 32)?)
|
||||
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||
let empty = StorageValue([0u8; 32]);
|
||||
let storage = self.0.runtime.env().storage.borrow();
|
||||
let val = storage.get(&key).unwrap_or(&empty);
|
||||
|
||||
memory.set(val_ptr as u32, val.as_slice());
|
||||
|
||||
println!("read storage {:?} (evaluated as {:?})", key, val);
|
||||
|
||||
Ok(Some(0.into()))
|
||||
}
|
||||
|
||||
pub fn malloc(&mut self, _memory: Arc<interpreter::Memory>, context: interpreter::CallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||
{
|
||||
let amount = context.value_stack.pop_as::<i32>()? as u32;
|
||||
let previous_top = self.dynamic_top;
|
||||
self.dynamic_top = previous_top + size;
|
||||
Ok(previous_top.into())
|
||||
}
|
||||
|
||||
pub fn alloc(&mut self, amount: u32) -> Result<u32, ErrorAlloc> {
|
||||
let previous_top = self.dynamic_top;
|
||||
self.dynamic_top = previous_top + size;
|
||||
Ok(previous_top.into())
|
||||
}
|
||||
|
||||
fn gas(&mut self, _memory: Arc<interpreter::Memory>, context: interpreter::CallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||
{
|
||||
let prev = self.gas_counter;
|
||||
let update = context.value_stack.pop_as::<i32>()? as u64;
|
||||
if prev + update > self.gas_limit {
|
||||
// exceeds gas
|
||||
Err(interpreter::Error::Trap(format!("Gas exceeds limits of {}", self.runtime.env().gas_limit)))
|
||||
} else {
|
||||
self.gas_counter.set(prev + update);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gas_counter(&self) -> gas_counter::GasCounter {
|
||||
gas_counter::GasCounter {
|
||||
runtime: self.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn storage(&self) -> storage::Storage {
|
||||
storage::Storage::new(self.clone())
|
||||
}
|
||||
|
||||
pub fn env(&self) -> &RuntimeEnv {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user_trap(funcs: &mut interpreter::UserFunctions, func_name: &str) {
|
||||
let func_str = func_name.to_owned();
|
||||
funcs.insert(func_str.clone(),
|
||||
interpreter::UserFunction {
|
||||
params: vec![],
|
||||
result: Some(elements::ValueType::I32),
|
||||
closure: Box::new(UserTrap(func_str)),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
struct UserTrap(String);
|
||||
|
||||
impl interpreter::UserFunctionInterface for UserTrap {
|
||||
fn call(&mut self,
|
||||
_module: &interpreter::ModuleInstance,
|
||||
_context: interpreter::CallerContext
|
||||
) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
|
||||
fn user_trap(&mut self, _memory: Arc<interpreter::Memory>, _context: interpreter::CallerContext)
|
||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||
{
|
||||
Err(interpreter::Error::Trap(self.0.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
struct UserNoop;
|
||||
|
||||
pub fn user_noop(funcs: &mut interpreter::UserFunctions, func_name: &str) {
|
||||
let func_str = func_name.to_owned();
|
||||
funcs.insert(func_str.clone(),
|
||||
interpreter::UserFunction {
|
||||
params: vec![],
|
||||
result: None,
|
||||
closure: Box::new(UserNoop),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
impl interpreter::UserFunctionInterface for UserNoop {
|
||||
fn call(&mut self,
|
||||
_module: &interpreter::ModuleInstance,
|
||||
fn user_noop(&mut self,
|
||||
_memory: Arc<interpreter::Memory>,
|
||||
_context: interpreter::CallerContext
|
||||
) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,118 +0,0 @@
|
||||
use parity_wasm::interpreter::{self, ItemIndex, ModuleInstanceInterface};
|
||||
use std::sync::Arc;
|
||||
|
||||
use DEFAULT_MEMORY_INDEX;
|
||||
use runtime::Runtime;
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Debug)]
|
||||
pub struct StorageKey([u8; 32]);
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct StorageValue([u8; 32]);
|
||||
|
||||
impl StorageKey {
|
||||
// todo: deal with memory views
|
||||
fn from_mem(vec: Vec<u8>) -> Result<Self, Error> {
|
||||
if vec.len() != 32 { return Err(Error); }
|
||||
let mut result = StorageKey([0u8; 32]);
|
||||
result.0.copy_from_slice(&vec[0..32]);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl StorageValue {
|
||||
// todo: deal with memory views
|
||||
// todo: deal with variable-length values when it comes
|
||||
fn from_mem(vec: Vec<u8>) -> Result<Self, Error> {
|
||||
if vec.len() != 32 { return Err(Error); }
|
||||
let mut result = StorageValue([0u8; 32]);
|
||||
result.0.copy_from_slice(&vec[0..32]);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn as_slice(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Storage {
|
||||
runtime: Runtime,
|
||||
}
|
||||
|
||||
pub struct Error;
|
||||
|
||||
impl Storage {
|
||||
|
||||
pub fn new(runtime: Runtime) -> Self {
|
||||
Storage {
|
||||
runtime: runtime,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writer(self) -> StorageWrite {
|
||||
StorageWrite(self)
|
||||
}
|
||||
|
||||
pub fn reader(self) -> StorageRead {
|
||||
StorageRead(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StorageWrite(Storage);
|
||||
|
||||
impl interpreter::UserFunctionInterface for StorageWrite {
|
||||
fn call(&mut self,
|
||||
module: &interpreter::ModuleInstance,
|
||||
context: interpreter::CallerContext,
|
||||
) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
|
||||
|
||||
// arguments passed are in backward order (since it is stack)
|
||||
let val_ptr = context.value_stack.pop_as::<i32>()?;
|
||||
let key_ptr = context.value_stack.pop_as::<i32>()?;
|
||||
|
||||
let memory = match module.memory(DEFAULT_MEMORY_INDEX) {
|
||||
Err(_) => { return Ok(Some((-1i32).into())) },
|
||||
Ok(memory) => memory,
|
||||
};
|
||||
|
||||
let key = StorageKey::from_mem(memory.get(key_ptr as u32, 32)?)
|
||||
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||
let val = StorageValue::from_mem(memory.get(val_ptr as u32, 32)?)
|
||||
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||
|
||||
println!("set storage {:?} = {:?}", key, val);
|
||||
|
||||
Ok(Some(0.into()))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StorageRead(Storage);
|
||||
|
||||
impl interpreter::UserFunctionInterface for StorageRead {
|
||||
fn call(&mut self,
|
||||
module: &interpreter::ModuleInstance,
|
||||
context: interpreter::CallerContext,
|
||||
) -> Result<Option<interpreter::RuntimeValue>, interpreter::Error> {
|
||||
|
||||
// arguments passed are in backward order (since it is stack)
|
||||
let val_ptr = context.value_stack.pop_as::<i32>()?;
|
||||
let key_ptr = context.value_stack.pop_as::<i32>()?;
|
||||
|
||||
let memory = match module.memory(DEFAULT_MEMORY_INDEX) {
|
||||
Err(_) => { return Ok(Some((-1i32).into())) },
|
||||
Ok(memory) => memory,
|
||||
};
|
||||
|
||||
let key = StorageKey::from_mem(memory.get(key_ptr as u32, 32)?)
|
||||
.map_err(|_| interpreter::Error::Trap("Memory access violation".to_owned()))?;
|
||||
let empty = StorageValue([0u8; 32]);
|
||||
let storage = self.0.runtime.env().storage.borrow();
|
||||
let val = storage.get(&key).unwrap_or(&empty);
|
||||
|
||||
memory.set(val_ptr as u32, val.as_slice());
|
||||
|
||||
println!("read storage {:?} (evaluated as {:?})", key, val);
|
||||
|
||||
Ok(Some(0.into()))
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user