Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4f5c5b6
Introduce first groundwork for Wasm executor.
gavofyork Dec 5, 2017
6237848
Remove old Rust-runtime code.
gavofyork Dec 6, 2017
293cf5d
Avoid commiting compled files.
gavofyork Dec 6, 2017
66b636e
Add runtime precompile.
gavofyork Dec 6, 2017
c7e7456
Rename so module makes more sense.
gavofyork Dec 6, 2017
0cfd67e
Further renaming.
gavofyork Dec 6, 2017
3011edf
Ensure tests work.
gavofyork Dec 6, 2017
a74b4fa
Allow bringing in of externalities.
gavofyork Dec 7, 2017
6dac275
Nice macros for imports.
gavofyork Dec 9, 2017
08f7b26
Allow passing in of data through allocators.
gavofyork Dec 11, 2017
1ace6b2
Can now pass in bytes to WasmExecutor.
gavofyork Dec 11, 2017
27e5fed
Additional cleanup.
gavofyork Dec 11, 2017
13dcd89
Switch usages of `OutData` to `u64`
gavofyork Dec 11, 2017
84b9f84
convert to safe but extremely verbose type conversion.
gavofyork Dec 11, 2017
7f31899
Remove StaticExternalities distinction.
gavofyork Dec 11, 2017
edf061e
Remove another unused use.
gavofyork Dec 11, 2017
edb6bea
Refactor wasm utils out
gavofyork Dec 11, 2017
9f59f48
Remove extraneous copies that weren't really testing anything.
gavofyork Dec 11, 2017
287b29d
Try to use wasm 0.15
gavofyork Dec 31, 2017
1bd55fe
Make it work!
gavofyork Dec 31, 2017
36e254a
Call-time externalities working.
gavofyork Jan 1, 2018
cd651a3
Add basic externalities.
gavofyork Jan 1, 2018
a8f9cca
Merge branch 'with-wasm-0.15' into with-wasm
gavofyork Jan 1, 2018
4404846
Fix grumbles and note unwraps to be sorted.
gavofyork Jan 1, 2018
b1d963a
Test storage externality.
gavofyork Jan 3, 2018
319d9c0
Fix nits.
gavofyork Jan 3, 2018
7ec9221
Merge branch 'master' into with-wasm
gavofyork Jan 3, 2018
2934d94
Compile collation logic.
gavofyork Jan 3, 2018
5998aa1
Move back to refs. Yey.
gavofyork Jan 3, 2018
3f4085a
Remove "object" id for storage access.
gavofyork Jan 4, 2018
4be0537
Fix test.
gavofyork Jan 4, 2018
01d7019
Fix up rest of tests.
gavofyork Jan 4, 2018
db1adee
remove unwrap.
gavofyork Jan 4, 2018
87c54f7
Expose set/get code in externalities
gavofyork Jan 5, 2018
471ea1e
Add validator set.
gavofyork Jan 5, 2018
fa35993
Introduce validator set into externalities and test.
gavofyork Jan 5, 2018
a0f64df
Add another external function.
gavofyork Jan 6, 2018
e736d46
Remove code and validators; use storage for everything.
gavofyork Jan 6, 2018
234297c
Introduce validators function.
gavofyork Jan 6, 2018
3f8a96d
Tests (and a fix) for the validators getter.
gavofyork Jan 6, 2018
6636520
Allow calls into runtime to return data.
gavofyork Jan 7, 2018
964659e
Remove unneeded trace.
gavofyork Jan 7, 2018
8ca1b7b
Make runtime printing a bit nicer.
gavofyork Jan 7, 2018
74156a2
Create separate runtimes for testing and polkadot.
gavofyork Jan 8, 2018
611a7ac
Remove commented code.
gavofyork Jan 8, 2018
c3afecc
Use new path.
gavofyork Jan 8, 2018
ea4d6c5
Refactor into shared support module.
gavofyork Jan 8, 2018
709693d
Fix warning.
gavofyork Jan 8, 2018
ec1e6b6
Remove unwraps.
gavofyork Jan 8, 2018
5c0ec3d
Make macro a little less unhygenic.
gavofyork Jan 8, 2018
79ab46f
Add wasm files.
gavofyork Jan 8, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove code and validators; use storage for everything.
  • Loading branch information
gavofyork committed Jan 6, 2018
commit e736d46a54200c89356f3117dea78a6c024e47fb
108 changes: 21 additions & 87 deletions executor/src/wasm_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,13 @@ impl WritePrimitive<u32> for MemoryInstance {
}

impl_function_executor!(this: FunctionExecutor<'e, E>,
imported(n: u64) -> u64 => { println!("imported {:?}", n); n + 1 },
ext_print(utf8_data: *const u8, utf8_len: i32) => {
if let Ok(utf8) = this.memory.get(utf8_data, utf8_len as usize) {
if let Ok(message) = String::from_utf8(utf8) {
println!("Runtime: {}", message);
}
}
},
ext_memcpy(dest: *mut u8, src: *const u8, count: usize) -> *mut u8 => {
let _ = this.memory.copy_nonoverlapping(src as usize, dest as usize, count as usize);
println!("memcpy {} from {}, {} bytes", dest, src, count);
Expand All @@ -88,7 +94,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
dest
},
ext_memset(dest: *mut u8, val: i32, count: usize) -> *mut u8 => {
// let _ = this.memory.set(dest as usize, val as u8, count as usize);
let _ = this.memory.clear(dest as usize, val as u8, count as usize);
println!("memset {} with {}, {} bytes", dest, val, count);
dest
},
Expand Down Expand Up @@ -117,40 +123,6 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,

this.memory.write_primitive(written_out, written);
offset as u32
},
set_code(code_data: *const u8, code_len: i32) => {
if let Ok(code) = this.memory.get(code_data, code_len as usize) {
this.ext.set_code(code);
}
},
get_allocated_code(written_out: *mut i32) -> *mut u8 => {
let (offset, written) = if let Ok(code) = this.ext.code() {
let offset = this.heap.allocate(code.len() as u32) as u32;
let _ = this.memory.set(offset, &code);
(offset, code.len() as u32)
} else { (0, 0) };
this.memory.write_primitive(written_out, written);
offset as u32
},
get_validator_count() -> i32 => {
this.ext.validator_count() as i32
},
get_allocated_validator(index: i32, written_out: *mut i32) -> *mut u8 => {
let (offset, written) = if let Ok(v) = this.ext.validator(index as usize) {
let offset = this.heap.allocate(v.len() as u32) as u32;
let _ = this.memory.set(offset, &v);
(offset, v.len() as u32)
} else { (0, 0) };
this.memory.write_primitive(written_out, written);
offset as u32
},
set_validator_count(validator_count: i32) => {
this.ext.set_validator_count(validator_count as usize);
},
set_validator(index: i32, validator_data: *const u8, validator_len: i32) => {
if let Ok(validator) = this.memory.get(validator_data, validator_len as usize) {
this.ext.set_validator(index as usize, validator);
}
}
=> <'e, E: Externalities + 'e>
);
Expand All @@ -167,21 +139,15 @@ impl CodeExecutor for WasmExecutor {
fn call<E: Externalities>(
&self,
ext: &mut E,
code: &[u8],
method: &str,
data: &CallData,
) -> Result<u64> {
// TODO: avoid copying code by requiring code to remain immutable through execution,
// splitting it off from potentially mutable externalities.
let code = match ext.code() {
Ok(e) => e.to_owned(),
Err(e) => Err(ErrorKind::Externalities(Box::new(e)))?,
};

// TODO: handle all expects as errors to be returned.

let program = ProgramInstance::new().expect("this really shouldn't be able to fail; qed");

let module = deserialize_buffer(code).expect("all modules compiled with rustc are valid wasm code; qed");
let module = deserialize_buffer(code.to_vec()).expect("all modules compiled with rustc are valid wasm code; qed");
let module = program.add_module_by_sigs("test", module, map!["env" => FunctionExecutor::<E>::SIGNATURES]).expect("runtime signatures always provided; qed");

let memory = module.memory(ItemIndex::Internal(0)).expect("all modules compiled with rustc include memory segments; qed");
Expand All @@ -208,56 +174,24 @@ mod tests {

#[derive(Debug, Default)]
struct TestExternalities {
data: HashMap<Vec<u8>, Vec<u8>>,
code: Vec<u8>,
validators: Vec<Vec<u8>>,
storage: HashMap<Vec<u8>, Vec<u8>>,
}
impl Externalities for TestExternalities {
type Error = Error;

fn code(&self) -> Result<&[u8]> {
Ok(self.code.as_slice())
}

fn storage(&self, key: &[u8]) -> Result<&[u8]> {
Ok(self.data.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice))
}

fn validator(&self, index: usize) -> Result<&[u8]> {
if index < self.validators.len() {
Ok(self.validators[index].as_slice())
} else {
Err(ErrorKind::InvalidIndex.into())
}
}

fn validator_count(&self) -> usize {
self.validators.len()
}

fn set_code(&mut self, code: Vec<u8>) {
self.code = code;
Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice))
}

fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
self.data.insert(key, value);
}

fn set_validator(&mut self, index: usize, value: Vec<u8>) {
if index < self.validators.len() {
self.validators[index] = value;
}
}

fn set_validator_count(&mut self, count: usize) {
self.validators.resize(count, vec![]);
self.storage.insert(key, value);
}
}

#[test]
fn should_pass_externalities_at_call() {
let mut ext = TestExternalities::default();
ext.code = b"The code".to_vec();
ext.set_storage(b"\0code".to_vec(), b"The code".to_vec());

let program = ProgramInstance::new().unwrap();

Expand All @@ -274,20 +208,20 @@ mod tests {
let offset = fec.heap.allocate(size);
memory.set(offset, data).unwrap();

module.execute_export("test_data_in",
assert!(module.execute_export("test_data_in",
program.params_with_external("env", &mut fec)
.add_argument(I32(offset as i32))
.add_argument(I32(size as i32))
).unwrap();
).is_ok());
}

let expected: HashMap<_, _> = map![
b"\0code".to_vec() => b"Hello world".to_vec(),
b"input".to_vec() => b"Hello world".to_vec(),
b"code".to_vec() => b"The code".to_vec()
b"code".to_vec() => b"The code".to_vec(),
b"\0validator_count".to_vec() => vec![1],
b"\0validator".to_vec() => b"Hello world".to_vec()
];
assert_eq!(expected, ext.data);

let expected = vec![ b"Hello world".to_vec() ];
assert_eq!(expected, ext.validators);
assert_eq!(expected, ext.storage);
}
}
78 changes: 32 additions & 46 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#![feature(alloc)]

extern crate alloc;
use alloc::boxed::Box;
use alloc::vec::Vec;

extern crate pwasm_libc;
Expand All @@ -18,22 +17,14 @@ pub fn panic_fmt() -> ! {
}

extern "C" {
fn imported(n: u64) -> u64;
fn ext_print(utf8_data: *const u8, utf8_len: i32);
fn set_storage(key_data: *const u8, key_len: i32, value_data: *const u8, value_len: i32);
fn get_allocated_storage(key_data: *const u8, key_len: i32, written_out: *mut i32) -> *mut u8;
fn set_code(code_data: *const u8, code_len: i32);
fn get_allocated_code(written_out: *mut i32) -> *mut u8;
fn get_validator_count() -> i32;
fn get_allocated_validator(index: i32, written_out: *mut i32) -> *mut u8;
fn set_validator_count(validator_count: i32);
fn set_validator(index: i32, validator_data: *const u8, validator_len: i32);
}

pub mod state {
use alloc::vec::Vec;
use super::{get_allocated_storage, set_storage as super_set_storage, get_allocated_code,
set_code as super_set_code, set_validator as super_set_validator, get_allocated_validator,
get_validator_count, set_validator_count as super_set_validator_count};
use super::{get_allocated_storage, set_storage as super_set_storage};

pub fn storage(key: &[u8]) -> Vec<u8> {
let mut length: i32 = 0;
Expand All @@ -53,43 +44,37 @@ pub mod state {
}

pub fn code() -> Vec<u8> {
let mut length: i32 = 0;
unsafe {
let ptr = get_allocated_code(&mut length);
Vec::from_raw_parts(ptr, length as usize, length as usize)
}
storage(b"\0code")
}

pub fn set_code(new: &[u8]) {
unsafe {
super_set_code(&new[0] as *const u8, new.len() as i32);
set_storage(b"\0code", new)
}

pub fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
let mut acc = initial;
while value > 0 {
acc.push(value as u8);
value /= 256;
}
acc
}

pub fn set_validator(index: usize, validator: &[u8]) {
unsafe {
super_set_validator(index as i32, &validator[0] as *const u8, validator.len() as i32);
}
set_storage(&value_vec(index, b"\0validator".to_vec()), validator);
}

pub fn validator(index: usize) -> Vec<u8> {
let mut length: i32 = 0;
unsafe {
let ptr = get_allocated_validator(index as i32, &mut length);
Vec::from_raw_parts(ptr, length as usize, length as usize)
}
storage(&value_vec(index, b"\0validator".to_vec()))
}

pub fn set_validator_count(count: usize) {
unsafe {
super_set_validator_count(count as i32);
}
(count..validator_count()).for_each(|i| set_validator(i, &[]));
set_storage(b"\0validator_count", &value_vec(count, Vec::new()));
}

pub fn validator_count() -> usize {
unsafe {
get_validator_count() as usize
}
storage(b"\0validator_count").into_iter().rev().fold(0, |acc, i| acc << 8 + (i as usize))
}

pub fn validators() -> Vec<Vec<u8>> {
Expand All @@ -102,15 +87,10 @@ pub mod state {
}
}

fn do_something(param: u64) -> u64 {
param * 2
}

/// Test some execution.
#[no_mangle]
pub fn test(value: u64) -> u64 {
let b = Box::new(unsafe { imported(value) });
do_something(*b)
pub fn print(utf8: &[u8]) {
unsafe {
ext_print(&utf8[0] as *const u8, utf8.len() as i32);
}
}

/// Test passing of data.
Expand All @@ -120,18 +100,24 @@ pub fn test_data_in(input_data: *mut u8, input_len: usize) {
Vec::from_raw_parts(input_data, input_len, input_len)
};

print(b"set_storage");
state::set_storage(b"input", &input);

print(b"code");
state::set_storage(b"code", &state::code());

print(b"set_code");
state::set_code(&input);
let copy = state::storage(b"input");

// Do some stuff.
for b in &copy {
unsafe { imported(*b as u64); }
}
print(b"storage");
let copy = state::storage(b"input");

print(b"validators");
let mut v = state::validators();
v.push(copy);

print(b"set_validators");
state::set_validators(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());

print(b"finished!");
}
Binary file not shown.
Binary file modified runtime/target/wasm32-unknown-unknown/release/runtime.wasm
Binary file not shown.
6 changes: 0 additions & 6 deletions state_machine/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,13 @@
//! State machine backends. These manage the code and storage of contracts.

use std::{error, fmt};
use primitives::hash;
use primitives::hash::H256;
use triehash::sec_trie_root;

use super::{Update, MemoryState};

/// Output of a commit.
pub struct Committed {
/// Root of the code tree after changes committed.
pub code_hash: H256,
/// Root of the storage tree after changes committed.
pub storage_tree_root: H256,
}
Expand Down Expand Up @@ -85,11 +82,8 @@ impl Backend for InMemory {
.map(|(k, v)| (k.to_vec(), v.clone()))
.collect()
).0);
let code_hash = hash(&self.inner.code().unwrap_or_else(|| &[]));
// TODO: include validators list.

Committed {
code_hash,
storage_tree_root,
}
}
Expand Down
10 changes: 2 additions & 8 deletions state_machine/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ use {Externalities, OverlayedChanges};
#[derive(Debug, Copy, Clone)]
pub enum Error<B, E> {
/// Failure to load state data from the backend.
#[allow(unused)]
Backend(B),
/// Failure to execute a function.
#[allow(unused)]
Executor(E),
}

Expand Down Expand Up @@ -61,21 +63,13 @@ impl<'a, B: 'a> Externalities for Ext<'a, B>
{
type Error = B::Error;

fn code(&self) -> Result<&[u8], Self::Error> {
Ok(self.overlay.code())
}

fn storage(&self, key: &[u8]) -> Result<&[u8], Self::Error> {
match self.overlay.storage(key) {
Some(x) => Ok(x),
None => self.backend.storage(key)
}
}

fn set_code(&mut self, code: Vec<u8>) {
self.overlay.set_code(code);
}

fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
self.overlay.set_storage(key, value);
}
Expand Down
Loading