refactor to native env initial

This commit is contained in:
NikVolf 2017-05-19 13:22:46 +03:00
parent 2f691bb360
commit b9acb877bc
4 changed files with 93 additions and 224 deletions

View File

@ -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)?;
// }
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}
}

View File

@ -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()))
}
}