Move authorities interface from Core to consensus (#1412)

* Move authorities interface from Core to consensus

f

* notify all caches of block insert + create with up-to-date best_fin

* merged authorities_are_cached from light_grandpa_import2

* Add ProvideCache trait

* Create helper function for 'get_cache'

* Fix some formatting

* Bump impl version

* Resolve wasm conflicts

* Apply review comments

* Use try_for_each

* Move authorities interface from Core to consensus

f

* notify all caches of block insert + create with up-to-date best_fin

* merged authorities_are_cached from light_grandpa_import2

* Add ProvideCache trait

* Create helper function for 'get_cache'

* Fix some formatting

* Bump impl version

* Resolve wasm conflicts

* Apply review comments

* Use try_for_each

* Move authorities interface from Core to consensus

f

* notify all caches of block insert + create with up-to-date best_fin

* merged authorities_are_cached from light_grandpa_import2

* Add ProvideCache trait

* Create helper function for 'get_cache'

* Fix some formatting

* Bump impl version

* Resolve wasm conflicts

* Apply review comments

* Use try_for_each

* Increment impl_version

* Update lib.rs
This commit is contained in:
Stanislav Tkach
2019-03-29 18:41:22 +02:00
committed by Gav Wood
parent 55788fdf77
commit cbfc36b39f
44 changed files with 650 additions and 409 deletions
+19
View File
@@ -1973,6 +1973,7 @@ dependencies = [
"srml-treasury 0.1.0", "srml-treasury 0.1.0",
"substrate-client 0.1.0", "substrate-client 0.1.0",
"substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-aura-primitives 0.1.0",
"substrate-consensus-authorities 0.1.0",
"substrate-keyring 0.1.0", "substrate-keyring 0.1.0",
"substrate-offchain-primitives 0.1.0", "substrate-offchain-primitives 0.1.0",
"substrate-primitives 0.1.0", "substrate-primitives 0.1.0",
@@ -2030,6 +2031,7 @@ dependencies = [
"srml-timestamp 0.1.0", "srml-timestamp 0.1.0",
"substrate-client 0.1.0", "substrate-client 0.1.0",
"substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-aura-primitives 0.1.0",
"substrate-consensus-authorities 0.1.0",
"substrate-offchain-primitives 0.1.0", "substrate-offchain-primitives 0.1.0",
"substrate-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)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-primitives 0.1.0", "sr-primitives 0.1.0",
"substrate-client 0.1.0", "substrate-client 0.1.0",
"substrate-consensus-common 0.1.0",
"substrate-executor 0.1.0", "substrate-executor 0.1.0",
"substrate-keyring 0.1.0", "substrate-keyring 0.1.0",
"substrate-primitives 0.1.0", "substrate-primitives 0.1.0",
@@ -3741,6 +3744,7 @@ dependencies = [
"substrate-client 0.1.0", "substrate-client 0.1.0",
"substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-aura-primitives 0.1.0",
"substrate-consensus-aura-slots 0.1.0", "substrate-consensus-aura-slots 0.1.0",
"substrate-consensus-authorities 0.1.0",
"substrate-consensus-common 0.1.0", "substrate-consensus-common 0.1.0",
"substrate-executor 0.1.0", "substrate-executor 0.1.0",
"substrate-inherents 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)", "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]] [[package]]
name = "substrate-consensus-common" name = "substrate-consensus-common"
version = "0.1.0" version = "0.1.0"
@@ -4251,6 +4269,7 @@ dependencies = [
"srml-support 0.1.0", "srml-support 0.1.0",
"substrate-client 0.1.0", "substrate-client 0.1.0",
"substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-aura-primitives 0.1.0",
"substrate-consensus-authorities 0.1.0",
"substrate-executor 0.1.0", "substrate-executor 0.1.0",
"substrate-inherents 0.1.0", "substrate-inherents 0.1.0",
"substrate-keyring 0.1.0", "substrate-keyring 0.1.0",
-4
View File
@@ -63,10 +63,6 @@ impl_runtime_apis! {
VERSION VERSION
} }
fn authorities() -> Vec<SessionKey> {
Consensus::authorities()
}
fn execute_block(block: Block) { fn execute_block(block: Block) {
Executive::execute_block(block) Executive::execute_block(block)
} }
+1
View File
@@ -26,6 +26,7 @@ trie = { package = "substrate-trie", path = "../../trie" }
kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" } kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" }
substrate-keyring = { path = "../../keyring" } substrate-keyring = { path = "../../keyring" }
test-client = { package = "substrate-test-client", path = "../../test-client" } test-client = { package = "substrate-test-client", path = "../../test-client" }
consensus_common = { package = "substrate-consensus-common", path = "../../consensus/common" }
env_logger = { version = "0.6" } env_logger = { version = "0.6" }
[features] [features]
+123 -47
View File
@@ -16,7 +16,7 @@
//! DB-backed cache of blockchain data. //! DB-backed cache of blockchain data.
use std::sync::Arc; use std::{sync::Arc, collections::HashMap};
use parking_lot::RwLock; use parking_lot::RwLock;
use kvdb::{KeyValueDB, DBTransaction}; use kvdb::{KeyValueDB, DBTransaction};
@@ -25,7 +25,7 @@ use client::blockchain::Cache as BlockchainCache;
use client::error::Result as ClientResult; use client::error::Result as ClientResult;
use parity_codec::{Encode, Decode}; use parity_codec::{Encode, Decode};
use runtime_primitives::generic::BlockId; 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 crate::utils::{self, COLUMN_META};
use self::list_cache::ListCache; use self::list_cache::ListCache;
@@ -64,7 +64,12 @@ impl<T> CacheItemT for T where T: Clone + Decode + Encode + PartialEq {}
/// Database-backed blockchain data cache. /// Database-backed blockchain data cache.
pub struct DbCache<Block: BlockT> { pub struct DbCache<Block: BlockT> {
authorities_at: ListCache<Block, Vec<AuthorityIdFor<Block>>, self::list_storage::DbStorage>, cache_at: HashMap<Vec<u8>, ListCache<Block, Vec<u8>, self::list_storage::DbStorage>>,
db: Arc<KeyValueDB>,
key_lookup_column: Option<u32>,
header_column: Option<u32>,
authorities_column: Option<u32>,
best_finalized_block: ComplexBlockId<Block>,
} }
impl<Block: BlockT> DbCache<Block> { impl<Block: BlockT> DbCache<Block> {
@@ -76,19 +81,13 @@ impl<Block: BlockT> DbCache<Block> {
authorities_column: Option<u32>, authorities_column: Option<u32>,
best_finalized_block: ComplexBlockId<Block>, best_finalized_block: ComplexBlockId<Block>,
) -> Self { ) -> Self {
DbCache { Self {
authorities_at: ListCache::new( cache_at: HashMap::new(),
self::list_storage::DbStorage::new(b"auth".to_vec(), db, db,
self::list_storage::DbColumns { key_lookup_column,
meta: COLUMN_META, header_column,
key_lookup: key_lookup_column, authorities_column,
header: header_column, best_finalized_block,
cache: authorities_column,
},
),
As::sa(PRUNE_DEPTH),
best_finalized_block,
),
} }
} }
@@ -97,35 +96,82 @@ impl<Block: BlockT> DbCache<Block> {
DbCacheTransaction { DbCacheTransaction {
cache: self, cache: self,
tx, tx,
authorities_at_op: None, cache_at_op: HashMap::new(),
best_finalized_block: None,
} }
} }
/// Run post-commit cache operations. /// Run post-commit cache operations.
pub fn commit(&mut self, ops: DbCacheTransactionOps<Block>) { pub fn commit(&mut self, ops: DbCacheTransactionOps<Block>) {
if let Some(authorities_at_op) = ops.authorities_at_op { for (name, op) in ops.cache_at_op.into_iter() {
self.authorities_at.on_transaction_commit(authorities_at_op); 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<u8>) -> &mut ListCache<Block, Vec<u8>, 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<Vec<u8>, ListCache<Block, Vec<u8>, self::list_storage::DbStorage>>,
name: Vec<u8>,
db: &Arc<KeyValueDB>,
key_lookup: Option<u32>,
header: Option<u32>,
cache: Option<u32>,
best_finalized_block: &ComplexBlockId<Block>,
) -> &'a mut ListCache<Block, Vec<u8>, 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. /// Cache operations that are to be committed after database transaction is committed.
pub struct DbCacheTransactionOps<Block: BlockT> { pub struct DbCacheTransactionOps<Block: BlockT> {
authorities_at_op: Option<self::list_cache::CommitOperation<Block, Vec<AuthorityIdFor<Block>>>>, cache_at_op: HashMap<Vec<u8>, self::list_cache::CommitOperation<Block, Vec<u8>>>,
best_finalized_block: Option<ComplexBlockId<Block>>,
} }
/// Database-backed blockchain data cache transaction valid for single block import. /// Database-backed blockchain data cache transaction valid for single block import.
pub struct DbCacheTransaction<'a, Block: BlockT> { pub struct DbCacheTransaction<'a, Block: BlockT> {
cache: &'a mut DbCache<Block>, cache: &'a mut DbCache<Block>,
tx: &'a mut DBTransaction, tx: &'a mut DBTransaction,
authorities_at_op: Option<self::list_cache::CommitOperation<Block, Vec<AuthorityIdFor<Block>>>>, cache_at_op: HashMap<Vec<u8>, self::list_cache::CommitOperation<Block, Vec<u8>>>,
best_finalized_block: Option<ComplexBlockId<Block>>,
} }
impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> { impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
/// Convert transaction into post-commit operations set. /// Convert transaction into post-commit operations set.
pub fn into_ops(self) -> DbCacheTransactionOps<Block> { pub fn into_ops(self) -> DbCacheTransactionOps<Block> {
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, mut self,
parent: ComplexBlockId<Block>, parent: ComplexBlockId<Block>,
block: ComplexBlockId<Block>, block: ComplexBlockId<Block>,
authorities_at: Option<Vec<AuthorityIdFor<Block>>>, data_at: HashMap<Vec<u8>, Vec<u8>>,
is_final: bool, is_final: bool,
) -> ClientResult<Self> { ) -> ClientResult<Self> {
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( // prepare list of caches that are not update
&mut self::list_storage::DbStorageTransaction::new( // (we might still need to do some cache maintenance in this case)
self.cache.authorities_at.storage(), let missed_caches = self.cache.cache_at.keys()
&mut self.tx .filter(|cache| !data_at.contains_key(cache.clone()))
), .cloned()
parent, .collect::<Vec<_>>();
block,
authorities_at, let mut insert_op = |name: Vec<u8>, value: Option<Vec<u8>>| -> Result<(), client::error::Error> {
is_final, 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) Ok(self)
} }
@@ -159,16 +226,24 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
parent: ComplexBlockId<Block>, parent: ComplexBlockId<Block>,
block: ComplexBlockId<Block> block: ComplexBlockId<Block>
) -> ClientResult<Self> { ) -> ClientResult<Self> {
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( for (name, cache_at) in self.cache.cache_at.iter() {
&mut self::list_storage::DbStorageTransaction::new( let op = cache_at.on_block_finalize(
self.cache.authorities_at.storage(), &mut self::list_storage::DbStorageTransaction::new(
&mut self.tx cache_at.storage(),
), &mut self.tx
parent, ),
block, 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) Ok(self)
} }
@@ -178,12 +253,12 @@ impl<'a, Block: BlockT> DbCacheTransaction<'a, Block> {
pub struct DbCacheSync<Block: BlockT>(pub RwLock<DbCache<Block>>); pub struct DbCacheSync<Block: BlockT>(pub RwLock<DbCache<Block>>);
impl<Block: BlockT> BlockchainCache<Block> for DbCacheSync<Block> { impl<Block: BlockT> BlockchainCache<Block> for DbCacheSync<Block> {
fn authorities_at(&self, at: BlockId<Block>) -> Option<Vec<AuthorityIdFor<Block>>> { fn get_at(&self, key: &[u8], at: &BlockId<Block>) -> Option<Vec<u8>> {
let cache = self.0.read(); let cache = self.0.read();
let storage = cache.authorities_at.storage(); let storage = cache.cache_at.get(key)?.storage();
let db = storage.db(); let db = storage.db();
let columns = storage.columns(); let columns = storage.columns();
let at = match at { let at = match *at {
BlockId::Hash(hash) => { BlockId::Hash(hash) => {
let header = utils::read_header::<Block>( let header = utils::read_header::<Block>(
&**db, &**db,
@@ -202,6 +277,7 @@ impl<Block: BlockT> BlockchainCache<Block> for DbCacheSync<Block> {
}, },
}; };
cache.authorities_at.value_at_block(&at).ok()? cache.cache_at.get(key)?.value_at_block(&at).ok()?
} }
} }
+11 -4
View File
@@ -33,6 +33,7 @@ mod utils;
use std::sync::Arc; use std::sync::Arc;
use std::path::PathBuf; use std::path::PathBuf;
use std::io; use std::io;
use std::collections::HashMap;
use client::backend::NewBlockState; use client::backend::NewBlockState;
use client::blockchain::HeaderBackend; use client::blockchain::HeaderBackend;
@@ -45,7 +46,7 @@ use parking_lot::RwLock;
use primitives::{H256, Blake2Hasher, ChangesTrieConfiguration, convert_hash}; use primitives::{H256, Blake2Hasher, ChangesTrieConfiguration, convert_hash};
use primitives::storage::well_known_keys; use primitives::storage::well_known_keys;
use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; 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 runtime_primitives::BuildStorage;
use state_machine::backend::Backend as StateBackend; use state_machine::backend::Backend as StateBackend;
use executor::RuntimeInfo; use executor::RuntimeInfo;
@@ -243,7 +244,7 @@ impl<Block: BlockT> client::blockchain::Backend<Block> for BlockchainDb<Block> {
Ok(self.meta.read().finalized_hash.clone()) Ok(self.meta.read().finalized_hash.clone())
} }
fn cache(&self) -> Option<&client::blockchain::Cache<Block>> { fn cache(&self) -> Option<Arc<client::blockchain::Cache<Block>>> {
None None
} }
@@ -256,6 +257,12 @@ impl<Block: BlockT> client::blockchain::Backend<Block> for BlockchainDb<Block> {
} }
} }
impl<Block: BlockT> client::blockchain::ProvideCache<Block> for BlockchainDb<Block> {
fn cache(&self) -> Option<Arc<client::blockchain::Cache<Block>>> {
None
}
}
/// Database transaction /// Database transaction
pub struct BlockImportOperation<Block: BlockT, H: Hasher> { pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
old_state: CachingState<Blake2Hasher, DbState, Block>, old_state: CachingState<Blake2Hasher, DbState, Block>,
@@ -306,8 +313,8 @@ where Block: BlockT<Hash=H256>,
Ok(()) Ok(())
} }
fn update_authorities(&mut self, _authorities: Vec<AuthorityIdFor<Block>>) { fn update_cache(&mut self, _cache: HashMap<Vec<u8>, Vec<u8>>) {
// currently authorities are not cached on full nodes // Currently cache isn't implemented on full nodes.
} }
fn update_db_storage(&mut self, update: PrefixedMemoryDB<Blake2Hasher>) -> Result<(), client::error::Error> { fn update_db_storage(&mut self, update: PrefixedMemoryDB<Blake2Hasher>) -> Result<(), client::error::Error> {
+156 -110
View File
@@ -16,7 +16,7 @@
//! RocksDB-based light client blockchain storage. //! RocksDB-based light client blockchain storage.
use std::sync::Arc; use std::{sync::Arc, collections::HashMap};
use parking_lot::RwLock; use parking_lot::RwLock;
use kvdb::{KeyValueDB, DBTransaction}; use kvdb::{KeyValueDB, DBTransaction};
@@ -32,7 +32,7 @@ use parity_codec::{Decode, Encode};
use primitives::Blake2Hasher; use primitives::Blake2Hasher;
use runtime_primitives::generic::BlockId; use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, 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::cache::{DbCacheSync, DbCache, ComplexBlockId};
use crate::utils::{self, meta_keys, Meta, db_err, open_database, use crate::utils::{self, meta_keys, Meta, db_err, open_database,
read_db, block_id_to_lookup_key, read_meta}; read_db, block_id_to_lookup_key, read_meta};
@@ -59,7 +59,7 @@ pub struct LightStorage<Block: BlockT> {
db: Arc<KeyValueDB>, db: Arc<KeyValueDB>,
meta: RwLock<Meta<NumberFor<Block>, Block::Hash>>, meta: RwLock<Meta<NumberFor<Block>, Block::Hash>>,
leaves: RwLock<LeafSet<Block::Hash, NumberFor<Block>>>, leaves: RwLock<LeafSet<Block::Hash, NumberFor<Block>>>,
cache: DbCacheSync<Block>, cache: Arc<DbCacheSync<Block>>,
} }
impl<Block> LightStorage<Block> impl<Block> LightStorage<Block>
@@ -96,7 +96,7 @@ impl<Block> LightStorage<Block>
Ok(LightStorage { Ok(LightStorage {
db, db,
meta: RwLock::new(meta), meta: RwLock::new(meta),
cache: DbCacheSync(RwLock::new(cache)), cache: Arc::new(DbCacheSync(RwLock::new(cache))),
leaves: RwLock::new(leaves), leaves: RwLock::new(leaves),
}) })
} }
@@ -370,7 +370,7 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
fn import_header( fn import_header(
&self, &self,
header: Block::Header, header: Block::Header,
authorities: Option<Vec<AuthorityIdFor<Block>>>, cache_at: HashMap<Vec<u8>, Vec<u8>>,
leaf_state: NewBlockState, leaf_state: NewBlockState,
aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>, aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
) -> ClientResult<()> { ) -> ClientResult<()> {
@@ -432,7 +432,7 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
.on_block_insert( .on_block_insert(
ComplexBlockId::new(*header.parent_hash(), if number.is_zero() { Zero::zero() } else { number - One::one() }), ComplexBlockId::new(*header.parent_hash(), if number.is_zero() { Zero::zero() } else { number - One::one() }),
ComplexBlockId::new(hash, number), ComplexBlockId::new(hash, number),
authorities, cache_at,
finalized, finalized,
)? )?
.into_ops(); .into_ops();
@@ -521,8 +521,8 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
Ok(self.meta.read().finalized_hash.clone()) Ok(self.meta.read().finalized_hash.clone())
} }
fn cache(&self) -> Option<&BlockchainCache<Block>> { fn cache(&self) -> Option<Arc<BlockchainCache<Block>>> {
Some(&self.cache) Some(self.cache.clone())
} }
} }
@@ -538,6 +538,8 @@ pub(crate) mod tests {
use client::cht; use client::cht;
use runtime_primitives::generic::DigestItem; use runtime_primitives::generic::DigestItem;
use runtime_primitives::testing::{H256 as Hash, Header, Block as RawBlock, ExtrinsicWrapper}; 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::*; use super::*;
type Block = RawBlock<ExtrinsicWrapper<u32>>; type Block = RawBlock<ExtrinsicWrapper<u32>>;
@@ -567,41 +569,41 @@ pub(crate) mod tests {
pub fn insert_block<F: Fn() -> Header>( pub fn insert_block<F: Fn() -> Header>(
db: &LightStorage<Block>, db: &LightStorage<Block>,
authorities: Option<Vec<AuthorityIdFor<Block>>>, cache: HashMap<Vec<u8>, Vec<u8>>,
header: F, header: F,
) -> Hash { ) -> Hash {
let header = header(); let header = header();
let hash = header.hash(); 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 hash
} }
fn insert_final_block<F: Fn() -> Header>( fn insert_final_block<F: Fn() -> Header>(
db: &LightStorage<Block>, db: &LightStorage<Block>,
authorities: Option<Vec<AuthorityIdFor<Block>>>, cache: HashMap<Vec<u8>, Vec<u8>>,
header: F, header: F,
) -> Hash { ) -> Hash {
let header = header(); let header = header();
let hash = header.hash(); 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 hash
} }
fn insert_non_best_block<F: Fn() -> Header>( fn insert_non_best_block<F: Fn() -> Header>(
db: &LightStorage<Block>, db: &LightStorage<Block>,
authorities: Option<Vec<AuthorityIdFor<Block>>>, cache: HashMap<Vec<u8>, Vec<u8>>,
header: F, header: F,
) -> Hash { ) -> Hash {
let header = header(); let header = header();
let hash = header.hash(); 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 hash
} }
#[test] #[test]
fn returns_known_header() { fn returns_known_header() {
let db = LightStorage::new_test(); 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_hash = db.header(BlockId::Hash(known_hash)).unwrap().unwrap();
let header_by_number = db.header(BlockId::Number(0)).unwrap().unwrap(); let header_by_number = db.header(BlockId::Number(0)).unwrap().unwrap();
assert_eq!(header_by_hash, header_by_number); assert_eq!(header_by_hash, header_by_number);
@@ -617,12 +619,12 @@ pub(crate) mod tests {
#[test] #[test]
fn returns_info() { fn returns_info() {
let db = LightStorage::new_test(); 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(); let info = db.info().unwrap();
assert_eq!(info.best_hash, genesis_hash); assert_eq!(info.best_hash, genesis_hash);
assert_eq!(info.best_number, 0); assert_eq!(info.best_number, 0);
assert_eq!(info.genesis_hash, genesis_hash); 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(); let info = db.info().unwrap();
assert_eq!(info.best_hash, best_hash); assert_eq!(info.best_hash, best_hash);
assert_eq!(info.best_number, 1); assert_eq!(info.best_number, 1);
@@ -632,7 +634,7 @@ pub(crate) mod tests {
#[test] #[test]
fn returns_block_status() { fn returns_block_status() {
let db = LightStorage::new_test(); 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::Hash(genesis_hash)).unwrap(), BlockStatus::InChain);
assert_eq!(db.status(BlockId::Number(0)).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); assert_eq!(db.status(BlockId::Hash(Hash::from_low_u64_be(1))).unwrap(), BlockStatus::Unknown);
@@ -642,7 +644,7 @@ pub(crate) mod tests {
#[test] #[test]
fn returns_block_hash() { fn returns_block_hash() {
let db = LightStorage::new_test(); 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(0).unwrap(), Some(genesis_hash));
assert_eq!(db.hash(1).unwrap(), None); assert_eq!(db.hash(1).unwrap(), None);
} }
@@ -651,11 +653,11 @@ pub(crate) mod tests {
fn import_header_works() { fn import_header_works() {
let db = LightStorage::new_test(); 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::HEADER).count(), 1);
assert_eq!(db.db.iter(columns::KEY_LOOKUP).count(), 2); 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::HEADER).count(), 2);
assert_eq!(db.db.iter(columns::KEY_LOOKUP).count(), 4); assert_eq!(db.db.iter(columns::KEY_LOOKUP).count(), 4);
} }
@@ -666,25 +668,25 @@ pub(crate) mod tests {
let db = LightStorage::new_test(); let db = LightStorage::new_test();
// insert genesis block header (never pruned) // 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 // insert SIZE blocks && ensure that nothing is pruned
for number in 0..cht::SIZE { 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::HEADER).count(), (1 + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::CHT).count(), 0); assert_eq!(db.db.iter(columns::CHT).count(), 0);
// insert next SIZE blocks && ensure that nothing is pruned // insert next SIZE blocks && ensure that nothing is pruned
for number in 0..cht::SIZE { 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::HEADER).count(), (1 + cht::SIZE + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::CHT).count(), 0); 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 // 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. // 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::HEADER).count(), (2 + cht::SIZE + cht::SIZE) as usize);
assert_eq!(db.db.iter(columns::CHT).count(), 0); assert_eq!(db.db.iter(columns::CHT).count(), 0);
@@ -733,9 +735,9 @@ pub(crate) mod tests {
let db = LightStorage::new_test(); let db = LightStorage::new_test();
// insert 1 + SIZE + SIZE + 1 blocks so that CHT#0 is created // 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 { 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(); db.finalize_header(BlockId::Hash(prev_hash)).unwrap();
} }
@@ -755,16 +757,16 @@ pub(crate) mod tests {
#[test] #[test]
fn tree_route_works() { fn tree_route_works() {
let db = LightStorage::new_test(); 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. // fork from genesis: 3 prong.
let a1 = insert_block(&db, None, || default_header(&block0, 1)); let a1 = insert_block(&db, HashMap::new(), || default_header(&block0, 1));
let a2 = insert_block(&db, None, || default_header(&a1, 2)); let a2 = insert_block(&db, HashMap::new(), || default_header(&a1, 2));
let a3 = insert_block(&db, None, || default_header(&a2, 3)); let a3 = insert_block(&db, HashMap::new(), || default_header(&a2, 3));
// fork from genesis: 2 prong. // fork from genesis: 2 prong.
let b1 = insert_block(&db, None, || header_with_extrinsics_root(&block0, 1, Hash::from([1; 32]))); let b1 = insert_block(&db, HashMap::new(), || header_with_extrinsics_root(&block0, 1, Hash::from([1; 32])));
let b2 = insert_block(&db, None, || default_header(&b1, 2)); let b2 = insert_block(&db, HashMap::new(), || default_header(&b1, 2));
{ {
let tree_route = ::client::blockchain::tree_route( let tree_route = ::client::blockchain::tree_route(
@@ -816,44 +818,64 @@ pub(crate) mod tests {
} }
#[test] #[test]
fn authorites_are_cached() { fn authorities_are_cached() {
let db = LightStorage::new_test(); let db = LightStorage::new_test();
fn run_checks(db: &LightStorage<Block>, max: u64, checks: &[(u64, Option<Vec<AuthorityIdFor<Block>>>)]) { fn run_checks(db: &LightStorage<Block>, max: u64, checks: &[(u64, Option<Vec<AuthorityIdFor<Block>>>)]) {
for (at, expected) in checks.iter().take_while(|(at, _)| *at <= max) { 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); assert_eq!(*expected, actual);
} }
} }
fn same_authorities() -> HashMap<Vec<u8>, Vec<u8>> {
HashMap::new()
}
fn make_authorities(authorities: Vec<AuthorityId>) -> HashMap<Vec<u8>, Vec<u8>> {
let mut map = HashMap::new();
map.insert(well_known_cache_keys::AUTHORITIES.to_vec(), authorities.encode());
map
}
fn get_authorities(cache: &BlockchainCache<Block>, at: BlockId<Block>) -> Option<Vec<AuthorityId>> {
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) = { let (hash2, hash6) = {
// first few blocks are instantly finalized // 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![ let checks = vec![
(0, None), (0, None),
(1, None), (1, None),
(2, Some(vec![AuthorityId::from_raw([1u8; 32])])), (2, Some(vec![auth1()])),
(3, Some(vec![AuthorityId::from_raw([1u8; 32])])), (3, Some(vec![auth1()])),
(4, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])])), (4, Some(vec![auth1(), auth2()])),
(5, Some(vec![AuthorityId::from_raw([1u8; 32]), AuthorityId::from_raw([2u8; 32])])), (5, Some(vec![auth1(), auth2()])),
(6, None), (6, Some(vec![auth1(), auth2()])),
(7, None), // block will work for 'future' block too
]; ];
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); 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); 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); 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); 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); 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); run_checks(&db, 5, &checks);
let hash6 = insert_final_block(&db, None, || default_header(&hash5, 6)); let hash6 = insert_final_block(&db, same_authorities(), || default_header(&hash5, 6));
run_checks(&db, 7, &checks); run_checks(&db, 6, &checks);
(hash2, hash6) (hash2, hash6)
}; };
@@ -862,10 +884,10 @@ pub(crate) mod tests {
// some older non-best blocks are inserted // some older non-best blocks are inserted
// ... -> B2(1) -> B2_1(1) -> B2_2(2) // ... -> B2(1) -> B2_1(1) -> B2_2(2)
// => the cache ignores all writes before best finalized block // => 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)); let hash2_1 = insert_non_best_block(&db, make_authorities(vec![auth1()]), || default_header(&hash2, 3));
assert_eq!(None, db.cache().authorities_at(BlockId::Hash(hash2_1))); assert_eq!(None, get_authorities(db.cache(), 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)); let hash2_2 = insert_non_best_block(&db, make_authorities(vec![auth1(), auth2()]), || default_header(&hash2_1, 4));
assert_eq!(None, db.cache().authorities_at(BlockId::Hash(hash2_2))); assert_eq!(None, get_authorities(db.cache(), BlockId::Hash(hash2_2)));
} }
let (hash7, hash8, hash6_1, hash6_2, hash6_1_1, hash6_1_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_1(5)
// \> B6_1_2(6) -> B6_1_3(7) // \> B6_1_2(6) -> B6_1_3(7)
let hash7 = insert_block(&db, Some(vec![AuthorityId::from_raw([3u8; 32])]), || default_header(&hash6, 7)); let hash7 = insert_block(&db, make_authorities(vec![auth3()]), || default_header(&hash6, 7));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); assert_eq!(
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); get_authorities(db.cache(), BlockId::Hash(hash6)),
let hash8 = insert_block(&db, Some(vec![AuthorityId::from_raw([3u8; 32])]), || default_header(&hash7, 8)); Some(vec![auth1(), auth2()]),
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!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); let hash8 = insert_block(&db, make_authorities(vec![auth3()]), || default_header(&hash7, 8));
let hash6_1 = insert_block(&db, Some(vec![AuthorityId::from_raw([4u8; 32])]), || default_header(&hash6, 7)); assert_eq!(
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); get_authorities(db.cache(), BlockId::Hash(hash6)),
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); Some(vec![auth1(), auth2()]),
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!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()]));
let hash6_1_1 = insert_non_best_block(&db, Some(vec![AuthorityId::from_raw([5u8; 32])]), || default_header(&hash6_1, 8)); assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); let hash6_1 = insert_block(&db, make_authorities(vec![auth4()]), || default_header(&hash6, 7));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); assert_eq!(
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); get_authorities(db.cache(), BlockId::Hash(hash6)),
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); Some(vec![auth1(), auth2()]),
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!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); let hash6_1_1 = insert_non_best_block(&db, make_authorities(vec![auth5()]), || default_header(&hash6_1, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); assert_eq!(
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_1)), Some(vec![AuthorityId::from_raw([5u8; 32])])); get_authorities(db.cache(), BlockId::Hash(hash6)),
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); Some(vec![auth1(), auth2()]),
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!(get_authorities(db.cache(), BlockId::Hash(hash7)), Some(vec![auth3()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), Some(vec![AuthorityId::from_raw([3u8; 32])])); assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), Some(vec![auth3()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), Some(vec![AuthorityId::from_raw([3u8; 32])])); assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1)), Some(vec![auth4()]));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1)), Some(vec![AuthorityId::from_raw([4u8; 32])])); assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash6_1_1)), Some(vec![auth5()]));
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, make_authorities(vec![auth6()]), || default_header(&hash6_1, 8));
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); assert_eq!(
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_2)), Some(vec![AuthorityId::from_raw([4u8; 32])])); 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) (hash7, hash8, hash6_1, hash6_2, hash6_1_1, hash6_1_2)
}; };
@@ -915,29 +955,35 @@ pub(crate) mod tests {
{ {
// finalize block hash6_1 // finalize block hash6_1
db.finalize_header(BlockId::Hash(hash6_1)).unwrap(); db.finalize_header(BlockId::Hash(hash6_1)).unwrap();
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); assert_eq!(
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), None); get_authorities(db.cache(), BlockId::Hash(hash6)),
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), None); Some(vec![auth1(), auth2()]),
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!(get_authorities(db.cache(), BlockId::Hash(hash7)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), Some(vec![AuthorityId::from_raw([6u8; 32])])); assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), 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_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 // finalize block hash6_2
db.finalize_header(BlockId::Hash(hash6_2)).unwrap(); db.finalize_header(BlockId::Hash(hash6_2)).unwrap();
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6)), None); assert_eq!(
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash7)), None); get_authorities(db.cache(), BlockId::Hash(hash6)),
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash8)), None); Some(vec![auth1(), auth2()]),
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!(get_authorities(db.cache(), BlockId::Hash(hash7)), None);
assert_eq!(db.cache().authorities_at(BlockId::Hash(hash6_1_2)), None); assert_eq!(get_authorities(db.cache(), BlockId::Hash(hash8)), 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_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] #[test]
fn database_is_reopened() { fn database_is_reopened() {
let db = LightStorage::new_test(); 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.info().unwrap().best_hash, hash0);
assert_eq!(db.header(BlockId::Hash(hash0)).unwrap().unwrap().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); assert_eq!(db.get_aux(&[3]).unwrap(), None);
// delete aux1 + insert aux3 using import operation // 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![3], Some(vec![103])),
(vec![1], None), (vec![1], None),
]).unwrap(); ]).unwrap();
@@ -974,17 +1020,17 @@ pub(crate) mod tests {
#[test] #[test]
fn test_leaves_pruned_on_finality() { fn test_leaves_pruned_on_finality() {
let db = LightStorage::<Block>::new_test(); let db = LightStorage::<Block>::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_a = insert_block(&db, HashMap::new(), || default_header(&block0, 1));
let block1_b = insert_block(&db, None, || header_with_extrinsics_root(&block0, 1, [1; 32].into())); let block1_b = insert_block(&db, HashMap::new(), || 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_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]); 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_a = insert_block(&db, HashMap::new(), || default_header(&block1_a, 2));
let block2_b = insert_block(&db, None, || header_with_extrinsics_root(&block1_b, 2, [1; 32].into())); let block2_b = insert_block(&db, HashMap::new(), || 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_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]); assert_eq!(db.leaves.read().hashes(), vec![block2_a, block2_b, block2_c, block1_c]);
+4 -4
View File
@@ -16,10 +16,11 @@
//! Substrate Client data backend //! Substrate Client data backend
use std::collections::HashMap;
use crate::error; use crate::error;
use primitives::ChangesTrieConfiguration; use primitives::ChangesTrieConfiguration;
use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; 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::backend::Backend as StateBackend;
use state_machine::ChangesTrieStorage as StateChangesTrieStorage; use state_machine::ChangesTrieStorage as StateChangesTrieStorage;
use hash_db::Hasher; use hash_db::Hasher;
@@ -73,9 +74,8 @@ pub trait BlockImportOperation<Block, H> where
state: NewBlockState, state: NewBlockState,
) -> error::Result<()>; ) -> error::Result<()>;
/// Append authorities set to the transaction. This is a set of parent block (set which /// Update cached data.
/// has been used to check justification of this block). fn update_cache(&mut self, cache: HashMap<Vec<u8>, Vec<u8>>);
fn update_authorities(&mut self, authorities: Vec<AuthorityIdFor<Block>>);
/// Inject storage data into the database. /// Inject storage data into the database.
fn update_db_storage(&mut self, update: <Self::State as StateBackend<H>>::Transaction) -> error::Result<()>; fn update_db_storage(&mut self, update: <Self::State as StateBackend<H>>::Transaction) -> error::Result<()>;
/// Inject storage data into the database replacing any existing data. /// Inject storage data into the database replacing any existing data.
+12 -4
View File
@@ -16,7 +16,9 @@
//! Substrate blockchain trait //! 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::generic::BlockId;
use runtime_primitives::Justification; use runtime_primitives::Justification;
@@ -78,7 +80,7 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> {
/// Get last finalized block hash. /// Get last finalized block hash.
fn last_finalized(&self) -> Result<Block::Hash>; fn last_finalized(&self) -> Result<Block::Hash>;
/// Returns data cache reference, if it is enabled on this backend. /// Returns data cache reference, if it is enabled on this backend.
fn cache(&self) -> Option<&Cache<Block>>; fn cache(&self) -> Option<Arc<Cache<Block>>>;
/// Returns hashes of all blocks that are leaves of the block tree. /// Returns hashes of all blocks that are leaves of the block tree.
/// in other words, that have no children, are chain heads. /// in other words, that have no children, are chain heads.
@@ -89,10 +91,16 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> {
fn children(&self, parent_hash: Block::Hash) -> Result<Vec<Block::Hash>>; fn children(&self, parent_hash: Block::Hash) -> Result<Vec<Block::Hash>>;
} }
/// Provides access to the optional cache.
pub trait ProvideCache<Block: BlockT> {
/// Returns data cache reference, if it is enabled on this backend.
fn cache(&self) -> Option<Arc<Cache<Block>>>;
}
/// Blockchain optional data cache. /// Blockchain optional data cache.
pub trait Cache<Block: BlockT>: Send + Sync { pub trait Cache<Block: BlockT>: Send + Sync {
/// Returns the set of authorities, that was active at given block or None if there's no entry in the cache. /// Returns cached value by the given key.
fn authorities_at(&self, block: BlockId<Block>) -> Option<Vec<AuthorityIdFor<Block>>>; fn get_at(&self, key: &[u8], block: &BlockId<Block>) -> Option<Vec<u8>>;
} }
/// Blockchain info /// Blockchain info
+20 -54
View File
@@ -16,7 +16,7 @@
//! Substrate Client //! 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 crate::error::Error;
use futures::sync::mpsc; use futures::sync::mpsc;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
@@ -31,7 +31,7 @@ use consensus::{
}; };
use runtime_primitives::traits::{ use runtime_primitives::traits::{
Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash, 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 runtime_primitives::BuildStorage;
use crate::runtime_api::{CallRuntimeAt, ConstructRuntimeApi}; use crate::runtime_api::{CallRuntimeAt, ConstructRuntimeApi};
@@ -49,7 +49,8 @@ use hash_db::Hasher;
use crate::backend::{self, BlockImportOperation, PrunableStateChangesTrieStorage}; use crate::backend::{self, BlockImportOperation, PrunableStateChangesTrieStorage};
use crate::blockchain::{ 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 crate::call_executor::{CallExecutor, LocalCallExecutor};
use executor::{RuntimeVersion, RuntimeInfo}; use executor::{RuntimeVersion, RuntimeInfo};
@@ -342,16 +343,6 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
.expect("None is returned if there's no value stored for the given key; ':code' key is always defined; qed").0) .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<Block>) -> error::Result<Vec<AuthorityIdFor<Block>>> {
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::<AuthorityIdFor<Block>>::decode(&mut &r[..])
.ok_or_else(|| error::ErrorKind::InvalidAuthoritiesSet.into()))
}
}
/// Get the RuntimeVersion at a given block. /// Get the RuntimeVersion at a given block.
pub fn runtime_version_at(&self, id: &BlockId<Block>) -> error::Result<RuntimeVersion> { pub fn runtime_version_at(&self, id: &BlockId<Block>) -> error::Result<RuntimeVersion> {
self.executor.runtime_version(id) self.executor.runtime_version(id)
@@ -681,7 +672,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
&self, &self,
operation: &mut ClientImportOperation<Block, Blake2Hasher, B>, operation: &mut ClientImportOperation<Block, Blake2Hasher, B>,
import_block: ImportBlock<Block>, import_block: ImportBlock<Block>,
new_authorities: Option<Vec<AuthorityIdFor<Block>>>, new_cache: HashMap<Vec<u8>, Vec<u8>>,
) -> error::Result<ImportResult> where ) -> error::Result<ImportResult> where
E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone, E: CallExecutor<Block, Blake2Hasher> + Send + Sync + Clone,
{ {
@@ -729,7 +720,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
import_headers, import_headers,
justification, justification,
body, body,
new_authorities, new_cache,
finalized, finalized,
auxiliary, auxiliary,
fork_choice, fork_choice,
@@ -752,7 +743,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
import_headers: PrePostHeader<Block::Header>, import_headers: PrePostHeader<Block::Header>,
justification: Option<Justification>, justification: Option<Justification>,
body: Option<Vec<Block::Extrinsic>>, body: Option<Vec<Block::Extrinsic>>,
authorities: Option<Vec<AuthorityIdFor<Block>>>, new_cache: HashMap<Vec<u8>, Vec<u8>>,
finalized: bool, finalized: bool,
aux: Vec<(Vec<u8>, Option<Vec<u8>>)>, aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
fork_choice: ForkChoiceStrategy, fork_choice: ForkChoiceStrategy,
@@ -810,9 +801,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
leaf_state, leaf_state,
)?; )?;
if let Some(authorities) = authorities { operation.op.update_cache(new_cache);
operation.op.update_authorities(authorities);
}
if let Some(storage_update) = storage_update { if let Some(storage_update) = storage_update {
operation.op.update_db_storage(storage_update)?; operation.op.update_db_storage(storage_update)?;
} }
@@ -1324,6 +1313,15 @@ impl<B, E, Block, RA> ChainHeaderBackend<Block> for Client<B, E, Block, RA> wher
} }
} }
impl<B, E, Block, RA> ProvideCache<Block> for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>,
Block: BlockT<Hash=H256>,
{
fn cache(&self) -> Option<Arc<Cache<Block>>> {
self.backend.blockchain().cache()
}
}
impl<B, E, Block, RA> ProvideRuntimeApi for Client<B, E, Block, RA> where impl<B, E, Block, RA> ProvideRuntimeApi for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>, B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync, E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
@@ -1398,10 +1396,10 @@ impl<B, E, Block, RA> consensus::BlockImport<Block> for Client<B, E, Block, RA>
fn import_block( fn import_block(
&self, &self,
import_block: ImportBlock<Block>, import_block: ImportBlock<Block>,
new_authorities: Option<Vec<AuthorityIdFor<Block>>>, new_cache: HashMap<Vec<u8>, Vec<u8>>,
) -> Result<ImportResult, Self::Error> { ) -> Result<ImportResult, Self::Error> {
self.lock_import_and_run(|operation| { 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()) }).map_err(|e| ConsensusErrorKind::ClientImport(e.to_string()).into())
} }
@@ -1431,17 +1429,6 @@ impl<B, E, Block, RA> consensus::BlockImport<Block> for Client<B, E, Block, RA>
} }
} }
impl<B, E, Block, RA> consensus::Authorities<Block> for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher> + Clone,
Block: BlockT<Hash=H256>,
{
type Error = Error;
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityIdFor<Block>>, Self::Error> {
self.authorities_at(at).map_err(|e| e.into())
}
}
impl<B, E, Block, RA> CurrentHeight for Client<B, E, Block, RA> where impl<B, E, Block, RA> CurrentHeight for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>, B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher>, E: CallExecutor<Block, Blake2Hasher>,
@@ -1550,7 +1537,7 @@ pub(crate) mod tests {
use primitives::twox_128; use primitives::twox_128;
use runtime_primitives::traits::DigestItem as DigestItemT; use runtime_primitives::traits::DigestItem as DigestItemT;
use runtime_primitives::generic::DigestItem; use runtime_primitives::generic::DigestItem;
use test_client::{self, TestClient, AccountKeyring, AuthorityKeyring}; use test_client::{self, TestClient, AccountKeyring};
use consensus::BlockOrigin; use consensus::BlockOrigin;
use test_client::client::backend::Backend as TestBackend; use test_client::client::backend::Backend as TestBackend;
use test_client::BlockBuilderExt; 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] #[test]
fn block_builder_works_with_no_transactions() { fn block_builder_works_with_no_transactions() {
let client = test_client::new(); 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] #[test]
fn block_builder_does_not_include_invalid() { fn block_builder_does_not_include_invalid() {
let client = test_client::new(); let client = test_client::new();
-6
View File
@@ -62,12 +62,6 @@ error_chain! {
display("Blockchain: {}", e), 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. /// Could not get runtime version.
VersionInvalid { VersionInvalid {
description("Runtime version error"), description("Runtime version error"),
+16 -59
View File
@@ -22,7 +22,7 @@ use parking_lot::RwLock;
use primitives::{ChangesTrieConfiguration, storage::well_known_keys}; use primitives::{ChangesTrieConfiguration, storage::well_known_keys};
use runtime_primitives::generic::BlockId; use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, 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 runtime_primitives::{Justification, StorageOverlay, ChildrenStorageOverlay};
use state_machine::backend::{Backend as StateBackend, InMemory, Consolidate}; use state_machine::backend::{Backend as StateBackend, InMemory, Consolidate};
use state_machine::{self, InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId}; use state_machine::{self, InMemoryChangesTrieStorage, ChangesTrieAnchorBlockId};
@@ -104,12 +104,6 @@ struct BlockchainStorage<Block: BlockT> {
/// In-memory blockchain. Supports concurrent reads. /// In-memory blockchain. Supports concurrent reads.
pub struct Blockchain<Block: BlockT> { pub struct Blockchain<Block: BlockT> {
storage: Arc<RwLock<BlockchainStorage<Block>>>, storage: Arc<RwLock<BlockchainStorage<Block>>>,
cache: Cache<Block>,
}
struct Cache<Block: BlockT> {
storage: Arc<RwLock<BlockchainStorage<Block>>>,
authorities_at: RwLock<HashMap<Block::Hash, Option<Vec<AuthorityIdFor<Block>>>>>,
} }
impl<Block: BlockT + Clone> Clone for Blockchain<Block> { impl<Block: BlockT + Clone> Clone for Blockchain<Block> {
@@ -117,10 +111,6 @@ impl<Block: BlockT + Clone> Clone for Blockchain<Block> {
let storage = Arc::new(RwLock::new(self.storage.read().clone())); let storage = Arc::new(RwLock::new(self.storage.read().clone()));
Blockchain { Blockchain {
storage: storage.clone(), storage: storage.clone(),
cache: Cache {
storage,
authorities_at: RwLock::new(self.cache.authorities_at.read().clone()),
},
} }
} }
} }
@@ -152,10 +142,6 @@ impl<Block: BlockT> Blockchain<Block> {
})); }));
Blockchain { Blockchain {
storage: storage.clone(), storage: storage.clone(),
cache: Cache {
storage: storage,
authorities_at: Default::default(),
},
} }
} }
@@ -355,8 +341,8 @@ impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
Ok(self.storage.read().finalized_hash.clone()) Ok(self.storage.read().finalized_hash.clone())
} }
fn cache(&self) -> Option<&blockchain::Cache<Block>> { fn cache(&self) -> Option<Arc<blockchain::Cache<Block>>> {
Some(&self.cache) None
} }
fn leaves(&self) -> error::Result<Vec<Block::Hash>> { fn leaves(&self) -> error::Result<Vec<Block::Hash>> {
@@ -368,6 +354,12 @@ impl<Block: BlockT> blockchain::Backend<Block> for Blockchain<Block> {
} }
} }
impl<Block: BlockT> blockchain::ProvideCache<Block> for Blockchain<Block> {
fn cache(&self) -> Option<Arc<blockchain::Cache<Block>>> {
None
}
}
impl<Block: BlockT> backend::AuxStore for Blockchain<Block> { impl<Block: BlockT> backend::AuxStore for Blockchain<Block> {
fn insert_aux< fn insert_aux<
'a, 'a,
@@ -398,16 +390,12 @@ impl<Block: BlockT> light::blockchain::Storage<Block> for Blockchain<Block>
fn import_header( fn import_header(
&self, &self,
header: Block::Header, header: Block::Header,
authorities: Option<Vec<AuthorityIdFor<Block>>>, _cache: HashMap<Vec<u8>, Vec<u8>>,
state: NewBlockState, state: NewBlockState,
aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>, aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
) -> error::Result<()> { ) -> error::Result<()> {
let hash = header.hash(); let hash = header.hash();
let parent_hash = *header.parent_hash();
self.insert(hash, header, None, None, state)?; self.insert(hash, header, None, None, state)?;
if state.is_best() {
self.cache.insert(parent_hash, authorities);
}
self.write_aux(aux_ops); self.write_aux(aux_ops);
Ok(()) Ok(())
@@ -435,15 +423,15 @@ impl<Block: BlockT> light::blockchain::Storage<Block> for Blockchain<Block>
.ok_or_else(|| error::ErrorKind::Backend(format!("Changes trie CHT for block {} not exists", block)).into()) .ok_or_else(|| error::ErrorKind::Backend(format!("Changes trie CHT for block {} not exists", block)).into())
} }
fn cache(&self) -> Option<&blockchain::Cache<Block>> { fn cache(&self) -> Option<Arc<blockchain::Cache<Block>>> {
Some(&self.cache) None
} }
} }
/// In-memory operation. /// In-memory operation.
pub struct BlockImportOperation<Block: BlockT, H: Hasher> { pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
pending_block: Option<PendingBlock<Block>>, pending_block: Option<PendingBlock<Block>>,
pending_authorities: Option<Vec<AuthorityIdFor<Block>>>, pending_cache: HashMap<Vec<u8>, Vec<u8>>,
old_state: InMemory<H>, old_state: InMemory<H>,
new_state: Option<InMemory<H>>, new_state: Option<InMemory<H>>,
changes_trie_update: Option<MemoryDB<H>>, changes_trie_update: Option<MemoryDB<H>>,
@@ -480,8 +468,8 @@ where
Ok(()) Ok(())
} }
fn update_authorities(&mut self, authorities: Vec<AuthorityIdFor<Block>>) { fn update_cache(&mut self, cache: HashMap<Vec<u8>, Vec<u8>>) {
self.pending_authorities = Some(authorities); self.pending_cache = cache;
} }
fn update_db_storage(&mut self, update: <InMemory<H> as StateBackend<H>>::Transaction) -> error::Result<()> { fn update_db_storage(&mut self, update: <InMemory<H> as StateBackend<H>>::Transaction) -> error::Result<()> {
@@ -602,7 +590,7 @@ where
let old_state = self.state_at(BlockId::Hash(Default::default()))?; let old_state = self.state_at(BlockId::Hash(Default::default()))?;
Ok(BlockImportOperation { Ok(BlockImportOperation {
pending_block: None, pending_block: None,
pending_authorities: None, pending_cache: Default::default(),
old_state, old_state,
new_state: None, new_state: None,
changes_trie_update: None, changes_trie_update: None,
@@ -629,7 +617,6 @@ where
let (header, body, justification) = pending_block.block.into_inner(); let (header, body, justification) = pending_block.block.into_inner();
let hash = header.hash(); let hash = header.hash();
let parent_hash = *header.parent_hash();
self.states.write().insert(hash, operation.new_state.unwrap_or_else(|| old_state.clone())); 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)?; 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() { if !operation.aux.is_empty() {
@@ -710,23 +693,6 @@ where
} }
} }
impl<Block: BlockT> Cache<Block> {
fn insert(&self, at: Block::Hash, authorities: Option<Vec<AuthorityIdFor<Block>>>) {
self.authorities_at.write().insert(at, authorities);
}
}
impl<Block: BlockT> blockchain::Cache<Block> for Cache<Block> {
fn authorities_at(&self, block: BlockId<Block>) -> Option<Vec<AuthorityIdFor<Block>>> {
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. /// Prunable in-memory changes trie storage.
pub struct ChangesTrieStorage<H: Hasher>(InMemoryChangesTrieStorage<H>) where H::Out: HeapSizeOf; pub struct ChangesTrieStorage<H: Hasher>(InMemoryChangesTrieStorage<H>) where H::Out: HeapSizeOf;
impl<H: Hasher> backend::PrunableStateChangesTrieStorage<H> for ChangesTrieStorage<H> where H::Out: HeapSizeOf { impl<H: Hasher> backend::PrunableStateChangesTrieStorage<H> for ChangesTrieStorage<H> where H::Out: HeapSizeOf {
@@ -747,15 +713,6 @@ impl<H: Hasher> state_machine::ChangesTrieStorage<H> for ChangesTrieStorage<H> w
} }
} }
/// Insert authorities entry into in-memory blockchain cache. Extracted as a separate function to use it in tests.
pub fn cache_authorities_at<Block: BlockT>(
blockchain: &Blockchain<Block>,
at: Block::Hash,
authorities: Option<Vec<AuthorityIdFor<Block>>>
) {
blockchain.cache.insert(at, authorities);
}
/// Check that genesis storage is valid. /// Check that genesis storage is valid.
pub fn check_genesis_storage(top: &StorageOverlay, children: &ChildrenStorageOverlay) -> error::Result<()> { pub fn check_genesis_storage(top: &StorageOverlay, children: &ChildrenStorageOverlay) -> error::Result<()> {
if top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) { if top.iter().any(|(k, _)| well_known_keys::is_child_storage_key(k)) {
+6 -6
View File
@@ -24,7 +24,7 @@ use parking_lot::RwLock;
use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay}; use runtime_primitives::{generic::BlockId, Justification, StorageOverlay, ChildrenStorageOverlay};
use state_machine::{Backend as StateBackend, TrieBackend, backend::InMemory as InMemoryState}; 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::in_mem::{self, check_genesis_storage};
use crate::backend::{AuxStore, Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState}; use crate::backend::{AuxStore, Backend as ClientBackend, BlockImportOperation, RemoteBackend, NewBlockState};
use crate::blockchain::HeaderBackend as BlockchainHeaderBackend; use crate::blockchain::HeaderBackend as BlockchainHeaderBackend;
@@ -46,7 +46,7 @@ pub struct Backend<S, F, H> {
/// Light block (header and justification) import operation. /// Light block (header and justification) import operation.
pub struct ImportOperation<Block: BlockT, S, F, H> { pub struct ImportOperation<Block: BlockT, S, F, H> {
header: Option<Block::Header>, header: Option<Block::Header>,
authorities: Option<Vec<AuthorityIdFor<Block>>>, cache: HashMap<Vec<u8>, Vec<u8>>,
leaf_state: NewBlockState, leaf_state: NewBlockState,
aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>, aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
finalized_blocks: Vec<BlockId<Block>>, finalized_blocks: Vec<BlockId<Block>>,
@@ -117,7 +117,7 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F, H> where
fn begin_operation(&self) -> ClientResult<Self::BlockImportOperation> { fn begin_operation(&self) -> ClientResult<Self::BlockImportOperation> {
Ok(ImportOperation { Ok(ImportOperation {
header: None, header: None,
authorities: None, cache: Default::default(),
leaf_state: NewBlockState::Normal, leaf_state: NewBlockState::Normal,
aux_ops: Vec::new(), aux_ops: Vec::new(),
finalized_blocks: Vec::new(), finalized_blocks: Vec::new(),
@@ -146,7 +146,7 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F, H> where
let is_genesis_import = header.number().is_zero(); let is_genesis_import = header.number().is_zero();
self.blockchain.storage().import_header( self.blockchain.storage().import_header(
header, header,
operation.authorities, operation.cache,
operation.leaf_state, operation.leaf_state,
operation.aux_ops, operation.aux_ops,
)?; )?;
@@ -254,8 +254,8 @@ where
Ok(()) Ok(())
} }
fn update_authorities(&mut self, authorities: Vec<AuthorityIdFor<Block>>) { fn update_cache(&mut self, cache: HashMap<Vec<u8>, Vec<u8>>) {
self.authorities = Some(authorities); self.cache = cache;
} }
fn update_db_storage(&mut self, _update: <Self::State as StateBackend<H>>::Transaction) -> ClientResult<()> { fn update_db_storage(&mut self, _update: <Self::State as StateBackend<H>>::Transaction) -> ClientResult<()> {
+14 -8
View File
@@ -17,16 +17,16 @@
//! Light client blockchin backend. Only stores headers and justifications of recent //! Light client blockchin backend. Only stores headers and justifications of recent
//! blocks. CHT roots are stored for headers of ancient blocks. //! 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 futures::{Future, IntoFuture};
use parking_lot::Mutex; use parking_lot::Mutex;
use runtime_primitives::{Justification, generic::BlockId}; 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::backend::{AuxStore, NewBlockState};
use crate::blockchain::{Backend as BlockchainBackend, BlockStatus, Cache as BlockchainCache, 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::cht;
use crate::error::{ErrorKind as ClientErrorKind, Result as ClientResult}; use crate::error::{ErrorKind as ClientErrorKind, Result as ClientResult};
use crate::light::fetcher::{Fetcher, RemoteHeaderRequest}; use crate::light::fetcher::{Fetcher, RemoteHeaderRequest};
@@ -40,7 +40,7 @@ pub trait Storage<Block: BlockT>: AuxStore + BlockchainHeaderBackend<Block> {
fn import_header( fn import_header(
&self, &self,
header: Block::Header, header: Block::Header,
authorities: Option<Vec<AuthorityIdFor<Block>>>, cache: HashMap<Vec<u8>, Vec<u8>>,
state: NewBlockState, state: NewBlockState,
aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>, aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
) -> ClientResult<()>; ) -> ClientResult<()>;
@@ -61,7 +61,7 @@ pub trait Storage<Block: BlockT>: AuxStore + BlockchainHeaderBackend<Block> {
fn changes_trie_cht_root(&self, cht_size: u64, block: NumberFor<Block>) -> ClientResult<Block::Hash>; fn changes_trie_cht_root(&self, cht_size: u64, block: NumberFor<Block>) -> ClientResult<Block::Hash>;
/// Get storage cache. /// Get storage cache.
fn cache(&self) -> Option<&BlockchainCache<Block>>; fn cache(&self) -> Option<Arc<BlockchainCache<Block>>>;
} }
/// Light client blockchain. /// Light client blockchain.
@@ -156,7 +156,7 @@ impl<S, F, Block> BlockchainBackend<Block> for Blockchain<S, F> where Block: Blo
self.storage.last_finalized() self.storage.last_finalized()
} }
fn cache(&self) -> Option<&BlockchainCache<Block>> { fn cache(&self) -> Option<Arc<BlockchainCache<Block>>> {
self.storage.cache() self.storage.cache()
} }
@@ -169,6 +169,12 @@ impl<S, F, Block> BlockchainBackend<Block> for Blockchain<S, F> where Block: Blo
} }
} }
impl<S: Storage<Block>, F, Block: BlockT> ProvideCache<Block> for Blockchain<S, F> {
fn cache(&self) -> Option<Arc<BlockchainCache<Block>>> {
self.storage.cache()
}
}
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use std::collections::HashMap; use std::collections::HashMap;
@@ -246,7 +252,7 @@ pub mod tests {
fn import_header( fn import_header(
&self, &self,
_header: Header, _header: Header,
_authorities: Option<Vec<AuthorityIdFor<Block>>>, _cache: HashMap<Vec<u8>, Vec<u8>>,
_state: NewBlockState, _state: NewBlockState,
_aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>, _aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
) -> ClientResult<()> { ) -> ClientResult<()> {
@@ -278,7 +284,7 @@ pub mod tests {
).into()) ).into())
} }
fn cache(&self) -> Option<&BlockchainCache<Block>> { fn cache(&self) -> Option<Arc<BlockchainCache<Block>>> {
None None
} }
} }
@@ -512,7 +512,7 @@ mod tests {
} }
// check method that doesn't requires environment // 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); assert_eq!(remote, local);
// check method that requires environment // check method that requires environment
+5 -2
View File
@@ -390,6 +390,7 @@ impl<'a, H, Number, Hash> ChangesTrieRootsStorage<H> for RootsStorage<'a, Number
pub mod tests { pub mod tests {
use futures::future::{ok, err, FutureResult}; use futures::future::{ok, err, FutureResult};
use parking_lot::Mutex; use parking_lot::Mutex;
use parity_codec::Decode;
use crate::client::tests::prepare_client_with_key_changes; use crate::client::tests::prepare_client_with_key_changes;
use executor::{self, NativeExecutionDispatch}; use executor::{self, NativeExecutionDispatch};
use crate::error::Error as ClientError; use crate::error::Error as ClientError;
@@ -436,7 +437,7 @@ pub mod tests {
type TestChecker = LightDataChecker<executor::NativeExecutor<test_client::LocalExecutor>, Blake2Hasher, Block, DummyStorage, OkCallFetcher>; type TestChecker = LightDataChecker<executor::NativeExecutor<test_client::LocalExecutor>, Blake2Hasher, Block, DummyStorage, OkCallFetcher>;
fn prepare_for_read_proof_check() -> (TestChecker, Header, Vec<Vec<u8>>, usize) { fn prepare_for_read_proof_check() -> (TestChecker, Header, Vec<Vec<u8>>, u32) {
// prepare remote client // prepare remote client
let remote_client = test_client::new(); let remote_client = test_client::new();
let remote_block_id = BlockId::Number(0); 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(); 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 // '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(); let remote_read_proof = remote_client.read_proof(&remote_block_id, well_known_keys::AUTHORITY_COUNT).unwrap();
// check remote read proof locally // check remote read proof locally
+1 -4
View File
@@ -38,7 +38,6 @@ use rstd::result;
pub use parity_codec::{Encode, Decode}; pub use parity_codec::{Encode, Decode};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::error; use crate::error;
use rstd::vec::Vec;
use sr_api_macros::decl_runtime_apis; use sr_api_macros::decl_runtime_apis;
use primitives::OpaqueMetadata; use primitives::OpaqueMetadata;
#[cfg(feature = "std")] #[cfg(feature = "std")]
@@ -112,13 +111,11 @@ pub trait CallRuntimeAt<Block: BlockT> {
} }
decl_runtime_apis! { 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] #[core_trait]
pub trait Core { pub trait Core {
/// Returns the version of the runtime. /// Returns the version of the runtime.
fn version() -> RuntimeVersion; fn version() -> RuntimeVersion;
/// Returns the authorities.
fn authorities() -> Vec<AuthorityIdFor<Block>>;
/// Execute the given block. /// Execute the given block.
fn execute_block(block: Block); fn execute_block(block: Block);
/// Initialize a block with the given header. /// Initialize a block with the given header.
+1
View File
@@ -25,6 +25,7 @@ parking_lot = "0.7.1"
error-chain = "0.12" error-chain = "0.12"
log = "0.4" log = "0.4"
consensus_common = { package = "substrate-consensus-common", path = "../common" } consensus_common = { package = "substrate-consensus-common", path = "../common" }
authorities = { package = "substrate-consensus-authorities", path = "../authorities" }
[dev-dependencies] [dev-dependencies]
keyring = { package = "substrate-keyring", path = "../../keyring" } keyring = { package = "substrate-keyring", path = "../../keyring" }
+59 -16
View File
@@ -29,21 +29,23 @@
use std::{sync::Arc, time::Duration, thread, marker::PhantomData, hash::Hash, fmt::Debug}; use std::{sync::Arc, time::Duration, thread, marker::PhantomData, hash::Hash, fmt::Debug};
use parity_codec::{Encode, Decode}; use parity_codec::{Encode, Decode};
use consensus_common::{ use consensus_common::{self, Authorities, BlockImport, Environment, Proposer,
Authorities, BlockImport, Environment, Proposer, ForkChoiceStrategy ForkChoiceStrategy, ImportBlock, BlockOrigin, Error as ConsensusError,
}; };
use consensus_common::well_known_cache_keys;
use consensus_common::import_queue::{Verifier, BasicQueue, SharedBlockImport, SharedJustificationImport}; use consensus_common::import_queue::{Verifier, BasicQueue, SharedBlockImport, SharedJustificationImport};
use client::ChainHead; use client::ChainHead;
use client::block_builder::api::BlockBuilder as BlockBuilderApi; use client::block_builder::api::BlockBuilder as BlockBuilderApi;
use client::blockchain::ProvideCache;
use client::runtime_api::ApiExt; use client::runtime_api::ApiExt;
use consensus_common::{ImportBlock, BlockOrigin};
use aura_primitives::AURA_ENGINE_ID; use aura_primitives::AURA_ENGINE_ID;
use runtime_primitives::{generic, generic::BlockId, Justification}; use runtime_primitives::{generic, generic::BlockId, Justification};
use runtime_primitives::traits::{ use runtime_primitives::traits::{
Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi Block, Header, Digest, DigestItemFor, DigestItem, ProvideRuntimeApi, AuthorityIdFor,
}; };
use primitives::Pair; use primitives::Pair;
use inherents::{InherentDataProviders, InherentData, RuntimeString}; use inherents::{InherentDataProviders, InherentData, RuntimeString};
use authorities::AuthoritiesApi;
use futures::{Stream, Future, IntoFuture, future}; use futures::{Stream, Future, IntoFuture, future};
use tokio::timer::Timeout; use tokio::timer::Timeout;
@@ -179,12 +181,13 @@ pub fn start_aura_thread<B, C, E, I, P, SO, Error, OnExit>(
force_authoring: bool, force_authoring: bool,
) -> Result<(), consensus_common::Error> where ) -> Result<(), consensus_common::Error> where
B: Block + 'static, B: Block + 'static,
C: Authorities<B> + ChainHead<B> + Send + Sync + 'static, C: ChainHead<B> + ProvideRuntimeApi + ProvideCache<B> + Send + Sync + 'static,
C::Api: AuthoritiesApi<B>,
E: Environment<B, Error=Error> + Send + Sync + 'static, E: Environment<B, Error=Error> + Send + Sync + 'static,
E::Proposer: Proposer<B, Error=Error> + Send + 'static, E::Proposer: Proposer<B, Error=Error> + Send + 'static,
<<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static, <<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static,
I: BlockImport<B> + Send + Sync + 'static, I: BlockImport<B> + Send + Sync + 'static,
Error: From<C::Error> + From<I::Error> + 'static, Error: From<I::Error> + 'static,
P: Pair + Send + Sync + 'static, P: Pair + Send + Sync + 'static,
P::Public: Encode + Decode + Eq + Clone + Debug + Hash + Send + Sync + 'static, P::Public: Encode + Decode + Eq + Clone + Debug + Hash + Send + Sync + 'static,
P::Signature: Encode, P::Signature: Encode,
@@ -226,12 +229,13 @@ pub fn start_aura<B, C, E, I, P, SO, Error, OnExit>(
force_authoring: bool, force_authoring: bool,
) -> Result<impl Future<Item=(), Error=()>, consensus_common::Error> where ) -> Result<impl Future<Item=(), Error=()>, consensus_common::Error> where
B: Block, B: Block,
C: Authorities<B> + ChainHead<B>, C: ChainHead<B> + ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
E: Environment<B, Error=Error>, E: Environment<B, Error=Error>,
E::Proposer: Proposer<B, Error=Error>, E::Proposer: Proposer<B, Error=Error>,
<<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static, <<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static,
I: BlockImport<B> + Send + Sync + 'static, I: BlockImport<B> + Send + Sync + 'static,
Error: From<C::Error> + From<I::Error>, Error: From<I::Error>,
P: Pair + Send + Sync + 'static, P: Pair + Send + Sync + 'static,
P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static, P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static,
P::Signature: Encode, P::Signature: Encode,
@@ -270,7 +274,8 @@ struct AuraWorker<C, E, I, P, SO> {
} }
impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, SO> where impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, SO> where
C: Authorities<B>, C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
E: Environment<B, Error=Error>, E: Environment<B, Error=Error>,
E::Proposer: Proposer<B, Error=Error>, E::Proposer: Proposer<B, Error=Error>,
<<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static, <<E::Proposer as Proposer<B>>::Create as IntoFuture>::Future: Send + 'static,
@@ -278,7 +283,7 @@ impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, S
P: Pair + Send + Sync + 'static, P: Pair + Send + Sync + 'static,
P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static, P::Public: Hash + Eq + Send + Sync + Clone + Debug + Encode + Decode + 'static,
P::Signature: Encode, P::Signature: Encode,
Error: From<C::Error> + From<I::Error>, Error: From<I::Error>,
SO: SyncOracle + Send + Clone, SO: SyncOracle + Send + Clone,
DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>, DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>,
Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>, Error: ::std::error::Error + Send + 'static + From<::consensus_common::Error>,
@@ -306,7 +311,7 @@ impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, S
let (timestamp, slot_num, slot_duration) = let (timestamp, slot_num, slot_duration) =
(slot_info.timestamp, slot_info.number, slot_info.duration); (slot_info.timestamp, slot_info.number, slot_info.duration);
let authorities = match client.authorities(&BlockId::Hash(chain_head.hash())) { let authorities = match authorities(client.as_ref(), &BlockId::Hash(chain_head.hash())) {
Ok(authorities) => authorities, Ok(authorities) => authorities,
Err(e) => { Err(e) => {
warn!( warn!(
@@ -418,7 +423,7 @@ impl<B: Block, C, E, I, P, Error, SO> SlotWorker<B> for AuraWorker<C, E, I, P, S
"hash_previously" => ?pre_hash "hash_previously" => ?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 {:?}: {:?}", warn!(target: "aura", "Error with block built on {:?}: {:?}",
parent_hash, e); parent_hash, e);
telemetry!(CONSENSUS_WARN; "aura.err_with_block_built_on"; telemetry!(CONSENSUS_WARN; "aura.err_with_block_built_on";
@@ -573,13 +578,14 @@ impl<B: Block> ExtraVerification<B> for NothingExtra {
#[forbid(deprecated)] #[forbid(deprecated)]
impl<B: Block, C, E, P> Verifier<B> for AuraVerifier<C, E, P> where impl<B: Block, C, E, P> Verifier<B> for AuraVerifier<C, E, P> where
C: Authorities<B> + ProvideRuntimeApi + Send + Sync, C: ProvideRuntimeApi + Send + Sync,
C::Api: BlockBuilderApi<B>, C::Api: BlockBuilderApi<B>,
DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>, DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>,
E: ExtraVerification<B>, E: ExtraVerification<B>,
P: Pair + Send + Sync + 'static, P: Pair + Send + Sync + 'static,
P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + AsRef<P::Public> + 'static, P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + AsRef<P::Public> + 'static,
P::Signature: Encode + Decode, P::Signature: Encode + Decode,
Self: Authorities<B>,
{ {
fn verify( fn verify(
&self, &self,
@@ -593,7 +599,7 @@ impl<B: Block, C, E, P> Verifier<B> for AuraVerifier<C, E, P> where
.map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?; .map_err(|e| format!("Could not extract timestamp and slot: {:?}", e))?;
let hash = header.hash(); let hash = header.hash();
let parent_hash = *header.parent_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))?; .map_err(|e| format!("Could not fetch authorities at {:?}: {:?}", parent_hash, e))?;
let extra_verification = self.extra.verify( let extra_verification = self.extra.verify(
@@ -669,6 +675,31 @@ impl<B: Block, C, E, P> Verifier<B> for AuraVerifier<C, E, P> where
} }
} }
impl<B, C, E, P> Authorities<B> for AuraVerifier<C, E, P> where
B: Block,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
{
type Error = ConsensusError;
fn authorities(&self, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B>>, Self::Error> {
authorities(self.client.as_ref(), at)
}
}
fn authorities<B, C>(client: &C, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B>>, ConsensusError> where
B: Block,
C: ProvideRuntimeApi + ProvideCache<B>,
C::Api: AuthoritiesApi<B>,
{
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. /// The Aura import queue type.
pub type AuraImportQueue<B> = BasicQueue<B>; pub type AuraImportQueue<B> = BasicQueue<B>;
@@ -697,8 +728,8 @@ pub fn import_queue<B, C, E, P>(
allow_old_seals: bool, allow_old_seals: bool,
) -> Result<AuraImportQueue<B>, consensus_common::Error> where ) -> Result<AuraImportQueue<B>, consensus_common::Error> where
B: Block, B: Block,
C: 'static + Authorities<B> + ProvideRuntimeApi + Send + Sync, C: 'static + ProvideRuntimeApi + ProvideCache<B> + Send + Sync,
C::Api: BlockBuilderApi<B>, C::Api: BlockBuilderApi<B> + AuthoritiesApi<B>,
DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>, DigestItemFor<B>: CompatibleDigestItem<P> + DigestItem<AuthorityId=AuthorityId<P>>,
E: 'static + ExtraVerification<B>, E: 'static + ExtraVerification<B>,
P: Pair + Send + Sync + 'static, P: Pair + Send + Sync + 'static,
@@ -889,4 +920,16 @@ mod tests {
runtime.block_on(wait_for.select(drive_to_completion).map_err(|_| ())).unwrap(); 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()
]);
}
} }
@@ -0,0 +1,29 @@
[package]
name = "substrate-consensus-authorities"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
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"
]
@@ -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 <http://www.gnu.org/licenses/>.
//! 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<AuthorityIdFor<Block>>;
}
}
@@ -16,9 +16,10 @@
//! Block import helpers. //! 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 runtime_primitives::Justification;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap;
/// Block import result. /// Block import result.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@@ -175,11 +176,13 @@ pub trait BlockImport<B: BlockT> {
parent_hash: B::Hash, parent_hash: B::Hash,
) -> Result<ImportResult, Self::Error>; ) -> Result<ImportResult, Self::Error>;
/// 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( fn import_block(
&self, &self,
block: ImportBlock<B>, block: ImportBlock<B>,
new_authorities: Option<Vec<AuthorityIdFor<B>>>, cache: HashMap<Vec<u8>, Vec<u8>>,
) -> Result<ImportResult, Self::Error>; ) -> Result<ImportResult, Self::Error>;
} }
@@ -58,6 +58,12 @@ error_chain! {
display("Message signature {:?} by {:?} is invalid.", s, a), 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. /// Account is not an authority.
InvalidAuthority(a: Public) { InvalidAuthority(a: Public) {
description("Message sender is not a valid authority"), description("Message sender is not a valid authority"),
@@ -28,6 +28,7 @@ use crate::block_import::{
BlockImport, BlockOrigin, ImportBlock, ImportedAux, ImportResult, JustificationImport, BlockImport, BlockOrigin, ImportBlock, ImportedAux, ImportResult, JustificationImport,
}; };
use crossbeam_channel::{self as channel, Receiver, Sender}; use crossbeam_channel::{self as channel, Receiver, Sender};
use parity_codec::Encode;
use std::sync::Arc; use std::sync::Arc;
use std::thread; use std::thread;
@@ -38,6 +39,7 @@ use runtime_primitives::traits::{
use runtime_primitives::Justification; use runtime_primitives::Justification;
use crate::error::Error as ConsensusError; use crate::error::Error as ConsensusError;
use parity_codec::alloc::collections::hash_map::HashMap;
/// Shared block import struct used by the queue. /// Shared block import struct used by the queue.
pub type SharedBlockImport<B> = Arc<dyn BlockImport<B, Error = ConsensusError> + Send + Sync>; pub type SharedBlockImport<B> = Arc<dyn BlockImport<B, Error = ConsensusError> + Send + Sync>;
@@ -566,7 +568,12 @@ pub fn import_single_block<B: BlockT, V: Verifier<B>>(
BlockImportError::VerificationFailed(peer.clone(), msg) 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)] #[cfg(test)]
+9 -1
View File
@@ -53,7 +53,9 @@ pub use block_import::{
/// Trait for getting the authorities at a given block. /// Trait for getting the authorities at a given block.
pub trait Authorities<B: Block> { pub trait Authorities<B: Block> {
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<B>) -> Result<Vec<AuthorityIdFor<B>>, Self::Error>; fn authorities(&self, at: &BlockId<B>) -> Result<Vec<AuthorityIdFor<B>>, Self::Error>;
} }
@@ -115,3 +117,9 @@ impl<T: SyncOracle> SyncOracle for Arc<T> {
T::is_offline(&*self) 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";
}
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc; use std::{sync::Arc, collections::HashMap};
use log::{debug, trace, info}; use log::{debug, trace, info};
use parity_codec::Encode; use parity_codec::Encode;
@@ -388,7 +388,7 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> BlockImport<Block>
{ {
type Error = ConsensusError; type Error = ConsensusError;
fn import_block(&self, mut block: ImportBlock<Block>, new_authorities: Option<Vec<AuthorityId>>) fn import_block(&self, mut block: ImportBlock<Block>, new_cache: HashMap<Vec<u8>, Vec<u8>>)
-> Result<ImportResult, Self::Error> -> Result<ImportResult, Self::Error>
{ {
let hash = block.post_header().hash(); let hash = block.post_header().hash();
@@ -406,8 +406,8 @@ impl<B, E, Block: BlockT<Hash=H256>, RA, PRA> BlockImport<Block>
// we don't want to finalize on `inner.import_block` // we don't want to finalize on `inner.import_block`
let mut justification = block.justification.take(); let mut justification = block.justification.take();
let enacts_consensus_change = new_authorities.is_some(); let enacts_consensus_change = !new_cache.is_empty();
let import_result = self.inner.import_block(block, new_authorities); let import_result = self.inner.import_block(block, new_cache);
let mut imported_aux = { let mut imported_aux = {
match import_result { match import_result {
+4 -14
View File
@@ -277,16 +277,6 @@ impl Core<Block> for RuntimeApi {
unimplemented!("Not required for testing!") unimplemented!("Not required for testing!")
} }
fn authorities_runtime_api_impl(
&self,
_: &BlockId<Block>,
_: ExecutionContext,
_: Option<()>,
_: Vec<u8>,
) -> Result<NativeOrEncoded<Vec<AuthorityId>>> {
unimplemented!("Not required for testing!")
}
fn execute_block_runtime_api_impl( fn execute_block_runtime_api_impl(
&self, &self,
_: &BlockId<Block>, _: &BlockId<Block>,
@@ -992,12 +982,12 @@ fn allows_reimporting_change_blocks() {
}; };
assert_eq!( 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 }), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, bad_justification: false }),
); );
assert_eq!( assert_eq!(
block_import.import_block(block(), None).unwrap(), block_import.import_block(block(), HashMap::new()).unwrap(),
ImportResult::AlreadyInChain ImportResult::AlreadyInChain
); );
} }
@@ -1035,12 +1025,12 @@ fn test_bad_justification() {
}; };
assert_eq!( 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 }), ImportResult::Imported(ImportedAux { needs_justification: true, clear_justification_requests: false, bad_justification: true }),
); );
assert_eq!( assert_eq!(
block_import.import_block(block(), None).unwrap(), block_import.import_block(block(), HashMap::new()).unwrap(),
ImportResult::AlreadyInChain ImportResult::AlreadyInChain
); );
} }
+1 -12
View File
@@ -20,18 +20,13 @@ use client::{self, Client as SubstrateClient, ClientInfo, BlockStatus, CallExecu
use client::error::Error; use client::error::Error;
use client::light::fetcher::ChangesProof; use client::light::fetcher::ChangesProof;
use consensus::{BlockImport, Error as ConsensusError}; 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 runtime_primitives::generic::{BlockId};
use consensus::{ImportBlock, ImportResult};
use runtime_primitives::Justification; use runtime_primitives::Justification;
use primitives::{H256, Blake2Hasher, storage::StorageKey}; use primitives::{H256, Blake2Hasher, storage::StorageKey};
/// Local client abstraction for the network. /// Local client abstraction for the network.
pub trait Client<Block: BlockT>: Send + Sync { pub trait Client<Block: BlockT>: Send + Sync {
/// Import a new block. Parent is supposed to be existing in the blockchain.
fn import(&self, block: ImportBlock<Block>, new_authorities: Option<Vec<AuthorityIdFor<Block>>>)
-> Result<ImportResult, ConsensusError>;
/// Get blockchain info. /// Get blockchain info.
fn info(&self) -> Result<ClientInfo<Block>, Error>; fn info(&self) -> Result<ClientInfo<Block>, Error>;
@@ -80,12 +75,6 @@ impl<B, E, Block, RA> Client<Block> for SubstrateClient<B, E, Block, RA> where
Block: BlockT<Hash=H256>, Block: BlockT<Hash=H256>,
RA: Send + Sync RA: Send + Sync
{ {
fn import(&self, block: ImportBlock<Block>, new_authorities: Option<Vec<AuthorityIdFor<Block>>>)
-> Result<ImportResult, ConsensusError>
{
(self as &SubstrateClient<B, E, Block, RA>).import_block(block, new_authorities)
}
fn info(&self) -> Result<ClientInfo<Block>, Error> { fn info(&self) -> Result<ClientInfo<Block>, Error> {
(self as &SubstrateClient<B, E, Block, RA>).info() (self as &SubstrateClient<B, E, Block, RA>).info()
} }
+1 -1
View File
@@ -221,7 +221,7 @@ fn should_return_runtime_version() {
assert_eq!( assert_eq!(
::serde_json::to_string(&api.runtime_version(None.into()).unwrap()).unwrap(), ::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]]}"#
); );
} }
+2 -1
View File
@@ -20,6 +20,7 @@ use std::iter;
use std::sync::Arc; use std::sync::Arc;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::time::Duration; use std::time::Duration;
use std::collections::HashMap;
use log::info; use log::info;
use futures::{Future, Stream}; use futures::{Future, Stream};
use tempdir::TempDir; use tempdir::TempDir;
@@ -227,7 +228,7 @@ where
info!("Generating #{}", i); info!("Generating #{}", i);
} }
let import_data = block_factory(&first_service); 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() first_service.network().node_id().unwrap()
}; };
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use runtime_primitives::traits::{GetNodeBlockType, Block as BlockT, AuthorityIdFor}; use runtime_primitives::traits::{GetNodeBlockType, Block as BlockT};
use runtime_primitives::generic::BlockId; use runtime_primitives::generic::BlockId;
use client::runtime_api::{self, RuntimeApiInfo}; use client::runtime_api::{self, RuntimeApiInfo};
use client::{error::Result, decl_runtime_apis, impl_runtime_apis}; use client::{error::Result, decl_runtime_apis, impl_runtime_apis};
@@ -68,9 +68,6 @@ impl_runtime_apis! {
fn version() -> runtime_api::RuntimeVersion { fn version() -> runtime_api::RuntimeVersion {
unimplemented!() unimplemented!()
} }
fn authorities() -> Vec<AuthorityIdFor<Block>> {
unimplemented!()
}
fn execute_block(_: Block) { fn execute_block(_: Block) {
unimplemented!() unimplemented!()
} }
+3 -2
View File
@@ -22,6 +22,7 @@ use runtime_primitives::Justification;
use runtime_primitives::generic::BlockId; use runtime_primitives::generic::BlockId;
use primitives::Blake2Hasher; use primitives::Blake2Hasher;
use runtime; use runtime;
use parity_codec::alloc::collections::hash_map::HashMap;
/// Extension trait for a test client. /// Extension trait for a test client.
pub trait TestClient: Sized { pub trait TestClient: Sized {
@@ -60,7 +61,7 @@ impl<B, E, RA> TestClient for Client<B, E, runtime::Block, RA>
fork_choice: ForkChoiceStrategy::LongestChain, 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) fn import_justified(&self, origin: BlockOrigin, block: runtime::Block, justification: Justification)
@@ -77,7 +78,7 @@ impl<B, E, RA> TestClient for Client<B, E, runtime::Block, RA>
fork_choice: ForkChoiceStrategy::LongestChain, fork_choice: ForkChoiceStrategy::LongestChain,
}; };
self.import_block(import, None).map(|_| ()) self.import_block(import, HashMap::new()).map(|_| ())
} }
fn finalize_block(&self, id: BlockId<runtime::Block>, justification: Option<Justification>) -> client::error::Result<()> { fn finalize_block(&self, id: BlockId<runtime::Block>, justification: Option<Justification>) -> client::error::Result<()> {
+1
View File
@@ -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} offchain-primitives = { package = "substrate-offchain-primitives", path = "../offchain/primitives", default-features = false}
executive = { package = "srml-executive", path = "../../srml/executive", default-features = false } executive = { package = "srml-executive", path = "../../srml/executive", default-features = false }
cfg-if = "0.1.6" cfg-if = "0.1.6"
consensus_authorities = { package = "substrate-consensus-authorities", path = "../../core/consensus/authorities", default-features = false }
[dev-dependencies] [dev-dependencies]
substrate-executor = { path = "../executor" } substrate-executor = { path = "../executor" }
+13 -9
View File
@@ -34,7 +34,7 @@ use runtime_primitives::{
create_runtime_str, create_runtime_str,
traits::{ traits::{
BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT,
GetNodeBlockType, GetRuntimeBlockType, GetNodeBlockType, GetRuntimeBlockType, AuthorityIdFor,
}, },
}; };
use runtime_version::RuntimeVersion; use runtime_version::RuntimeVersion;
@@ -289,10 +289,6 @@ cfg_if! {
version() version()
} }
fn authorities() -> Vec<AuthorityId> {
system::authorities()
}
fn execute_block(block: Block) { fn execute_block(block: Block) {
system::execute_block(block) system::execute_block(block)
} }
@@ -386,6 +382,12 @@ cfg_if! {
runtime_io::submit_extrinsic(&ex) runtime_io::submit_extrinsic(&ex)
} }
} }
impl consensus_authorities::AuthoritiesApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityIdFor<Block>> {
crate::system::authorities()
}
}
} }
} else { } else {
impl_runtime_apis! { impl_runtime_apis! {
@@ -394,10 +396,6 @@ cfg_if! {
version() version()
} }
fn authorities() -> Vec<AuthorityId> {
system::authorities()
}
fn execute_block(block: Block) { fn execute_block(block: Block) {
system::execute_block(block) system::execute_block(block)
} }
@@ -496,6 +494,12 @@ cfg_if! {
runtime_io::submit_extrinsic(&ex) runtime_io::submit_extrinsic(&ex)
} }
} }
impl consensus_authorities::AuthoritiesApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityIdFor<Block>> {
crate::system::authorities()
}
}
} }
} }
} }
+15
View File
@@ -2284,6 +2284,20 @@ dependencies = [
"substrate-client 0.1.0", "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]] [[package]]
name = "substrate-consensus-common" name = "substrate-consensus-common"
version = "0.1.0" version = "0.1.0"
@@ -2453,6 +2467,7 @@ dependencies = [
"srml-support 0.1.0", "srml-support 0.1.0",
"substrate-client 0.1.0", "substrate-client 0.1.0",
"substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-aura-primitives 0.1.0",
"substrate-consensus-authorities 0.1.0",
"substrate-inherents 0.1.0", "substrate-inherents 0.1.0",
"substrate-keyring 0.1.0", "substrate-keyring 0.1.0",
"substrate-offchain-primitives 0.1.0", "substrate-offchain-primitives 0.1.0",
@@ -26,6 +26,7 @@ runtime-primitives = { package = "sr-primitives", path = "../../core/sr-primitiv
client = { package = "substrate-client", path = "../../core/client", default_features = false } 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 } 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 } 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] [features]
default = ["std"] default = ["std"]
+6 -4
View File
@@ -234,10 +234,6 @@ impl_runtime_apis! {
VERSION VERSION
} }
fn authorities() -> Vec<AuthorityId> {
Consensus::authorities()
}
fn execute_block(block: Block) { fn execute_block(block: Block) {
Executive::execute_block(block) Executive::execute_block(block)
} }
@@ -292,4 +288,10 @@ impl_runtime_apis! {
Executive::offchain_worker(n) Executive::offchain_worker(n)
} }
} }
impl consensus_authorities::AuthoritiesApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityId> {
Consensus::authorities()
}
}
} }
+15
View File
@@ -1273,6 +1273,7 @@ dependencies = [
"srml-timestamp 0.1.0", "srml-timestamp 0.1.0",
"substrate-client 0.1.0", "substrate-client 0.1.0",
"substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-aura-primitives 0.1.0",
"substrate-consensus-authorities 0.1.0",
"substrate-offchain-primitives 0.1.0", "substrate-offchain-primitives 0.1.0",
"substrate-primitives 0.1.0", "substrate-primitives 0.1.0",
] ]
@@ -2449,6 +2450,20 @@ dependencies = [
"substrate-client 0.1.0", "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]] [[package]]
name = "substrate-consensus-common" name = "substrate-consensus-common"
version = "0.1.0" version = "0.1.0"
+18 -16
View File
@@ -86,30 +86,32 @@ construct_service_factory! {
FullImportQueue = AuraImportQueue< FullImportQueue = AuraImportQueue<
Self::Block, Self::Block,
> >
{ |config: &mut FactoryFullConfiguration<Self> , client: Arc<FullClient<Self>>| { |config: &mut FactoryFullConfiguration<Self> , client: Arc<FullClient<Self>>| {
import_queue::<_, _, _, Pair>( import_queue::<_, _, _, Pair>(
SlotDuration::get_or_compute(&*client)?, SlotDuration::get_or_compute(&*client)?,
client.clone(), client.clone(),
None, None,
client, client,
NothingExtra, NothingExtra,
config.custom.inherent_data_providers.clone(), config.custom.inherent_data_providers.clone(),
true, true,
).map_err(Into::into) ).map_err(Into::into)
}
}, },
LightImportQueue = AuraImportQueue< LightImportQueue = AuraImportQueue<
Self::Block, Self::Block,
> >
{ |config: &mut FactoryFullConfiguration<Self>, client: Arc<LightClient<Self>>| { |config: &mut FactoryFullConfiguration<Self>, client: Arc<LightClient<Self>>| {
import_queue::<_, _, _, Pair>( import_queue::<_, _, _, Pair>(
SlotDuration::get_or_compute(&*client)?, SlotDuration::get_or_compute(&*client)?,
client.clone(), client.clone(),
None, None,
client, client,
NothingExtra, NothingExtra,
config.custom.inherent_data_providers.clone(), config.custom.inherent_data_providers.clone(),
true, true,
).map_err(Into::into) ).map_err(Into::into)
}
}, },
} }
} }
+1
View File
@@ -37,6 +37,7 @@ rustc-hex = { version = "2.0", optional = true }
hex-literal = { version = "0.1.0", optional = true } hex-literal = { version = "0.1.0", optional = true }
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
substrate-keyring = { path = "../../core/keyring", optional = true } substrate-keyring = { path = "../../core/keyring", optional = true }
consensus_authorities = { package = "substrate-consensus-authorities", path = "../../core/consensus/authorities", default-features = false }
[features] [features]
default = ["std"] default = ["std"]
+10 -7
View File
@@ -34,7 +34,8 @@ use client::{
use runtime_primitives::{ApplyResult, generic, create_runtime_str}; use runtime_primitives::{ApplyResult, generic, create_runtime_str};
use runtime_primitives::transaction_validity::TransactionValidity; use runtime_primitives::transaction_validity::TransactionValidity;
use runtime_primitives::traits::{ 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 version::RuntimeVersion;
use council::{motions as council_motions, voting as council_voting}; 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"), spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"), impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10, authoring_version: 10,
spec_version: 52, spec_version: 53,
impl_version: 52, impl_version: 53,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
}; };
@@ -243,10 +244,6 @@ impl_runtime_apis! {
VERSION VERSION
} }
fn authorities() -> Vec<AuthorityId> {
Consensus::authorities()
}
fn execute_block(block: Block) { fn execute_block(block: Block) {
Executive::execute_block(block) Executive::execute_block(block)
} }
@@ -335,4 +332,10 @@ impl_runtime_apis! {
Aura::slot_duration() Aura::slot_duration()
} }
} }
impl consensus_authorities::AuthoritiesApi<Block> for Runtime {
fn authorities() -> Vec<AuthorityIdFor<Block>> {
Consensus::authorities()
}
}
} }
+15
View File
@@ -1296,6 +1296,7 @@ dependencies = [
"srml-treasury 0.1.0", "srml-treasury 0.1.0",
"substrate-client 0.1.0", "substrate-client 0.1.0",
"substrate-consensus-aura-primitives 0.1.0", "substrate-consensus-aura-primitives 0.1.0",
"substrate-consensus-authorities 0.1.0",
"substrate-keyring 0.1.0", "substrate-keyring 0.1.0",
"substrate-offchain-primitives 0.1.0", "substrate-offchain-primitives 0.1.0",
"substrate-primitives 0.1.0", "substrate-primitives 0.1.0",
@@ -2593,6 +2594,20 @@ dependencies = [
"substrate-client 0.1.0", "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]] [[package]]
name = "substrate-consensus-common" name = "substrate-consensus-common"
version = "0.1.0" version = "0.1.0"
+1 -1
View File
@@ -470,7 +470,7 @@ impl<T: Trait> Module<T> {
// NOTE: this must be the last potential bailer, since it changes state. // NOTE: this must be the last potential bailer, since it changes state.
T::Currency::reserve(&who, Self::voting_bond())?; T::Currency::reserve(&who, Self::voting_bond())?;
<Voters<T>>::mutate(|mut v| v.push(who.clone())); <Voters<T>>::mutate(|v| v.push(who.clone()));
} }
<LastActiveOf<T>>::insert(&who, index); <LastActiveOf<T>>::insert(&who, index);
<ApprovalsOf<T>>::insert(&who, votes); <ApprovalsOf<T>>::insert(&who, votes);