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