Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
2 changes: 2 additions & 0 deletions core/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ mod wasm_executor;
mod native_executor;
mod sandbox;
mod allocator;
mod wasm_runtimes_cache;

pub mod error;
pub use wasmi;
pub use wasm_executor::WasmExecutor;
pub use native_executor::{with_native_environment, NativeExecutor, NativeExecutionDispatch};
pub use wasm_runtimes_cache::RuntimesCache;
pub use state_machine::Externalities;
pub use runtime_version::{RuntimeVersion, NativeVersion};
pub use parity_codec::Codec;
Expand Down
109 changes: 23 additions & 86 deletions core/executor/src/native_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,86 +14,20 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.

use std::{borrow::BorrowMut, result, cell::{RefMut, RefCell}};
use std::{result, cell::RefCell, panic::UnwindSafe};
use crate::error::{Error, Result};
use state_machine::{CodeExecutor, Externalities};
use crate::wasm_executor::WasmExecutor;
use wasmi::{Module as WasmModule, ModuleRef as WasmModuleInstanceRef};
use runtime_version::{NativeVersion, RuntimeVersion};
use std::{collections::HashMap, panic::UnwindSafe};
use parity_codec::{Decode, Encode};
use crate::RuntimeInfo;
use primitives::{Blake2Hasher, NativeOrEncoded};
use primitives::storage::well_known_keys;
use log::trace;

/// Default num of pages for the heap
const DEFAULT_HEAP_PAGES: u64 = 1024;

// For the internal Runtime Cache:
// Is it compatible enough to run this natively or do we need to fall back on the WasmModule

enum RuntimePreproc {
InvalidCode,
ValidCode(WasmModuleInstanceRef, Option<RuntimeVersion>),
}

type CacheType = HashMap<[u8; 32], RuntimePreproc>;
use crate::RuntimesCache;

thread_local! {
static RUNTIMES_CACHE: RefCell<CacheType> = RefCell::new(HashMap::new());
}

/// fetch a runtime version from the cache or if there is no cached version yet, create
/// the runtime version entry for `code`, determines whether `Compatibility::IsCompatible`
/// can be used by comparing returned RuntimeVersion to `ref_version`
fn fetch_cached_runtime_version<'a, E: Externalities<Blake2Hasher>>(
wasm_executor: &WasmExecutor,
cache: &'a mut RefMut<CacheType>,
ext: &mut E,
default_heap_pages: Option<u64>,
) -> Result<(&'a WasmModuleInstanceRef, &'a Option<RuntimeVersion>)> {
let code_hash = match ext.original_storage_hash(well_known_keys::CODE) {
Some(code_hash) => code_hash,
None => return Err(Error::InvalidCode(vec![])),
};

let maybe_runtime_preproc = cache.borrow_mut().entry(code_hash.into())
.or_insert_with(|| {
let code = match ext.original_storage(well_known_keys::CODE) {
Some(code) => code,
None => return RuntimePreproc::InvalidCode,
};
let heap_pages = ext.storage(well_known_keys::HEAP_PAGES)
.and_then(|pages| u64::decode(&mut &pages[..]))
.or(default_heap_pages)
.unwrap_or(DEFAULT_HEAP_PAGES);
match WasmModule::from_buffer(code)
.map_err(|_| Error::InvalidCode(vec![]))
.and_then(|module| wasm_executor.prepare_module(ext, heap_pages as usize, &module))
{
Ok(module) => {
let version = wasm_executor.call_in_wasm_module(ext, &module, "Core_version", &[])
.ok()
.and_then(|v| RuntimeVersion::decode(&mut v.as_slice()));
RuntimePreproc::ValidCode(module, version)
}
Err(e) => {
trace!(target: "executor", "Invalid code presented to executor ({:?})", e);
RuntimePreproc::InvalidCode
}
}
});

match maybe_runtime_preproc {
RuntimePreproc::InvalidCode => {
let code = ext.original_storage(well_known_keys::CODE).unwrap_or(vec![]);
Err(Error::InvalidCode(code))
},
RuntimePreproc::ValidCode(m, v) => {
Ok((m, v))
}
}
static RUNTIMES_CACHE: RefCell<RuntimesCache> = RefCell::new(RuntimesCache::new());
}

fn safe_call<F, U>(f: F) -> Result<U>
Expand Down Expand Up @@ -140,18 +74,18 @@ pub struct NativeExecutor<D> {
fallback: WasmExecutor,
/// Native runtime version info.
native_version: NativeVersion,
/// The default number of 64KB pages to allocate for Wasm execution.
default_heap_pages: Option<u64>,
/// The number of 64KB pages to allocate for Wasm execution.
initial_heap_pages: Option<u64>,
}

impl<D: NativeExecutionDispatch> NativeExecutor<D> {
/// Create new instance.
pub fn new(default_heap_pages: Option<u64>) -> Self {
pub fn new(initial_heap_pages: Option<u64>) -> Self {
NativeExecutor {
_dummy: Default::default(),
fallback: WasmExecutor::new(),
native_version: D::native_version(),
default_heap_pages,
initial_heap_pages: initial_heap_pages,
}
}
}
Expand All @@ -162,7 +96,7 @@ impl<D: NativeExecutionDispatch> Clone for NativeExecutor<D> {
_dummy: Default::default(),
fallback: self.fallback.clone(),
native_version: D::native_version(),
default_heap_pages: self.default_heap_pages,
initial_heap_pages: self.initial_heap_pages,
}
}
}
Expand All @@ -176,10 +110,11 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
&self,
ext: &mut E,
) -> Option<RuntimeVersion> {
RUNTIMES_CACHE.with(|c|
fetch_cached_runtime_version(&self.fallback, &mut c.borrow_mut(), ext, self.default_heap_pages)
RUNTIMES_CACHE.with(|cache| {
let cache = &mut cache.borrow_mut();
cache.fetch_runtime(&self.fallback, ext, self.initial_heap_pages, None)
.ok()?.1.clone()
)
})
}
}

Expand All @@ -198,13 +133,15 @@ impl<D: NativeExecutionDispatch> CodeExecutor<Blake2Hasher> for NativeExecutor<D
data: &[u8],
use_native: bool,
native_call: Option<NC>,
) -> (Result<NativeOrEncoded<R>>, bool) {
RUNTIMES_CACHE.with(|c| {
let mut c = c.borrow_mut();
let (module, onchain_version) = match fetch_cached_runtime_version(
&self.fallback, &mut c, ext, self.default_heap_pages) {
Ok((module, onchain_version)) => (module, onchain_version),
Err(e) => return (Err(e), false),
) -> (Result<NativeOrEncoded<R>>, bool){
RUNTIMES_CACHE.with(|cache| {
let cache = &mut cache.borrow_mut();
let (module, onchain_version) = match cache.fetch_runtime(
&self.fallback, ext, self.initial_heap_pages,
Some(&self.native_version.runtime_version)
) {
Ok((module, onchain_version)) => (module, onchain_version),
Err(e) => return (Err(e), false),
};
match (
use_native,
Expand All @@ -224,15 +161,15 @@ impl<D: NativeExecutionDispatch> CodeExecutor<Blake2Hasher> for NativeExecutor<D
);
(
self.fallback
.call_in_wasm_module(ext, module, method, data)
.call_in_wasm_module(ext, &module, method, data)
.map(NativeOrEncoded::Encoded),
false
)
}
(false, _, _) => {
(
self.fallback
.call_in_wasm_module(ext, module, method, data)
.call_in_wasm_module(ext, &module, method, data)
.map(NativeOrEncoded::Encoded),
false
)
Expand Down
9 changes: 0 additions & 9 deletions core/executor/src/wasm_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1290,8 +1290,6 @@ impl WasmExecutor {
.export_by_name("__indirect_function_table")
.and_then(|e| e.as_table().cloned());

let low = memory.lowest_used();
let used_mem = memory.used_size();
let mut fec = FunctionExecutor::new(memory.clone(), table, ext)?;
let parameters = create_parameters(&mut |data: &[u8]| {
let offset = fec.heap.allocate(data.len() as u32)?;
Expand All @@ -1315,13 +1313,6 @@ impl WasmExecutor {
},
};

// cleanup module instance for next use
let new_low = memory.lowest_used();
if new_low < low {
memory.zero(new_low as usize, (low - new_low) as usize)?;
memory.reset_lowest_used(low);
}
memory.with_direct_access_mut(|buf| buf.resize(used_mem.0, 0));
result
}

Expand Down
Loading