Files
pezkuwi-subxt/substrate/primitives/sr-sandbox/without_std.rs
T
Benjamin Kampmann 60e5011c72 Reorganising the repository - external renames and moves (#4074)
* Adding first rough ouline of the repository structure

* Remove old CI stuff

* add title

* formatting fixes

* move node-exits job's script to scripts dir

* Move docs into subdir

* move to bin

* move maintainence scripts, configs and helpers into its own dir

* add .local to ignore

* move core->client

* start up 'test' area

* move test client

* move test runtime

* make test move compile

* Add dependencies rule enforcement.

* Fix indexing.

* Update docs to reflect latest changes

* Moving /srml->/paint

* update docs

* move client/sr-* -> primitives/

* clean old readme

* remove old broken code in rhd

* update lock

* Step 1.

* starting to untangle client

* Fix after merge.

* start splitting out client interfaces

* move children and blockchain interfaces

* Move trie and state-machine to primitives.

* Fix WASM builds.

* fixing broken imports

* more interface moves

* move backend and light to interfaces

* move CallExecutor

* move cli off client

* moving around more interfaces

* re-add consensus crates into the mix

* fix subkey path

* relieve client from executor

* starting to pull out client from grandpa

* move is_decendent_of out of client

* grandpa still depends on client directly

* lemme tests pass

* rename srml->paint

* Make it compile.

* rename interfaces->client-api

* Move keyring to primitives.

* fixup libp2p dep

* fix broken use

* allow dependency enforcement to fail

* move fork-tree

* Moving wasm-builder

* make env

* move build-script-utils

* fixup broken crate depdencies and names

* fix imports for authority discovery

* fix typo

* update cargo.lock

* fixing imports

* Fix paths and add missing crates

* re-add missing crates
2019-11-14 21:51:17 +01:00

279 lines
7.8 KiB
Rust
Executable File

// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use rstd::{prelude::*, slice, marker, mem, vec, rc::Rc};
use codec::{Decode, Encode};
use primitives::sandbox as sandbox_primitives;
use super::{Error, TypedValue, ReturnValue, HostFuncType};
use runtime_io::sandbox;
mod ffi {
use rstd::mem;
use super::HostFuncType;
/// Index into the default table that points to a `HostFuncType`.
pub type HostFuncIndex = usize;
/// Coerce `HostFuncIndex` to a callable host function pointer.
///
/// # Safety
///
/// This function should be only called with a `HostFuncIndex` that was previously registered
/// in the environment definition. Typically this should only
/// be called with an argument received in `dispatch_thunk`.
pub unsafe fn coerce_host_index_to_func<T>(idx: HostFuncIndex) -> HostFuncType<T> {
// We need to ensure that sizes of a callable function pointer and host function index is
// indeed equal.
// We can't use `static_assertions` create because it makes compiler panic, fallback to runtime assert.
// const_assert!(mem::size_of::<HostFuncIndex>() == mem::size_of::<HostFuncType<T>>(),);
assert!(mem::size_of::<HostFuncIndex>() == mem::size_of::<HostFuncType<T>>());
mem::transmute::<HostFuncIndex, HostFuncType<T>>(idx)
}
}
struct MemoryHandle {
memory_idx: u32,
}
impl Drop for MemoryHandle {
fn drop(&mut self) {
sandbox::memory_teardown(self.memory_idx);
}
}
#[derive(Clone)]
pub struct Memory {
// Handle to memory instance is wrapped to add reference-counting semantics
// to `Memory`.
handle: Rc<MemoryHandle>,
}
impl Memory {
pub fn new(initial: u32, maximum: Option<u32>) -> Result<Memory, Error> {
let maximum = if let Some(maximum) = maximum {
maximum
} else {
sandbox_primitives::MEM_UNLIMITED
};
match sandbox::memory_new(initial, maximum) {
sandbox_primitives::ERR_MODULE => Err(Error::Module),
memory_idx => Ok(Memory {
handle: Rc::new(MemoryHandle { memory_idx, }),
}),
}
}
pub fn get(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> {
let result = sandbox::memory_get(
self.handle.memory_idx,
offset,
buf.as_mut_ptr(),
buf.len() as u32,
);
match result {
sandbox_primitives::ERR_OK => Ok(()),
sandbox_primitives::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds),
_ => unreachable!(),
}
}
pub fn set(&self, offset: u32, val: &[u8]) -> Result<(), Error> {
let result = sandbox::memory_set(
self.handle.memory_idx,
offset,
val.as_ptr() as _ ,
val.len() as u32,
);
match result {
sandbox_primitives::ERR_OK => Ok(()),
sandbox_primitives::ERR_OUT_OF_BOUNDS => Err(Error::OutOfBounds),
_ => unreachable!(),
}
}
}
pub struct EnvironmentDefinitionBuilder<T> {
env_def: sandbox_primitives::EnvironmentDefinition,
retained_memories: Vec<Memory>,
_marker: marker::PhantomData<T>,
}
impl<T> EnvironmentDefinitionBuilder<T> {
pub fn new() -> EnvironmentDefinitionBuilder<T> {
EnvironmentDefinitionBuilder {
env_def: sandbox_primitives::EnvironmentDefinition {
entries: Vec::new(),
},
retained_memories: Vec::new(),
_marker: marker::PhantomData::<T>,
}
}
fn add_entry<N1, N2>(
&mut self,
module: N1,
field: N2,
extern_entity: sandbox_primitives::ExternEntity,
) where
N1: Into<Vec<u8>>,
N2: Into<Vec<u8>>,
{
let entry = sandbox_primitives::Entry {
module_name: module.into(),
field_name: field.into(),
entity: extern_entity,
};
self.env_def.entries.push(entry);
}
pub fn add_host_func<N1, N2>(&mut self, module: N1, field: N2, f: HostFuncType<T>)
where
N1: Into<Vec<u8>>,
N2: Into<Vec<u8>>,
{
let f = sandbox_primitives::ExternEntity::Function(f as u32);
self.add_entry(module, field, f);
}
pub fn add_memory<N1, N2>(&mut self, module: N1, field: N2, mem: Memory)
where
N1: Into<Vec<u8>>,
N2: Into<Vec<u8>>,
{
// We need to retain memory to keep it alive while the EnvironmentDefinitionBuilder alive.
self.retained_memories.push(mem.clone());
let mem = sandbox_primitives::ExternEntity::Memory(mem.handle.memory_idx as u32);
self.add_entry(module, field, mem);
}
}
pub struct Instance<T> {
instance_idx: u32,
_retained_memories: Vec<Memory>,
_marker: marker::PhantomData<T>,
}
/// The primary responsibility of this thunk is to deserialize arguments and
/// call the original function, specified by the index.
extern "C" fn dispatch_thunk<T>(
serialized_args_ptr: *const u8,
serialized_args_len: usize,
state: usize,
f: ffi::HostFuncIndex,
) -> u64 {
let serialized_args = unsafe {
if serialized_args_len == 0 {
&[]
} else {
slice::from_raw_parts(serialized_args_ptr, serialized_args_len)
}
};
let args = Vec::<TypedValue>::decode(&mut &serialized_args[..]).expect(
"serialized args should be provided by the runtime;
correctly serialized data should be deserializable;
qed",
);
unsafe {
// This should be safe since `coerce_host_index_to_func` is called with an argument
// received in an `dispatch_thunk` implementation, so `f` should point
// on a valid host function.
let f = ffi::coerce_host_index_to_func(f);
// This should be safe since mutable reference to T is passed upon the invocation.
let state = &mut *(state as *mut T);
// Pass control flow to the designated function.
let result = f(state, &args).encode();
// Leak the result vector and return the pointer to return data.
let result_ptr = result.as_ptr() as u64;
let result_len = result.len() as u64;
mem::forget(result);
(result_ptr << 32) | result_len
}
}
impl<T> Instance<T> {
pub fn new(
code: &[u8],
env_def_builder: &EnvironmentDefinitionBuilder<T>,
state: &mut T,
) -> Result<Instance<T>, Error> {
let serialized_env_def: Vec<u8> = env_def_builder.env_def.encode();
// It's very important to instantiate thunk with the right type.
let dispatch_thunk = dispatch_thunk::<T>;
let result = sandbox::instantiate(
dispatch_thunk as u32,
code,
&serialized_env_def,
state as *const T as _,
);
let instance_idx = match result {
sandbox_primitives::ERR_MODULE => return Err(Error::Module),
sandbox_primitives::ERR_EXECUTION => return Err(Error::Execution),
instance_idx => instance_idx,
};
// We need to retain memories to keep them alive while the Instance is alive.
let retained_memories = env_def_builder.retained_memories.clone();
Ok(Instance {
instance_idx,
_retained_memories: retained_memories,
_marker: marker::PhantomData::<T>,
})
}
pub fn invoke(
&mut self,
name: &str,
args: &[TypedValue],
state: &mut T,
) -> Result<ReturnValue, Error> {
let serialized_args = args.to_vec().encode();
let mut return_val = vec![0u8; sandbox_primitives::ReturnValue::ENCODED_MAX_SIZE];
let result = sandbox::invoke(
self.instance_idx,
name,
&serialized_args,
return_val.as_mut_ptr() as _,
return_val.len() as u32,
state as *const T as _,
);
match result {
sandbox_primitives::ERR_OK => {
let return_val = sandbox_primitives::ReturnValue::decode(&mut &return_val[..])
.map_err(|_| Error::Execution)?;
Ok(return_val)
}
sandbox_primitives::ERR_EXECUTION => Err(Error::Execution),
_ => unreachable!(),
}
}
}
impl<T> Drop for Instance<T> {
fn drop(&mut self) {
sandbox::instance_teardown(self.instance_idx);
}
}