diff --git a/Cargo.lock b/Cargo.lock index 6ff9929eb7837..7edf2b97e2a97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1973,6 +1973,7 @@ dependencies = [ "srml-treasury 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-consensus-authorities 0.1.0", "substrate-keyring 0.1.0", "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", @@ -2030,6 +2031,7 @@ dependencies = [ "srml-timestamp 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-consensus-authorities 0.1.0", "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", ] @@ -3713,6 +3715,7 @@ dependencies = [ "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "substrate-client 0.1.0", + "substrate-consensus-common 0.1.0", "substrate-executor 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", @@ -3741,6 +3744,7 @@ dependencies = [ "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-aura-slots 0.1.0", + "substrate-consensus-authorities 0.1.0", "substrate-consensus-common 0.1.0", "substrate-executor 0.1.0", "substrate-inherents 0.1.0", @@ -3779,6 +3783,20 @@ dependencies = [ "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-consensus-authorities" +version = "0.1.0" +dependencies = [ + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", + "sr-primitives 0.1.0", + "sr-std 0.1.0", + "sr-version 0.1.0", + "srml-support 0.1.0", + "substrate-client 0.1.0", + "substrate-primitives 0.1.0", +] + [[package]] name = "substrate-consensus-common" version = "0.1.0" @@ -4251,6 +4269,7 @@ dependencies = [ "srml-support 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-consensus-authorities 0.1.0", "substrate-executor 0.1.0", "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", diff --git a/README.adoc b/README.adoc index cf0e1970a7f59..92a5418170fb9 100644 --- a/README.adoc +++ b/README.adoc @@ -63,10 +63,6 @@ impl_runtime_apis! { VERSION } - fn authorities() -> Vec { - Consensus::authorities() - } - fn execute_block(block: Block) { Executive::execute_block(block) } diff --git a/core/client/db/Cargo.toml b/core/client/db/Cargo.toml index 7fc1cc5d95750..cc6e38d0174e5 100644 --- a/core/client/db/Cargo.toml +++ b/core/client/db/Cargo.toml @@ -26,6 +26,7 @@ trie = { package = "substrate-trie", path = "../../trie" } kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } substrate-keyring = { path = "../../keyring" } test-client = { package = "substrate-test-client", path = "../../test-client" } +consensus_common = { package = "substrate-consensus-common", path = "../../consensus/common" } env_logger = { version = "0.6" } [features] diff --git a/core/client/db/src/cache/mod.rs b/core/client/db/src/cache/mod.rs index 3d669e392d01c..93555f3c1528e 100644 --- a/core/client/db/src/cache/mod.rs +++ b/core/client/db/src/cache/mod.rs @@ -16,7 +16,7 @@ //! DB-backed cache of blockchain data. -use std::sync::Arc; +use std::{sync::Arc, collections::HashMap}; use parking_lot::RwLock; use kvdb::{KeyValueDB, DBTransaction}; @@ -25,7 +25,7 @@ use client::blockchain::Cache as BlockchainCache; use client::error::Result as ClientResult; use parity_codec::{Encode, Decode}; use runtime_primitives::generic::BlockId; -use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, As, AuthorityIdFor}; +use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, As}; use crate::utils::{self, COLUMN_META}; use self::list_cache::ListCache; @@ -64,7 +64,12 @@ impl CacheItemT for T where T: Clone + Decode + Encode + PartialEq {} /// Database-backed blockchain data cache. pub struct DbCache { - authorities_at: ListCache>, self::list_storage::DbStorage>, + cache_at: HashMap, ListCache, self::list_storage::DbStorage>>, + db: Arc, + key_lookup_column: Option, + header_column: Option, + authorities_column: Option, + best_finalized_block: ComplexBlockId, } impl DbCache { @@ -76,19 +81,13 @@ impl DbCache { authorities_column: Option, best_finalized_block: ComplexBlockId, ) -> Self { - DbCache { - authorities_at: ListCache::new( - self::list_storage::DbStorage::new(b"auth".to_vec(), db, - self::list_storage::DbColumns { - meta: COLUMN_META, - key_lookup: key_lookup_column, - header: header_column, - cache: authorities_column, - }, - ), - As::sa(PRUNE_DEPTH), - best_finalized_block, - ), + Self { + cache_at: HashMap::new(), + db, + key_lookup_column, + header_column, + authorities_column, + best_finalized_block, } } @@ -97,35 +96,82 @@ impl DbCache { DbCacheTransaction { cache: self, tx, - authorities_at_op: None, + cache_at_op: HashMap::new(), + best_finalized_block: None, } } /// Run post-commit cache operations. pub fn commit(&mut self, ops: DbCacheTransactionOps) { - if let Some(authorities_at_op) = ops.authorities_at_op { - self.authorities_at.on_transaction_commit(authorities_at_op); + for (name, op) in ops.cache_at_op.into_iter() { + self.get_cache(name).on_transaction_commit(op); + } + if let Some(best_finalized_block) = ops.best_finalized_block { + self.best_finalized_block = best_finalized_block; } } + + /// Creates `ListCache` with the given name or returns a reference to the existing. + fn get_cache(&mut self, name: Vec) -> &mut ListCache, self::list_storage::DbStorage> { + get_cache_helper( + &mut self.cache_at, + name, + &self.db, + self.key_lookup_column, + self.header_column, + self.authorities_column, + &self.best_finalized_block + ) + } +} + +// This helper is needed because otherwise the borrow checker will require to +// clone all parameters outside of the closure. +fn get_cache_helper<'a, Block: BlockT>( + cache_at: &'a mut HashMap, ListCache, self::list_storage::DbStorage>>, + name: Vec, + db: &Arc, + key_lookup: Option, + header: Option, + cache: Option, + best_finalized_block: &ComplexBlockId, +) -> &'a mut ListCache, self::list_storage::DbStorage> { + cache_at.entry(name.clone()).or_insert_with(|| { + ListCache::new( + self::list_storage::DbStorage::new(name, db.clone(), + self::list_storage::DbColumns { + meta: COLUMN_META, + key_lookup, + header, + cache, + }, + ), + As::sa(PRUNE_DEPTH), + best_finalized_block.clone(), + ) + }) } /// Cache operations that are to be committed after database transaction is committed. pub struct DbCacheTransactionOps { - authorities_at_op: Option>>>, + cache_at_op: HashMap, self::list_cache::CommitOperation>>, + best_finalized_block: Option>, } /// Database-backed blockchain data cache transaction valid for single block import. pub struct DbCacheTransaction<'a, Block: BlockT> { cache: &'a mut DbCache, tx: &'a mut DBTransaction, - authorities_at_op: Option>>>, + cache_at_op: HashMap, self::list_cache::CommitOperation>>, + best_finalized_block: Option>, } impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { /// Convert transaction into post-commit operations set. pub fn into_ops(self) -> DbCacheTransactionOps { DbCacheTransactionOps { - authorities_at_op: self.authorities_at_op, + cache_at_op: self.cache_at_op, + best_finalized_block: self.best_finalized_block, } } @@ -134,21 +180,42 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { mut self, parent: ComplexBlockId, block: ComplexBlockId, - authorities_at: Option>>, + data_at: HashMap, Vec>, is_final: bool, ) -> ClientResult { - assert!(self.authorities_at_op.is_none()); + assert!(self.cache_at_op.is_empty()); - self.authorities_at_op = self.cache.authorities_at.on_block_insert( - &mut self::list_storage::DbStorageTransaction::new( - self.cache.authorities_at.storage(), - &mut self.tx - ), - parent, - block, - authorities_at, - is_final, - )?; + // prepare list of caches that are not update + // (we might still need to do some cache maintenance in this case) + let missed_caches = self.cache.cache_at.keys() + .filter(|cache| !data_at.contains_key(cache.clone())) + .cloned() + .collect::>(); + + let mut insert_op = |name: Vec, value: Option>| -> Result<(), client::error::Error> { + let cache = self.cache.get_cache(name.clone()); + let op = cache.on_block_insert( + &mut self::list_storage::DbStorageTransaction::new( + cache.storage(), + &mut self.tx, + ), + parent.clone(), + block.clone(), + value.or(cache.value_at_block(&parent)?), + is_final, + )?; + if let Some(op) = op { + self.cache_at_op.insert(name, op); + } + Ok(()) + }; + + data_at.into_iter().try_for_each(|(name, data)| insert_op(name, Some(data)))?; + missed_caches.into_iter().try_for_each(|name| insert_op(name, None))?; + + if is_final { + self.best_finalized_block = Some(block); + } Ok(self) } @@ -159,16 +226,24 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { parent: ComplexBlockId, block: ComplexBlockId ) -> ClientResult { - assert!(self.authorities_at_op.is_none()); + assert!(self.cache_at_op.is_empty()); - self.authorities_at_op = self.cache.authorities_at.on_block_finalize( - &mut self::list_storage::DbStorageTransaction::new( - self.cache.authorities_at.storage(), - &mut self.tx - ), - parent, - block, - )?; + for (name, cache_at) in self.cache.cache_at.iter() { + let op = cache_at.on_block_finalize( + &mut self::list_storage::DbStorageTransaction::new( + cache_at.storage(), + &mut self.tx + ), + parent.clone(), + block.clone(), + )?; + + if let Some(op) = op { + self.cache_at_op.insert(name.to_owned(), op); + } + } + + self.best_finalized_block = Some(block); Ok(self) } @@ -178,12 +253,12 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { pub struct DbCacheSync(pub RwLock>); impl BlockchainCache for DbCacheSync { - fn authorities_at(&self, at: BlockId) -> Option>> { + fn get_at(&self, key: &[u8], at: &BlockId) -> Option> { let cache = self.0.read(); - let storage = cache.authorities_at.storage(); + let storage = cache.cache_at.get(key)?.storage(); let db = storage.db(); let columns = storage.columns(); - let at = match at { + let at = match *at { BlockId::Hash(hash) => { let header = utils::read_header::( &**db, @@ -202,6 +277,7 @@ impl BlockchainCache for DbCacheSync { }, }; - cache.authorities_at.value_at_block(&at).ok()? + cache.cache_at.get(key)?.value_at_block(&at).ok()? } } + diff --git a/core/client/db/src/lib.rs b/core/client/db/src/lib.rs index 93adb990240a6..dde01bf9291c7 100644 --- a/core/client/db/src/lib.rs +++ b/core/client/db/src/lib.rs @@ -33,6 +33,7 @@ mod utils; use std::sync::Arc; use std::path::PathBuf; use std::io; +use std::collections::HashMap; use client::backend::NewBlockState; use client::blockchain::HeaderBackend; @@ -45,7 +46,7 @@ use parking_lot::RwLock; use primitives::{H256, Blake2Hasher, ChangesTrieConfiguration, convert_hash}; use primitives::storage::well_known_keys; use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; -use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor, Zero, Digest, DigestItem, AuthorityIdFor}; +use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberFor, Zero, Digest, DigestItem}; use runtime_primitives::BuildStorage; use state_machine::backend::Backend as StateBackend; use executor::RuntimeInfo; @@ -243,7 +244,7 @@ impl client::blockchain::Backend for BlockchainDb { Ok(self.meta.read().finalized_hash.clone()) } - fn cache(&self) -> Option<&client::blockchain::Cache> { + fn cache(&self) -> Option>> { None } @@ -256,6 +257,12 @@ impl client::blockchain::Backend for BlockchainDb { } } +impl client::blockchain::ProvideCache for BlockchainDb { + fn cache(&self) -> Option>> { + None + } +} + /// Database transaction pub struct BlockImportOperation { old_state: CachingState, @@ -306,8 +313,8 @@ where Block: BlockT, Ok(()) } - fn update_authorities(&mut self, _authorities: Vec>) { - // currently authorities are not cached on full nodes + fn update_cache(&mut self, _cache: HashMap, Vec>) { + // Currently cache isn't implemented on full nodes. } fn update_db_storage(&mut self, update: PrefixedMemoryDB) -> Result<(), client::error::Error> { diff --git a/core/client/db/src/light.rs b/core/client/db/src/light.rs index d99ef503b2f81..f064035d51ff0 100644 --- a/core/client/db/src/light.rs +++ b/core/client/db/src/light.rs @@ -16,7 +16,7 @@ //! RocksDB-based light client blockchain storage. -use std::sync::Arc; +use std::{sync::Arc, collections::HashMap}; use parking_lot::RwLock; use kvdb::{KeyValueDB, DBTransaction}; @@ -32,7 +32,7 @@ use parity_codec::{Decode, Encode}; use primitives::Blake2Hasher; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, - Zero, One, As, NumberFor, Digest, DigestItem, AuthorityIdFor}; + Zero, One, As, NumberFor, Digest, DigestItem}; use crate::cache::{DbCacheSync, DbCache, ComplexBlockId}; use crate::utils::{self, meta_keys, Meta, db_err, open_database, read_db, block_id_to_lookup_key, read_meta}; @@ -59,7 +59,7 @@ pub struct LightStorage { db: Arc, meta: RwLock, Block::Hash>>, leaves: RwLock>>, - cache: DbCacheSync, + cache: Arc>, } impl LightStorage @@ -96,7 +96,7 @@ impl LightStorage Ok(LightStorage { db, meta: RwLock::new(meta), - cache: DbCacheSync(RwLock::new(cache)), + cache: Arc::new(DbCacheSync(RwLock::new(cache))), leaves: RwLock::new(leaves), }) } @@ -370,7 +370,7 @@ impl LightBlockchainStorage for LightStorage fn import_header( &self, header: Block::Header, - authorities: Option>>, + cache_at: HashMap, Vec>, leaf_state: NewBlockState, aux_ops: Vec<(Vec, Option>)>, ) -> ClientResult<()> { @@ -432,7 +432,7 @@ impl LightBlockchainStorage for LightStorage .on_block_insert( ComplexBlockId::new(*header.parent_hash(), if number.is_zero() { Zero::zero() } else { number - One::one() }), ComplexBlockId::new(hash, number), - authorities, + cache_at, finalized, )? .into_ops(); @@ -521,8 +521,8 @@ impl LightBlockchainStorage for LightStorage Ok(self.meta.read().finalized_hash.clone()) } - fn cache(&self) -> Option<&BlockchainCache> { - Some(&self.cache) + fn cache(&self) -> Option>> { + Some(self.cache.clone()) } } @@ -538,6 +538,8 @@ pub(crate) mod tests { use client::cht; use runtime_primitives::generic::DigestItem; use runtime_primitives::testing::{H256 as Hash, Header, Block as RawBlock, ExtrinsicWrapper}; + use runtime_primitives::traits::AuthorityIdFor; + use consensus_common::well_known_cache_keys; use super::*; type Block = RawBlock>; @@ -567,41 +569,41 @@ pub(crate) mod tests { pub fn insert_block Header>( db: &LightStorage, - authorities: Option>>, + cache: HashMap, Vec>, header: F, ) -> Hash { let header = header(); let hash = header.hash(); - db.import_header(header, authorities, NewBlockState::Best, Vec::new()).unwrap(); + db.import_header(header, cache, NewBlockState::Best, Vec::new()).unwrap(); hash } fn insert_final_block Header>( db: &LightStorage, - authorities: Option>>, + cache: HashMap, Vec>, header: F, ) -> Hash { let header = header(); let hash = header.hash(); - db.import_header(header, authorities, NewBlockState::Final, Vec::new()).unwrap(); + db.import_header(header, cache, NewBlockState::Final, Vec::new()).unwrap(); hash } fn insert_non_best_block Header>( db: &LightStorage, - authorities: Option>>, + cache: HashMap, Vec>, header: F, ) -> Hash { let header = header(); let hash = header.hash(); - db.import_header(header, authorities, NewBlockState::Normal, Vec::new()).unwrap(); + db.import_header(header, cache, NewBlockState::Normal, Vec::new()).unwrap(); hash } #[test] fn returns_known_header() { let db = LightStorage::new_test(); - let known_hash = insert_block(&db, None, || default_header(&Default::default(), 0)); + let known_hash = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); let header_by_hash = db.header(BlockId::Hash(known_hash)).unwrap().unwrap(); let header_by_number = db.header(BlockId::Number(0)).unwrap().unwrap(); assert_eq!(header_by_hash, header_by_number); @@ -617,12 +619,12 @@ pub(crate) mod tests { #[test] fn returns_info() { let db = LightStorage::new_test(); - let genesis_hash = insert_block(&db, None, || default_header(&Default::default(), 0)); + let genesis_hash = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); let info = db.info().unwrap(); assert_eq!(info.best_hash, genesis_hash); assert_eq!(info.best_number, 0); assert_eq!(info.genesis_hash, genesis_hash); - let best_hash = insert_block(&db, None, || default_header(&genesis_hash, 1)); + let best_hash = insert_block(&db, HashMap::new(), || default_header(&genesis_hash, 1)); let info = db.info().unwrap(); assert_eq!(info.best_hash, best_hash); assert_eq!(info.best_number, 1); @@ -632,7 +634,7 @@ pub(crate) mod tests { #[test] fn returns_block_status() { let db = LightStorage::new_test(); - let genesis_hash = insert_block(&db, None, || default_header(&Default::default(), 0)); + let genesis_hash = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); assert_eq!(db.status(BlockId::Hash(genesis_hash)).unwrap(), BlockStatus::InChain); assert_eq!(db.status(BlockId::Number(0)).unwrap(), BlockStatus::InChain); assert_eq!(db.status(BlockId::Hash(Hash::from_low_u64_be(1))).unwrap(), BlockStatus::Unknown); @@ -642,7 +644,7 @@ pub(crate) mod tests { #[test] fn returns_block_hash() { let db = LightStorage::new_test(); - let genesis_hash = insert_block(&db, None, || default_header(&Default::default(), 0)); + let genesis_hash = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); assert_eq!(db.hash(0).unwrap(), Some(genesis_hash)); assert_eq!(db.hash(1).unwrap(), None); } @@ -651,11 +653,11 @@ pub(crate) mod tests { fn import_header_works() { let db = LightStorage::new_test(); - let genesis_hash = insert_block(&db, None, || default_header(&Default::default(), 0)); + let genesis_hash = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); assert_eq!(db.db.iter(columns::HEADER).count(), 1); assert_eq!(db.db.iter(columns::KEY_LOOKUP).count(), 2); - let _ = insert_block(&db, None, || default_header(&genesis_hash, 1)); + let _ = insert_block(&db, HashMap::new(), || default_header(&genesis_hash, 1)); assert_eq!(db.db.iter(columns::HEADER).count(), 2); assert_eq!(db.db.iter(columns::KEY_LOOKUP).count(), 4); } @@ -666,25 +668,25 @@ pub(crate) mod tests { let db = LightStorage::new_test(); // insert genesis block header (never pruned) - let mut prev_hash = insert_final_block(&db, None, || header_producer(&Default::default(), 0)); + let mut prev_hash = insert_final_block(&db, HashMap::new(), || header_producer(&Default::default(), 0)); // insert SIZE blocks && ensure that nothing is pruned for number in 0..cht::SIZE { - prev_hash = insert_block(&db, None, || header_producer(&prev_hash, 1 + number)); + prev_hash = insert_block(&db, HashMap::new(), || header_producer(&prev_hash, 1 + number)); } assert_eq!(db.db.iter(columns::HEADER).count(), (1 + cht::SIZE) as usize); assert_eq!(db.db.iter(columns::CHT).count(), 0); // insert next SIZE blocks && ensure that nothing is pruned for number in 0..cht::SIZE { - prev_hash = insert_block(&db, None, || header_producer(&prev_hash, 1 + cht::SIZE + number)); + prev_hash = insert_block(&db, HashMap::new(), || header_producer(&prev_hash, 1 + cht::SIZE + number)); } assert_eq!(db.db.iter(columns::HEADER).count(), (1 + cht::SIZE + cht::SIZE) as usize); assert_eq!(db.db.iter(columns::CHT).count(), 0); // insert block #{2 * cht::SIZE + 1} && check that new CHT is created + headers of this CHT are pruned // nothing is yet finalized, so nothing is pruned. - prev_hash = insert_block(&db, None, || header_producer(&prev_hash, 1 + cht::SIZE + cht::SIZE)); + prev_hash = insert_block(&db, HashMap::new(), || header_producer(&prev_hash, 1 + cht::SIZE + cht::SIZE)); assert_eq!(db.db.iter(columns::HEADER).count(), (2 + cht::SIZE + cht::SIZE) as usize); assert_eq!(db.db.iter(columns::CHT).count(), 0); @@ -733,9 +735,9 @@ pub(crate) mod tests { let db = LightStorage::new_test(); // insert 1 + SIZE + SIZE + 1 blocks so that CHT#0 is created - let mut prev_hash = insert_final_block(&db, None, || header_with_changes_trie(&Default::default(), 0)); + let mut prev_hash = insert_final_block(&db, HashMap::new(), || header_with_changes_trie(&Default::default(), 0)); for i in 1..1 + cht::SIZE + cht::SIZE + 1 { - prev_hash = insert_block(&db, None, || header_with_changes_trie(&prev_hash, i as u64)); + prev_hash = insert_block(&db, HashMap::new(), || header_with_changes_trie(&prev_hash, i as u64)); db.finalize_header(BlockId::Hash(prev_hash)).unwrap(); } @@ -755,16 +757,16 @@ pub(crate) mod tests { #[test] fn tree_route_works() { let db = LightStorage::new_test(); - let block0 = insert_block(&db, None, || default_header(&Default::default(), 0)); + let block0 = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); // fork from genesis: 3 prong. - let a1 = insert_block(&db, None, || default_header(&block0, 1)); - let a2 = insert_block(&db, None, || default_header(&a1, 2)); - let a3 = insert_block(&db, None, || default_header(&a2, 3)); + let a1 = insert_block(&db, HashMap::new(), || default_header(&block0, 1)); + let a2 = insert_block(&db, HashMap::new(), || default_header(&a1, 2)); + let a3 = insert_block(&db, HashMap::new(), || default_header(&a2, 3)); // fork from genesis: 2 prong. - let b1 = insert_block(&db, None, || header_with_extrinsics_root(&block0, 1, Hash::from([1; 32]))); - let b2 = insert_block(&db, None, || default_header(&b1, 2)); + let b1 = insert_block(&db, HashMap::new(), || header_with_extrinsics_root(&block0, 1, Hash::from([1; 32]))); + let b2 = insert_block(&db, HashMap::new(), || default_header(&b1, 2)); { let tree_route = ::client::blockchain::tree_route( @@ -816,44 +818,64 @@ pub(crate) mod tests { } #[test] - fn authorites_are_cached() { + fn authorities_are_cached() { let db = LightStorage::new_test(); fn run_checks(db: &LightStorage, max: u64, checks: &[(u64, Option>>)]) { for (at, expected) in checks.iter().take_while(|(at, _)| *at <= max) { - let actual = db.cache().authorities_at(BlockId::Number(*at)); + let actual = get_authorities(db.cache(), BlockId::Number(*at)); assert_eq!(*expected, actual); } } + fn same_authorities() -> HashMap, Vec> { + HashMap::new() + } + + fn make_authorities(authorities: Vec) -> HashMap, Vec> { + let mut map = HashMap::new(); + map.insert(well_known_cache_keys::AUTHORITIES.to_vec(), authorities.encode()); + map + } + + fn get_authorities(cache: &BlockchainCache, at: BlockId) -> Option> { + cache.get_at(well_known_cache_keys::AUTHORITIES, &at).and_then(|val| Decode::decode(&mut &val[..])) + } + + let auth1 = || AuthorityId::from_raw([1u8; 32]); + let auth2 = || AuthorityId::from_raw([2u8; 32]); + let auth3 = || AuthorityId::from_raw([3u8; 32]); + let auth4 = || AuthorityId::from_raw([4u8; 32]); + let auth5 = || AuthorityId::from_raw([5u8; 32]); + let auth6 = || AuthorityId::from_raw([6u8; 32]); + let (hash2, hash6) = { // first few blocks are instantly finalized - // B0(None) -> B1(None) -> B2(1) -> B3(1) -> B4(1, 2) -> B5(1, 2) -> B6(None) + // B0(None) -> B1(None) -> B2(1) -> B3(1) -> B4(1, 2) -> B5(1, 2) -> B6(1, 2) let checks = vec![ (0, None), (1, None), - (2, Some(vec![AuthorityId::from_raw([1u8; 32])])), - (3, Some(vec![AuthorityId::from_raw([1u8; 32])])), - (4, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])])), - (5, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])])), - (6, None), - (7, None), // block will work for 'future' block too + (2, Some(vec![auth1()])), + (3, Some(vec![auth1()])), + (4, Some(vec![auth1(), auth2()])), + (5, Some(vec![auth1(), auth2()])), + (6, Some(vec![auth1(), auth2()])), ]; - let hash0 = insert_final_block(&db, None, || default_header(&Default::default(), 0)); + let hash0 = insert_final_block(&db, same_authorities(), || default_header(&Default::default(), 0)); run_checks(&db, 0, &checks); - let hash1 = insert_final_block(&db, None, || default_header(&hash0, 1)); + let hash1 = insert_final_block(&db, same_authorities(), || default_header(&hash0, 1)); run_checks(&db, 1, &checks); - let hash2 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash1, 2)); + let hash2 = insert_final_block(&db, make_authorities(vec![auth1()]), || default_header(&hash1, 2)); run_checks(&db, 2, &checks); - let hash3 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash2, 3)); + let hash3 = insert_final_block(&db, make_authorities(vec![auth1()]), || default_header(&hash2, 3)); run_checks(&db, 3, &checks); - let hash4 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash3, 4)); + let hash4 = insert_final_block(&db, make_authorities(vec![auth1(), auth2()]), || default_header(&hash3, 4)); run_checks(&db, 4, &checks); - let hash5 = insert_final_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash4, 5)); + let hash5 = insert_final_block(&db, make_authorities(vec![auth1(), auth2()]), || default_header(&hash4, 5)); run_checks(&db, 5, &checks); - let hash6 = insert_final_block(&db, None, || default_header(&hash5, 6)); - run_checks(&db, 7, &checks); + let hash6 = insert_final_block(&db, same_authorities(), || default_header(&hash5, 6)); + run_checks(&db, 6, &checks); (hash2, hash6) }; @@ -862,10 +884,10 @@ pub(crate) mod tests { // some older non-best blocks are inserted // ... -> B2(1) -> B2_1(1) -> B2_2(2) // => the cache ignores all writes before best finalized block - let hash2_1 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32])]), || default_header(&hash2, 3)); - assert_eq!(None, db.cache().authorities_at(BlockId::Hash(hash2_1))); - let hash2_2 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])]), || default_header(&hash2_1, 4)); - assert_eq!(None, db.cache().authorities_at(BlockId::Hash(hash2_2))); + let hash2_1 = insert_non_best_block(&db, make_authorities(vec![auth1()]), || default_header(&hash2, 3)); + assert_eq!(None, get_authorities(db.cache(), BlockId::Hash(hash2_1))); + let hash2_2 = insert_non_best_block(&db, make_authorities(vec![auth1(), auth2()]), || default_header(&hash2_1, 4)); + assert_eq!(None, get_authorities(db.cache(), BlockId::Hash(hash2_2))); } let (hash7, hash8, hash6_1, hash6_2, hash6_1_1, hash6_1_2) = { @@ -875,39 +897,57 @@ pub(crate) mod tests { // \> B6_1_1(5) // \> B6_1_2(6) -> B6_1_3(7) - let hash7 = insert_block(&db, Some(vec![AuthorityId::from_raw([3u8; 32])]), || default_header(&hash6, 7)); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - let hash8 = insert_block(&db, Some(vec![AuthorityId::from_raw([3u8; 32])]), || default_header(&hash7, 8)); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - let hash6_1 = insert_block(&db, Some(vec![AuthorityId::from_raw([4u8; 32])]), || default_header(&hash6, 7)); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); - let hash6_1_1 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([5u8; 32])]), || default_header(&hash6_1, 8)); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); - let hash6_1_2 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([6u8; 32])]), || default_header(&hash6_1, 8)); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); - let hash6_2 = insert_block(&db, Some(vec![AuthorityId::from_raw([4u8; 32])]), || default_header(&hash6_1, 8)); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])])); + let hash7 = insert_block(&db, make_authorities(vec![auth3()]), || default_header(&hash6, 7)); + assert_eq!( + get_authorities(db.cache(), BlockId::Hash(hash6)), + Some(vec![auth1(), auth2()]), + ); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); + let hash8 = insert_block(&db, make_authorities(vec![auth3()]), || default_header(&hash7, 8)); + assert_eq!( + get_authorities(db.cache(), BlockId::Hash(hash6)), + Some(vec![auth1(), auth2()]), + ); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); + let hash6_1 = insert_block(&db, make_authorities(vec![auth4()]), || default_header(&hash6, 7)); + assert_eq!( + get_authorities(db.cache(), BlockId::Hash(hash6)), + Some(vec![auth1(), auth2()]), + ); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); + let hash6_1_1 = insert_non_best_block(&db, make_authorities(vec![auth5()]), || default_header(&hash6_1, 8)); + assert_eq!( + get_authorities(db.cache(), BlockId::Hash(hash6)), + Some(vec![auth1(), auth2()]), + ); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()])); + let hash6_1_2 = insert_non_best_block(&db, make_authorities(vec![auth6()]), || default_header(&hash6_1, 8)); + assert_eq!( + get_authorities(db.cache(), BlockId::Hash(hash6)), + Some(vec![auth1(), auth2()]), + ); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_2)), Some(vec![auth6()])); + let hash6_2 = insert_block(&db, make_authorities(vec![auth4()]), || default_header(&hash6_1, 8)); + assert_eq!( + get_authorities(db.cache(), BlockId::Hash(hash6)), + Some(vec![auth1(), auth2()]), + ); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_2)), Some(vec![auth6()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_2)), Some(vec![auth4()])); (hash7, hash8, hash6_1, hash6_2, hash6_1_1, hash6_1_2) }; @@ -915,29 +955,35 @@ pub(crate) mod tests { { // finalize block hash6_1 db.finalize_header(BlockId::Hash(hash6_1)).unwrap(); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])])); + assert_eq!( + get_authorities(db.cache(), BlockId::Hash(hash6)), + Some(vec![auth1(), auth2()]), + ); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash7)), None); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), None); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_2)), Some(vec![auth6()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_2)), Some(vec![auth4()])); // finalize block hash6_2 db.finalize_header(BlockId::Hash(hash6_2)).unwrap(); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), None); - assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])])); + assert_eq!( + get_authorities(db.cache(), BlockId::Hash(hash6)), + Some(vec![auth1(), auth2()]), + ); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash7)), None); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), None); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()])); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_1)), None); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_2)), None); + assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_2)), Some(vec![auth4()])); } } #[test] fn database_is_reopened() { let db = LightStorage::new_test(); - let hash0 = insert_final_block(&db, None, || default_header(&Default::default(), 0)); + let hash0 = insert_final_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); assert_eq!(db.info().unwrap().best_hash, hash0); assert_eq!(db.header(BlockId::Hash(hash0)).unwrap().unwrap().hash(), hash0); @@ -960,7 +1006,7 @@ pub(crate) mod tests { assert_eq!(db.get_aux(&[3]).unwrap(), None); // delete aux1 + insert aux3 using import operation - db.import_header(default_header(&Default::default(), 0), None, NewBlockState::Best, vec![ + db.import_header(default_header(&Default::default(), 0), HashMap::new(), NewBlockState::Best, vec![ (vec![3], Some(vec![103])), (vec![1], None), ]).unwrap(); @@ -974,17 +1020,17 @@ pub(crate) mod tests { #[test] fn test_leaves_pruned_on_finality() { let db = LightStorage::::new_test(); - let block0 = insert_block(&db, None, || default_header(&Default::default(), 0)); + let block0 = insert_block(&db, HashMap::new(), || default_header(&Default::default(), 0)); - let block1_a = insert_block(&db, None, || default_header(&block0, 1)); - let block1_b = insert_block(&db, None, || header_with_extrinsics_root(&block0, 1, [1; 32].into())); - let block1_c = insert_block(&db, None, || header_with_extrinsics_root(&block0, 1, [2; 32].into())); + let block1_a = insert_block(&db, HashMap::new(), || default_header(&block0, 1)); + let block1_b = insert_block(&db, HashMap::new(), || header_with_extrinsics_root(&block0, 1, [1; 32].into())); + let block1_c = insert_block(&db, HashMap::new(), || header_with_extrinsics_root(&block0, 1, [2; 32].into())); assert_eq!(db.leaves.read().hashes(), vec![block1_a, block1_b, block1_c]); - let block2_a = insert_block(&db, None, || default_header(&block1_a, 2)); - let block2_b = insert_block(&db, None, || header_with_extrinsics_root(&block1_b, 2, [1; 32].into())); - let block2_c = insert_block(&db, None, || header_with_extrinsics_root(&block1_b, 2, [2; 32].into())); + let block2_a = insert_block(&db, HashMap::new(), || default_header(&block1_a, 2)); + let block2_b = insert_block(&db, HashMap::new(), || header_with_extrinsics_root(&block1_b, 2, [1; 32].into())); + let block2_c = insert_block(&db, HashMap::new(), || header_with_extrinsics_root(&block1_b, 2, [2; 32].into())); assert_eq!(db.leaves.read().hashes(), vec![block2_a, block2_b, block2_c, block1_c]); diff --git a/core/client/src/backend.rs b/core/client/src/backend.rs index 9b063177ff14b..864d04ed618e9 100644 --- a/core/client/src/backend.rs +++ b/core/client/src/backend.rs @@ -16,10 +16,11 @@ //! Substrate Client data backend +use std::collections::HashMap; use crate::error; use primitives::ChangesTrieConfiguration; use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; -use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, NumberFor}; +use runtime_primitives::traits::{Block as BlockT, NumberFor}; use state_machine::backend::Backend as StateBackend; use state_machine::ChangesTrieStorage as StateChangesTrieStorage; use hash_db::Hasher; @@ -73,9 +74,8 @@ pub trait BlockImportOperation where state: NewBlockState, ) -> error::Result<()>; - /// Append authorities set to the transaction. This is a set of parent block (set which - /// has been used to check justification of this block). - fn update_authorities(&mut self, authorities: Vec>); + /// Update cached data. + fn update_cache(&mut self, cache: HashMap, Vec>); /// Inject storage data into the database. fn update_db_storage(&mut self, update: >::Transaction) -> error::Result<()>; /// Inject storage data into the database replacing any existing data. diff --git a/core/client/src/blockchain.rs b/core/client/src/blockchain.rs index a18c6e5d577a8..682d686bd5310 100644 --- a/core/client/src/blockchain.rs +++ b/core/client/src/blockchain.rs @@ -16,7 +16,9 @@ //! Substrate blockchain trait -use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, Header as HeaderT, NumberFor}; +use std::sync::Arc; + +use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use runtime_primitives::generic::BlockId; use runtime_primitives::Justification; @@ -78,7 +80,7 @@ pub trait Backend: HeaderBackend { /// Get last finalized block hash. fn last_finalized(&self) -> Result; /// Returns data cache reference, if it is enabled on this backend. - fn cache(&self) -> Option<&Cache>; + fn cache(&self) -> Option>>; /// Returns hashes of all blocks that are leaves of the block tree. /// in other words, that have no children, are chain heads. @@ -89,10 +91,16 @@ pub trait Backend: HeaderBackend { fn children(&self, parent_hash: Block::Hash) -> Result>; } +/// Provides access to the optional cache. +pub trait ProvideCache { + /// Returns data cache reference, if it is enabled on this backend. + fn cache(&self) -> Option>>; +} + /// Blockchain optional data cache. pub trait Cache: Send + Sync { - /// Returns the set of authorities, that was active at given block or None if there's no entry in the cache. - fn authorities_at(&self, block: BlockId) -> Option>>; + /// Returns cached value by the given key. + fn get_at(&self, key: &[u8], block: &BlockId) -> Option>; } /// Blockchain info diff --git a/core/client/src/client.rs b/core/client/src/client.rs index 86d643d3b786e..7ab66cbc09c69 100644 --- a/core/client/src/client.rs +++ b/core/client/src/client.rs @@ -16,7 +16,7 @@ //! Substrate Client -use std::{marker::PhantomData, collections::{HashSet, BTreeMap}, sync::Arc, panic::UnwindSafe, result}; +use std::{marker::PhantomData, collections::{HashSet, BTreeMap, HashMap}, sync::Arc, panic::UnwindSafe, result}; use crate::error::Error; use futures::sync::mpsc; use parking_lot::{Mutex, RwLock}; @@ -31,7 +31,7 @@ use consensus::{ }; use runtime_primitives::traits::{ Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash, - ApiRef, ProvideRuntimeApi, Digest, DigestItem, AuthorityIdFor + ApiRef, ProvideRuntimeApi, Digest, DigestItem }; use runtime_primitives::BuildStorage; use crate::runtime_api::{CallRuntimeAt, ConstructRuntimeApi}; @@ -49,7 +49,8 @@ use hash_db::Hasher; use crate::backend::{self, BlockImportOperation, PrunableStateChangesTrieStorage}; use crate::blockchain::{ - self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend + self, Info as ChainInfo, Backend as ChainBackend, HeaderBackend as ChainHeaderBackend, + ProvideCache, Cache, }; use crate::call_executor::{CallExecutor, LocalCallExecutor}; use executor::{RuntimeVersion, RuntimeInfo}; @@ -342,16 +343,6 @@ impl Client where .expect("None is returned if there's no value stored for the given key; ':code' key is always defined; qed").0) } - /// Get the set of authorities at a given block. - pub fn authorities_at(&self, id: &BlockId) -> error::Result>> { - 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", &[], ExecutionStrategy::NativeElseWasm, NeverOffchainExt::new()) - .and_then(|r| Vec::>::decode(&mut &r[..]) - .ok_or_else(|| error::ErrorKind::InvalidAuthoritiesSet.into())) - } - } - /// Get the RuntimeVersion at a given block. pub fn runtime_version_at(&self, id: &BlockId) -> error::Result { self.executor.runtime_version(id) @@ -681,7 +672,7 @@ impl Client where &self, operation: &mut ClientImportOperation, import_block: ImportBlock, - new_authorities: Option>>, + new_cache: HashMap, Vec>, ) -> error::Result where E: CallExecutor + Send + Sync + Clone, { @@ -729,7 +720,7 @@ impl Client where import_headers, justification, body, - new_authorities, + new_cache, finalized, auxiliary, fork_choice, @@ -752,7 +743,7 @@ impl Client where import_headers: PrePostHeader, justification: Option, body: Option>, - authorities: Option>>, + new_cache: HashMap, Vec>, finalized: bool, aux: Vec<(Vec, Option>)>, fork_choice: ForkChoiceStrategy, @@ -810,9 +801,7 @@ impl Client where leaf_state, )?; - if let Some(authorities) = authorities { - operation.op.update_authorities(authorities); - } + operation.op.update_cache(new_cache); if let Some(storage_update) = storage_update { operation.op.update_db_storage(storage_update)?; } @@ -1324,6 +1313,15 @@ impl ChainHeaderBackend for Client wher } } +impl ProvideCache for Client where + B: backend::Backend, + Block: BlockT, +{ + fn cache(&self) -> Option>> { + self.backend.blockchain().cache() + } +} + impl ProvideRuntimeApi for Client where B: backend::Backend, E: CallExecutor + Clone + Send + Sync, @@ -1398,10 +1396,10 @@ impl consensus::BlockImport for Client fn import_block( &self, import_block: ImportBlock, - new_authorities: Option>>, + new_cache: HashMap, Vec>, ) -> Result { self.lock_import_and_run(|operation| { - self.apply_block(operation, import_block, new_authorities) + self.apply_block(operation, import_block, new_cache) }).map_err(|e| ConsensusErrorKind::ClientImport(e.to_string()).into()) } @@ -1431,17 +1429,6 @@ impl consensus::BlockImport for Client } } -impl consensus::Authorities for Client where - B: backend::Backend, - E: CallExecutor + Clone, - Block: BlockT, -{ - type Error = Error; - fn authorities(&self, at: &BlockId) -> Result>, Self::Error> { - self.authorities_at(at).map_err(|e| e.into()) - } -} - impl CurrentHeight for Client where B: backend::Backend, E: CallExecutor, @@ -1550,7 +1537,7 @@ pub(crate) mod tests { use primitives::twox_128; use runtime_primitives::traits::DigestItem as DigestItemT; use runtime_primitives::generic::DigestItem; - use test_client::{self, TestClient, AccountKeyring, AuthorityKeyring}; + use test_client::{self, TestClient, AccountKeyring}; use consensus::BlockOrigin; use test_client::client::backend::Backend as TestBackend; use test_client::BlockBuilderExt; @@ -1649,18 +1636,6 @@ pub(crate) mod tests { ); } - #[test] - fn authorities_call_works() { - let client = test_client::new(); - - assert_eq!(client.info().unwrap().chain.best_number, 0); - assert_eq!(client.authorities_at(&BlockId::Number(0)).unwrap(), vec![ - AuthorityKeyring::Alice.into(), - AuthorityKeyring::Bob.into(), - AuthorityKeyring::Charlie.into() - ]); - } - #[test] fn block_builder_works_with_no_transactions() { let client = test_client::new(); @@ -1705,15 +1680,6 @@ pub(crate) mod tests { ); } - #[test] - fn client_uses_authorities_from_blockchain_cache() { - let client = test_client::new_light(); - let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); - // authorities cache is first filled in genesis block - // => should be read from cache here (remote request will fail in this test) - assert!(!client.authorities_at(&BlockId::Hash(genesis_hash)).unwrap().is_empty()); - } - #[test] fn block_builder_does_not_include_invalid() { let client = test_client::new(); diff --git a/core/client/src/error.rs b/core/client/src/error.rs index edc179ec6a701..3ee3c0e2a1ac5 100644 --- a/core/client/src/error.rs +++ b/core/client/src/error.rs @@ -62,12 +62,6 @@ error_chain! { display("Blockchain: {}", e), } - /// Invalid authorities set received from the runtime. - InvalidAuthoritiesSet { - description("authorities set is invalid"), - display("Current state of blockchain has invalid authorities set"), - } - /// Could not get runtime version. VersionInvalid { description("Runtime version error"), diff --git a/core/client/src/in_mem.rs b/core/client/src/in_mem.rs index 7f3cdfd8dde62..d2721356289cf 100644 --- a/core/client/src/in_mem.rs +++ b/core/client/src/in_mem.rs @@ -22,7 +22,7 @@ use parking_lot::RwLock; use primitives::{ChangesTrieConfiguration, storage::well_known_keys}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, - NumberFor, As, Digest, DigestItem, AuthorityIdFor}; + NumberFor, As, Digest, DigestItem}; use runtime_primitives::{Justification, StorageOverlay, ChildrenStorageOverlay}; use state_machine::backend::{Backend as StateBackend, InMemory, Consolidate}; use state_machine::{self, InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId}; @@ -104,12 +104,6 @@ struct BlockchainStorage { /// In-memory blockchain. Supports concurrent reads. pub struct Blockchain { storage: Arc>>, - cache: Cache, -} - -struct Cache { - storage: Arc>>, - authorities_at: RwLock>>>>, } impl Clone for Blockchain { @@ -117,10 +111,6 @@ impl Clone for Blockchain { let storage = Arc::new(RwLock::new(self.storage.read().clone())); Blockchain { storage: storage.clone(), - cache: Cache { - storage, - authorities_at: RwLock::new(self.cache.authorities_at.read().clone()), - }, } } } @@ -152,10 +142,6 @@ impl Blockchain { })); Blockchain { storage: storage.clone(), - cache: Cache { - storage: storage, - authorities_at: Default::default(), - }, } } @@ -355,8 +341,8 @@ impl blockchain::Backend for Blockchain { Ok(self.storage.read().finalized_hash.clone()) } - fn cache(&self) -> Option<&blockchain::Cache> { - Some(&self.cache) + fn cache(&self) -> Option>> { + None } fn leaves(&self) -> error::Result> { @@ -368,6 +354,12 @@ impl blockchain::Backend for Blockchain { } } +impl blockchain::ProvideCache for Blockchain { + fn cache(&self) -> Option>> { + None + } +} + impl backend::AuxStore for Blockchain { fn insert_aux< 'a, @@ -398,16 +390,12 @@ impl light::blockchain::Storage for Blockchain fn import_header( &self, header: Block::Header, - authorities: Option>>, + _cache: HashMap, Vec>, state: NewBlockState, aux_ops: Vec<(Vec, Option>)>, ) -> error::Result<()> { let hash = header.hash(); - let parent_hash = *header.parent_hash(); self.insert(hash, header, None, None, state)?; - if state.is_best() { - self.cache.insert(parent_hash, authorities); - } self.write_aux(aux_ops); Ok(()) @@ -435,15 +423,15 @@ impl light::blockchain::Storage for Blockchain .ok_or_else(|| error::ErrorKind::Backend(format!("Changes trie CHT for block {} not exists", block)).into()) } - fn cache(&self) -> Option<&blockchain::Cache> { - Some(&self.cache) + fn cache(&self) -> Option>> { + None } } /// In-memory operation. pub struct BlockImportOperation { pending_block: Option>, - pending_authorities: Option>>, + pending_cache: HashMap, Vec>, old_state: InMemory, new_state: Option>, changes_trie_update: Option>, @@ -480,8 +468,8 @@ where Ok(()) } - fn update_authorities(&mut self, authorities: Vec>) { - self.pending_authorities = Some(authorities); + fn update_cache(&mut self, cache: HashMap, Vec>) { + self.pending_cache = cache; } fn update_db_storage(&mut self, update: as StateBackend>::Transaction) -> error::Result<()> { @@ -602,7 +590,7 @@ where let old_state = self.state_at(BlockId::Hash(Default::default()))?; Ok(BlockImportOperation { pending_block: None, - pending_authorities: None, + pending_cache: Default::default(), old_state, new_state: None, changes_trie_update: None, @@ -629,7 +617,6 @@ where let (header, body, justification) = pending_block.block.into_inner(); let hash = header.hash(); - let parent_hash = *header.parent_hash(); self.states.write().insert(hash, operation.new_state.unwrap_or_else(|| old_state.clone())); @@ -642,10 +629,6 @@ where } self.blockchain.insert(hash, header, justification, body, pending_block.state)?; - // dumb implementation - store value for each block - if pending_block.state.is_best() { - self.blockchain.cache.insert(parent_hash, operation.pending_authorities); - } } if !operation.aux.is_empty() { @@ -710,23 +693,6 @@ where } } -impl Cache { - fn insert(&self, at: Block::Hash, authorities: Option>>) { - self.authorities_at.write().insert(at, authorities); - } -} - -impl blockchain::Cache for Cache { - fn authorities_at(&self, block: BlockId) -> Option>> { - let hash = match block { - BlockId::Hash(hash) => hash, - BlockId::Number(number) => self.storage.read().hashes.get(&number).cloned()?, - }; - - self.authorities_at.read().get(&hash).cloned().unwrap_or(None) - } -} - /// Prunable in-memory changes trie storage. pub struct ChangesTrieStorage(InMemoryChangesTrieStorage) where H::Out: HeapSizeOf; impl backend::PrunableStateChangesTrieStorage for ChangesTrieStorage where H::Out: HeapSizeOf { @@ -747,15 +713,6 @@ impl state_machine::ChangesTrieStorage for ChangesTrieStorage w } } -/// Insert authorities entry into in-memory blockchain cache. Extracted as a separate function to use it in tests. -pub fn cache_authorities_at( - blockchain: &Blockchain, - at: Block::Hash, - authorities: Option>> -) { - blockchain.cache.insert(at, authorities); -} - /// Check that genesis storage is valid. pub fn check_genesis_storage(top: &StorageOverlay, children: &ChildrenStorageOverlay) -> error::Result<()> { if top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) { diff --git a/core/client/src/light/backend.rs b/core/client/src/light/backend.rs index a00d42e67394f..c62a89ce9d10b 100644 --- a/core/client/src/light/backend.rs +++ b/core/client/src/light/backend.rs @@ -24,7 +24,7 @@ use parking_lot::RwLock; use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; use state_machine::{Backend as StateBackend, TrieBackend, backend::InMemory as InMemoryState}; -use runtime_primitives::traits::{Block as BlockT, NumberFor, AuthorityIdFor, Zero, Header}; +use runtime_primitives::traits::{Block as BlockT, NumberFor, Zero, Header}; use crate::in_mem::{self, check_genesis_storage}; use crate::backend::{AuxStore, Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState}; use crate::blockchain::HeaderBackend as BlockchainHeaderBackend; @@ -46,7 +46,7 @@ pub struct Backend { /// Light block (header and justification) import operation. pub struct ImportOperation { header: Option, - authorities: Option>>, + cache: HashMap, Vec>, leaf_state: NewBlockState, aux_ops: Vec<(Vec, Option>)>, finalized_blocks: Vec>, @@ -117,7 +117,7 @@ impl ClientBackend for Backend where fn begin_operation(&self) -> ClientResult { Ok(ImportOperation { header: None, - authorities: None, + cache: Default::default(), leaf_state: NewBlockState::Normal, aux_ops: Vec::new(), finalized_blocks: Vec::new(), @@ -146,7 +146,7 @@ impl ClientBackend for Backend where let is_genesis_import = header.number().is_zero(); self.blockchain.storage().import_header( header, - operation.authorities, + operation.cache, operation.leaf_state, operation.aux_ops, )?; @@ -254,8 +254,8 @@ where Ok(()) } - fn update_authorities(&mut self, authorities: Vec>) { - self.authorities = Some(authorities); + fn update_cache(&mut self, cache: HashMap, Vec>) { + self.cache = cache; } fn update_db_storage(&mut self, _update: >::Transaction) -> ClientResult<()> { diff --git a/core/client/src/light/blockchain.rs b/core/client/src/light/blockchain.rs index add183f67df59..cf6304253ac05 100644 --- a/core/client/src/light/blockchain.rs +++ b/core/client/src/light/blockchain.rs @@ -17,16 +17,16 @@ //! Light client blockchin backend. Only stores headers and justifications of recent //! blocks. CHT roots are stored for headers of ancient blocks. -use std::sync::Weak; +use std::{sync::{Weak, Arc}, collections::HashMap}; use futures::{Future, IntoFuture}; use parking_lot::Mutex; use runtime_primitives::{Justification, generic::BlockId}; -use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero, AuthorityIdFor}; +use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}; use crate::backend::{AuxStore, NewBlockState}; use crate::blockchain::{Backend as BlockchainBackend, BlockStatus, Cache as BlockchainCache, - HeaderBackend as BlockchainHeaderBackend, Info as BlockchainInfo}; + HeaderBackend as BlockchainHeaderBackend, Info as BlockchainInfo, ProvideCache}; use crate::cht; use crate::error::{ErrorKind as ClientErrorKind, Result as ClientResult}; use crate::light::fetcher::{Fetcher, RemoteHeaderRequest}; @@ -40,7 +40,7 @@ pub trait Storage: AuxStore + BlockchainHeaderBackend { fn import_header( &self, header: Block::Header, - authorities: Option>>, + cache: HashMap, Vec>, state: NewBlockState, aux_ops: Vec<(Vec, Option>)>, ) -> ClientResult<()>; @@ -61,7 +61,7 @@ pub trait Storage: AuxStore + BlockchainHeaderBackend { fn changes_trie_cht_root(&self, cht_size: u64, block: NumberFor) -> ClientResult; /// Get storage cache. - fn cache(&self) -> Option<&BlockchainCache>; + fn cache(&self) -> Option>>; } /// Light client blockchain. @@ -156,7 +156,7 @@ impl BlockchainBackend for Blockchain where Block: Blo self.storage.last_finalized() } - fn cache(&self) -> Option<&BlockchainCache> { + fn cache(&self) -> Option>> { self.storage.cache() } @@ -169,6 +169,12 @@ impl BlockchainBackend for Blockchain where Block: Blo } } +impl, F, Block: BlockT> ProvideCache for Blockchain { + fn cache(&self) -> Option>> { + self.storage.cache() + } +} + #[cfg(test)] pub mod tests { use std::collections::HashMap; @@ -246,7 +252,7 @@ pub mod tests { fn import_header( &self, _header: Header, - _authorities: Option>>, + _cache: HashMap, Vec>, _state: NewBlockState, _aux_ops: Vec<(Vec, Option>)>, ) -> ClientResult<()> { @@ -278,7 +284,7 @@ pub mod tests { ).into()) } - fn cache(&self) -> Option<&BlockchainCache> { + fn cache(&self) -> Option>> { None } } diff --git a/core/client/src/light/call_executor.rs b/core/client/src/light/call_executor.rs index b2e4c45a7d45f..1e50d3398ecf7 100644 --- a/core/client/src/light/call_executor.rs +++ b/core/client/src/light/call_executor.rs @@ -512,7 +512,7 @@ mod tests { } // check method that doesn't requires environment - let (remote, local) = execute(&remote_client, 0, "Core_authorities"); + let (remote, local) = execute(&remote_client, 0, "Core_version"); assert_eq!(remote, local); // check method that requires environment diff --git a/core/client/src/light/fetcher.rs b/core/client/src/light/fetcher.rs index 893682d5f8698..4cbbc819b3141 100644 --- a/core/client/src/light/fetcher.rs +++ b/core/client/src/light/fetcher.rs @@ -390,6 +390,7 @@ impl<'a, H, Number, Hash> ChangesTrieRootsStorage for RootsStorage<'a, Number pub mod tests { use futures::future::{ok, err, FutureResult}; use parking_lot::Mutex; + use parity_codec::Decode; use crate::client::tests::prepare_client_with_key_changes; use executor::{self, NativeExecutionDispatch}; use crate::error::Error as ClientError; @@ -436,7 +437,7 @@ pub mod tests { type TestChecker = LightDataChecker, Blake2Hasher, Block, DummyStorage, OkCallFetcher>; - fn prepare_for_read_proof_check() -> (TestChecker, Header, Vec>, usize) { + fn prepare_for_read_proof_check() -> (TestChecker, Header, Vec>, u32) { // prepare remote client let remote_client = test_client::new(); let remote_block_id = BlockId::Number(0); @@ -445,7 +446,9 @@ pub mod tests { remote_block_header.state_root = remote_client.state_at(&remote_block_id).unwrap().storage_root(::std::iter::empty()).0.into(); // 'fetch' read proof from remote node - let authorities_len = remote_client.authorities_at(&remote_block_id).unwrap().len(); + let authorities_len = remote_client.storage(&remote_block_id, &StorageKey(well_known_keys::AUTHORITY_COUNT.to_vec())) + .unwrap() + .and_then(|v| Decode::decode(&mut &v.0[..])).unwrap(); let remote_read_proof = remote_client.read_proof(&remote_block_id, well_known_keys::AUTHORITY_COUNT).unwrap(); // check remote read proof locally diff --git a/core/client/src/runtime_api.rs b/core/client/src/runtime_api.rs index a912b8c5767e2..6bc43ab270f56 100644 --- a/core/client/src/runtime_api.rs +++ b/core/client/src/runtime_api.rs @@ -38,7 +38,6 @@ use rstd::result; pub use parity_codec::{Encode, Decode}; #[cfg(feature = "std")] use crate::error; -use rstd::vec::Vec; use sr_api_macros::decl_runtime_apis; use primitives::OpaqueMetadata; #[cfg(feature = "std")] @@ -112,13 +111,11 @@ pub trait CallRuntimeAt { } decl_runtime_apis! { - /// The `Core` api trait that is mandantory for each runtime. + /// The `Core` api trait that is mandatory for each runtime. #[core_trait] pub trait Core { /// Returns the version of the runtime. fn version() -> RuntimeVersion; - /// Returns the authorities. - fn authorities() -> Vec>; /// Execute the given block. fn execute_block(block: Block); /// Initialize a block with the given header. diff --git a/core/consensus/aura/Cargo.toml b/core/consensus/aura/Cargo.toml index ca4f139ee4901..190ace413de83 100644 --- a/core/consensus/aura/Cargo.toml +++ b/core/consensus/aura/Cargo.toml @@ -25,6 +25,7 @@ parking_lot = "0.7.1" error-chain = "0.12" log = "0.4" consensus_common = { package = "substrate-consensus-common", path = "../common" } +authorities = { package = "substrate-consensus-authorities", path = "../authorities" } [dev-dependencies] keyring = { package = "substrate-keyring", path = "../../keyring" } diff --git a/core/consensus/aura/src/lib.rs b/core/consensus/aura/src/lib.rs index cf83d3fa6eb8f..d3ea731795c71 100644 --- a/core/consensus/aura/src/lib.rs +++ b/core/consensus/aura/src/lib.rs @@ -29,21 +29,23 @@ use std::{sync::Arc, time::Duration, thread, marker::PhantomData, hash::Hash, fmt::Debug}; use parity_codec::{Encode, Decode}; -use consensus_common::{ - Authorities, BlockImport, Environment, Proposer, ForkChoiceStrategy +use consensus_common::{self, Authorities, BlockImport, Environment, Proposer, + ForkChoiceStrategy, ImportBlock, BlockOrigin, Error as ConsensusError, }; +use consensus_common::well_known_cache_keys; use consensus_common::import_queue::{Verifier, BasicQueue, SharedBlockImport, SharedJustificationImport}; use client::ChainHead; use client::block_builder::api::BlockBuilder as BlockBuilderApi; +use client::blockchain::ProvideCache; use client::runtime_api::ApiExt; -use consensus_common::{ImportBlock, BlockOrigin}; use aura_primitives::AURA_ENGINE_ID; use runtime_primitives::{generic, generic::BlockId, Justification}; use runtime_primitives::traits::{ - Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi + Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi, AuthorityIdFor, }; use primitives::Pair; use inherents::{InherentDataProviders, InherentData, RuntimeString}; +use authorities::AuthoritiesApi; use futures::{Stream, Future, IntoFuture, future}; use tokio::timer::Timeout; @@ -179,12 +181,13 @@ pub fn start_aura_thread( force_authoring: bool, ) -> Result<(), consensus_common::Error> where B: Block + 'static, - C: Authorities + ChainHead + Send + Sync + 'static, + C: ChainHead + ProvideRuntimeApi + ProvideCache + Send + Sync + 'static, + C::Api: AuthoritiesApi, E: Environment + Send + Sync + 'static, E::Proposer: Proposer + Send + 'static, <>::Create as IntoFuture>::Future: Send + 'static, I: BlockImport + Send + Sync + 'static, - Error: From + From + 'static, + Error: From + 'static, P: Pair + Send + Sync + 'static, P::Public: Encode + Decode + Eq + Clone + Debug + Hash + Send + Sync + 'static, P::Signature: Encode, @@ -226,12 +229,13 @@ pub fn start_aura( force_authoring: bool, ) -> Result, consensus_common::Error> where B: Block, - C: Authorities + ChainHead, + C: ChainHead + ProvideRuntimeApi + ProvideCache, + C::Api: AuthoritiesApi, E: Environment, E::Proposer: Proposer, <>::Create as IntoFuture>::Future: Send + 'static, I: BlockImport + Send + Sync + 'static, - Error: From + From, + Error: From, P: Pair + Send + Sync + 'static, P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static, P::Signature: Encode, @@ -270,7 +274,8 @@ struct AuraWorker { } impl SlotWorker for AuraWorker where - C: Authorities, + C: ProvideRuntimeApi + ProvideCache, + C::Api: AuthoritiesApi, E: Environment, E::Proposer: Proposer, <>::Create as IntoFuture>::Future: Send + 'static, @@ -278,7 +283,7 @@ impl SlotWorker for AuraWorker + From, + Error: From, SO: SyncOracle + Send + Clone, DigestItemFor: CompatibleDigestItem

+ DigestItem>, Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>, @@ -306,7 +311,7 @@ impl SlotWorker for AuraWorker authorities, Err(e) => { warn!( @@ -418,7 +423,7 @@ impl SlotWorker for AuraWorker ?pre_hash ); - if let Err(e) = block_import.import_block(import_block, None) { + if let Err(e) = block_import.import_block(import_block, Default::default()) { warn!(target: "aura", "Error with block built on {:?}: {:?}", parent_hash, e); telemetry!(CONSENSUS_WARN; "aura.err_with_block_built_on"; @@ -573,13 +578,14 @@ impl ExtraVerification for NothingExtra { #[forbid(deprecated)] impl Verifier for AuraVerifier where - C: Authorities + ProvideRuntimeApi + Send + Sync, + C: ProvideRuntimeApi + Send + Sync, C::Api: BlockBuilderApi, DigestItemFor: CompatibleDigestItem

+ DigestItem>, E: ExtraVerification, P: Pair + Send + Sync + 'static, P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + AsRef + 'static, P::Signature: Encode + Decode, + Self: Authorities, { fn verify( &self, @@ -593,7 +599,7 @@ impl Verifier for AuraVerifier where .map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?; let hash = header.hash(); let parent_hash = *header.parent_hash(); - let authorities = self.client.authorities(&BlockId::Hash(parent_hash)) + let authorities = self.authorities(&BlockId::Hash(parent_hash)) .map_err(|e| format!("Could not fetch authorities at {:?}: {:?}", parent_hash, e))?; let extra_verification = self.extra.verify( @@ -669,6 +675,31 @@ impl Verifier for AuraVerifier where } } +impl Authorities for AuraVerifier where + B: Block, + C: ProvideRuntimeApi + ProvideCache, + C::Api: AuthoritiesApi, +{ + type Error = ConsensusError; + + fn authorities(&self, at: &BlockId) -> Result>, Self::Error> { + authorities(self.client.as_ref(), at) + } +} + +fn authorities(client: &C, at: &BlockId) -> Result>, ConsensusError> where + B: Block, + C: ProvideRuntimeApi + ProvideCache, + C::Api: AuthoritiesApi, +{ + client + .cache() + .and_then(|cache| cache.get_at(well_known_cache_keys::AUTHORITIES, at) + .and_then(|v| Decode::decode(&mut &v[..]))) + .or_else(|| client.runtime_api().authorities(at).ok()) + .ok_or_else(|| consensus_common::ErrorKind::InvalidAuthoritiesSet.into()) +} + /// The Aura import queue type. pub type AuraImportQueue = BasicQueue; @@ -697,8 +728,8 @@ pub fn import_queue( allow_old_seals: bool, ) -> Result, consensus_common::Error> where B: Block, - C: 'static + Authorities + ProvideRuntimeApi + Send + Sync, - C::Api: BlockBuilderApi, + C: 'static + ProvideRuntimeApi + ProvideCache + Send + Sync, + C::Api: BlockBuilderApi + AuthoritiesApi, DigestItemFor: CompatibleDigestItem

+ DigestItem>, E: 'static + ExtraVerification, P: Pair + Send + Sync + 'static, @@ -889,4 +920,16 @@ mod tests { runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); } + + #[test] + fn authorities_call_works() { + let client = test_client::new(); + + assert_eq!(client.info().unwrap().chain.best_number, 0); + assert_eq!(authorities(&client, &BlockId::Number(0)).unwrap(), vec![ + Keyring::Alice.into(), + Keyring::Bob.into(), + Keyring::Charlie.into() + ]); + } } diff --git a/core/consensus/authorities/Cargo.toml b/core/consensus/authorities/Cargo.toml new file mode 100644 index 0000000000000..0800656f76f6e --- /dev/null +++ b/core/consensus/authorities/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "substrate-consensus-authorities" +version = "0.1.0" +authors = ["Parity Technologies "] +description = "Primitives for Aura consensus" +edition = "2018" + +[dependencies] +parity-codec = { version = "3.0", default-features = false } +substrate-client = { path = "../../client", default-features = false } +primitives = { package = "substrate-primitives", path = "../../primitives", default-features = false } +runtime_support = { package = "srml-support", path = "../../../srml/support", default-features = false } +runtime_primitives = { package = "sr-primitives", path = "../../sr-primitives", default-features = false } +sr-version = { path = "../../sr-version", default-features = false } +runtime_io = { package = "sr-io", path = "../../sr-io", default-features = false } +rstd = { package = "sr-std", path = "../../sr-std", default-features = false } + +[features] +default = ["std"] +std = [ + "parity-codec/std", + "substrate-client/std", + "primitives/std", + "runtime_support/std", + "runtime_primitives/std", + "sr-version/std", + "runtime_io/std", + "rstd/std" +] diff --git a/core/consensus/authorities/src/lib.rs b/core/consensus/authorities/src/lib.rs new file mode 100644 index 0000000000000..a5ad974f5b40e --- /dev/null +++ b/core/consensus/authorities/src/lib.rs @@ -0,0 +1,31 @@ +// 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 . + +//! Authorities API. + +#![cfg_attr(not(feature = "std"), no_std)] + +use substrate_client::decl_runtime_apis; +use runtime_primitives::traits::AuthorityIdFor; +use rstd::vec::Vec; + +decl_runtime_apis! { + /// Authorities API. + pub trait AuthoritiesApi { + /// Returns the authorities at the given block. + fn authorities() -> Vec>; + } +} diff --git a/core/consensus/common/src/block_import.rs b/core/consensus/common/src/block_import.rs index 06c78d74afd43..a4a765da4e146 100644 --- a/core/consensus/common/src/block_import.rs +++ b/core/consensus/common/src/block_import.rs @@ -16,9 +16,10 @@ //! Block import helpers. -use runtime_primitives::traits::{AuthorityIdFor, Block as BlockT, DigestItemFor, Header as HeaderT, NumberFor}; +use runtime_primitives::traits::{Block as BlockT, DigestItemFor, Header as HeaderT, NumberFor}; use runtime_primitives::Justification; use std::borrow::Cow; +use std::collections::HashMap; /// Block import result. #[derive(Debug, PartialEq, Eq)] @@ -175,11 +176,13 @@ pub trait BlockImport { parent_hash: B::Hash, ) -> Result; - /// Import a Block alongside the new authorities valid from this block forward + /// Import a block. + /// + /// Cached data can be accessed through the blockchain cache. fn import_block( &self, block: ImportBlock, - new_authorities: Option>>, + cache: HashMap, Vec>, ) -> Result; } diff --git a/core/consensus/common/src/error.rs b/core/consensus/common/src/error.rs index 58362b8e80e2e..0f1914087bf8c 100644 --- a/core/consensus/common/src/error.rs +++ b/core/consensus/common/src/error.rs @@ -58,6 +58,12 @@ error_chain! { display("Message signature {:?} by {:?} is invalid.", s, a), } + /// Invalid authorities set received from the runtime. + InvalidAuthoritiesSet { + description("authorities set is invalid"), + display("Current state of blockchain has invalid authorities set"), + } + /// Account is not an authority. InvalidAuthority(a: Public) { description("Message sender is not a valid authority"), diff --git a/core/consensus/common/src/import_queue.rs b/core/consensus/common/src/import_queue.rs index 2e1c29d4d804d..1d0a52d324626 100644 --- a/core/consensus/common/src/import_queue.rs +++ b/core/consensus/common/src/import_queue.rs @@ -28,6 +28,7 @@ use crate::block_import::{ BlockImport, BlockOrigin, ImportBlock, ImportedAux, ImportResult, JustificationImport, }; use crossbeam_channel::{self as channel, Receiver, Sender}; +use parity_codec::Encode; use std::sync::Arc; use std::thread; @@ -38,6 +39,7 @@ use runtime_primitives::traits::{ use runtime_primitives::Justification; use crate::error::Error as ConsensusError; +use parity_codec::alloc::collections::hash_map::HashMap; /// Shared block import struct used by the queue. pub type SharedBlockImport = Arc + Send + Sync>; @@ -566,7 +568,12 @@ pub fn import_single_block>( BlockImportError::VerificationFailed(peer.clone(), msg) })?; - import_error(import_handle.import_block(import_block, new_authorities)) + let mut cache = HashMap::new(); + if let Some(authorities) = new_authorities { + cache.insert(crate::well_known_cache_keys::AUTHORITIES.to_vec(), authorities.encode()); + } + + import_error(import_handle.import_block(import_block, cache)) } #[cfg(test)] diff --git a/core/consensus/common/src/lib.rs b/core/consensus/common/src/lib.rs index 73315ed7aa9c6..c1308f2da91a7 100644 --- a/core/consensus/common/src/lib.rs +++ b/core/consensus/common/src/lib.rs @@ -53,7 +53,9 @@ pub use block_import::{ /// Trait for getting the authorities at a given block. pub trait Authorities { - type Error: ::std::error::Error + Send + 'static; /// Get the authorities at the given block. + type Error: std::error::Error + Send + 'static; + + /// Get the authorities at the given block. fn authorities(&self, at: &BlockId) -> Result>, Self::Error>; } @@ -115,3 +117,9 @@ impl SyncOracle for Arc { T::is_offline(&*self) } } + +/// A list of all well known keys in the cache. +pub mod well_known_cache_keys { + /// A list of authorities. + pub const AUTHORITIES: &'static [u8] = b"auth"; +} diff --git a/core/finality-grandpa/src/import.rs b/core/finality-grandpa/src/import.rs index 9afbe443f9c78..7914660e299c9 100644 --- a/core/finality-grandpa/src/import.rs +++ b/core/finality-grandpa/src/import.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use std::sync::Arc; +use std::{sync::Arc, collections::HashMap}; use log::{debug, trace, info}; use parity_codec::Encode; @@ -388,7 +388,7 @@ impl, RA, PRA> BlockImport { type Error = ConsensusError; - fn import_block(&self, mut block: ImportBlock, new_authorities: Option>) + fn import_block(&self, mut block: ImportBlock, new_cache: HashMap, Vec>) -> Result { let hash = block.post_header().hash(); @@ -406,8 +406,8 @@ impl, RA, PRA> BlockImport // we don't want to finalize on `inner.import_block` let mut justification = block.justification.take(); - let enacts_consensus_change = new_authorities.is_some(); - let import_result = self.inner.import_block(block, new_authorities); + let enacts_consensus_change = !new_cache.is_empty(); + let import_result = self.inner.import_block(block, new_cache); let mut imported_aux = { match import_result { diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 582439419e758..f0d5894bb6d6a 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -277,16 +277,6 @@ impl Core for RuntimeApi { unimplemented!("Not required for testing!") } - fn authorities_runtime_api_impl( - &self, - _: &BlockId, - _: ExecutionContext, - _: Option<()>, - _: Vec, - ) -> Result>> { - unimplemented!("Not required for testing!") - } - fn execute_block_runtime_api_impl( &self, _: &BlockId, @@ -992,12 +982,12 @@ fn allows_reimporting_change_blocks() { }; assert_eq!( - block_import.import_block(block(), None).unwrap(), + block_import.import_block(block(), HashMap::new()).unwrap(), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, bad_justification: false }), ); assert_eq!( - block_import.import_block(block(), None).unwrap(), + block_import.import_block(block(), HashMap::new()).unwrap(), ImportResult::AlreadyInChain ); } @@ -1035,12 +1025,12 @@ fn test_bad_justification() { }; assert_eq!( - block_import.import_block(block(), None).unwrap(), + block_import.import_block(block(), HashMap::new()).unwrap(), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, bad_justification: true }), ); assert_eq!( - block_import.import_block(block(), None).unwrap(), + block_import.import_block(block(), HashMap::new()).unwrap(), ImportResult::AlreadyInChain ); } diff --git a/core/network/src/chain.rs b/core/network/src/chain.rs index 87c0dca9c1306..92236e7c63848 100644 --- a/core/network/src/chain.rs +++ b/core/network/src/chain.rs @@ -20,18 +20,13 @@ use client::{self, Client as SubstrateClient, ClientInfo, BlockStatus, CallExecu use client::error::Error; use client::light::fetcher::ChangesProof; use consensus::{BlockImport, Error as ConsensusError}; -use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, AuthorityIdFor}; +use runtime_primitives::traits::{Block as BlockT, Header as HeaderT}; use runtime_primitives::generic::{BlockId}; -use consensus::{ImportBlock, ImportResult}; use runtime_primitives::Justification; use primitives::{H256, Blake2Hasher, storage::StorageKey}; /// Local client abstraction for the network. pub trait Client: Send + Sync { - /// Import a new block. Parent is supposed to be existing in the blockchain. - fn import(&self, block: ImportBlock, new_authorities: Option>>) - -> Result; - /// Get blockchain info. fn info(&self) -> Result, Error>; @@ -80,12 +75,6 @@ impl Client for SubstrateClient where Block: BlockT, RA: Send + Sync { - fn import(&self, block: ImportBlock, new_authorities: Option>>) - -> Result - { - (self as &SubstrateClient).import_block(block, new_authorities) - } - fn info(&self) -> Result, Error> { (self as &SubstrateClient).info() } diff --git a/core/rpc/src/state/tests.rs b/core/rpc/src/state/tests.rs index f28e63b15d62c..6746685d368ff 100644 --- a/core/rpc/src/state/tests.rs +++ b/core/rpc/src/state/tests.rs @@ -221,7 +221,7 @@ fn should_return_runtime_version() { assert_eq!( ::serde_json::to_string(&api.runtime_version(None.into()).unwrap()).unwrap(), - r#"{"specName":"test","implName":"parity-test","authoringVersion":1,"specVersion":1,"implVersion":1,"apis":[["0xdf6acb689907609b",1],["0x37e397fc7c91f5e4",1],["0xd2bc9897eed08f15",1],["0x40fe3ad401f8959a",2],["0xc6e9a76309f39b09",1],["0xdd718d5cc53262d4",1],["0xf78b278be53f454c",1]]}"# + r#"{"specName":"test","implName":"parity-test","authoringVersion":1,"specVersion":1,"implVersion":1,"apis":[["0xdf6acb689907609b",1],["0x37e397fc7c91f5e4",1],["0xd2bc9897eed08f15",1],["0x40fe3ad401f8959a",2],["0xc6e9a76309f39b09",1],["0xdd718d5cc53262d4",1],["0xf78b278be53f454c",1],["0x7801759919ee83e5",1]]}"# ); } diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 1735382bb23ca..66975d4f20932 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -20,6 +20,7 @@ use std::iter; use std::sync::Arc; use std::net::Ipv4Addr; use std::time::Duration; +use std::collections::HashMap; use log::info; use futures::{Future, Stream}; use tempdir::TempDir; @@ -227,7 +228,7 @@ where info!("Generating #{}", i); } let import_data = block_factory(&first_service); - first_service.client().import_block(import_data, None).expect("Error importing test block"); + first_service.client().import_block(import_data, HashMap::new()).expect("Error importing test block"); } first_service.network().node_id().unwrap() }; diff --git a/core/sr-api-macros/tests/decl_and_impl.rs b/core/sr-api-macros/tests/decl_and_impl.rs index c5ef8cbb3e35a..a8b31561238ae 100644 --- a/core/sr-api-macros/tests/decl_and_impl.rs +++ b/core/sr-api-macros/tests/decl_and_impl.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use runtime_primitives::traits::{GetNodeBlockType, Block as BlockT, AuthorityIdFor}; +use runtime_primitives::traits::{GetNodeBlockType, Block as BlockT}; use runtime_primitives::generic::BlockId; use client::runtime_api::{self, RuntimeApiInfo}; use client::{error::Result, decl_runtime_apis, impl_runtime_apis}; @@ -68,9 +68,6 @@ impl_runtime_apis! { fn version() -> runtime_api::RuntimeVersion { unimplemented!() } - fn authorities() -> Vec> { - unimplemented!() - } fn execute_block(_: Block) { unimplemented!() } diff --git a/core/test-client/src/client_ext.rs b/core/test-client/src/client_ext.rs index 511b55ff62280..70e7feb078882 100644 --- a/core/test-client/src/client_ext.rs +++ b/core/test-client/src/client_ext.rs @@ -22,6 +22,7 @@ use runtime_primitives::Justification; use runtime_primitives::generic::BlockId; use primitives::Blake2Hasher; use runtime; +use parity_codec::alloc::collections::hash_map::HashMap; /// Extension trait for a test client. pub trait TestClient: Sized { @@ -60,7 +61,7 @@ impl TestClient for Client fork_choice: ForkChoiceStrategy::LongestChain, }; - self.import_block(import, None).map(|_| ()) + self.import_block(import, HashMap::new()).map(|_| ()) } fn import_justified(&self, origin: BlockOrigin, block: runtime::Block, justification: Justification) @@ -77,7 +78,7 @@ impl TestClient for Client fork_choice: ForkChoiceStrategy::LongestChain, }; - self.import_block(import, None).map(|_| ()) + self.import_block(import, HashMap::new()).map(|_| ()) } fn finalize_block(&self, id: BlockId, justification: Option) -> client::error::Result<()> { diff --git a/core/test-runtime/Cargo.toml b/core/test-runtime/Cargo.toml index 6132cbbb1aeaa..eb74eb68abb3b 100644 --- a/core/test-runtime/Cargo.toml +++ b/core/test-runtime/Cargo.toml @@ -23,6 +23,7 @@ runtime_support = { package = "srml-support", path = "../../srml/support", defau offchain-primitives = { package = "substrate-offchain-primitives", path = "../offchain/primitives", default-features = false} executive = { package = "srml-executive", path = "../../srml/executive", default-features = false } cfg-if = "0.1.6" +consensus_authorities = { package = "substrate-consensus-authorities", path = "../../core/consensus/authorities", default-features = false } [dev-dependencies] substrate-executor = { path = "../executor" } diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 744bdd7fea494..028bb7ba52b2a 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -34,7 +34,7 @@ use runtime_primitives::{ create_runtime_str, traits::{ BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, - GetNodeBlockType, GetRuntimeBlockType, + GetNodeBlockType, GetRuntimeBlockType, AuthorityIdFor, }, }; use runtime_version::RuntimeVersion; @@ -289,10 +289,6 @@ cfg_if! { version() } - fn authorities() -> Vec { - system::authorities() - } - fn execute_block(block: Block) { system::execute_block(block) } @@ -386,6 +382,12 @@ cfg_if! { runtime_io::submit_extrinsic(&ex) } } + + impl consensus_authorities::AuthoritiesApi for Runtime { + fn authorities() -> Vec> { + crate::system::authorities() + } + } } } else { impl_runtime_apis! { @@ -394,10 +396,6 @@ cfg_if! { version() } - fn authorities() -> Vec { - system::authorities() - } - fn execute_block(block: Block) { system::execute_block(block) } @@ -496,6 +494,12 @@ cfg_if! { runtime_io::submit_extrinsic(&ex) } } + + impl consensus_authorities::AuthoritiesApi for Runtime { + fn authorities() -> Vec> { + crate::system::authorities() + } + } } } } \ No newline at end of file diff --git a/core/test-runtime/wasm/Cargo.lock b/core/test-runtime/wasm/Cargo.lock index ced5304a73bd5..e3c211fa936c9 100644 --- a/core/test-runtime/wasm/Cargo.lock +++ b/core/test-runtime/wasm/Cargo.lock @@ -2284,6 +2284,20 @@ dependencies = [ "substrate-client 0.1.0", ] +[[package]] +name = "substrate-consensus-authorities" +version = "0.1.0" +dependencies = [ + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", + "sr-primitives 0.1.0", + "sr-std 0.1.0", + "sr-version 0.1.0", + "srml-support 0.1.0", + "substrate-client 0.1.0", + "substrate-primitives 0.1.0", +] + [[package]] name = "substrate-consensus-common" version = "0.1.0" @@ -2453,6 +2467,7 @@ dependencies = [ "srml-support 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-consensus-authorities 0.1.0", "substrate-inherents 0.1.0", "substrate-keyring 0.1.0", "substrate-offchain-primitives 0.1.0", diff --git a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 9113d509fd767..8f90cec76d61d 100644 Binary files a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 2ba64a3a9cdb9..6a312e5530fa5 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -26,6 +26,7 @@ runtime-primitives = { package = "sr-primitives", path = "../../core/sr-primitiv client = { package = "substrate-client", path = "../../core/client", default_features = false } consensus-aura = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives", default_features = false } offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false } +consensus_authorities = { package = "substrate-consensus-authorities", path = "../../core/consensus/authorities", default-features = false } [features] default = ["std"] diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index c5c3b0d01d72b..5299831ea5cf2 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -234,10 +234,6 @@ impl_runtime_apis! { VERSION } - fn authorities() -> Vec { - Consensus::authorities() - } - fn execute_block(block: Block) { Executive::execute_block(block) } @@ -292,4 +288,10 @@ impl_runtime_apis! { Executive::offchain_worker(n) } } + + impl consensus_authorities::AuthoritiesApi for Runtime { + fn authorities() -> Vec { + Consensus::authorities() + } + } } diff --git a/node-template/runtime/wasm/Cargo.lock b/node-template/runtime/wasm/Cargo.lock index b54048856d655..824a8f3650fec 100644 --- a/node-template/runtime/wasm/Cargo.lock +++ b/node-template/runtime/wasm/Cargo.lock @@ -1273,6 +1273,7 @@ dependencies = [ "srml-timestamp 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-consensus-authorities 0.1.0", "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", ] @@ -2449,6 +2450,20 @@ dependencies = [ "substrate-client 0.1.0", ] +[[package]] +name = "substrate-consensus-authorities" +version = "0.1.0" +dependencies = [ + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", + "sr-primitives 0.1.0", + "sr-std 0.1.0", + "sr-version 0.1.0", + "srml-support 0.1.0", + "substrate-client 0.1.0", + "substrate-primitives 0.1.0", +] + [[package]] name = "substrate-consensus-common" version = "0.1.0" diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 95283c03f2540..2b7554c79dacd 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -86,30 +86,32 @@ construct_service_factory! { FullImportQueue = AuraImportQueue< Self::Block, > - { |config: &mut FactoryFullConfiguration , client: Arc>| + { |config: &mut FactoryFullConfiguration , client: Arc>| { import_queue::<_, _, _, Pair>( - SlotDuration::get_or_compute(&*client)?, - client.clone(), - None, - client, - NothingExtra, - config.custom.inherent_data_providers.clone(), + SlotDuration::get_or_compute(&*client)?, + client.clone(), + None, + client, + NothingExtra, + config.custom.inherent_data_providers.clone(), true, - ).map_err(Into::into) + ).map_err(Into::into) + } }, LightImportQueue = AuraImportQueue< Self::Block, > - { |config: &mut FactoryFullConfiguration, client: Arc>| + { |config: &mut FactoryFullConfiguration, client: Arc>| { import_queue::<_, _, _, Pair>( - SlotDuration::get_or_compute(&*client)?, - client.clone(), - None, - client, - NothingExtra, - config.custom.inherent_data_providers.clone(), + SlotDuration::get_or_compute(&*client)?, + client.clone(), + None, + client, + NothingExtra, + config.custom.inherent_data_providers.clone(), true, - ).map_err(Into::into) + ).map_err(Into::into) + } }, } } diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 6c0307d47e1f7..3fe3adce30a49 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -37,6 +37,7 @@ rustc-hex = { version = "2.0", optional = true } hex-literal = { version = "0.1.0", optional = true } serde = { version = "1.0", optional = true } substrate-keyring = { path = "../../core/keyring", optional = true } +consensus_authorities = { package = "substrate-consensus-authorities", path = "../../core/consensus/authorities", default-features = false } [features] default = ["std"] diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d720681ebe4bd..8be70a6bcfb1e 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -34,7 +34,8 @@ use client::{ use runtime_primitives::{ApplyResult, generic, create_runtime_str}; use runtime_primitives::transaction_validity::TransactionValidity; use runtime_primitives::traits::{ - BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, CurrencyToVoteHandler + BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup, CurrencyToVoteHandler, + AuthorityIdFor, }; use version::RuntimeVersion; use council::{motions as council_motions, voting as council_voting}; @@ -58,8 +59,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node"), impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, - spec_version: 52, - impl_version: 52, + spec_version: 53, + impl_version: 53, apis: RUNTIME_API_VERSIONS, }; @@ -243,10 +244,6 @@ impl_runtime_apis! { VERSION } - fn authorities() -> Vec { - Consensus::authorities() - } - fn execute_block(block: Block) { Executive::execute_block(block) } @@ -335,4 +332,10 @@ impl_runtime_apis! { Aura::slot_duration() } } + + impl consensus_authorities::AuthoritiesApi for Runtime { + fn authorities() -> Vec> { + Consensus::authorities() + } + } } diff --git a/node/runtime/wasm/Cargo.lock b/node/runtime/wasm/Cargo.lock index 146474068affd..d9bb349bc9823 100644 --- a/node/runtime/wasm/Cargo.lock +++ b/node/runtime/wasm/Cargo.lock @@ -1296,6 +1296,7 @@ dependencies = [ "srml-treasury 0.1.0", "substrate-client 0.1.0", "substrate-consensus-aura-primitives 0.1.0", + "substrate-consensus-authorities 0.1.0", "substrate-keyring 0.1.0", "substrate-offchain-primitives 0.1.0", "substrate-primitives 0.1.0", @@ -2593,6 +2594,20 @@ dependencies = [ "substrate-client 0.1.0", ] +[[package]] +name = "substrate-consensus-authorities" +version = "0.1.0" +dependencies = [ + "parity-codec 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", + "sr-primitives 0.1.0", + "sr-std 0.1.0", + "sr-version 0.1.0", + "srml-support 0.1.0", + "substrate-client 0.1.0", + "substrate-primitives 0.1.0", +] + [[package]] name = "substrate-consensus-common" version = "0.1.0" diff --git a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 1ae0a286ed67c..53c5a9e15e62c 100644 Binary files a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/srml/council/src/seats.rs b/srml/council/src/seats.rs index 08bcd5f5d4823..9ace6227da636 100644 --- a/srml/council/src/seats.rs +++ b/srml/council/src/seats.rs @@ -470,7 +470,7 @@ impl Module { // NOTE: this must be the last potential bailer, since it changes state. T::Currency::reserve(&who, Self::voting_bond())?; - >::mutate(|mut v| v.push(who.clone())); + >::mutate(|v| v.push(who.clone())); } >::insert(&who, index); >::insert(&who, votes);