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 6 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
99 changes: 18 additions & 81 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 @@ -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.default_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.default_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