From b104c02eb63969cc74725d8781609dfb25142cd5 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 8 Jan 2019 15:13:13 +0300 Subject: [PATCH] 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 --- substrate/Cargo.lock | 16 + substrate/core/client/db/Cargo.toml | 1 + substrate/core/client/db/src/lib.rs | 88 ++-- substrate/core/client/db/src/storage_cache.rs | 416 ++++++++++++++++++ substrate/core/client/src/backend.rs | 8 +- substrate/core/client/src/call_executor.rs | 67 +-- substrate/core/client/src/client.rs | 14 +- substrate/core/client/src/in_mem.rs | 6 +- substrate/core/client/src/lib.rs | 2 +- substrate/core/client/src/light/backend.rs | 7 +- .../core/client/src/light/call_executor.rs | 14 +- substrate/core/client/src/light/fetcher.rs | 12 +- substrate/core/executor/src/lib.rs | 5 - .../core/executor/src/native_executor.rs | 123 +++--- substrate/core/executor/src/wasm_executor.rs | 123 +++--- substrate/core/network/src/on_demand.rs | 17 +- substrate/core/rpc/src/lib.rs | 1 - substrate/core/rpc/src/state/mod.rs | 3 +- substrate/core/state-machine/src/backend.rs | 9 +- substrate/core/state-machine/src/ext.rs | 5 + substrate/core/state-machine/src/lib.rs | 28 +- .../state-machine/src/overlayed_changes.rs | 2 +- substrate/core/state-machine/src/testing.rs | 17 +- .../substrate_test_runtime.compact.wasm | Bin 42281 -> 41771 bytes substrate/node/executor/src/lib.rs | 78 ++-- .../release/node_runtime.compact.wasm | Bin 809938 -> 808984 bytes 26 files changed, 796 insertions(+), 266 deletions(-) create mode 100644 substrate/core/client/db/src/storage_cache.rs diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 53489b81a2..678f3e4154 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1570,6 +1570,11 @@ dependencies = [ "make-cmd 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "linked-hash-map" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "linked-hash-map" version = "0.5.1" @@ -1600,6 +1605,14 @@ dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lru-cache" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "make-cmd" version = "0.1.0" @@ -3417,6 +3430,7 @@ dependencies = [ "kvdb-memorydb 0.1.0 (git+https://github.com/paritytech/parity-common?rev=616b40150ded71f57f650067fcbc5c99d7c343e6)", "kvdb-rocksdb 0.1.4 (git+https://github.com/paritytech/parity-common?rev=616b40150ded71f57f650067fcbc5c99d7c343e6)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec-derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4846,10 +4860,12 @@ dependencies = [ "checksum libp2p-websocket 0.1.0 (git+https://github.com/libp2p/rust-libp2p?rev=d961e656a74d1bab5366d371a06f9e10d5f4a6c5)" = "" "checksum libp2p-yamux 0.1.0 (git+https://github.com/libp2p/rust-libp2p?rev=d961e656a74d1bab5366d371a06f9e10d5f4a6c5)" = "" "checksum librocksdb-sys 5.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "474d805d72e23a06310fa5201dfe182dc4b80ab1f18bb2823c1ac17ff9dcbaa2" +"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +"checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" "checksum make-cmd 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3" "checksum mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b" "checksum mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb" diff --git a/substrate/core/client/db/Cargo.toml b/substrate/core/client/db/Cargo.toml index a228a8e9ca..77dd4d9bf8 100644 --- a/substrate/core/client/db/Cargo.toml +++ b/substrate/core/client/db/Cargo.toml @@ -8,6 +8,7 @@ parking_lot = "0.7.1" log = "0.4" kvdb = { git = "https://github.com/paritytech/parity-common", rev="616b40150ded71f57f650067fcbc5c99d7c343e6" } kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common", rev="616b40150ded71f57f650067fcbc5c99d7c343e6" } +lru-cache = "0.1" hash-db = { git = "https://github.com/paritytech/trie" } substrate-primitives = { path = "../../primitives" } sr-primitives = { path = "../../sr-primitives" } diff --git a/substrate/core/client/db/src/lib.rs b/substrate/core/client/db/src/lib.rs index 371f0a4013..f663cc0834 100644 --- a/substrate/core/client/db/src/lib.rs +++ b/substrate/core/client/db/src/lib.rs @@ -29,6 +29,7 @@ extern crate kvdb_rocksdb; extern crate kvdb; extern crate hash_db; extern crate parking_lot; +extern crate lru_cache; extern crate substrate_state_machine as state_machine; extern crate substrate_primitives as primitives; extern crate sr_primitives as runtime_primitives; @@ -52,6 +53,7 @@ extern crate kvdb_memorydb; pub mod light; mod cache; +mod storage_cache; mod utils; use std::sync::Arc; @@ -75,10 +77,12 @@ use state_machine::{CodeExecutor, DBValue, ExecutionStrategy}; use utils::{Meta, db_err, meta_keys, open_database, read_db, block_id_to_lookup_key, read_meta}; use client::LeafSet; use state_db::StateDb; +use storage_cache::{CachingState, SharedCache, new_shared_cache}; pub use state_db::PruningMode; const CANONICALIZATION_DELAY: u64 = 256; const MIN_BLOCKS_TO_KEEP_CHANGES_TRIES_FOR: u64 = 32768; +const STATE_CACHE_SIZE_BYTES: usize = 16 * 1024 * 1024; /// DB-backed patricia trie state, transaction type is an overlay of changes to commit. pub type DbState = state_machine::TrieBackend>, Blake2Hasher>; @@ -270,8 +274,9 @@ impl client::blockchain::Backend for BlockchainDb { /// Database transaction pub struct BlockImportOperation { - old_state: DbState, - updates: MemoryDB, + old_state: CachingState, + db_updates: MemoryDB, + storage_updates: Vec<(Vec, Option>)>, changes_trie_updates: MemoryDB, pending_block: Option>, aux_ops: Vec<(Vec, Option>)>, @@ -292,7 +297,7 @@ impl client::backend::BlockImportOperation for BlockImportOperation where Block: BlockT, { - type State = DbState; + type State = CachingState; fn state(&self) -> Result, client::error::Error> { Ok(Some(&self.old_state)) @@ -319,8 +324,8 @@ where Block: BlockT, // currently authorities are not cached on full nodes } - fn update_storage(&mut self, update: MemoryDB) -> Result<(), client::error::Error> { - self.updates = update; + fn update_db_storage(&mut self, update: MemoryDB) -> Result<(), client::error::Error> { + self.db_updates = update; Ok(()) } @@ -349,7 +354,7 @@ where Block: BlockT, let (root, update) = self.old_state.storage_root(top.into_iter().map(|(k, v)| (k, Some(v)))); transaction.consolidate(update); - self.updates = transaction; + self.db_updates = transaction; Ok(root) } @@ -364,6 +369,11 @@ where Block: BlockT, self.aux_ops = ops.into_iter().collect(); Ok(()) } + + fn update_storage(&mut self, update: Vec<(Vec, Option>)>) -> Result<(), client::error::Error> { + self.storage_updates = update; + Ok(()) + } } struct StorageDb { @@ -503,6 +513,7 @@ pub struct Backend { changes_tries_storage: DbChangesTrieStorage, blockchain: BlockchainDb, canonicalization_delay: u64, + shared_cache: SharedCache, } impl Backend { @@ -550,6 +561,7 @@ impl Backend { changes_tries_storage, blockchain, canonicalization_delay, + shared_cache: new_shared_cache(STATE_CACHE_SIZE_BYTES), }) } @@ -669,7 +681,7 @@ impl client::backend::AuxStore for Backend where Block: BlockT client::backend::Backend for Backend where Block: BlockT { type BlockImportOperation = BlockImportOperation; type Blockchain = BlockchainDb; - type State = DbState; + type State = CachingState; type ChangesTrieStorage = DbChangesTrieStorage; fn begin_operation(&self, block: BlockId) -> Result { @@ -677,7 +689,8 @@ impl client::backend::Backend for Backend whe Ok(BlockImportOperation { pending_block: None, old_state: state, - updates: MemoryDB::default(), + db_updates: MemoryDB::default(), + storage_updates: Default::default(), changes_trie_updates: MemoryDB::default(), aux_ops: Vec::new(), }) @@ -697,6 +710,9 @@ impl client::backend::Backend for Backend whe // blocks are keyed by number + hash. let lookup_key = ::utils::number_and_hash_to_lookup_key(number, hash); + let mut enacted = Vec::default(); + let mut retracted = Vec::default(); + if pending_block.leaf_state.is_best() { let meta = self.blockchain.meta.read(); @@ -710,10 +726,11 @@ impl client::backend::Backend for Backend whe // uncanonicalize: check safety violations and ensure the numbers no longer // point to these block hashes in the key mapping. - for retracted in tree_route.retracted() { - if retracted.hash == meta.finalized_hash { + for r in tree_route.retracted() { + retracted.push(r.hash.clone()); + if r.hash == meta.finalized_hash { warn!("Potential safety failure: reverting finalized block {:?}", - (&retracted.number, &retracted.hash)); + (&r.number, &r.hash)); return Err(::client::error::ErrorKind::NotInFinalizedChain.into()); } @@ -721,17 +738,18 @@ impl client::backend::Backend for Backend whe ::utils::remove_number_to_key_mapping( &mut transaction, columns::KEY_LOOKUP, - retracted.number + r.number ); } // canonicalize: set the number lookup to map to this block's hash. - for enacted in tree_route.enacted() { + for e in tree_route.enacted() { + enacted.push(e.hash.clone()); ::utils::insert_number_to_key_mapping( &mut transaction, columns::KEY_LOOKUP, - enacted.number, - enacted.hash + e.number, + e.hash ); } } @@ -766,7 +784,7 @@ impl client::backend::Backend for Backend whe } let mut changeset: state_db::ChangeSet = state_db::ChangeSet::default(); - for (key, (val, rc)) in operation.updates.drain() { + for (key, (val, rc)) in operation.db_updates.drain() { if rc > 0 { changeset.inserted.push((key, val.to_vec())); } else if rc < 0 { @@ -792,8 +810,8 @@ impl client::backend::Backend for Backend whe self.force_delayed_canonicalize(&mut transaction, hash, *pending_block.header.number())? } - debug!(target: "db", "DB Commit {:?} ({}), best = {}", hash, number, - pending_block.leaf_state.is_best()); + let is_best = pending_block.leaf_state.is_best(); + debug!(target: "db", "DB Commit {:?} ({}), best = {}", hash, number, is_best); { let mut leaves = self.blockchain.leaves.write(); @@ -817,6 +835,16 @@ impl client::backend::Backend for Backend whe pending_block.leaf_state.is_best(), finalized, ); + + // sync canonical state cache + operation.old_state.sync_cache( + &enacted, + &retracted, + operation.storage_updates, + Some(hash), + Some(number), + || is_best + ); } Ok(()) } @@ -898,7 +926,8 @@ impl client::backend::Backend for Backend whe BlockId::Hash(h) if h == Default::default() => { let genesis_storage = DbGenesisStorage::new(); let root = genesis_storage.0.clone(); - return Ok(DbState::new(Arc::new(genesis_storage), root)); + let state = DbState::new(Arc::new(genesis_storage), root); + return Ok(CachingState::new(state, self.shared_cache.clone(), None)); }, _ => {} } @@ -906,12 +935,21 @@ impl client::backend::Backend for Backend whe match self.blockchain.header(block) { Ok(Some(ref hdr)) if !self.storage.state_db.is_pruned(hdr.number().as_()) => { let root = H256::from_slice(hdr.state_root().as_ref()); - Ok(DbState::new(self.storage.clone(), root)) + let state = DbState::new(self.storage.clone(), root); + Ok(CachingState::new(state, self.shared_cache.clone(), Some(hdr.hash()))) }, Err(e) => Err(e), _ => Err(client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()), } } + + fn destroy_state(&self, mut state: Self::State) -> Result<(), client::error::Error> { + if let Some(hash) = state.parent_hash.clone() { + let is_best = || self.blockchain.meta.read().best_hash == hash; + state.sync_cache(&[], &[], vec![], None, None, is_best); + } + Ok(()) + } } impl client::backend::LocalBackend for Backend @@ -1092,7 +1130,7 @@ mod tests { ]; let (root, overlay) = op.old_state.storage_root(storage.iter().cloned()); - op.update_storage(overlay).unwrap(); + op.update_db_storage(overlay).unwrap(); header.state_root = root.into(); op.set_block_data( @@ -1138,7 +1176,7 @@ mod tests { op.reset_storage(storage.iter().cloned().collect(), Default::default()).unwrap(); - key = op.updates.insert(b"hello"); + key = op.db_updates.insert(b"hello"); op.set_block_data( header, Some(vec![]), @@ -1171,8 +1209,8 @@ mod tests { ).0.into(); let hash = header.hash(); - op.updates.insert(b"hello"); - op.updates.remove(&key); + op.db_updates.insert(b"hello"); + op.db_updates.remove(&key); op.set_block_data( header, Some(vec![]), @@ -1204,7 +1242,7 @@ mod tests { .map(|(x, y)| (x, Some(y))) ).0.into(); - op.updates.remove(&key); + op.db_updates.remove(&key); op.set_block_data( header, Some(vec![]), diff --git a/substrate/core/client/db/src/storage_cache.rs b/substrate/core/client/db/src/storage_cache.rs new file mode 100644 index 0000000000..27d5cec088 --- /dev/null +++ b/substrate/core/client/db/src/storage_cache.rs @@ -0,0 +1,416 @@ +// Copyright 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 . + +//! Global cache state. + +use std::collections::{VecDeque, HashSet, HashMap}; +use std::sync::Arc; +use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; +use lru_cache::LruCache; +use hash_db::Hasher; +use runtime_primitives::traits::{Block, Header}; +use state_machine::{backend::Backend as StateBackend, TrieBackend}; + +const STATE_CACHE_BLOCKS: usize = 12; + +type StorageKey = Vec; +type StorageValue = Vec; + +/// Shared canonical state cache. +pub struct Cache { + /// Storage cache. `None` indicates that key is known to be missing. + storage: LruCache>, + /// Storage hashes cache. `None` indicates that key is known to be missing. + hashes: LruCache>, + /// Information on the modifications in recently committed blocks; specifically which keys + /// changed in which block. Ordered by block number. + modifications: VecDeque>, +} + +pub type SharedCache = Arc>>; + +/// Create new shared cache instance with given max memory usage. +pub fn new_shared_cache(shared_cache_size: usize) -> SharedCache { + let cache_items = shared_cache_size / 100; // Estimated average item size. TODO: more accurate tracking + Arc::new(Mutex::new(Cache { + storage: LruCache::new(cache_items), + hashes: LruCache::new(cache_items), + modifications: VecDeque::new(), + })) +} + +#[derive(Debug)] +/// Accumulates a list of storage changed in a block. +struct BlockChanges { + /// Block number. + number: B::Number, + /// Block hash. + hash: B::Hash, + /// Parent block hash. + parent: B::Hash, + /// A set of modified storage keys. + storage: HashSet, + /// Block is part of the canonical chain. + is_canon: bool, +} + +/// Cached values specific to a state. +struct LocalCache { + /// Storage cache. `None` indicates that key is known to be missing. + storage: HashMap>, + /// Storage hashes cache. `None` indicates that key is known to be missing. + hashes: HashMap>, +} + +/// State abstraction. +/// Manages shared global state cache which reflects the canonical +/// state as it is on the disk. +/// A instance of `CachingState` may be created as canonical or not. +/// For canonical instances local cache is accumulated and applied +/// in `sync_cache` along with the change overlay. +/// For non-canonical clones local cache and changes are dropped. +pub struct CachingState, B: Block> { + /// Backing state. + state: S, + /// Shared canonical state cache. + shared_cache: SharedCache, + /// Local cache of values for this state. + local_cache: RwLock>, + /// Hash of the block on top of which this instance was created or + /// `None` if cache is disabled + pub parent_hash: Option, +} + +impl, B: Block> CachingState { + /// Create a new instance wrapping generic State and shared cache. + pub fn new(state: S, shared_cache: SharedCache, parent_hash: Option) -> CachingState { + CachingState { + state, + shared_cache, + local_cache: RwLock::new(LocalCache { + storage: Default::default(), + hashes: Default::default(), + }), + parent_hash: parent_hash, + } + } + + /// Propagate local cache into the shared cache and synchonize + /// the shared cache with the best block state. + /// This function updates the shared cache by removing entries + /// that are invalidated by chain reorganization. `sync_cache` + /// should be called after the block has been committed and the + /// blockchain route has been calculated. + pub fn sync_cache bool> ( + &mut self, + enacted: &[B::Hash], + retracted: &[B::Hash], + changes: Vec<(StorageKey, Option)>, + commit_hash: Option, + commit_number: Option<::Number>, + is_best: F, + ) { + let mut cache = self.shared_cache.lock(); + let is_best = is_best(); + trace!("Syncing cache, id = (#{:?}, {:?}), parent={:?}, best={}", commit_number, commit_hash, self.parent_hash, is_best); + let cache = &mut *cache; + + // Purge changes from re-enacted and retracted blocks. + // Filter out commiting block if any. + let mut clear = false; + for block in enacted.iter().filter(|h| commit_hash.as_ref().map_or(true, |p| *h != p)) { + clear = clear || { + if let Some(ref mut m) = cache.modifications.iter_mut().find(|m| &m.hash == block) { + trace!("Reverting enacted block {:?}", block); + m.is_canon = true; + for a in &m.storage { + trace!("Reverting enacted key {:?}", a); + cache.storage.remove(a); + } + false + } else { + true + } + }; + } + + for block in retracted { + clear = clear || { + if let Some(ref mut m) = cache.modifications.iter_mut().find(|m| &m.hash == block) { + trace!("Retracting block {:?}", block); + m.is_canon = false; + for a in &m.storage { + trace!("Retracted key {:?}", a); + cache.storage.remove(a); + } + false + } else { + true + } + }; + } + if clear { + // We don't know anything about the block; clear everything + trace!("Wiping cache"); + cache.storage.clear(); + cache.modifications.clear(); + } + + // Propagate cache only if committing on top of the latest canonical state + // blocks are ordered by number and only one block with a given number is marked as canonical + // (contributed to canonical state cache) + if let Some(_) = self.parent_hash { + let mut local_cache = self.local_cache.write(); + if is_best { + trace!("Committing {} local, {} hashes, {} modified entries", local_cache.storage.len(), local_cache.hashes.len(), changes.len()); + for (k, v) in local_cache.storage.drain() { + cache.storage.insert(k, v); + } + for (k, v) in local_cache.hashes.drain() { + cache.hashes.insert(k, v); + } + } + } + + if let ( + Some(ref number), Some(ref hash), Some(ref parent)) + = (commit_number, commit_hash, self.parent_hash) + { + if cache.modifications.len() == STATE_CACHE_BLOCKS { + cache.modifications.pop_back(); + } + let mut modifications = HashSet::new(); + for (k, v) in changes.into_iter() { + modifications.insert(k.clone()); + if is_best { + cache.hashes.remove(&k); + cache.storage.insert(k, v); + } + } + // Save modified storage. These are ordered by the block number. + let block_changes = BlockChanges { + storage: modifications, + number: *number, + hash: hash.clone(), + is_canon: is_best, + parent: parent.clone(), + }; + let insert_at = cache.modifications.iter() + .enumerate() + .find(|&(_, m)| m.number < *number) + .map(|(i, _)| i); + trace!("Inserting modifications at {:?}", insert_at); + if let Some(insert_at) = insert_at { + cache.modifications.insert(insert_at, block_changes); + } else { + cache.modifications.push_back(block_changes); + } + } + } + + /// Check if the key can be returned from cache by matching current block parent hash against canonical + /// state and filtering out entries modified in later blocks. + fn is_allowed( + key: &[u8], + parent_hash: &Option, + modifications: + &VecDeque> + ) -> bool + { + let mut parent = match *parent_hash { + None => { + trace!("Cache lookup skipped for {:?}: no parent hash", key); + return false; + } + Some(ref parent) => parent, + }; + if modifications.is_empty() { + trace!("Cache lookup allowed for {:?}", key); + return true; + } + // Ignore all storage modified in later blocks + // Modifications contains block ordered by the number + // We search for our parent in that list first and then for + // all its parent until we hit the canonical block, + // checking against all the intermediate modifications. + for m in modifications { + if &m.hash == parent { + if m.is_canon { + return true; + } + parent = &m.parent; + } + if m.storage.contains(key) { + trace!("Cache lookup skipped for {:?}: modified in a later block", key); + return false; + } + } + trace!("Cache lookup skipped for {:?}: parent hash is unknown", key); + false + } +} + +impl, B:Block> StateBackend for CachingState { + type Error = S::Error; + type Transaction = S::Transaction; + type TrieBackendStorage = S::TrieBackendStorage; + + fn storage(&self, key: &[u8]) -> Result>, Self::Error> { + let local_cache = self.local_cache.upgradable_read(); + if let Some(entry) = local_cache.storage.get(key).cloned() { + trace!("Found in local cache: {:?}", key); + return Ok(entry) + } + let mut cache = self.shared_cache.lock(); + if Self::is_allowed(key, &self.parent_hash, &cache.modifications) { + if let Some(entry) = cache.storage.get_mut(key).map(|a| a.clone()) { + trace!("Found in shared cache: {:?}", key); + return Ok(entry) + } + } + trace!("Cache miss: {:?}", key); + let value = self.state.storage(key)?; + RwLockUpgradableReadGuard::upgrade(local_cache).storage.insert(key.to_vec(), value.clone()); + Ok(value) + } + + fn storage_hash(&self, key: &[u8]) -> Result, Self::Error> { + let local_cache = self.local_cache.upgradable_read(); + if let Some(entry) = local_cache.hashes.get(key).cloned() { + trace!("Found hash in local cache: {:?}", key); + return Ok(entry) + } + let mut cache = self.shared_cache.lock(); + if Self::is_allowed(key, &self.parent_hash, &cache.modifications) { + if let Some(entry) = cache.hashes.get_mut(key).map(|a| a.clone()) { + trace!("Found hash in shared cache: {:?}", key); + return Ok(entry) + } + } + trace!("Cache hash miss: {:?}", key); + let hash = self.state.storage_hash(key)?; + RwLockUpgradableReadGuard::upgrade(local_cache).hashes.insert(key.to_vec(), hash.clone()); + Ok(hash) + } + + fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result>, Self::Error> { + self.state.child_storage(storage_key, key) + } + + fn exists_storage(&self, key: &[u8]) -> Result { + Ok(self.storage(key)?.is_some()) + } + + fn exists_child_storage(&self, storage_key: &[u8], key: &[u8]) -> Result { + self.state.exists_child_storage(storage_key, key) + } + + fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { + self.state.for_keys_with_prefix(prefix, f) + } + + fn for_keys_in_child_storage(&self, storage_key: &[u8], f: F) { + self.state.for_keys_in_child_storage(storage_key, f) + } + + fn storage_root(&self, delta: I) -> (H::Out, Self::Transaction) + where + I: IntoIterator, Option>)>, + H::Out: Ord + { + self.state.storage_root(delta) + } + + fn child_storage_root(&self, storage_key: &[u8], delta: I) -> (Vec, bool, Self::Transaction) + where + I: IntoIterator, Option>)>, + H::Out: Ord + { + self.state.child_storage_root(storage_key, delta) + } + + fn pairs(&self) -> Vec<(Vec, Vec)> { + self.state.pairs() + } + + fn try_into_trie_backend(self) -> Option> { + self.state.try_into_trie_backend() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use runtime_primitives::testing::{H256, Block as RawBlock, ExtrinsicWrapper}; + use state_machine::backend::InMemory; + use primitives::Blake2Hasher; + + type Block = RawBlock>; + #[test] + fn smoke() { + //init_log(); + let root_parent = H256::random(); + let key = H256::random()[..].to_vec(); + let h0 = H256::random(); + let h1a = H256::random(); + let h1b = H256::random(); + let h2a = H256::random(); + let h2b = H256::random(); + let h3a = H256::random(); + let h3b = H256::random(); + + let shared = new_shared_cache::(256*1024); + + // blocks [ 3a(c) 2a(c) 2b 1b 1a(c) 0 ] + // state [ 5 5 4 3 2 2 ] + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(root_parent.clone())); + s.sync_cache(&[], &[], vec![(key.clone(), Some(vec![2]))], Some(h0.clone()), Some(0), || true); + + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(h0.clone())); + s.sync_cache(&[], &[], vec![], Some(h1a.clone()), Some(1), || true); + + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(h0.clone())); + s.sync_cache(&[], &[], vec![(key.clone(), Some(vec![3]))], Some(h1b.clone()), Some(1), || false); + + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(h1b.clone())); + s.sync_cache(&[], &[], vec![(key.clone(), Some(vec![4]))], Some(h2b.clone()), Some(2), || false); + + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(h1a.clone())); + s.sync_cache(&[], &[], vec![(key.clone(), Some(vec![5]))], Some(h2a.clone()), Some(2), || true); + + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(h2a.clone())); + s.sync_cache(&[], &[], vec![], Some(h3a.clone()), Some(3), || true); + + let s = CachingState::new(InMemory::::default(), shared.clone(), Some(h3a.clone())); + assert_eq!(s.storage(&key).unwrap().unwrap(), vec![5]); + + let s = CachingState::new(InMemory::::default(), shared.clone(), Some(h1a.clone())); + assert!(s.storage(&key).unwrap().is_none()); + + let s = CachingState::new(InMemory::::default(), shared.clone(), Some(h2b.clone())); + assert!(s.storage(&key).unwrap().is_none()); + + let s = CachingState::new(InMemory::::default(), shared.clone(), Some(h1b.clone())); + assert!(s.storage(&key).unwrap().is_none()); + + // reorg to 3b + // blocks [ 3b(c) 3a 2a 2b(c) 1b 1a 0 ] + let mut s = CachingState::new(InMemory::::default(), shared.clone(), Some(h2b.clone())); + s.sync_cache(&[h1b.clone(), h2b.clone(), h3b.clone()], &[h1a.clone(), h2a.clone(), h3a.clone()], vec![], Some(h3b.clone()), Some(3), || true); + let s = CachingState::new(InMemory::::default(), shared.clone(), Some(h3a.clone())); + assert!(s.storage(&key).unwrap().is_none()); + } +} diff --git a/substrate/core/client/src/backend.rs b/substrate/core/client/src/backend.rs index 1f370f0e1b..88e97c7ec4 100644 --- a/substrate/core/client/src/backend.rs +++ b/substrate/core/client/src/backend.rs @@ -68,9 +68,11 @@ pub trait BlockImportOperation where /// has been used to check justification of this block). fn update_authorities(&mut self, authorities: Vec>); /// Inject storage data into the database. - fn update_storage(&mut self, update: >::Transaction) -> error::Result<()>; + fn update_db_storage(&mut self, update: >::Transaction) -> error::Result<()>; /// Inject storage data into the database replacing any existing data. fn reset_storage(&mut self, top: StorageMap, children: ChildrenStorageMap) -> error::Result; + /// Set top level storage changes. + fn update_storage(&mut self, update: Vec<(Vec, Option>)>) -> error::Result<()>; /// Inject changes trie data into the database. fn update_changes_trie(&mut self, update: MemoryDB) -> error::Result<()>; /// Update auxiliary keys. Values are `None` if should be deleted. @@ -127,6 +129,10 @@ pub trait Backend: AuxStore + Send + Sync where fn changes_trie_storage(&self) -> Option<&Self::ChangesTrieStorage>; /// Returns state backend with post-state of given block. fn state_at(&self, block: BlockId) -> error::Result; + /// Destroy state and save any useful data, such as cache. + fn destroy_state(&self, _state: Self::State) -> error::Result<()> { + Ok(()) + } /// Attempts to revert the chain by `n` blocks. Returns the number of blocks that were /// successfully reverted. fn revert(&self, n: NumberFor) -> error::Result>; diff --git a/substrate/core/client/src/call_executor.rs b/substrate/core/client/src/call_executor.rs index 8cbb40dfa2..62104d4aa0 100644 --- a/substrate/core/client/src/call_executor.rs +++ b/substrate/core/client/src/call_executor.rs @@ -24,22 +24,11 @@ use state_machine::{self, OverlayedChanges, Ext, use executor::{RuntimeVersion, RuntimeInfo, NativeVersion}; use hash_db::Hasher; use trie::MemoryDB; -use codec::Decode; use primitives::{H256, Blake2Hasher}; -use primitives::storage::well_known_keys; use backend; use error; -/// Information regarding the result of a call. -#[derive(Debug, Clone)] -pub struct CallResult { - /// The data that was returned from the call. - pub return_data: Vec, - /// The changes made to the state by the call. - pub changes: OverlayedChanges, -} - /// Method call executor. pub trait CallExecutor where @@ -58,7 +47,7 @@ where id: &BlockId, method: &str, call_data: &[u8], - ) -> Result; + ) -> Result, error::Error>; /// Execute a contextual call on top of state in a block of a given hash. /// @@ -163,16 +152,22 @@ where id: &BlockId, method: &str, call_data: &[u8], - ) -> error::Result { + ) -> error::Result> { let mut changes = OverlayedChanges::default(); - let (return_data, _, _) = self.call_at_state( - &self.backend.state_at(*id)?, + let state = self.backend.state_at(*id)?; + let return_data = state_machine::execute_using_consensus_failure_handler( + &state, + self.backend.changes_trie_storage(), &mut changes, + &self.executor, method, call_data, native_when_possible(), - )?; - Ok(CallResult { return_data, changes }) + false, + ) + .map(|(result, _, _)| result)?; + self.backend.destroy_state(state)?; + Ok(return_data) } fn contextual_call< @@ -192,28 +187,40 @@ where //TODO: Find a better way to prevent double block initialization if method != "Core_initialise_block" && initialised_block.map(|id| id != *at).unwrap_or(true) { let header = prepare_environment_block()?; - self.call_at_state(&state, changes, "Core_initialise_block", &header.encode(), manager.clone())?; + state_machine::execute_using_consensus_failure_handler( + &state, + self.backend.changes_trie_storage(), + changes, + &self.executor, + "Core_initialise_block", + &header.encode(), + manager.clone(), + false, + )?; *initialised_block = Some(*at); } - self.call_at_state(&state, changes, method, call_data, manager).map(|cr| cr.0) + let result = state_machine::execute_using_consensus_failure_handler( + &state, + self.backend.changes_trie_storage(), + changes, + &self.executor, + method, + call_data, + manager, + false, + ) + .map(|(result, _, _)| result)?; + + self.backend.destroy_state(state)?; + Ok(result) } fn runtime_version(&self, id: &BlockId) -> error::Result { let mut overlay = OverlayedChanges::default(); let state = self.backend.state_at(*id)?; - use state_machine::Backend; - let code = state.storage(well_known_keys::CODE) - .map_err(|e| error::ErrorKind::Execution(Box::new(e)))? - .ok_or(error::ErrorKind::VersionInvalid)? - .to_vec(); - let heap_pages = state.storage(well_known_keys::HEAP_PAGES) - .map_err(|e| error::ErrorKind::Execution(Box::new(e)))? - .and_then(|v| u64::decode(&mut &v[..])) - .unwrap_or(1024) as usize; - let mut ext = Ext::new(&mut overlay, &state, self.backend.changes_trie_storage()); - self.executor.runtime_version(&mut ext, heap_pages, &code) + self.executor.runtime_version(&mut ext) .ok_or(error::ErrorKind::VersionInvalid.into()) } diff --git a/substrate/core/client/src/client.rs b/substrate/core/client/src/client.rs index 79a112e616..f02e25f78c 100644 --- a/substrate/core/client/src/client.rs +++ b/substrate/core/client/src/client.rs @@ -230,7 +230,6 @@ impl Client where let (genesis_storage, children_genesis_storage) = build_genesis_storage.build_storage()?; let mut op = backend.begin_operation(BlockId::Hash(Default::default()))?; let state_root = op.reset_storage(genesis_storage, children_genesis_storage)?; - let genesis_block = genesis::construct_genesis_block::(state_root.into()); info!("Initialising Genesis block/state (state: {}, header-hash: {})", genesis_block.header().state_root(), genesis_block.header().hash()); op.set_block_data( @@ -284,8 +283,8 @@ impl Client where match self.backend.blockchain().cache().and_then(|cache| cache.authorities_at(*id)) { Some(cached_value) => Ok(cached_value), None => self.executor.call(id, "Core_authorities", &[]) - .and_then(|r| Vec::>::decode(&mut &r.return_data[..]) - .ok_or(error::ErrorKind::InvalidAuthoritiesSet.into())) + .and_then(|r| Vec::>::decode(&mut &r[..]) + .ok_or_else(|| error::ErrorKind::InvalidAuthoritiesSet.into())) } } @@ -602,7 +601,7 @@ impl Client where ); let (_, storage_update, changes_update) = r?; overlay.commit_prospective(); - (Some(storage_update), Some(changes_update), Some(overlay.into_committed())) + (Some(storage_update), Some(changes_update), Some(overlay.into_committed().collect())) }, None => (None, None, None) }; @@ -633,7 +632,10 @@ impl Client where transaction.update_authorities(authorities); } if let Some(storage_update) = storage_update { - transaction.update_storage(storage_update)?; + transaction.update_db_storage(storage_update)?; + } + if let Some(storage_changes) = storage_changes.clone() { + transaction.update_storage(storage_changes)?; } if let Some(Some(changes_update)) = changes_update { transaction.update_changes_trie(changes_update)?; @@ -646,7 +648,7 @@ impl Client where if let Some(storage_changes) = storage_changes { // TODO [ToDr] How to handle re-orgs? Should we re-emit all storage changes? self.storage_notifications.lock() - .trigger(&hash, storage_changes); + .trigger(&hash, storage_changes.into_iter()); } if finalized { diff --git a/substrate/core/client/src/in_mem.rs b/substrate/core/client/src/in_mem.rs index 896f9821de..606f03d870 100644 --- a/substrate/core/client/src/in_mem.rs +++ b/substrate/core/client/src/in_mem.rs @@ -448,7 +448,7 @@ where self.pending_authorities = Some(authorities); } - fn update_storage(&mut self, update: as StateBackend>::Transaction) -> error::Result<()> { + fn update_db_storage(&mut self, update: as StateBackend>::Transaction) -> error::Result<()> { self.new_state = Some(self.old_state.update(update)); Ok(()) } @@ -491,6 +491,10 @@ where self.aux = Some(ops.into_iter().collect()); Ok(()) } + + fn update_storage(&mut self, _update: Vec<(Vec, Option>)>) -> error::Result<()> { + Ok(()) + } } /// In-memory backend. Keeps all states and blocks in memory. Useful for testing. diff --git a/substrate/core/client/src/lib.rs b/substrate/core/client/src/lib.rs index fb07c130b2..3bb65df9d1 100644 --- a/substrate/core/client/src/lib.rs +++ b/substrate/core/client/src/lib.rs @@ -102,7 +102,7 @@ mod notifications; #[cfg(feature = "std")] pub use blockchain::Info as ChainInfo; #[cfg(feature = "std")] -pub use call_executor::{CallResult, CallExecutor, LocalCallExecutor}; +pub use call_executor::{CallExecutor, LocalCallExecutor}; #[cfg(feature = "std")] pub use client::{ new_with_backend, diff --git a/substrate/core/client/src/light/backend.rs b/substrate/core/client/src/light/backend.rs index 79a636bfbc..6beaf1271b 100644 --- a/substrate/core/client/src/light/backend.rs +++ b/substrate/core/client/src/light/backend.rs @@ -188,7 +188,7 @@ where self.authorities = Some(authorities); } - fn update_storage(&mut self, _update: >::Transaction) -> ClientResult<()> { + fn update_db_storage(&mut self, _update: >::Transaction) -> ClientResult<()> { // we're not storing anything locally => ignore changes Ok(()) } @@ -210,6 +210,11 @@ where self.aux_ops = ops.into_iter().collect(); Ok(()) } + + fn update_storage(&mut self, _update: Vec<(Vec, Option>)>) -> ClientResult<()> { + // we're not storing anything locally => ignore changes + Ok(()) + } } impl StateBackend for OnDemandState diff --git a/substrate/core/client/src/light/call_executor.rs b/substrate/core/client/src/light/call_executor.rs index d30e459215..84d7545d6f 100644 --- a/substrate/core/client/src/light/call_executor.rs +++ b/substrate/core/client/src/light/call_executor.rs @@ -31,7 +31,7 @@ use state_machine::{self, Backend as StateBackend, CodeExecutor, OverlayedChange use hash_db::Hasher; use blockchain::Backend as ChainBackend; -use call_executor::{CallExecutor, CallResult}; +use call_executor::CallExecutor; use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult}; use light::fetcher::{Fetcher, RemoteCallRequest}; use executor::{RuntimeVersion, NativeVersion}; @@ -74,7 +74,7 @@ where { type Error = ClientError; - fn call(&self, id: &BlockId, method: &str, call_data: &[u8]) -> ClientResult { + fn call(&self, id: &BlockId, method: &str, call_data: &[u8]) -> ClientResult> { let block_hash = self.blockchain.expect_block_hash_from_id(id)?; let block_header = self.blockchain.expect_header(id.clone())?; @@ -105,12 +105,12 @@ where return Err(ClientErrorKind::NotAvailableOnLightClient.into()); } - self.call(at, method, call_data).map(|cr| cr.return_data) + self.call(at, method, call_data) } fn runtime_version(&self, id: &BlockId) -> ClientResult { let call_result = self.call(id, "version", &[])?; - RuntimeVersion::decode(&mut call_result.return_data.as_slice()) + RuntimeVersion::decode(&mut call_result.as_slice()) .ok_or_else(|| ClientErrorKind::VersionInvalid.into()) } @@ -189,7 +189,7 @@ pub fn check_execution_proof( executor: &E, request: &RemoteCallRequest
, remote_proof: Vec> -) -> ClientResult +) -> ClientResult> where Header: HeaderT, E: CodeExecutor, @@ -226,7 +226,7 @@ pub fn check_execution_proof( &request.call_data, )?; - Ok(CallResult { return_data: local_result, changes }) + Ok(local_result) } #[cfg(test)] @@ -273,7 +273,7 @@ mod tests { retry_count: None, }, remote_execution_proof).unwrap(); - (remote_result, local_result.return_data) + (remote_result, local_result) } // prepare remote client diff --git a/substrate/core/client/src/light/fetcher.rs b/substrate/core/client/src/light/fetcher.rs index 1171e15f49..5f9aed2fe1 100644 --- a/substrate/core/client/src/light/fetcher.rs +++ b/substrate/core/client/src/light/fetcher.rs @@ -28,7 +28,6 @@ use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT, NumberF use state_machine::{CodeExecutor, ChangesTrieRootsStorage, ChangesTrieAnchorBlockId, TrieBackend, read_proof_check, key_changes_proof_check, create_proof_check_backend_storage}; -use call_executor::CallResult; use cht; use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult}; use light::blockchain::{Blockchain, Storage as BlockchainStorage}; @@ -118,7 +117,7 @@ pub trait Fetcher: Send + Sync { /// Remote storage read future. type RemoteReadResult: IntoFuture>, Error=ClientError>; /// Remote call result future. - type RemoteCallResult: IntoFuture; + type RemoteCallResult: IntoFuture, Error=ClientError>; /// Remote changes result future. type RemoteChangesResult: IntoFuture, u32)>, Error=ClientError>; @@ -156,7 +155,7 @@ pub trait FetchChecker: Send + Sync { &self, request: &RemoteCallRequest, remote_proof: Vec> - ) -> ClientResult; + ) -> ClientResult>; /// Check remote changes query proof. fn check_changes_proof( &self, @@ -344,7 +343,7 @@ impl FetchChecker for LightDataChecker, remote_proof: Vec> - ) -> ClientResult { + ) -> ClientResult> { check_execution_proof::<_, _, H>(&self.executor, request, remote_proof) } @@ -392,7 +391,6 @@ pub mod tests { use futures::future::{ok, err, FutureResult}; use parking_lot::Mutex; use keyring::Keyring; - use call_executor::CallResult; use client::tests::prepare_client_with_key_changes; use executor::{self, NativeExecutionDispatch}; use error::Error as ClientError; @@ -410,12 +408,12 @@ pub mod tests { use state_machine::Backend; use super::*; - pub type OkCallFetcher = Mutex; + pub type OkCallFetcher = Mutex>; impl Fetcher for OkCallFetcher { type RemoteHeaderResult = FutureResult; type RemoteReadResult = FutureResult>, ClientError>; - type RemoteCallResult = FutureResult; + type RemoteCallResult = FutureResult, ClientError>; type RemoteChangesResult = FutureResult, u32)>, ClientError>; fn remote_header(&self, _request: RemoteHeaderRequest
) -> Self::RemoteHeaderResult { diff --git a/substrate/core/executor/src/lib.rs b/substrate/core/executor/src/lib.rs index 5f05b33f53..ae2b383ae7 100644 --- a/substrate/core/executor/src/lib.rs +++ b/substrate/core/executor/src/lib.rs @@ -44,9 +44,6 @@ extern crate parking_lot; #[macro_use] extern crate log; -#[macro_use] -extern crate lazy_static; - #[macro_use] extern crate error_chain; @@ -84,7 +81,5 @@ pub trait RuntimeInfo { fn runtime_version> ( &self, ext: &mut E, - heap_pages: usize, - code: &[u8] ) -> Option; } diff --git a/substrate/core/executor/src/native_executor.rs b/substrate/core/executor/src/native_executor.rs index 15cc8abac3..09606bc904 100644 --- a/substrate/core/executor/src/native_executor.rs +++ b/substrate/core/executor/src/native_executor.rs @@ -14,38 +14,34 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . +use std::borrow::BorrowMut; +use std::cell::{RefMut, RefCell}; use error::{Error, ErrorKind, Result}; use state_machine::{CodeExecutor, Externalities}; use wasm_executor::WasmExecutor; -use wasmi::Module as WasmModule; +use wasmi::{Module as WasmModule, ModuleRef as WasmModuleInstanceRef}; use runtime_version::{NativeVersion, RuntimeVersion}; use std::collections::HashMap; use codec::Decode; -use primitives::hashing::blake2_256; -use parking_lot::{Mutex, MutexGuard}; use RuntimeInfo; use primitives::Blake2Hasher; +use primitives::storage::well_known_keys; + +/// 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(WasmModule, Option), + ValidCode(WasmModuleInstanceRef, Option), } type CacheType = HashMap<[u8; 32], RuntimePreproc>; -lazy_static! { - static ref RUNTIMES_CACHE: Mutex = Mutex::new(HashMap::new()); -} - -// helper function to generate low-over-head caching_keys -// it is asserted that part of the audit process that any potential on-chain code change -// will have done is to ensure that the two-x hash is different to that of any other -// :code value from the same chain -fn gen_cache_key(code: &[u8]) -> [u8; 32] { - blake2_256(code) +thread_local! { + static RUNTIMES_CACHE: RefCell = RefCell::new(HashMap::new()); } /// fetch a runtime version from the cache or if there is no cached version yet, create @@ -53,27 +49,48 @@ fn gen_cache_key(code: &[u8]) -> [u8; 32] { /// can be used by comparing returned RuntimeVersion to `ref_version` fn fetch_cached_runtime_version<'a, E: Externalities>( wasm_executor: &WasmExecutor, - cache: &'a mut MutexGuard, + cache: &'a mut RefMut, ext: &mut E, - heap_pages: usize, - code: &[u8] -) -> Result<(&'a WasmModule, &'a Option)> { - let maybe_runtime_preproc = cache.entry(gen_cache_key(code)) - .or_insert_with(|| match WasmModule::from_buffer(code) { - Ok(module) => { - let version = wasm_executor.call_in_wasm_module(ext, heap_pages, &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 +) -> Result<(&'a WasmModuleInstanceRef, &'a Option)> { + + let code_hash = match ext.storage_hash(well_known_keys::CODE) { + Some(code_hash) => code_hash, + None => return Err(ErrorKind::InvalidCode(vec![]).into()), + }; + let maybe_runtime_preproc = cache.borrow_mut().entry(code_hash.into()) + .or_insert_with(|| { + let code = match ext.storage(well_known_keys::CODE) { + Some(code) => code, + None => return RuntimePreproc::InvalidCode, + }; + let heap_pages = match ext.storage(well_known_keys::HEAP_PAGES) { + Some(pages) => u64::decode(&mut &pages[..]).unwrap_or(DEFAULT_HEAP_PAGES), + None => DEFAULT_HEAP_PAGES, + }; + match WasmModule::from_buffer(code) + .map_err(|_| ErrorKind::InvalidCode(vec![]).into()) + .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 => Err(ErrorKind::InvalidCode(code.into()).into()), - RuntimePreproc::ValidCode(m, v) => Ok((m, v)), + RuntimePreproc::InvalidCode => { + let code = ext.storage(well_known_keys::CODE).unwrap_or(vec![]); + Err(ErrorKind::InvalidCode(code).into()) + }, + RuntimePreproc::ValidCode(m, v) => { + Ok((m, v)) + } } } @@ -154,10 +171,10 @@ impl RuntimeInfo for NativeExecutor { fn runtime_version>( &self, ext: &mut E, - heap_pages: usize, - code: &[u8], ) -> Option { - fetch_cached_runtime_version(&self.fallback, &mut RUNTIMES_CACHE.lock(), ext, heap_pages, code).ok()?.1.clone() + RUNTIMES_CACHE.with(|c| + fetch_cached_runtime_version(&self.fallback, &mut c.borrow_mut(), ext).ok()?.1.clone() + ) } } @@ -167,30 +184,30 @@ impl CodeExecutor for NativeExecutor>( &self, ext: &mut E, - heap_pages: usize, - code: &[u8], method: &str, data: &[u8], use_native: bool, ) -> (Result>, bool) { - let mut c = RUNTIMES_CACHE.lock(); - let (module, onchain_version) = match fetch_cached_runtime_version(&self.fallback, &mut c, ext, heap_pages, code) { - Ok((module, onchain_version)) => (module, onchain_version), - Err(_) => return (Err(ErrorKind::InvalidCode(code.into()).into()), false), - }; - match (use_native, onchain_version.as_ref().map_or(false, |v| v.can_call_with(&self.native_version.runtime_version))) { - (_, false) => { - trace!(target: "executor", "Request for native execution failed (native: {}, chain: {})", self.native_version.runtime_version, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); - (self.fallback.call_in_wasm_module(ext, heap_pages, module, method, data), false) + RUNTIMES_CACHE.with(|c| { + let mut c = c.borrow_mut(); + let (module, onchain_version) = match fetch_cached_runtime_version(&self.fallback, &mut c, ext) { + Ok((module, onchain_version)) => (module, onchain_version), + Err(e) => return (Err(e), false), + }; + match (use_native, onchain_version.as_ref().map_or(false, |v| v.can_call_with(&self.native_version.runtime_version))) { + (_, false) => { + trace!(target: "executor", "Request for native execution failed (native: {}, chain: {})", self.native_version.runtime_version, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); + (self.fallback.call_in_wasm_module(ext, module, method, data), false) + } + (false, _) => { + (self.fallback.call_in_wasm_module(ext, module, method, data), false) + } + _ => { + trace!(target: "executor", "Request for native execution succeeded (native: {}, chain: {})", self.native_version.runtime_version, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); + (D::dispatch(ext, method, data), true) + } } - (false, _) => { - (self.fallback.call_in_wasm_module(ext, heap_pages, module, method, data), false) - } - _ => { - trace!(target: "executor", "Request for native execution succeeded (native: {}, chain: {})", self.native_version.runtime_version, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); - (D::dispatch(ext, method, data), true) - } - } + }) } } diff --git a/substrate/core/executor/src/wasm_executor.rs b/substrate/core/executor/src/wasm_executor.rs index 40357946f0..60e2c84b1e 100644 --- a/substrate/core/executor/src/wasm_executor.rs +++ b/substrate/core/executor/src/wasm_executor.rs @@ -19,10 +19,10 @@ use std::collections::HashMap; use wasmi::{ - Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder + Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder, ModuleRef, }; use wasmi::RuntimeValue::{I32, I64}; -use wasmi::memory_units::{Pages, Bytes}; +use wasmi::memory_units::Pages; use state_machine::Externalities; use error::{Error, ErrorKind, Result}; use wasm_utils::UserError; @@ -39,19 +39,17 @@ struct Heap { } impl Heap { - /// Construct new `Heap` struct with a given number of pages. + /// Construct new `Heap` struct. /// /// Returns `Err` if the heap couldn't allocate required /// number of pages. /// /// This could mean that wasm binary specifies memory /// limit and we are trying to allocate beyond that limit. - fn new(memory: &MemoryRef, pages: usize) -> Result { - let prev_page_count = memory.initial(); - memory.grow(Pages(pages)).map_err(|_| Error::from(ErrorKind::Runtime))?; - Ok(Heap { - end: Bytes::from(prev_page_count).0 as u32, - }) + fn new(memory: &MemoryRef) -> Self { + Heap { + end: memory.used_size().0 as u32, + } } fn allocate(&mut self, size: u32) -> u32 { @@ -83,10 +81,10 @@ struct FunctionExecutor<'e, E: Externalities + 'e> { } impl<'e, E: Externalities> FunctionExecutor<'e, E> { - fn new(m: MemoryRef, heap_pages: usize, t: Option, e: &'e mut E) -> Result { + fn new(m: MemoryRef, t: Option, e: &'e mut E) -> Result { Ok(FunctionExecutor { sandbox_store: sandbox::Store::new(), - heap: Heap::new(&m, heap_pages)?, + heap: Heap::new(&m), memory: m, table: t, ext: e, @@ -638,51 +636,43 @@ impl WasmExecutor { method: &str, data: &[u8], ) -> Result> { - let module = ::wasmi::Module::from_buffer(code).expect("all modules compiled with rustc are valid wasm code; qed"); - self.call_in_wasm_module(ext, heap_pages, &module, method, data) + let module = ::wasmi::Module::from_buffer(code)?; + let module = self.prepare_module(ext, heap_pages, &module)?; + self.call_in_wasm_module(ext, &module, method, data) + } + + fn get_mem_instance(module: &ModuleRef) -> Result { + Ok(module + .export_by_name("memory") + .ok_or_else(|| Error::from(ErrorKind::InvalidMemoryReference))? + .as_memory() + .ok_or_else(|| Error::from(ErrorKind::InvalidMemoryReference))? + .clone()) } /// Call a given method in the given wasm-module runtime. pub fn call_in_wasm_module>( &self, ext: &mut E, - heap_pages: usize, - module: &Module, + module_instance: &ModuleRef, method: &str, data: &[u8], ) -> Result> { - // start module instantiation. Don't run 'start' function yet. - let intermediate_instance = ModuleInstance::new( - module, - &ImportsBuilder::new() - .with_resolver("env", FunctionExecutor::::resolver()) - )?; - // extract a reference to a linear memory, optional reference to a table // and then initialize FunctionExecutor. - let memory = intermediate_instance - .not_started_instance() - .export_by_name("memory") - // TODO: with code coming from the blockchain it isn't strictly been compiled with rustc anymore. - // these assumptions are probably not true anymore - .expect("all modules compiled with rustc should have an export named 'memory'; qed") - .as_memory() - .expect("in module generated by rustc export named 'memory' should be a memory; qed") - .clone(); - let table: Option = intermediate_instance - .not_started_instance() + let memory = Self::get_mem_instance(module_instance)?; + let table: Option = module_instance .export_by_name("__indirect_function_table") .and_then(|e| e.as_table().cloned()); - let mut fec = FunctionExecutor::new(memory.clone(), heap_pages, table, ext)?; - - // finish instantiation by running 'start' function (if any). - let instance = intermediate_instance.run_start(&mut fec)?; + let low = memory.lowest_used(); + let used_mem = memory.used_size(); + let mut fec = FunctionExecutor::new(memory.clone(), table, ext)?; let size = data.len() as u32; let offset = fec.heap.allocate(size); memory.set(offset, &data)?; - let result = instance.invoke_export( + let result = module_instance.invoke_export( method, &[ I32(offset as i32), @@ -690,22 +680,57 @@ impl WasmExecutor { ], &mut fec ); - let returned = match result { - Ok(x) => x, + let result = match result { + Ok(Some(I64(r))) => { + let offset = r as u32; + let length = (r >> 32) as u32 as usize; + memory.get(offset, length) + .map_err(|_| ErrorKind::Runtime.into()) + }, + Ok(_) => Err(ErrorKind::InvalidReturn.into()), Err(e) => { - trace!(target: "wasm-executor", "Failed to execute code with {} pages", heap_pages); - return Err(e.into()) + trace!(target: "wasm-executor", "Failed to execute code with {} pages", memory.current_size().0); + Err(e.into()) }, }; - if let Some(I64(r)) = returned { - let offset = r as u32; - let length = (r >> 32) as u32 as usize; - memory.get(offset, length) - .map_err(|_| ErrorKind::Runtime.into()) - } else { - Err(ErrorKind::InvalidReturn.into()) + // 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 + } + + /// Prepare module instance + pub fn prepare_module>( + &self, + ext: &mut E, + heap_pages: usize, + module: &Module, + ) -> Result + { + // start module instantiation. Don't run 'start' function yet. + let intermediate_instance = ModuleInstance::new( + module, + &ImportsBuilder::new() + .with_resolver("env", FunctionExecutor::::resolver()) + )?; + + // extract a reference to a linear memory, optional reference to a table + // and then initialize FunctionExecutor. + let memory = Self::get_mem_instance(intermediate_instance.not_started_instance())?; + memory.grow(Pages(heap_pages)).map_err(|_| Error::from(ErrorKind::Runtime))?; + let table: Option = intermediate_instance + .not_started_instance() + .export_by_name("__indirect_function_table") + .and_then(|e| e.as_table().cloned()); + let mut fec = FunctionExecutor::new(memory.clone(), table, ext)?; + + // finish instantiation by running 'start' function (if any). + Ok(intermediate_instance.run_start(&mut fec)?) } } diff --git a/substrate/core/network/src/on_demand.rs b/substrate/core/network/src/on_demand.rs index 0c5140f2fe..db56eaf592 100644 --- a/substrate/core/network/src/on_demand.rs +++ b/substrate/core/network/src/on_demand.rs @@ -24,7 +24,7 @@ use futures::sync::oneshot::{channel, Receiver, Sender}; use linked_hash_map::LinkedHashMap; use linked_hash_map::Entry; use parking_lot::Mutex; -use client::{self, error::{Error as ClientError, ErrorKind as ClientErrorKind}}; +use client::{error::{Error as ClientError, ErrorKind as ClientErrorKind}}; use client::light::fetcher::{Fetcher, FetchChecker, RemoteHeaderRequest, RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof}; use io::SyncIo; @@ -107,7 +107,7 @@ struct Request { enum RequestData { RemoteHeader(RemoteHeaderRequest, Sender>), RemoteRead(RemoteReadRequest, Sender>, ClientError>>), - RemoteCall(RemoteCallRequest, Sender>), + RemoteCall(RemoteCallRequest, Sender, ClientError>>), RemoteChanges(RemoteChangesRequest, Sender, u32)>, ClientError>>), } @@ -312,7 +312,7 @@ impl Fetcher for OnDemand where { type RemoteHeaderResult = RemoteResponse; type RemoteReadResult = RemoteResponse>>; - type RemoteCallResult = RemoteResponse; + type RemoteCallResult = RemoteResponse>; type RemoteChangesResult = RemoteResponse, u32)>>; fn remote_header(&self, request: RemoteHeaderRequest) -> Self::RemoteHeaderResult { @@ -529,7 +529,7 @@ pub mod tests { use futures::Future; use parking_lot::RwLock; use runtime_primitives::traits::NumberFor; - use client::{self, error::{ErrorKind as ClientErrorKind, Result as ClientResult}}; + use client::{error::{ErrorKind as ClientErrorKind, Result as ClientResult}}; use client::light::fetcher::{Fetcher, FetchChecker, RemoteHeaderRequest, RemoteCallRequest, RemoteReadRequest, RemoteChangesRequest, ChangesProof}; use config::Roles; @@ -567,12 +567,9 @@ pub mod tests { } } - fn check_execution_proof(&self, _: &RemoteCallRequest
, _: Vec>) -> ClientResult { + fn check_execution_proof(&self, _: &RemoteCallRequest
, _: Vec>) -> ClientResult> { match self.ok { - true => Ok(client::CallResult { - return_data: vec![42], - changes: Default::default(), - }), + true => Ok(vec![42]), false => Err(ClientErrorKind::Backend("Test error".into()).into()), } } @@ -796,7 +793,7 @@ pub mod tests { }); let thread = ::std::thread::spawn(move || { let result = response.wait().unwrap(); - assert_eq!(result.return_data, vec![42]); + assert_eq!(result, vec![42]); }); receive_call_response(&*on_demand, &mut network, 0, 0); diff --git a/substrate/core/rpc/src/lib.rs b/substrate/core/rpc/src/lib.rs index e96078ff6e..2e7d4b1fa8 100644 --- a/substrate/core/rpc/src/lib.rs +++ b/substrate/core/rpc/src/lib.rs @@ -37,7 +37,6 @@ extern crate error_chain; extern crate jsonrpc_macros; #[macro_use] extern crate log; -#[macro_use] extern crate serde_derive; #[cfg(test)] diff --git a/substrate/core/rpc/src/state/mod.rs b/substrate/core/rpc/src/state/mod.rs index d044962f0a..19f4046aa8 100644 --- a/substrate/core/rpc/src/state/mod.rs +++ b/substrate/core/rpc/src/state/mod.rs @@ -144,8 +144,7 @@ impl StateApi for State where .call( &BlockId::Hash(block), &method, &data.0 - )? - .return_data; + )?; Ok(Bytes(return_data)) } diff --git a/substrate/core/state-machine/src/backend.rs b/substrate/core/state-machine/src/backend.rs index f9949deae9..ea1d19859e 100644 --- a/substrate/core/state-machine/src/backend.rs +++ b/substrate/core/state-machine/src/backend.rs @@ -40,10 +40,15 @@ pub trait Backend { /// Type of trie backend storage. type TrieBackendStorage: TrieBackendStorage; - /// 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>, 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, 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>, Self::Error>; /// true if a key exists in storage. diff --git a/substrate/core/state-machine/src/ext.rs b/substrate/core/state-machine/src/ext.rs index 1bcb3fb732..6274eef720 100644 --- a/substrate/core/state-machine/src/ext.rs +++ b/substrate/core/state-machine/src/ext.rs @@ -184,6 +184,11 @@ where self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL)) } + fn storage_hash(&self, key: &[u8]) -> Option { + 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> { 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)) diff --git a/substrate/core/state-machine/src/lib.rs b/substrate/core/state-machine/src/lib.rs index 5f9757bd55..bc0189d398 100644 --- a/substrate/core/state-machine/src/lib.rs +++ b/substrate/core/state-machine/src/lib.rs @@ -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 { - /// Read storage of current contract being called. + /// Read runtime storage. fn storage(&self, key: &[u8]) -> Option>; - /// 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 { + self.storage(key).map(|v| H::hash(&v)) + } + + /// Read child runtime storage. fn child_storage(&self, storage_key: &[u8], key: &[u8]) -> Option>; /// Set storage entry `key` of current contract being called (effective immediately). @@ -171,8 +173,6 @@ pub trait CodeExecutor: Sized + Send + Sync { fn call>( &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)? - .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>( &self, ext: &mut E, - _heap_pages: usize, - _code: &[u8], _method: &str, _data: &[u8], use_native: bool diff --git a/substrate/core/state-machine/src/overlayed_changes.rs b/substrate/core/state-machine/src/overlayed_changes.rs index 29ff7262da..3a208ad3e2 100644 --- a/substrate/core/state-machine/src/overlayed_changes.rs +++ b/substrate/core/state-machine/src/overlayed_changes.rs @@ -44,7 +44,7 @@ pub struct OverlayedValue { /// Current value. None if value has been deleted. pub value: Option>, /// 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>, } diff --git a/substrate/core/state-machine/src/testing.rs b/substrate/core/state-machine/src/testing.rs index 876a190a96..b9f14f18e5 100644 --- a/substrate/core/state-machine/src/testing.rs +++ b/substrate/core/state-machine/src/testing.rs @@ -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 where H::Out: HeapSizeOf { inner: HashMap, Vec>, changes_trie_storage: ChangesTrieInMemoryStorage, changes: OverlayedChanges, + code: Vec, } impl TestExternalities where H::Out: HeapSizeOf { /// Create a new instance of `TestExternalities` pub fn new(inner: HashMap, Vec>) -> Self { + Self::new_with_code(&[], inner) + } + + /// Create a new instance of `TestExternalities` + pub fn new_with_code(code: &[u8], inner: HashMap, Vec>) -> Self { let mut overlay = OverlayedChanges::default(); super::set_changes_trie_config( &mut overlay, @@ -47,6 +54,7 @@ impl TestExternalities where H::Out: HeapSizeOf { inner, changes_trie_storage: ChangesTrieInMemoryStorage::new(), changes: overlay, + code: code.to_vec(), } } @@ -94,13 +102,18 @@ impl From< HashMap, Vec> > for TestExternalities where inner: hashmap, changes_trie_storage: ChangesTrieInMemoryStorage::new(), changes: Default::default(), + code: Default::default(), } } } impl Externalities for TestExternalities where H::Out: Ord + HeapSizeOf { fn storage(&self, key: &[u8]) -> Option> { - 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> { diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 81ebc41cba2fd76b0f351690a23482ac162df581..56ba7e35f138a83916bd8f93c578ab046b606de7 100644 GIT binary patch delta 7135 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 b_QHuxEiqWNs;06AjYngd-dMahp6dR8z=}Co delta 7787 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::new(map![ + let mut t = TestExternalities::::new_with_code(BLOATY_CODE, map![ twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![70u8; 16], @@ -134,16 +134,16 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let r = executor().call(&mut t, 8, BLOATY_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = executor().call(&mut t, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; assert!(r.is_ok()); - let v = executor().call(&mut t, 8, BLOATY_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0.unwrap(); + let v = executor().call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0.unwrap(); let r = ApplyResult::decode(&mut &v[..]).unwrap(); assert_eq!(r, Err(ApplyError::CantPay)); } #[test] fn bad_extrinsic_with_native_equivalent_code_gives_error() { - let mut t = TestExternalities::::new(map![ + let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![70u8; 16], @@ -155,16 +155,16 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let r = executor().call(&mut t, 8, COMPACT_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = executor().call(&mut t, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; assert!(r.is_ok()); - let v = executor().call(&mut t, 8, COMPACT_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0.unwrap(); + let v = executor().call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0.unwrap(); let r = ApplyResult::decode(&mut &v[..]).unwrap(); assert_eq!(r, Err(ApplyError::CantPay)); } #[test] fn successful_execution_with_native_equivalent_code_gives_ok() { - let mut t = TestExternalities::::new(map![ + let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![0u8; 16], @@ -176,9 +176,9 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let r = executor().call(&mut t, 8, COMPACT_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = executor().call(&mut t, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; assert!(r.is_ok()); - let r = executor().call(&mut t, 8, COMPACT_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; + let r = executor().call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { @@ -189,7 +189,7 @@ mod tests { #[test] fn successful_execution_with_foreign_code_gives_ok() { - let mut t = TestExternalities::::new(map![ + let mut t = TestExternalities::::new_with_code(BLOATY_CODE, map![ twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![0u8; 16], @@ -201,9 +201,9 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let r = executor().call(&mut t, 8, BLOATY_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = executor().call(&mut t, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; assert!(r.is_ok()); - let r = executor().call(&mut t, 8, BLOATY_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; + let r = executor().call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { @@ -212,10 +212,10 @@ mod tests { }); } - fn new_test_ext(support_changes_trie: bool) -> TestExternalities { + fn new_test_ext(code: &[u8], support_changes_trie: bool) -> TestExternalities { use keyring::Keyring::*; let three = [3u8; 32].into(); - TestExternalities::new(GenesisConfig { + TestExternalities::new_with_code(code, GenesisConfig { consensus: Some(Default::default()), system: Some(SystemConfig { changes_trie_config: if support_changes_trie { Some(ChangesTrieConfiguration { @@ -387,9 +387,9 @@ mod tests { #[test] fn full_native_block_import_works() { - let mut t = new_test_ext(false); + let mut t = new_test_ext(COMPACT_CODE, false); - executor().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(false).0, true).0.unwrap(); + executor().call(&mut t, "Core_execute_block", &block1(false).0, true).0.unwrap(); runtime_io::with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 41); @@ -431,7 +431,7 @@ mod tests { ]); }); - executor().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2().0, true).0.unwrap(); + executor().call(&mut t, "Core_execute_block", &block2().0, true).0.unwrap(); runtime_io::with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 30); @@ -505,7 +505,7 @@ mod tests { #[test] fn full_wasm_block_import_works() { - let mut t = new_test_ext(false); + let mut t = new_test_ext(COMPACT_CODE, false); WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(false).0).unwrap(); @@ -646,7 +646,7 @@ mod tests { #[test] fn deploying_wasm_contract_should_work() { - let mut t = new_test_ext(false); + let mut t = new_test_ext(COMPACT_CODE, false); let code_transfer = wabt::wat2wasm(CODE_TRANSFER).unwrap(); let code_ctor_transfer = wabt::wat2wasm(&code_ctor(&code_transfer)).unwrap(); @@ -682,7 +682,7 @@ mod tests { ] ); - WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &b.0).unwrap(); + WasmExecutor::new().call(&mut t, 8, COMPACT_CODE,"Core_execute_block", &b.0).unwrap(); runtime_io::with_externalities(&mut t, || { // Verify that the contract constructor worked well and code of TRANSFER contract is actually deployed. @@ -692,7 +692,7 @@ mod tests { #[test] fn wasm_big_block_import_fails() { - let mut t = new_test_ext(false); + let mut t = new_test_ext(COMPACT_CODE, false); assert!( WasmExecutor::new().call( @@ -707,12 +707,10 @@ mod tests { #[test] fn native_big_block_import_succeeds() { - let mut t = new_test_ext(false); + let mut t = new_test_ext(COMPACT_CODE, false); Executor::new().call( &mut t, - 8, - COMPACT_CODE, "Core_execute_block", &block1big().0, true @@ -721,13 +719,11 @@ mod tests { #[test] fn native_big_block_import_fails_on_fallback() { - let mut t = new_test_ext(false); + let mut t = new_test_ext(COMPACT_CODE, false); assert!( Executor::new().call( &mut t, - 8, - COMPACT_CODE, "Core_execute_block", &block1big().0, false @@ -737,7 +733,8 @@ mod tests { #[test] fn panic_execution_gives_error() { - let mut t = TestExternalities::::new(map![ + let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm"); + let mut t = TestExternalities::::new_with_code(foreign_code, map![ twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![70u8; 16], @@ -749,17 +746,17 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm"); - let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "Core_initialise_block", &vec![].and(&from_block_number(1u64))); + let r = WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64))); assert!(r.is_ok()); - let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).unwrap(); + let r = WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).unwrap(); let r = ApplyResult::decode(&mut &r[..]).unwrap(); assert_eq!(r, Err(ApplyError::CantPay)); } #[test] fn successful_execution_gives_ok() { - let mut t = TestExternalities::::new(map![ + let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm"); + let mut t = TestExternalities::::new_with_code(foreign_code, map![ twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(>::key()).to_vec() => vec![0u8; 16], @@ -771,10 +768,9 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm"); - let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "Core_initialise_block", &vec![].and(&from_block_number(1u64))); + let r = WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_initialise_block", &vec![].and(&from_block_number(1u64))); assert!(r.is_ok()); - let r = WasmExecutor::new().call(&mut t, 8, &foreign_code[..], "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).unwrap(); + let r = WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).unwrap(); let r = ApplyResult::decode(&mut &r[..]).unwrap(); assert_eq!(r, Ok(ApplyOutcome::Success)); @@ -786,15 +782,15 @@ mod tests { #[test] fn full_native_block_import_works_with_changes_trie() { - let mut t = new_test_ext(true); - Executor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(true).0, true).0.unwrap(); + let mut t = new_test_ext(COMPACT_CODE, true); + Executor::new().call(&mut t, "Core_execute_block", &block1(true).0, true).0.unwrap(); assert!(t.storage_changes_root(Default::default(), 0).is_some()); } #[test] fn full_wasm_block_import_works_with_changes_trie() { - let mut t = new_test_ext(true); + let mut t = new_test_ext(COMPACT_CODE, true); WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(true).0).unwrap(); assert!(t.storage_changes_root(Default::default(), 0).is_some()); @@ -808,9 +804,9 @@ mod tests { #[bench] fn wasm_execute_block(b: &mut Bencher) { b.iter(|| { - let mut t = new_test_ext(false); - WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1(false).0).unwrap(); - WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2().0).unwrap(); + let mut t = new_test_ext(COMPACT_CODE, false); + WasmExecutor::new().call(&mut t, "Core_execute_block", &block1(false).0).unwrap(); + WasmExecutor::new().call(&mut t, "Core_execute_block", &block2().0).unwrap(); }); } } diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index b73bd2e691a2704cdf31e0ba762d627c57ed11c1..657189d728982a285676bb91353fb1a98e30e24a 100644 GIT binary patch delta 86591 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%0A)uiyorl{1^EG2%Y^jn5I)gHHS2o1Jj5?WJPm+- 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 delta 87779 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