Introduce first groundwork for Wasm executor (#27)

* Introduce first groundwork for Wasm executor.

* Remove old Rust-runtime code.

* Avoid commiting compled files.

* Add runtime precompile.

* Rename so module makes more sense.

* Further renaming.

* Ensure tests work.

* Allow bringing in of externalities.

- Add util functions/macros.
- Add uncompacted runtime.
- Add some external crates from pwasm-std for managing allocs/memory
stuff.

* Nice macros for imports.

* Allow passing in of data through allocators.

Make memcpy and malloc work.
Basic allocator.

* Can now pass in bytes to WasmExecutor.

* Additional cleanup.

* Switch usages of `OutData` to `u64`

No need to be able to return bytes anymore.

* convert to safe but extremely verbose type conversion.

@rphmeier any more concise way of doing this?

* Remove StaticExternalities distinction.

* Remove another unused use.

* Refactor wasm utils out

* Remove extraneous copies that weren't really testing anything.

* Try to use wasm 0.15

* Make it work!

* Call-time externalities working.

* Add basic externalities.

* Fix grumbles and note unwraps to be sorted.

* Test storage externality.

Unforunately had to change signatures of externalities to avoid
immutable function returning a reference. Not sure what to do about
this...

* Fix nits.

* Compile collation logic.

* Move back to refs. Yey.

* Remove "object" id for storage access.

* Fix test.

* Fix up rest of tests.

* remove unwrap.

* Expose set/get code in externalities

Also improve tests and add nice wrappers in rust-wasm.

* Add validator set.

* Introduce validator set into externalities and test.

* Add another external function.

* Remove code and validators; use storage for everything.

* Introduce validators function.

* Tests (and a fix) for the validators getter.

* Allow calls into runtime to return data.

* Remove unneeded trace.

* Make runtime printing a bit nicer.

* Create separate runtimes for testing and polkadot.

* Remove commented code.

* Use new path.

* Refactor into shared support module.

* Fix warning.

* Remove unwraps.

* Make macro a little less unhygenic.

* Add wasm files.
This commit is contained in:
Gav Wood
2018-01-08 16:48:45 +01:00
committed by Robert Habermeier
parent 45c3e40a62
commit a670208a33
44 changed files with 1087 additions and 611 deletions
+12 -109
View File
@@ -19,17 +19,16 @@
use std::{error, fmt};
use backend::Backend;
use primitives::Address;
use primitives::contract::{CallData, OutData};
use primitives::hash::H256;
use {Externalities, CodeExecutor, StaticExternalities, OverlayedChanges};
use {Externalities, OverlayedChanges};
/// Errors that can occur when interacting with the externalities.
#[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),
}
@@ -52,122 +51,26 @@ impl<B: error::Error, E: error::Error> error::Error for Error<B, E> {
}
/// Wraps a read-only backend, call executor, and current overlayed changes.
pub struct Ext<'a, B: 'a, E: 'a> {
pub struct Ext<'a, B: 'a> {
/// The overlayed changes to write to.
pub overlay: &'a mut OverlayedChanges,
/// The storage backend to read from.
pub backend: &'a B,
/// Contract code executor.
pub exec: &'a E,
/// Contract address.
pub local: Address,
}
impl<'a, B: 'a, E: 'a> StaticExternalities<E> for Ext<'a, B, E>
where B: Backend, E: CodeExecutor
impl<'a, B: 'a> Externalities for Ext<'a, B>
where B: Backend
{
type Error = Error<B::Error, E::Error>;
type Error = B::Error;
fn storage(&self, key: &H256) -> Result<&[u8], Self::Error> {
match self.overlay.storage(&self.local, key) {
fn storage(&self, key: &[u8]) -> Result<&[u8], Self::Error> {
match self.overlay.storage(key) {
Some(x) => Ok(x),
None => self.backend.storage(&self.local, key).map_err(Error::Backend)
None => self.backend.storage(key)
}
}
fn call_static(&self, address: &Address, method: &str, data: &CallData) -> Result<OutData, Self::Error> {
let inner_ext = StaticExt {
backend: self.backend,
exec: self.exec,
local: address.clone(),
overlay: self.overlay,
};
let code = match self.overlay.code(address) {
Some(x) => x,
None => self.backend.code(address).map_err(Error::Backend)?,
};
self.exec.call_static(
&inner_ext,
code,
method,
data,
).map_err(Error::Executor)
}
}
impl<'a, B: 'a, E: 'a> Externalities<E> for Ext<'a, B, E>
where B: Backend, E: CodeExecutor
{
fn set_storage(&mut self, key: H256, value: Vec<u8>) {
self.overlay.set_storage(self.local, key, value);
}
fn call(&mut self, address: &Address, method: &str, data: &CallData) -> Result<OutData, Self::Error> {
let code = {
let code = match self.overlay.code(address) {
Some(x) => x,
None => self.backend.code(address).map_err(Error::Backend)?,
};
code.to_owned()
};
let mut inner_ext = Ext {
backend: self.backend,
exec: self.exec,
local: address.clone(),
overlay: &mut *self.overlay,
};
self.exec.call(
&mut inner_ext,
&code[..],
method,
data,
).map_err(Error::Executor)
}
}
// Static externalities
struct StaticExt<'a, B: 'a, E: 'a> {
overlay: &'a OverlayedChanges,
backend: &'a B,
exec: &'a E,
local: Address,
}
impl<'a, B: 'a, E: 'a> StaticExternalities<E> for StaticExt<'a, B, E>
where B: Backend, E: CodeExecutor
{
type Error = Error<B::Error, E::Error>;
fn storage(&self, key: &H256) -> Result<&[u8], Self::Error> {
match self.overlay.storage(&self.local, key) {
Some(x) => Ok(x),
None => self.backend.storage(&self.local, key).map_err(Error::Backend)
}
}
fn call_static(&self, address: &Address, method: &str, data: &CallData) -> Result<OutData, Self::Error> {
let inner_ext = StaticExt {
backend: self.backend,
exec: self.exec,
local: address.clone(),
overlay: self.overlay,
};
let code = match self.overlay.code(address) {
Some(x) => x,
None => self.backend.code(address).map_err(Error::Backend)?,
};
self.exec.call_static(
&inner_ext,
code,
method,
data,
).map_err(Error::Executor)
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
self.overlay.set_storage(key, value);
}
}