State cache and other performance optimizations (#1345)

* State caching

* Better code caching

* Execution optimizaton

* More optimizations

* Updated wasmi

* Caching test

* Style

* Style

* Reverted some minor changes

* Style and typos

* Style and typos

* Removed panics on missing memory
This commit is contained in:
Arkadiy Paronyan
2019-01-08 15:13:13 +03:00
committed by Gav Wood
parent e0639c435b
commit b104c02eb6
26 changed files with 796 additions and 266 deletions
+7 -2
View File
@@ -40,10 +40,15 @@ pub trait Backend<H: Hasher> {
/// Type of trie backend storage.
type TrieBackendStorage: TrieBackendStorage<H>;
/// Get keyed storage associated with specific address, or None if there is nothing associated.
/// Get keyed storage or None if there is nothing associated.
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
/// Get keyed child storage associated with specific address, or None if there is nothing associated.
/// Get keyed storage value hash or None if there is nothing associated.
fn storage_hash(&self, key: &[u8]) -> Result<Option<H::Out>, Self::Error> {
self.storage(key).map(|v| v.map(|v| H::hash(&v)))
}
/// Get keyed child storage or None if there is nothing associated.
fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
/// true if a key exists in storage.
+5
View File
@@ -184,6 +184,11 @@ where
self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL))
}
fn storage_hash(&self, key: &[u8]) -> Option<H::Out> {
self.overlay.storage(key).map(|x| x.map(|x| H::hash(x))).unwrap_or_else(||
self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL))
}
fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
self.overlay.child_storage(storage_key, key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
self.backend.child_storage(storage_key, key).expect(EXT_NOT_ALLOWED_TO_FAIL))
+7 -21
View File
@@ -65,9 +65,6 @@ pub use proving_backend::{create_proof_check_backend, create_proof_check_backend
pub use trie_backend_essence::{TrieBackendStorage, Storage};
pub use trie_backend::TrieBackend;
/// Default num of pages for the heap
const DEFAULT_HEAP_PAGES :u64 = 1024;
/// State Machine Error bound.
///
/// This should reflect WASM error type bound for future compatibility.
@@ -98,10 +95,15 @@ impl fmt::Display for ExecutionError {
/// Externalities: pinned to specific active address.
pub trait Externalities<H: Hasher> {
/// Read storage of current contract being called.
/// Read runtime storage.
fn storage(&self, key: &[u8]) -> Option<Vec<u8>>;
/// Read child storage of current contract being called.
/// Get storage value hash. This may be optimized for large values.
fn storage_hash(&self, key: &[u8]) -> Option<H::Out> {
self.storage(key).map(|v| H::hash(&v))
}
/// Read child runtime storage.
fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>>;
/// Set storage entry `key` of current contract being called (effective immediately).
@@ -171,8 +173,6 @@ pub trait CodeExecutor<H: Hasher>: Sized + Send + Sync {
fn call<E: Externalities<H>>(
&self,
ext: &mut E,
heap_pages: usize,
code: &[u8],
method: &str,
data: &[u8],
use_native: bool
@@ -297,14 +297,6 @@ where
{
let strategy: ExecutionStrategy = (&manager).into();
// make a copy.
let code = try_read_overlay_value(overlay, backend, well_known_keys::CODE)?
.ok_or_else(|| Box::new(ExecutionError::CodeEntryDoesNotExist) as Box<Error>)?
.to_vec();
let heap_pages = try_read_overlay_value(overlay, backend, well_known_keys::HEAP_PAGES)?
.and_then(|v| u64::decode(&mut &v[..])).unwrap_or(DEFAULT_HEAP_PAGES) as usize;
// read changes trie configuration. The reason why we're doing it here instead of the
// `OverlayedChanges` constructor is that we need proofs for this read as a part of
// proof-of-execution on light clients. And the proof is recorded by the backend which
@@ -328,8 +320,6 @@ where
let mut externalities = ext::Ext::new(overlay, backend, changes_trie_storage);
let retval = exec.call(
&mut externalities,
heap_pages,
&code,
method,
call_data,
// attempt to run native first, if we're not directed to run wasm only
@@ -357,8 +347,6 @@ where
let mut externalities = ext::Ext::new(overlay, backend, changes_trie_storage);
let retval = exec.call(
&mut externalities,
heap_pages,
&code,
method,
call_data,
false,
@@ -614,8 +602,6 @@ mod tests {
fn call<E: Externalities<H>>(
&self,
ext: &mut E,
_heap_pages: usize,
_code: &[u8],
_method: &str,
_data: &[u8],
use_native: bool
@@ -44,7 +44,7 @@ pub struct OverlayedValue {
/// Current value. None if value has been deleted.
pub value: Option<Vec<u8>>,
/// The set of extinsic indices where the values has been changed.
/// Is filled only if runtime ahs announced changes trie support.
/// Is filled only if runtime has announced changes trie support.
pub extrinsics: Option<HashSet<u32>>,
}
+15 -2
View File
@@ -23,7 +23,8 @@ use heapsize::HeapSizeOf;
use trie::trie_root;
use backend::InMemory;
use changes_trie::{compute_changes_trie_root, InMemoryStorage as ChangesTrieInMemoryStorage, AnchorBlockId};
use primitives::storage::well_known_keys::CHANGES_TRIE_CONFIG;
use primitives::storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES};
use codec::Encode;
use super::{Externalities, OverlayedChanges};
/// Simple HashMap-based Externalities impl.
@@ -31,11 +32,17 @@ pub struct TestExternalities<H: Hasher> where H::Out: HeapSizeOf {
inner: HashMap<Vec<u8>, Vec<u8>>,
changes_trie_storage: ChangesTrieInMemoryStorage<H>,
changes: OverlayedChanges,
code: Vec<u8>,
}
impl<H: Hasher> TestExternalities<H> where H::Out: HeapSizeOf {
/// Create a new instance of `TestExternalities`
pub fn new(inner: HashMap<Vec<u8>, Vec<u8>>) -> Self {
Self::new_with_code(&[], inner)
}
/// Create a new instance of `TestExternalities`
pub fn new_with_code(code: &[u8], inner: HashMap<Vec<u8>, Vec<u8>>) -> Self {
let mut overlay = OverlayedChanges::default();
super::set_changes_trie_config(
&mut overlay,
@@ -47,6 +54,7 @@ impl<H: Hasher> TestExternalities<H> where H::Out: HeapSizeOf {
inner,
changes_trie_storage: ChangesTrieInMemoryStorage::new(),
changes: overlay,
code: code.to_vec(),
}
}
@@ -94,13 +102,18 @@ impl<H: Hasher> From< HashMap<Vec<u8>, Vec<u8>> > for TestExternalities<H> where
inner: hashmap,
changes_trie_storage: ChangesTrieInMemoryStorage::new(),
changes: Default::default(),
code: Default::default(),
}
}
}
impl<H: Hasher> Externalities<H> for TestExternalities<H> where H::Out: Ord + HeapSizeOf {
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
self.inner.get(key).map(|x| x.to_vec())
match key {
CODE => Some(self.code.clone()),
HEAP_PAGES => Some(8u64.encode()),
_ => self.inner.get(key).map(|x| x.to_vec()),
}
}
fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> Option<Vec<u8>> {