Run cargo fmt on the whole code base (#9394)

* Run cargo fmt on the whole code base

* Second run

* Add CI check

* Fix compilation

* More unnecessary braces

* Handle weights

* Use --all

* Use correct attributes...

* Fix UI tests

* AHHHHHHHHH

* 🤦

* Docs

* Fix compilation

* 🤷

* Please stop

* 🤦 x 2

* More

* make rustfmt.toml consistent with polkadot

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-07-21 16:32:32 +02:00
committed by GitHub
parent d451c38c1c
commit 7b56ab15b4
1010 changed files with 53339 additions and 51208 deletions
@@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
use sc_finality_grandpa::FinalityProofProvider;
use sp_runtime::traits::{Block as BlockT, NumberFor};
@@ -44,7 +44,6 @@ where
&self,
block: NumberFor<Block>,
) -> Result<Option<EncodedFinalityProof>, sc_finality_grandpa::FinalityProofError> {
self.prove_finality(block)
.map(|x| x.map(|y| EncodedFinalityProof(y.into())))
self.prove_finality(block).map(|x| x.map(|y| EncodedFinalityProof(y.into())))
}
}
@@ -19,17 +19,16 @@
//! RPC API for GRANDPA.
#![warn(missing_docs)]
use std::sync::Arc;
use futures::{FutureExt, TryFutureExt, TryStreamExt, StreamExt};
use log::warn;
use jsonrpc_derive::rpc;
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId, manager::SubscriptionManager};
use futures::{FutureExt, StreamExt, TryFutureExt, TryStreamExt};
use jsonrpc_core::futures::{
future::{Executor as Executor01, Future as Future01},
sink::Sink as Sink01,
stream::Stream as Stream01,
future::Future as Future01,
future::Executor as Executor01,
};
use jsonrpc_derive::rpc;
use jsonrpc_pubsub::{manager::SubscriptionManager, typed::Subscriber, SubscriptionId};
use log::warn;
use std::sync::Arc;
mod error;
mod finality;
@@ -40,8 +39,8 @@ use sc_finality_grandpa::GrandpaJustificationStream;
use sp_runtime::traits::{Block as BlockT, NumberFor};
use finality::{EncodedFinalityProof, RpcFinalityProofProvider};
use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates};
use notification::JustificationNotification;
use report::{ReportAuthoritySet, ReportVoterState, ReportedRoundStates};
type FutureResult<T> =
Box<dyn jsonrpc_core::futures::Future<Item = T, Error = jsonrpc_core::Error> + Send>;
@@ -67,7 +66,7 @@ pub trait GrandpaApi<Notification, Hash, Number> {
fn subscribe_justifications(
&self,
metadata: Self::Metadata,
subscriber: Subscriber<Notification>
subscriber: Subscriber<Notification>,
);
/// Unsubscribe from receiving notifications about recently finalized blocks.
@@ -79,16 +78,13 @@ pub trait GrandpaApi<Notification, Hash, Number> {
fn unsubscribe_justifications(
&self,
metadata: Option<Self::Metadata>,
id: SubscriptionId
id: SubscriptionId,
) -> jsonrpc_core::Result<bool>;
/// Prove finality for the given block number by returning the Justification for the last block
/// in the set and all the intermediary headers to link them together.
#[rpc(name = "grandpa_proveFinality")]
fn prove_finality(
&self,
block: Number,
) -> FutureResult<Option<EncodedFinalityProof>>;
fn prove_finality(&self, block: Number) -> FutureResult<Option<EncodedFinalityProof>>;
}
/// Implements the GrandpaApi RPC trait for interacting with GRANDPA.
@@ -115,13 +111,7 @@ impl<AuthoritySet, VoterState, Block: BlockT, ProofProvider>
E: Executor01<Box<dyn Future01<Item = (), Error = ()> + Send>> + Send + Sync + 'static,
{
let manager = SubscriptionManager::new(Arc::new(executor));
Self {
authority_set,
voter_state,
justification_stream,
manager,
finality_proof_provider,
}
Self { authority_set, voter_state, justification_stream, manager, finality_proof_provider }
}
}
@@ -145,10 +135,12 @@ where
fn subscribe_justifications(
&self,
_metadata: Self::Metadata,
subscriber: Subscriber<JustificationNotification>
subscriber: Subscriber<JustificationNotification>,
) {
let stream = self.justification_stream.subscribe()
.map(|x| Ok::<_,()>(JustificationNotification::from(x)))
let stream = self
.justification_stream
.subscribe()
.map(|x| Ok::<_, ()>(JustificationNotification::from(x)))
.map_err(|e| warn!("Notification stream error: {:?}", e))
.compat();
@@ -163,7 +155,7 @@ where
fn unsubscribe_justifications(
&self,
_metadata: Option<Self::Metadata>,
id: SubscriptionId
id: SubscriptionId,
) -> jsonrpc_core::Result<bool> {
Ok(self.manager.cancel(id))
}
@@ -181,7 +173,7 @@ where
error::Error::ProveFinalityFailed(e)
})
.map_err(jsonrpc_core::Error::from)
.compat()
.compat(),
)
}
}
@@ -189,14 +181,13 @@ where
#[cfg(test)]
mod tests {
use super::*;
use jsonrpc_core::{types::Params, Notification, Output};
use std::{collections::HashSet, convert::TryInto, sync::Arc};
use jsonrpc_core::{Notification, Output, types::Params};
use parity_scale_codec::{Encode, Decode};
use parity_scale_codec::{Decode, Encode};
use sc_block_builder::{BlockBuilder, RecordProof};
use sc_finality_grandpa::{
report, AuthorityId, GrandpaJustificationSender, GrandpaJustification,
FinalityProof,
report, AuthorityId, FinalityProof, GrandpaJustification, GrandpaJustificationSender,
};
use sp_blockchain::HeaderBackend;
use sp_core::crypto::Public;
@@ -204,9 +195,7 @@ mod tests {
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use substrate_test_runtime_client::{
runtime::{Block, Header, H256},
DefaultTestClientBuilderExt,
TestClientBuilderExt,
TestClientBuilder,
DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
};
struct TestAuthoritySet;
@@ -253,14 +242,14 @@ mod tests {
impl<Block: BlockT> RpcFinalityProofProvider<Block> for TestFinalityProofProvider {
fn rpc_prove_finality(
&self,
_block: NumberFor<Block>
_block: NumberFor<Block>,
) -> Result<Option<EncodedFinalityProof>, sc_finality_grandpa::FinalityProofError> {
Ok(Some(EncodedFinalityProof(
self.finality_proof
.as_ref()
.expect("Don't call rpc_prove_finality without setting the FinalityProof")
.encode()
.into()
.into(),
)))
}
}
@@ -290,17 +279,14 @@ mod tests {
let background_rounds = vec![(1, past_round_state)].into_iter().collect();
Some(report::VoterState {
background_rounds,
best_round: (2, best_round_state),
})
Some(report::VoterState { background_rounds, best_round: (2, best_round_state) })
}
}
fn setup_io_handler<VoterState>(voter_state: VoterState) -> (
jsonrpc_core::MetaIoHandler<sc_rpc::Metadata>,
GrandpaJustificationSender<Block>,
) where
fn setup_io_handler<VoterState>(
voter_state: VoterState,
) -> (jsonrpc_core::MetaIoHandler<sc_rpc::Metadata>, GrandpaJustificationSender<Block>)
where
VoterState: ReportVoterState + Send + Sync + 'static,
{
setup_io_handler_with_finality_proofs(voter_state, None)
@@ -309,10 +295,8 @@ mod tests {
fn setup_io_handler_with_finality_proofs<VoterState>(
voter_state: VoterState,
finality_proof: Option<FinalityProof<Header>>,
) -> (
jsonrpc_core::MetaIoHandler<sc_rpc::Metadata>,
GrandpaJustificationSender<Block>,
) where
) -> (jsonrpc_core::MetaIoHandler<sc_rpc::Metadata>, GrandpaJustificationSender<Block>)
where
VoterState: ReportVoterState + Send + Sync + 'static,
{
let (justification_sender, justification_stream) = GrandpaJustificationStream::channel();
@@ -345,7 +329,7 @@ mod tests {
#[test]
fn working_rpc_handler() {
let (io, _) = setup_io_handler(TestVoterState);
let (io, _) = setup_io_handler(TestVoterState);
let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":1}"#;
let response = "{\"jsonrpc\":\"2.0\",\"result\":{\
@@ -378,7 +362,8 @@ mod tests {
let (meta, _) = setup_session();
// Subscribe
let sub_request = r#"{"jsonrpc":"2.0","method":"grandpa_subscribeJustifications","params":[],"id":1}"#;
let sub_request =
r#"{"jsonrpc":"2.0","method":"grandpa_subscribeJustifications","params":[],"id":1}"#;
let resp = io.handle_request_sync(sub_request, meta.clone());
let resp: Output = serde_json::from_str(&resp.unwrap()).unwrap();
@@ -410,7 +395,8 @@ mod tests {
let (meta, _) = setup_session();
// Subscribe
let sub_request = r#"{"jsonrpc":"2.0","method":"grandpa_subscribeJustifications","params":[],"id":1}"#;
let sub_request =
r#"{"jsonrpc":"2.0","method":"grandpa_subscribeJustifications","params":[],"id":1}"#;
let resp = io.handle_request_sync(sub_request, meta.clone());
let resp: Output = serde_json::from_str(&resp.unwrap()).unwrap();
assert!(matches!(resp, Output::Success(_)));
@@ -440,7 +426,10 @@ mod tests {
RecordProof::No,
Default::default(),
&*backend,
).unwrap().build().unwrap();
)
.unwrap()
.build()
.unwrap();
let block = built_block.block;
let block_hash = block.hash();
@@ -501,8 +490,7 @@ mod tests {
_ => panic!(),
};
let recv_sub_id: String =
serde_json::from_value(json_map["subscription"].take()).unwrap();
let recv_sub_id: String = serde_json::from_value(json_map["subscription"].take()).unwrap();
let recv_justification: sp_core::Bytes =
serde_json::from_value(json_map["result"].take()).unwrap();
let recv_justification: GrandpaJustification<Block> =
@@ -520,10 +508,8 @@ mod tests {
justification: create_justification().encode(),
unknown_headers: vec![header(2)],
};
let (io, _) = setup_io_handler_with_finality_proofs(
TestVoterState,
Some(finality_proof.clone()),
);
let (io, _) =
setup_io_handler_with_finality_proofs(TestVoterState, Some(finality_proof.clone()));
let request =
"{\"jsonrpc\":\"2.0\",\"method\":\"grandpa_proveFinality\",\"params\":[42],\"id\":1}";
@@ -16,10 +16,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use serde::{Serialize, Deserialize};
use parity_scale_codec::Encode;
use sp_runtime::traits::Block as BlockT;
use sc_finality_grandpa::GrandpaJustification;
use serde::{Deserialize, Serialize};
use sp_runtime::traits::Block as BlockT;
/// An encoded justification proving that the given header has been finalized
#[derive(Clone, Serialize, Deserialize)]
@@ -44,11 +44,8 @@ where
H: Clone + Debug + Eq,
{
fn get(&self) -> (u64, HashSet<AuthorityId>) {
let current_voters: HashSet<AuthorityId> = self
.current_authorities()
.iter()
.map(|p| p.0.clone())
.collect();
let current_voters: HashSet<AuthorityId> =
self.current_authorities().iter().map(|p| p.0.clone()).collect();
(self.set_id(), current_voters)
}
@@ -152,10 +149,6 @@ impl ReportedRoundStates {
.map(|(round, round_state)| RoundState::from(*round, round_state, &current_voters))
.collect::<Result<Vec<_>, Error>>()?;
Ok(Self {
set_id,
best,
background,
})
Ok(Self { set_id, best, background })
}
}
@@ -18,18 +18,16 @@
//! Utilities for dealing with authorities, authority sets, and handoffs.
use std::cmp::Ord;
use std::fmt::Debug;
use std::ops::Add;
use std::{cmp::Ord, fmt::Debug, ops::Add};
use fork_tree::ForkTree;
use parking_lot::MappedMutexGuard;
use finality_grandpa::voter_set::VoterSet;
use parity_scale_codec::{Encode, Decode};
use fork_tree::ForkTree;
use log::debug;
use parity_scale_codec::{Decode, Encode};
use parking_lot::MappedMutexGuard;
use sc_consensus::shared_data::{SharedData, SharedDataLocked};
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO};
use sp_finality_grandpa::{AuthorityId, AuthorityList};
use sc_consensus::shared_data::{SharedData, SharedDataLocked};
use crate::SetId;
@@ -77,9 +75,7 @@ pub struct SharedAuthoritySet<H, N> {
impl<H, N> Clone for SharedAuthoritySet<H, N> {
fn clone(&self) -> Self {
SharedAuthoritySet {
inner: self.inner.clone(),
}
SharedAuthoritySet { inner: self.inner.clone() }
}
}
@@ -92,16 +88,15 @@ impl<H, N> SharedAuthoritySet<H, N> {
/// Returns access to the [`AuthoritySet`] and locks it.
///
/// For more information see [`SharedDataLocked`].
pub(crate) fn inner_locked(
&self,
) -> SharedDataLocked<AuthoritySet<H, N>> {
pub(crate) fn inner_locked(&self) -> SharedDataLocked<AuthoritySet<H, N>> {
self.inner.shared_data_locked()
}
}
impl<H: Eq, N> SharedAuthoritySet<H, N>
where N: Add<Output=N> + Ord + Clone + Debug,
H: Clone + Debug
where
N: Add<Output = N> + Ord + Clone + Debug,
H: Clone + Debug,
{
/// Get the earliest limit-block number that's higher or equal to the given
/// min number, if any.
@@ -136,9 +131,7 @@ where N: Add<Output=N> + Ord + Clone + Debug,
impl<H, N> From<AuthoritySet<H, N>> for SharedAuthoritySet<H, N> {
fn from(set: AuthoritySet<H, N>) -> Self {
SharedAuthoritySet {
inner: SharedData::new(set),
}
SharedAuthoritySet { inner: SharedData::new(set) }
}
}
@@ -191,7 +184,7 @@ where
/// Get a genesis set with given authorities.
pub(crate) fn genesis(initial: AuthorityList) -> Option<Self> {
if Self::invalid_authority_list(&initial) {
return None;
return None
}
Some(AuthoritySet {
@@ -212,7 +205,7 @@ where
authority_set_changes: AuthoritySetChanges<N>,
) -> Option<Self> {
if Self::invalid_authority_list(&authorities) {
return None;
return None
}
Some(AuthoritySet {
@@ -255,7 +248,7 @@ where
for change in &self.pending_forced_changes {
if is_descendent_of(&change.canon_hash, best_hash)? {
forced = Some((change.canon_hash.clone(), change.canon_height.clone()));
break;
break
}
}
@@ -263,16 +256,13 @@ where
for (_, _, change) in self.pending_standard_changes.roots() {
if is_descendent_of(&change.canon_hash, best_hash)? {
standard = Some((change.canon_hash.clone(), change.canon_height.clone()));
break;
break
}
}
let earliest = match (forced, standard) {
(Some(forced), Some(standard)) => Some(if forced.1 < standard.1 {
forced
} else {
standard
}),
(Some(forced), Some(standard)) =>
Some(if forced.1 < standard.1 { forced } else { standard }),
(Some(forced), None) => Some(forced),
(None, Some(standard)) => Some(standard),
(None, None) => None,
@@ -300,12 +290,7 @@ where
pending.delay,
);
self.pending_standard_changes.import(
hash,
number,
pending,
is_descendent_of,
)?;
self.pending_standard_changes.import(hash, number, pending, is_descendent_of)?;
debug!(
target: "afg",
@@ -329,21 +314,21 @@ where
{
for change in &self.pending_forced_changes {
if change.canon_hash == pending.canon_hash {
return Err(Error::DuplicateAuthoritySetChange);
return Err(Error::DuplicateAuthoritySetChange)
}
if is_descendent_of(&change.canon_hash, &pending.canon_hash)? {
return Err(Error::MultiplePendingForcedAuthoritySetChanges);
return Err(Error::MultiplePendingForcedAuthoritySetChanges)
}
}
// ordered first by effective number and then by signal-block number.
let key = (pending.effective_number(), pending.canon_height.clone());
let idx = self.pending_forced_changes
.binary_search_by_key(&key, |change| (
change.effective_number(),
change.canon_height.clone(),
))
let idx = self
.pending_forced_changes
.binary_search_by_key(&key, |change| {
(change.effective_number(), change.canon_height.clone())
})
.unwrap_or_else(|i| i);
debug!(
@@ -376,24 +361,22 @@ where
E: std::error::Error,
{
if Self::invalid_authority_list(&pending.next_authorities) {
return Err(Error::InvalidAuthoritySet);
return Err(Error::InvalidAuthoritySet)
}
match pending.delay_kind {
DelayKind::Best { .. } => {
self.add_forced_change(pending, is_descendent_of)
},
DelayKind::Finalized => {
self.add_standard_change(pending, is_descendent_of)
},
DelayKind::Best { .. } => self.add_forced_change(pending, is_descendent_of),
DelayKind::Finalized => self.add_standard_change(pending, is_descendent_of),
}
}
/// Inspect pending changes. Standard pending changes are iterated first,
/// and the changes in the tree are traversed in pre-order, afterwards all
/// forced changes are iterated.
pub(crate) fn pending_changes(&self) -> impl Iterator<Item=&PendingChange<H, N>> {
self.pending_standard_changes.iter().map(|(_, _, c)| c)
pub(crate) fn pending_changes(&self) -> impl Iterator<Item = &PendingChange<H, N>> {
self.pending_standard_changes
.iter()
.map(|(_, _, c)| c)
.chain(self.pending_forced_changes.iter())
}
@@ -404,7 +387,8 @@ where
/// Only standard changes are taken into account for the current
/// limit, since any existing forced change should preclude the voter from voting.
pub(crate) fn current_limit(&self, min: N) -> Option<N> {
self.pending_standard_changes.roots()
self.pending_standard_changes
.roots()
.filter(|&(_, _, c)| c.effective_number() >= min)
.min_by_key(|&(_, _, c)| c.effective_number())
.map(|(_, _, c)| c.effective_number())
@@ -450,9 +434,7 @@ where
// the block that signaled the change.
if change.canon_hash == best_hash || is_descendent_of(&change.canon_hash, &best_hash)? {
let median_last_finalized = match change.delay_kind {
DelayKind::Best {
ref median_last_finalized,
} => median_last_finalized.clone(),
DelayKind::Best { ref median_last_finalized } => median_last_finalized.clone(),
_ => unreachable!(
"pending_forced_changes only contains forced changes; forced changes have delay kind Best; qed."
),
@@ -460,8 +442,8 @@ where
// check if there's any pending standard change that we depend on
for (_, _, standard_change) in self.pending_standard_changes.roots() {
if standard_change.effective_number() <= median_last_finalized
&& is_descendent_of(&standard_change.canon_hash, &change.canon_hash)?
if standard_change.effective_number() <= median_last_finalized &&
is_descendent_of(&standard_change.canon_hash, &change.canon_hash)?
{
log::info!(target: "afg",
"Not applying authority set change forced at block #{:?}, due to pending standard change at block #{:?}",
@@ -469,11 +451,9 @@ where
standard_change.effective_number(),
);
return Err(
Error::ForcedAuthoritySetChangeDependencyUnsatisfied(
standard_change.effective_number()
)
);
return Err(Error::ForcedAuthoritySetChangeDependencyUnsatisfied(
standard_change.effective_number(),
))
}
}
@@ -505,7 +485,7 @@ where
},
));
break;
break
}
}
@@ -536,24 +516,19 @@ where
F: Fn(&H, &H) -> Result<bool, E>,
E: std::error::Error,
{
let mut status = Status {
changed: false,
new_set_block: None,
};
let mut status = Status { changed: false, new_set_block: None };
match self.pending_standard_changes.finalize_with_descendent_if(
&finalized_hash,
finalized_number.clone(),
is_descendent_of,
|change| change.effective_number() <= finalized_number
|change| change.effective_number() <= finalized_number,
)? {
fork_tree::FinalizationResult::Changed(change) => {
status.changed = true;
let pending_forced_changes = std::mem::replace(
&mut self.pending_forced_changes,
Vec::new(),
);
let pending_forced_changes =
std::mem::replace(&mut self.pending_forced_changes, Vec::new());
// we will keep all forced changes for any later blocks and that are a
// descendent of the finalized block (i.e. they are part of this branch).
@@ -566,7 +541,8 @@ where
}
if let Some(change) = change {
afg_log!(initial_sync,
afg_log!(
initial_sync,
"👴 Applying authority set change scheduled at block #{:?}",
change.canon_height,
);
@@ -583,10 +559,7 @@ where
self.current_authorities = change.next_authorities;
self.set_id += 1;
status.new_set_block = Some((
finalized_hash,
finalized_number,
));
status.new_set_block = Some((finalized_hash, finalized_number));
}
},
fork_tree::FinalizationResult::Unchanged => {},
@@ -615,12 +588,14 @@ where
F: Fn(&H, &H) -> Result<bool, E>,
E: std::error::Error,
{
self.pending_standard_changes.finalizes_any_with_descendent_if(
&finalized_hash,
finalized_number.clone(),
is_descendent_of,
|change| change.effective_number() == finalized_number
).map_err(Error::ForkTree)
self.pending_standard_changes
.finalizes_any_with_descendent_if(
&finalized_hash,
finalized_number.clone(),
is_descendent_of,
|change| change.effective_number() == finalized_number,
)
.map_err(Error::ForkTree)
}
}
@@ -654,7 +629,9 @@ pub struct PendingChange<H, N> {
}
impl<H: Decode, N: Decode> Decode for PendingChange<H, N> {
fn decode<I: parity_scale_codec::Input>(value: &mut I) -> Result<Self, parity_scale_codec::Error> {
fn decode<I: parity_scale_codec::Input>(
value: &mut I,
) -> Result<Self, parity_scale_codec::Error> {
let next_authorities = Decode::decode(value)?;
let delay = Decode::decode(value)?;
let canon_height = Decode::decode(value)?;
@@ -662,17 +639,11 @@ impl<H: Decode, N: Decode> Decode for PendingChange<H, N> {
let delay_kind = DelayKind::decode(value).unwrap_or(DelayKind::Finalized);
Ok(PendingChange {
next_authorities,
delay,
canon_height,
canon_hash,
delay_kind,
})
Ok(PendingChange { next_authorities, delay, canon_height, canon_hash, delay_kind })
}
}
impl<H, N: Add<Output=N> + Clone> PendingChange<H, N> {
impl<H, N: Add<Output = N> + Clone> PendingChange<H, N> {
/// Returns the effective number this change will be applied at.
pub fn effective_number(&self) -> N {
self.canon_height.clone() + self.delay.clone()
@@ -715,15 +686,17 @@ impl<N: Ord + Clone> AuthoritySetChanges<N> {
}
pub(crate) fn get_set_id(&self, block_number: N) -> AuthoritySetChangeId<N> {
if self.0
if self
.0
.last()
.map(|last_auth_change| last_auth_change.1 < block_number)
.unwrap_or(false)
{
return AuthoritySetChangeId::Latest;
return AuthoritySetChangeId::Latest
}
let idx = self.0
let idx = self
.0
.binary_search_by_key(&block_number, |(_, n)| n.clone())
.unwrap_or_else(|b| b);
@@ -732,7 +705,7 @@ impl<N: Ord + Clone> AuthoritySetChanges<N> {
// if this is the first index but not the first set id then we are missing data.
if idx == 0 && set_id != 0 {
return AuthoritySetChangeId::Unknown;
return AuthoritySetChangeId::Unknown
}
AuthoritySetChangeId::Set(set_id, block_number)
@@ -745,7 +718,9 @@ impl<N: Ord + Clone> AuthoritySetChanges<N> {
/// number (excluded). The iterator yields a tuple representing the set id and the block number
/// of the last block in that set.
pub fn iter_from(&self, block_number: N) -> Option<impl Iterator<Item = &(u64, N)>> {
let idx = self.0.binary_search_by_key(&block_number, |(_, n)| n.clone())
let idx = self
.0
.binary_search_by_key(&block_number, |(_, n)| n.clone())
// if there was a change at the given block number then we should start on the next
// index since we want to exclude the current block number
.map(|n| n + 1)
@@ -756,7 +731,7 @@ impl<N: Ord + Clone> AuthoritySetChanges<N> {
// if this is the first index but not the first set id then we are missing data.
if idx == 0 && set_id != 0 {
return None;
return None
}
}
@@ -769,14 +744,13 @@ mod tests {
use super::*;
use sp_core::crypto::Public;
fn static_is_descendent_of<A>(value: bool)
-> impl Fn(&A, &A) -> Result<bool, std::io::Error>
{
fn static_is_descendent_of<A>(value: bool) -> impl Fn(&A, &A) -> Result<bool, std::io::Error> {
move |_, _| Ok(value)
}
fn is_descendent_of<A, F>(f: F) -> impl Fn(&A, &A) -> Result<bool, std::io::Error>
where F: Fn(&A, &A) -> bool
where
F: Fn(&A, &A) -> bool,
{
move |base, hash| Ok(f(base, hash))
}
@@ -793,14 +767,12 @@ mod tests {
authority_set_changes: AuthoritySetChanges::empty(),
};
let change = |height| {
PendingChange {
next_authorities: current_authorities.clone(),
delay: 0,
canon_height: height,
canon_hash: height.to_string(),
delay_kind: DelayKind::Finalized,
}
let change = |height| PendingChange {
next_authorities: current_authorities.clone(),
delay: 0,
canon_height: height,
canon_hash: height.to_string(),
delay_kind: DelayKind::Finalized,
};
let is_descendent_of = static_is_descendent_of(false);
@@ -808,25 +780,13 @@ mod tests {
authorities.add_pending_change(change(1), &is_descendent_of).unwrap();
authorities.add_pending_change(change(2), &is_descendent_of).unwrap();
assert_eq!(
authorities.current_limit(0),
Some(1),
);
assert_eq!(authorities.current_limit(0), Some(1),);
assert_eq!(
authorities.current_limit(1),
Some(1),
);
assert_eq!(authorities.current_limit(1), Some(1),);
assert_eq!(
authorities.current_limit(2),
Some(2),
);
assert_eq!(authorities.current_limit(2), Some(2),);
assert_eq!(
authorities.current_limit(3),
None,
);
assert_eq!(authorities.current_limit(3), None,);
}
#[test]
@@ -865,13 +825,22 @@ mod tests {
delay_kind: DelayKind::Finalized,
};
authorities.add_pending_change(change_a.clone(), &static_is_descendent_of(false)).unwrap();
authorities.add_pending_change(change_b.clone(), &static_is_descendent_of(false)).unwrap();
authorities.add_pending_change(change_c.clone(), &is_descendent_of(|base, hash| match (*base, *hash) {
("hash_a", "hash_c") => true,
("hash_b", "hash_c") => false,
_ => unreachable!(),
})).unwrap();
authorities
.add_pending_change(change_a.clone(), &static_is_descendent_of(false))
.unwrap();
authorities
.add_pending_change(change_b.clone(), &static_is_descendent_of(false))
.unwrap();
authorities
.add_pending_change(
change_c.clone(),
&is_descendent_of(|base, hash| match (*base, *hash) {
("hash_a", "hash_c") => true,
("hash_b", "hash_c") => false,
_ => unreachable!(),
}),
)
.unwrap();
// forced changes are iterated last
let change_d = PendingChange {
@@ -890,8 +859,12 @@ mod tests {
delay_kind: DelayKind::Best { median_last_finalized: 0 },
};
authorities.add_pending_change(change_d.clone(), &static_is_descendent_of(false)).unwrap();
authorities.add_pending_change(change_e.clone(), &static_is_descendent_of(false)).unwrap();
authorities
.add_pending_change(change_d.clone(), &static_is_descendent_of(false))
.unwrap();
authorities
.add_pending_change(change_e.clone(), &static_is_descendent_of(false))
.unwrap();
// ordered by subtree depth
assert_eq!(
@@ -930,46 +903,48 @@ mod tests {
delay_kind: DelayKind::Finalized,
};
authorities.add_pending_change(change_a.clone(), &static_is_descendent_of(true)).unwrap();
authorities.add_pending_change(change_b.clone(), &static_is_descendent_of(true)).unwrap();
authorities
.add_pending_change(change_a.clone(), &static_is_descendent_of(true))
.unwrap();
authorities
.add_pending_change(change_b.clone(), &static_is_descendent_of(true))
.unwrap();
assert_eq!(
authorities.pending_changes().collect::<Vec<_>>(),
vec![&change_a, &change_b],
);
assert_eq!(authorities.pending_changes().collect::<Vec<_>>(), vec![&change_a, &change_b],);
// finalizing "hash_c" won't enact the change signaled at "hash_a" but it will prune out "hash_b"
let status = authorities.apply_standard_changes(
"hash_c",
11,
&is_descendent_of(|base, hash| match (*base, *hash) {
("hash_a", "hash_c") => true,
("hash_b", "hash_c") => false,
_ => unreachable!(),
}),
false,
None,
).unwrap();
let status = authorities
.apply_standard_changes(
"hash_c",
11,
&is_descendent_of(|base, hash| match (*base, *hash) {
("hash_a", "hash_c") => true,
("hash_b", "hash_c") => false,
_ => unreachable!(),
}),
false,
None,
)
.unwrap();
assert!(status.changed);
assert_eq!(status.new_set_block, None);
assert_eq!(
authorities.pending_changes().collect::<Vec<_>>(),
vec![&change_a],
);
assert_eq!(authorities.pending_changes().collect::<Vec<_>>(), vec![&change_a],);
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges::empty());
// finalizing "hash_d" will enact the change signaled at "hash_a"
let status = authorities.apply_standard_changes(
"hash_d",
15,
&is_descendent_of(|base, hash| match (*base, *hash) {
("hash_a", "hash_d") => true,
_ => unreachable!(),
}),
false,
None,
).unwrap();
let status = authorities
.apply_standard_changes(
"hash_d",
15,
&is_descendent_of(|base, hash| match (*base, *hash) {
("hash_a", "hash_d") => true,
_ => unreachable!(),
}),
false,
None,
)
.unwrap();
assert!(status.changed);
assert_eq!(status.new_set_block, Some(("hash_d", 15)));
@@ -1010,8 +985,12 @@ mod tests {
delay_kind: DelayKind::Finalized,
};
authorities.add_pending_change(change_a.clone(), &static_is_descendent_of(true)).unwrap();
authorities.add_pending_change(change_c.clone(), &static_is_descendent_of(true)).unwrap();
authorities
.add_pending_change(change_a.clone(), &static_is_descendent_of(true))
.unwrap();
authorities
.add_pending_change(change_c.clone(), &static_is_descendent_of(true))
.unwrap();
let is_descendent_of = is_descendent_of(|base, hash| match (*base, *hash) {
("hash_a", "hash_b") => true,
@@ -1032,13 +1011,9 @@ mod tests {
));
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges::empty());
let status = authorities.apply_standard_changes(
"hash_b",
15,
&is_descendent_of,
false,
None,
).unwrap();
let status = authorities
.apply_standard_changes("hash_b", 15, &is_descendent_of, false, None)
.unwrap();
assert!(status.changed);
assert_eq!(status.new_set_block, Some(("hash_b", 15)));
@@ -1048,13 +1023,9 @@ mod tests {
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15)]));
// after finalizing `change_a` it should be possible to finalize `change_c`
let status = authorities.apply_standard_changes(
"hash_d",
40,
&is_descendent_of,
false,
None,
).unwrap();
let status = authorities
.apply_standard_changes("hash_d", 40, &is_descendent_of, false, None)
.unwrap();
assert!(status.changed);
assert_eq!(status.new_set_block, Some(("hash_d", 40)));
@@ -1092,8 +1063,12 @@ mod tests {
delay_kind: DelayKind::Finalized,
};
authorities.add_pending_change(change_a.clone(), &static_is_descendent_of(false)).unwrap();
authorities.add_pending_change(change_b.clone(), &static_is_descendent_of(true)).unwrap();
authorities
.add_pending_change(change_a.clone(), &static_is_descendent_of(false))
.unwrap();
authorities
.add_pending_change(change_b.clone(), &static_is_descendent_of(true))
.unwrap();
let is_descendent_of = is_descendent_of(|base, hash| match (*base, *hash) {
("hash_a", "hash_d") => true,
@@ -1160,8 +1135,12 @@ mod tests {
delay_kind: DelayKind::Best { median_last_finalized: 0 },
};
authorities.add_pending_change(change_a, &static_is_descendent_of(false)).unwrap();
authorities.add_pending_change(change_b.clone(), &static_is_descendent_of(false)).unwrap();
authorities
.add_pending_change(change_a, &static_is_descendent_of(false))
.unwrap();
authorities
.add_pending_change(change_b.clone(), &static_is_descendent_of(false))
.unwrap();
// no duplicates are allowed
assert!(matches!(
@@ -1172,7 +1151,9 @@ mod tests {
// there's an effective change triggered at block 15 but not a standard one.
// so this should do nothing.
assert_eq!(
authorities.enacts_standard_change("hash_c", 15, &static_is_descendent_of(true)).unwrap(),
authorities
.enacts_standard_change("hash_c", 15, &static_is_descendent_of(true))
.unwrap(),
None,
);
@@ -1194,20 +1175,16 @@ mod tests {
// let's try and apply the forced changes.
// too early and there's no forced changes to apply.
assert!(
authorities
.apply_forced_changes("hash_a10", 10, &static_is_descendent_of(true), false, None)
.unwrap()
.is_none()
);
assert!(authorities
.apply_forced_changes("hash_a10", 10, &static_is_descendent_of(true), false, None)
.unwrap()
.is_none());
// too late.
assert!(
authorities
.apply_forced_changes("hash_a16", 16, &is_descendent_of_a, false, None)
.unwrap()
.is_none()
);
assert!(authorities
.apply_forced_changes("hash_a16", 16, &is_descendent_of_a, false, None)
.unwrap()
.is_none());
// on time -- chooses the right change for this fork.
assert_eq!(
@@ -1247,9 +1224,7 @@ mod tests {
delay: 0,
canon_height: 5,
canon_hash: "hash_a",
delay_kind: DelayKind::Best {
median_last_finalized: 0,
},
delay_kind: DelayKind::Best { median_last_finalized: 0 },
};
// and import it
@@ -1258,12 +1233,10 @@ mod tests {
.unwrap();
// it should be enacted at the same block that signaled it
assert!(
authorities
.apply_forced_changes("hash_a", 5, &static_is_descendent_of(false), false, None)
.unwrap()
.is_some()
);
assert!(authorities
.apply_forced_changes("hash_a", 5, &static_is_descendent_of(false), false, None)
.unwrap()
.is_some());
}
#[test]
@@ -1306,9 +1279,15 @@ mod tests {
};
// add some pending standard changes all on the same fork
authorities.add_pending_change(change_a, &static_is_descendent_of(true)).unwrap();
authorities.add_pending_change(change_b, &static_is_descendent_of(true)).unwrap();
authorities.add_pending_change(change_c, &static_is_descendent_of(true)).unwrap();
authorities
.add_pending_change(change_a, &static_is_descendent_of(true))
.unwrap();
authorities
.add_pending_change(change_b, &static_is_descendent_of(true))
.unwrap();
authorities
.add_pending_change(change_c, &static_is_descendent_of(true))
.unwrap();
// effective at #45
let change_d = PendingChange {
@@ -1316,18 +1295,24 @@ mod tests {
delay: 5,
canon_height: 40,
canon_hash: "hash_d",
delay_kind: DelayKind::Best {
median_last_finalized: 31,
},
delay_kind: DelayKind::Best { median_last_finalized: 31 },
};
// now add a forced change on the same fork
authorities.add_pending_change(change_d, &static_is_descendent_of(true)).unwrap();
authorities
.add_pending_change(change_d, &static_is_descendent_of(true))
.unwrap();
// the forced change cannot be applied since the pending changes it depends on
// have not been applied yet.
assert!(matches!(
authorities.apply_forced_changes("hash_d45", 45, &static_is_descendent_of(true), false, None),
authorities.apply_forced_changes(
"hash_d45",
45,
&static_is_descendent_of(true),
false,
None
),
Err(Error::ForcedAuthoritySetChangeDependencyUnsatisfied(15))
));
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges::empty());
@@ -1340,7 +1325,13 @@ mod tests {
// but the forced change still depends on the next standard change
assert!(matches!(
authorities.apply_forced_changes("hash_d", 45, &static_is_descendent_of(true), false, None),
authorities.apply_forced_changes(
"hash_d",
45,
&static_is_descendent_of(true),
false,
None
),
Err(Error::ForcedAuthoritySetChangeDependencyUnsatisfied(20))
));
assert_eq!(authorities.authority_set_changes, AuthoritySetChanges(vec![(0, 15)]));
@@ -1425,29 +1416,19 @@ mod tests {
});
// add the three pending changes
authorities
.add_pending_change(change_b, &is_descendent_of)
.unwrap();
authorities
.add_pending_change(change_a0, &is_descendent_of)
.unwrap();
authorities
.add_pending_change(change_a1, &is_descendent_of)
.unwrap();
authorities.add_pending_change(change_b, &is_descendent_of).unwrap();
authorities.add_pending_change(change_a0, &is_descendent_of).unwrap();
authorities.add_pending_change(change_a1, &is_descendent_of).unwrap();
// the earliest change at block `best_a` should be the change at A0 (#5)
assert_eq!(
authorities
.next_change(&"best_a", &is_descendent_of)
.unwrap(),
authorities.next_change(&"best_a", &is_descendent_of).unwrap(),
Some(("hash_a0", 5)),
);
// the earliest change at block `best_b` should be the change at B (#4)
assert_eq!(
authorities
.next_change(&"best_b", &is_descendent_of)
.unwrap(),
authorities.next_change(&"best_b", &is_descendent_of).unwrap(),
Some(("hash_b", 4)),
);
@@ -1458,19 +1439,12 @@ mod tests {
// the next change is now at A1 (#10)
assert_eq!(
authorities
.next_change(&"best_a", &is_descendent_of)
.unwrap(),
authorities.next_change(&"best_a", &is_descendent_of).unwrap(),
Some(("hash_a1", 10)),
);
// there's no longer any pending change at `best_b` fork
assert_eq!(
authorities
.next_change(&"best_b", &is_descendent_of)
.unwrap(),
None,
);
assert_eq!(authorities.next_change(&"best_b", &is_descendent_of).unwrap(), None,);
// we a forced change at A10 (#8)
let change_a10 = PendingChange {
@@ -1478,9 +1452,7 @@ mod tests {
delay: 0,
canon_height: 8,
canon_hash: "hash_a10",
delay_kind: DelayKind::Best {
median_last_finalized: 0,
},
delay_kind: DelayKind::Best { median_last_finalized: 0 },
};
authorities
@@ -1489,9 +1461,7 @@ mod tests {
// it should take precedence over the change at A1 (#10)
assert_eq!(
authorities
.next_change(&"best_a", &is_descendent_of)
.unwrap(),
authorities.next_change(&"best_a", &is_descendent_of).unwrap(),
Some(("hash_a10", 8)),
);
}
@@ -1511,16 +1481,11 @@ mod tests {
None,
);
let invalid_authorities_weight = vec![
(AuthorityId::from_slice(&[1; 32]), 5),
(AuthorityId::from_slice(&[2; 32]), 0),
];
let invalid_authorities_weight =
vec![(AuthorityId::from_slice(&[1; 32]), 5), (AuthorityId::from_slice(&[2; 32]), 0)];
// authority weight of zero is invalid
assert_eq!(
AuthoritySet::<(), ()>::genesis(invalid_authorities_weight.clone()),
None
);
assert_eq!(AuthoritySet::<(), ()>::genesis(invalid_authorities_weight.clone()), None);
assert_eq!(
AuthoritySet::<(), ()>::new(
invalid_authorities_weight.clone(),
@@ -1557,9 +1522,7 @@ mod tests {
delay: 10,
canon_height: 5,
canon_hash: (),
delay_kind: DelayKind::Best {
median_last_finalized: 0,
},
delay_kind: DelayKind::Best { median_last_finalized: 0 },
};
// pending change contains an an authority set
@@ -1617,17 +1580,13 @@ mod tests {
canon_height,
canon_hash,
delay_kind: if forced {
DelayKind::Best {
median_last_finalized: 0,
}
DelayKind::Best { median_last_finalized: 0 }
} else {
DelayKind::Finalized
},
};
authorities
.add_pending_change(change, &is_descendent_of)
.unwrap();
authorities.add_pending_change(change, &is_descendent_of).unwrap();
};
add_pending_change(5, "A", false);
@@ -1669,14 +1628,7 @@ mod tests {
.unwrap();
assert_eq!(authorities.pending_forced_changes.len(), 1);
assert_eq!(
authorities
.pending_forced_changes
.first()
.unwrap()
.canon_hash,
"D"
);
assert_eq!(authorities.pending_forced_changes.first().unwrap().canon_hash, "D");
}
#[test]
@@ -1714,10 +1666,7 @@ mod tests {
authority_set_changes.append(2, 81);
// we are missing the data for the first set, therefore we should return `None`
assert_eq!(
None,
authority_set_changes.iter_from(40).map(|it| it.collect::<Vec<_>>()),
);
assert_eq!(None, authority_set_changes.iter_from(40).map(|it| it.collect::<Vec<_>>()),);
// after adding the data for the first set the same query should work
let mut authority_set_changes = AuthoritySetChanges::empty();
@@ -1736,14 +1685,8 @@ mod tests {
authority_set_changes.iter_from(41).map(|it| it.cloned().collect::<Vec<_>>()),
);
assert_eq!(
0,
authority_set_changes.iter_from(121).unwrap().count(),
);
assert_eq!(0, authority_set_changes.iter_from(121).unwrap().count(),);
assert_eq!(
0,
authority_set_changes.iter_from(200).unwrap().count(),
);
assert_eq!(0, authority_set_changes.iter_from(200).unwrap().count(),);
}
}
@@ -30,13 +30,16 @@ use sp_blockchain::{Error as ClientError, Result as ClientResult};
use sp_finality_grandpa::{AuthorityList, RoundNumber, SetId};
use sp_runtime::traits::{Block as BlockT, NumberFor};
use crate::authorities::{
AuthoritySet, AuthoritySetChanges, DelayKind, PendingChange, SharedAuthoritySet,
use crate::{
authorities::{
AuthoritySet, AuthoritySetChanges, DelayKind, PendingChange, SharedAuthoritySet,
},
environment::{
CompletedRound, CompletedRounds, CurrentRounds, HasVoted, SharedVoterSetState,
VoterSetState,
},
GrandpaJustification, NewAuthoritySet,
};
use crate::environment::{
CompletedRound, CompletedRounds, CurrentRounds, HasVoted, SharedVoterSetState, VoterSetState,
};
use crate::{GrandpaJustification, NewAuthoritySet};
const VERSION_KEY: &[u8] = b"grandpa_schema_version";
const SET_STATE_KEY: &[u8] = b"grandpa_completed_round";
@@ -141,13 +144,13 @@ struct V2AuthoritySet<H, N> {
pub(crate) fn load_decode<B: AuxStore, T: Decode>(
backend: &B,
key: &[u8]
key: &[u8],
) -> ClientResult<Option<T>> {
match backend.get_aux(key)? {
None => Ok(None),
Some(t) => T::decode(&mut &t[..])
.map_err(|e| ClientError::Backend(format!("GRANDPA DB is corrupted: {}", e)))
.map(Some)
.map(Some),
}
}
@@ -160,24 +163,16 @@ pub(crate) struct PersistentData<Block: BlockT> {
fn migrate_from_version0<Block: BlockT, B, G>(
backend: &B,
genesis_round: &G,
) -> ClientResult<
Option<(
AuthoritySet<Block::Hash, NumberFor<Block>>,
VoterSetState<Block>,
)>,
>
) -> ClientResult<Option<(AuthoritySet<Block::Hash, NumberFor<Block>>, VoterSetState<Block>)>>
where
B: AuxStore,
G: Fn() -> RoundState<Block::Hash, NumberFor<Block>>,
{
CURRENT_VERSION.using_encoded(|s|
backend.insert_aux(&[(VERSION_KEY, s)], &[])
)?;
CURRENT_VERSION.using_encoded(|s| backend.insert_aux(&[(VERSION_KEY, s)], &[]))?;
if let Some(old_set) = load_decode::<_, V0AuthoritySet<Block::Hash, NumberFor<Block>>>(
backend,
AUTHORITY_SET_KEY,
)? {
if let Some(old_set) =
load_decode::<_, V0AuthoritySet<Block::Hash, NumberFor<Block>>>(backend, AUTHORITY_SET_KEY)?
{
let new_set: AuthoritySet<Block::Hash, NumberFor<Block>> = old_set.into();
backend.insert_aux(&[(AUTHORITY_SET_KEY, new_set.encode().as_slice())], &[])?;
@@ -193,7 +188,7 @@ where
let set_id = new_set.set_id;
let base = last_round_state.prevote_ghost.expect(
"state is for completed round; completed rounds must have a prevote ghost; qed."
"state is for completed round; completed rounds must have a prevote ghost; qed.",
);
let mut current_rounds = CurrentRounds::new();
@@ -215,7 +210,7 @@ where
backend.insert_aux(&[(SET_STATE_KEY, set_state.encode().as_slice())], &[])?;
return Ok(Some((new_set, set_state)));
return Ok(Some((new_set, set_state)))
}
Ok(None)
@@ -224,36 +219,25 @@ where
fn migrate_from_version1<Block: BlockT, B, G>(
backend: &B,
genesis_round: &G,
) -> ClientResult<
Option<(
AuthoritySet<Block::Hash, NumberFor<Block>>,
VoterSetState<Block>,
)>,
>
) -> ClientResult<Option<(AuthoritySet<Block::Hash, NumberFor<Block>>, VoterSetState<Block>)>>
where
B: AuxStore,
G: Fn() -> RoundState<Block::Hash, NumberFor<Block>>,
{
CURRENT_VERSION.using_encoded(|s|
backend.insert_aux(&[(VERSION_KEY, s)], &[])
)?;
CURRENT_VERSION.using_encoded(|s| backend.insert_aux(&[(VERSION_KEY, s)], &[]))?;
if let Some(set) = load_decode::<_, AuthoritySet<Block::Hash, NumberFor<Block>>>(
backend,
AUTHORITY_SET_KEY,
)? {
if let Some(set) =
load_decode::<_, AuthoritySet<Block::Hash, NumberFor<Block>>>(backend, AUTHORITY_SET_KEY)?
{
let set_id = set.set_id;
let completed_rounds = |number, state, base| CompletedRounds::new(
CompletedRound {
number,
state,
votes: Vec::new(),
base,
},
set_id,
&set,
);
let completed_rounds = |number, state, base| {
CompletedRounds::new(
CompletedRound { number, state, votes: Vec::new(), base },
set_id,
&set,
)
};
let set_state = match load_decode::<_, V1VoterSetState<Block::Hash, NumberFor<Block>>>(
backend,
@@ -284,17 +268,13 @@ where
let base = set_state.prevote_ghost
.expect("state is for completed round; completed rounds must have a prevote ghost; qed.");
VoterSetState::live(
set_id,
&set,
base,
)
VoterSetState::live(set_id, &set, base)
},
};
backend.insert_aux(&[(SET_STATE_KEY, set_state.encode().as_slice())], &[])?;
return Ok(Some((set, set_state)));
return Ok(Some((set, set_state)))
}
Ok(None)
@@ -303,46 +283,31 @@ where
fn migrate_from_version2<Block: BlockT, B, G>(
backend: &B,
genesis_round: &G,
) -> ClientResult<
Option<(
AuthoritySet<Block::Hash, NumberFor<Block>>,
VoterSetState<Block>,
)>,
>
) -> ClientResult<Option<(AuthoritySet<Block::Hash, NumberFor<Block>>, VoterSetState<Block>)>>
where
B: AuxStore,
G: Fn() -> RoundState<Block::Hash, NumberFor<Block>>,
{
CURRENT_VERSION.using_encoded(|s|
backend.insert_aux(&[(VERSION_KEY, s)], &[])
)?;
CURRENT_VERSION.using_encoded(|s| backend.insert_aux(&[(VERSION_KEY, s)], &[]))?;
if let Some(old_set) = load_decode::<_, V2AuthoritySet<Block::Hash, NumberFor<Block>>>(
backend,
AUTHORITY_SET_KEY,
)? {
if let Some(old_set) =
load_decode::<_, V2AuthoritySet<Block::Hash, NumberFor<Block>>>(backend, AUTHORITY_SET_KEY)?
{
let new_set: AuthoritySet<Block::Hash, NumberFor<Block>> = old_set.into();
backend.insert_aux(&[(AUTHORITY_SET_KEY, new_set.encode().as_slice())], &[])?;
let set_state = match load_decode::<_, VoterSetState<Block>>(
backend,
SET_STATE_KEY,
)? {
let set_state = match load_decode::<_, VoterSetState<Block>>(backend, SET_STATE_KEY)? {
Some(state) => state,
None => {
let state = genesis_round();
let base = state.prevote_ghost
.expect("state is for completed round; completed rounds must have a prevote ghost; qed.");
VoterSetState::live(
new_set.set_id,
&new_set,
base,
)
}
VoterSetState::live(new_set.set_id, &new_set, base)
},
};
return Ok(Some((new_set, set_state)));
return Ok(Some((new_set, set_state)))
}
Ok(None)
@@ -371,7 +336,7 @@ where
return Ok(PersistentData {
authority_set: new_set.into(),
set_state: set_state.into(),
});
})
}
},
Some(1) => {
@@ -381,7 +346,7 @@ where
return Ok(PersistentData {
authority_set: new_set.into(),
set_state: set_state.into(),
});
})
}
},
Some(2) => {
@@ -391,41 +356,31 @@ where
return Ok(PersistentData {
authority_set: new_set.into(),
set_state: set_state.into(),
});
})
}
}
},
Some(3) => {
if let Some(set) = load_decode::<_, AuthoritySet<Block::Hash, NumberFor<Block>>>(
backend,
AUTHORITY_SET_KEY,
)? {
let set_state = match load_decode::<_, VoterSetState<Block>>(
backend,
SET_STATE_KEY,
)? {
Some(state) => state,
None => {
let state = make_genesis_round();
let base = state.prevote_ghost
let set_state =
match load_decode::<_, VoterSetState<Block>>(backend, SET_STATE_KEY)? {
Some(state) => state,
None => {
let state = make_genesis_round();
let base = state.prevote_ghost
.expect("state is for completed round; completed rounds must have a prevote ghost; qed.");
VoterSetState::live(
set.set_id,
&set,
base,
)
}
};
VoterSetState::live(set.set_id, &set, base)
},
};
return Ok(PersistentData {
authority_set: set.into(),
set_state: set_state.into(),
});
return Ok(PersistentData { authority_set: set.into(), set_state: set_state.into() })
}
}
Some(other) => return Err(ClientError::Backend(
format!("Unsupported GRANDPA DB version: {:?}", other)
)),
},
Some(other) =>
return Err(ClientError::Backend(format!("Unsupported GRANDPA DB version: {:?}", other))),
}
// genesis.
@@ -436,14 +391,11 @@ where
let genesis_set = AuthoritySet::genesis(genesis_authorities)
.expect("genesis authorities is non-empty; all weights are non-zero; qed.");
let state = make_genesis_round();
let base = state.prevote_ghost
let base = state
.prevote_ghost
.expect("state is for completed round; completed rounds must have a prevote ghost; qed.");
let genesis_state = VoterSetState::live(
0,
&genesis_set,
base,
);
let genesis_state = VoterSetState::live(0, &genesis_set, base);
backend.insert_aux(
&[
@@ -453,10 +405,7 @@ where
&[],
)?;
Ok(PersistentData {
authority_set: genesis_set.into(),
set_state: genesis_state.into(),
})
Ok(PersistentData { authority_set: genesis_set.into(), set_state: genesis_state.into() })
}
/// Update the authority set on disk after a change.
@@ -486,10 +435,7 @@ where
);
let encoded = set_state.encode();
write_aux(&[
(AUTHORITY_SET_KEY, &encoded_set[..]),
(SET_STATE_KEY, &encoded[..]),
])
write_aux(&[(AUTHORITY_SET_KEY, &encoded_set[..]), (SET_STATE_KEY, &encoded[..])])
} else {
write_aux(&[(AUTHORITY_SET_KEY, &encoded_set[..])])
}
@@ -527,10 +473,7 @@ pub(crate) fn write_voter_set_state<Block: BlockT, B: AuxStore>(
backend: &B,
state: &VoterSetState<Block>,
) -> ClientResult<()> {
backend.insert_aux(
&[(SET_STATE_KEY, state.encode().as_slice())],
&[]
)
backend.insert_aux(&[(SET_STATE_KEY, state.encode().as_slice())], &[])
}
/// Write concluded round.
@@ -554,10 +497,10 @@ pub(crate) fn load_authorities<B: AuxStore, H: Decode, N: Decode + Clone + Ord>(
#[cfg(test)]
mod test {
use sp_finality_grandpa::AuthorityId;
use sp_core::H256;
use substrate_test_runtime_client;
use super::*;
use sp_core::H256;
use sp_finality_grandpa::AuthorityId;
use substrate_test_runtime_client;
#[test]
fn load_decode_from_v0_migrates_data_format() {
@@ -582,19 +525,18 @@ mod test {
let voter_set_state = (round_number, round_state.clone());
client.insert_aux(
&[
(AUTHORITY_SET_KEY, authority_set.encode().as_slice()),
(SET_STATE_KEY, voter_set_state.encode().as_slice()),
],
&[],
).unwrap();
client
.insert_aux(
&[
(AUTHORITY_SET_KEY, authority_set.encode().as_slice()),
(SET_STATE_KEY, voter_set_state.encode().as_slice()),
],
&[],
)
.unwrap();
}
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
None,
);
assert_eq!(load_decode::<_, u32>(&client, VERSION_KEY).unwrap(), None,);
// should perform the migration
load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
@@ -602,23 +544,19 @@ mod test {
H256::random(),
0,
|| unreachable!(),
).unwrap();
)
.unwrap();
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(3),
);
assert_eq!(load_decode::<_, u32>(&client, VERSION_KEY).unwrap(), Some(3),);
let PersistentData {
authority_set,
set_state,
..
} = load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
|| unreachable!(),
).unwrap();
let PersistentData { authority_set, set_state, .. } =
load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
|| unreachable!(),
)
.unwrap();
assert_eq!(
*authority_set.inner(),
@@ -628,7 +566,8 @@ mod test {
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
).unwrap(),
)
.unwrap(),
);
let mut current_rounds = CurrentRounds::new();
@@ -673,24 +612,24 @@ mod test {
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
).unwrap();
)
.unwrap();
let voter_set_state = V1VoterSetState::Live(round_number, round_state.clone());
client.insert_aux(
&[
(AUTHORITY_SET_KEY, authority_set.encode().as_slice()),
(SET_STATE_KEY, voter_set_state.encode().as_slice()),
(VERSION_KEY, 1u32.encode().as_slice()),
],
&[],
).unwrap();
client
.insert_aux(
&[
(AUTHORITY_SET_KEY, authority_set.encode().as_slice()),
(SET_STATE_KEY, voter_set_state.encode().as_slice()),
(VERSION_KEY, 1u32.encode().as_slice()),
],
&[],
)
.unwrap();
}
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(1),
);
assert_eq!(load_decode::<_, u32>(&client, VERSION_KEY).unwrap(), Some(1),);
// should perform the migration
load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
@@ -698,23 +637,19 @@ mod test {
H256::random(),
0,
|| unreachable!(),
).unwrap();
)
.unwrap();
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(3),
);
assert_eq!(load_decode::<_, u32>(&client, VERSION_KEY).unwrap(), Some(3),);
let PersistentData {
authority_set,
set_state,
..
} = load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
|| unreachable!(),
).unwrap();
let PersistentData { authority_set, set_state, .. } =
load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
|| unreachable!(),
)
.unwrap();
assert_eq!(
*authority_set.inner(),
@@ -724,7 +659,8 @@ mod test {
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
).unwrap(),
)
.unwrap(),
);
let mut current_rounds = CurrentRounds::new();
@@ -768,23 +704,22 @@ mod test {
VoterSetState::live(
set_id,
&authority_set.clone().into(), // Note the conversion!
genesis_state
genesis_state,
);
client.insert_aux(
&[
(AUTHORITY_SET_KEY, authority_set.encode().as_slice()),
(SET_STATE_KEY, voter_set_state.encode().as_slice()),
(VERSION_KEY, 2u32.encode().as_slice()),
],
&[],
).unwrap();
client
.insert_aux(
&[
(AUTHORITY_SET_KEY, authority_set.encode().as_slice()),
(SET_STATE_KEY, voter_set_state.encode().as_slice()),
(VERSION_KEY, 2u32.encode().as_slice()),
],
&[],
)
.unwrap();
}
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(2),
);
assert_eq!(load_decode::<_, u32>(&client, VERSION_KEY).unwrap(), Some(2),);
// should perform the migration
load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
@@ -792,22 +727,17 @@ mod test {
H256::random(),
0,
|| unreachable!(),
).unwrap();
)
.unwrap();
assert_eq!(
load_decode::<_, u32>(&client, VERSION_KEY).unwrap(),
Some(3),
);
assert_eq!(load_decode::<_, u32>(&client, VERSION_KEY).unwrap(), Some(3),);
let PersistentData {
authority_set,
..
} = load_persistent::<substrate_test_runtime_client::runtime::Block, _, _>(
&client,
H256::random(),
0,
|| unreachable!(),
).unwrap();
let PersistentData { authority_set, .. } = load_persistent::<
substrate_test_runtime_client::runtime::Block,
_,
_,
>(&client, H256::random(), 0, || unreachable!())
.unwrap();
assert_eq!(
*authority_set.inner(),
@@ -817,7 +747,8 @@ mod test {
ForkTree::new(),
Vec::new(),
AuthoritySetChanges::empty(),
).unwrap(),
)
.unwrap(),
);
}
@@ -843,7 +774,8 @@ mod test {
assert_eq!(
load_decode::<_, CompletedRound::<substrate_test_runtime_client::runtime::Block>>(
&client, &key
).unwrap(),
)
.unwrap(),
Some(completed_round),
);
}
File diff suppressed because it is too large Load Diff
@@ -29,37 +29,36 @@
//! In the future, there will be a fallback for allowing sending the same message
//! under certain conditions that are used to un-stick the protocol.
use futures::{prelude::*, channel::mpsc};
use futures::{channel::mpsc, prelude::*};
use log::{debug, trace};
use parking_lot::Mutex;
use prometheus_endpoint::Registry;
use std::{pin::Pin, sync::Arc, task::{Context, Poll}};
use std::{
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use sp_keystore::SyncCryptoStorePtr;
use finality_grandpa::Message::{Prevote, Precommit, PrimaryPropose};
use finality_grandpa::{voter, voter_set::VoterSet};
use finality_grandpa::{
voter,
voter_set::VoterSet,
Message::{Precommit, Prevote, PrimaryPropose},
};
use parity_scale_codec::{Decode, Encode};
use sc_network::{NetworkService, ReputationChange};
use sc_network_gossip::{GossipEngine, Network as GossipNetwork};
use parity_scale_codec::{Encode, Decode};
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor};
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO};
use sp_keystore::SyncCryptoStorePtr;
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor};
use crate::{
CatchUp, Commit, CommunicationIn, CommunicationOutH,
CompactCommit, Error, Message, SignedMessage,
environment::HasVoted, CatchUp, Commit, CommunicationIn, CommunicationOutH, CompactCommit,
Error, Message, SignedMessage,
};
use crate::environment::HasVoted;
use gossip::{
FullCatchUpMessage,
FullCommitMessage,
GossipMessage,
GossipValidator,
PeerReport,
VoteMessage,
};
use sp_finality_grandpa::{
AuthorityId, AuthoritySignature, SetId as SetIdNumber, RoundNumber,
FullCatchUpMessage, FullCommitMessage, GossipMessage, GossipValidator, PeerReport, VoteMessage,
};
use sp_finality_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber};
use sp_utils::mpsc::TracingUnboundedReceiver;
pub mod gossip;
@@ -89,11 +88,13 @@ mod cost {
pub(super) const INVALID_CATCH_UP: Rep = Rep::new(-5000, "Grandpa: Invalid catch-up");
pub(super) const INVALID_COMMIT: Rep = Rep::new(-5000, "Grandpa: Invalid commit");
pub(super) const OUT_OF_SCOPE_MESSAGE: Rep = Rep::new(-500, "Grandpa: Out-of-scope message");
pub(super) const CATCH_UP_REQUEST_TIMEOUT: Rep = Rep::new(-200, "Grandpa: Catch-up request timeout");
pub(super) const CATCH_UP_REQUEST_TIMEOUT: Rep =
Rep::new(-200, "Grandpa: Catch-up request timeout");
// cost of answering a catch up request
pub(super) const CATCH_UP_REPLY: Rep = Rep::new(-200, "Grandpa: Catch-up reply");
pub(super) const HONEST_OUT_OF_SCOPE_CATCH_UP: Rep = Rep::new(-200, "Grandpa: Out-of-scope catch-up");
pub(super) const HONEST_OUT_OF_SCOPE_CATCH_UP: Rep =
Rep::new(-200, "Grandpa: Out-of-scope catch-up");
}
// benefit scalars for reporting peers.
@@ -144,14 +145,25 @@ pub trait Network<Block: BlockT>: GossipNetwork<Block> + Clone + Send + 'static
/// If the given vector of peers is empty then the underlying implementation
/// should make a best effort to fetch the block from any peers it is
/// connected to (NOTE: this assumption will change in the future #3629).
fn set_sync_fork_request(&self, peers: Vec<sc_network::PeerId>, hash: Block::Hash, number: NumberFor<Block>);
fn set_sync_fork_request(
&self,
peers: Vec<sc_network::PeerId>,
hash: Block::Hash,
number: NumberFor<Block>,
);
}
impl<B, H> Network<B> for Arc<NetworkService<B, H>> where
impl<B, H> Network<B> for Arc<NetworkService<B, H>>
where
B: BlockT,
H: sc_network::ExHashT,
{
fn set_sync_fork_request(&self, peers: Vec<sc_network::PeerId>, hash: B::Hash, number: NumberFor<B>) {
fn set_sync_fork_request(
&self,
peers: Vec<sc_network::PeerId>,
hash: B::Hash,
number: NumberFor<B>,
) {
NetworkService::set_sync_fork_request(self, peers, hash, number)
}
}
@@ -179,14 +191,12 @@ pub(crate) struct NetworkBridge<B: BlockT, N: Network<B>> {
neighbor_sender: periodic::NeighborPacketSender<B>,
/// `NeighborPacketWorker` processing packets sent through the `NeighborPacketSender`.
//
// `NetworkBridge` is required to be cloneable, thus one needs to be able to clone its children,
// thus one has to wrap `neighbor_packet_worker` with an `Arc` `Mutex`.
neighbor_packet_worker: Arc<Mutex<periodic::NeighborPacketWorker<B>>>,
/// Receiver side of the peer report stream populated by the gossip validator, forwarded to the
/// gossip engine.
//
// `NetworkBridge` is required to be cloneable, thus one needs to be able to clone its children,
// thus one has to wrap gossip_validator_report_stream with an `Arc` `Mutex`. Given that it is
// just an `UnboundedReceiver`, one could also switch to a multi-producer-*multi*-consumer
@@ -210,12 +220,8 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
prometheus_registry: Option<&Registry>,
telemetry: Option<TelemetryHandle>,
) -> Self {
let (validator, report_stream) = GossipValidator::new(
config,
set_state.clone(),
prometheus_registry,
telemetry.clone(),
);
let (validator, report_stream) =
GossipValidator::new(config, set_state.clone(), prometheus_registry, telemetry.clone());
let validator = Arc::new(validator);
let gossip_engine = Arc::new(Mutex::new(GossipEngine::new(
@@ -239,18 +245,13 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
validator.note_round(Round(round.number), |_, _| {});
for signed in round.votes.iter() {
let message = gossip::GossipMessage::Vote(
gossip::VoteMessage::<B> {
message: signed.clone(),
round: Round(round.number),
set_id: SetId(set_id),
}
);
let message = gossip::GossipMessage::Vote(gossip::VoteMessage::<B> {
message: signed.clone(),
round: Round(round.number),
set_id: SetId(set_id),
});
gossip_engine.lock().register_gossip_message(
topic,
message.encode(),
);
gossip_engine.lock().register_gossip_message(topic, message.encode());
}
trace!(target: "afg",
@@ -263,7 +264,8 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
}
}
let (neighbor_packet_worker, neighbor_packet_sender) = periodic::NeighborPacketWorker::new();
let (neighbor_packet_worker, neighbor_packet_sender) =
periodic::NeighborPacketWorker::new();
NetworkBridge {
service,
@@ -277,12 +279,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
}
/// Note the beginning of a new round to the `GossipValidator`.
pub(crate) fn note_round(
&self,
round: Round,
set_id: SetId,
voters: &VoterSet<AuthorityId>,
) {
pub(crate) fn note_round(&self, round: Round, set_id: SetId, voters: &VoterSet<AuthorityId>) {
// is a no-op if currently in that set.
self.validator.note_set(
set_id,
@@ -290,10 +287,8 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
|to, neighbor| self.neighbor_sender.send(to, neighbor),
);
self.validator.note_round(
round,
|to, neighbor| self.neighbor_sender.send(to, neighbor),
);
self.validator
.note_round(round, |to, neighbor| self.neighbor_sender.send(to, neighbor));
}
/// Get a stream of signature-checked round messages from the network as well as a sink for round messages to the
@@ -305,15 +300,8 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
set_id: SetId,
voters: Arc<VoterSet<AuthorityId>>,
has_voted: HasVoted<B>,
) -> (
impl Stream<Item = SignedMessage<B>> + Unpin,
OutgoingMessages<B>,
) {
self.note_round(
round,
set_id,
&*voters,
);
) -> (impl Stream<Item = SignedMessage<B>> + Unpin, OutgoingMessages<B>) {
self.note_round(round, set_id, &*voters);
let keystore = keystore.and_then(|ks| {
let id = ks.local_id();
@@ -326,20 +314,20 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
let topic = round_topic::<B>(round.0, set_id.0);
let telemetry = self.telemetry.clone();
let incoming = self.gossip_engine.lock().messages_for(topic)
.filter_map(move |notification| {
let incoming =
self.gossip_engine.lock().messages_for(topic).filter_map(move |notification| {
let decoded = GossipMessage::<B>::decode(&mut &notification.message[..]);
match decoded {
Err(ref e) => {
debug!(target: "afg", "Skipping malformed message {:?}: {}", notification, e);
future::ready(None)
}
},
Ok(GossipMessage::Vote(msg)) => {
// check signature.
if !voters.contains(&msg.message.id) {
debug!(target: "afg", "Skipping message from unknown voter {}", msg.message.id);
return future::ready(None);
return future::ready(None)
}
if voters.len().get() <= TELEMETRY_VOTERS_LIMIT {
@@ -378,11 +366,11 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
}
future::ready(Some(msg.message))
}
},
_ => {
debug!(target: "afg", "Skipping unknown message type");
future::ready(None)
}
},
}
});
@@ -458,7 +446,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
&self,
peers: Vec<sc_network::PeerId>,
hash: B::Hash,
number: NumberFor<B>
number: NumberFor<B>,
) {
Network::set_sync_fork_request(&self.service, peers, hash, number)
}
@@ -473,9 +461,10 @@ impl<B: BlockT, N: Network<B>> Future for NetworkBridge<B, N> {
Poll::Ready(Some((to, packet))) => {
self.gossip_engine.lock().send_message(to, packet.encode());
},
Poll::Ready(None) => return Poll::Ready(
Err(Error::Network("Neighbor packet worker stream closed.".into()))
),
Poll::Ready(None) =>
return Poll::Ready(Err(Error::Network(
"Neighbor packet worker stream closed.".into(),
))),
Poll::Pending => break,
}
}
@@ -485,17 +474,17 @@ impl<B: BlockT, N: Network<B>> Future for NetworkBridge<B, N> {
Poll::Ready(Some(PeerReport { who, cost_benefit })) => {
self.gossip_engine.lock().report(who, cost_benefit);
},
Poll::Ready(None) => return Poll::Ready(
Err(Error::Network("Gossip validator report stream closed.".into()))
),
Poll::Ready(None) =>
return Poll::Ready(Err(Error::Network(
"Gossip validator report stream closed.".into(),
))),
Poll::Pending => break,
}
}
match self.gossip_engine.lock().poll_unpin(cx) {
Poll::Ready(()) => return Poll::Ready(
Err(Error::Network("Gossip engine future finished.".into()))
),
Poll::Ready(()) =>
return Poll::Ready(Err(Error::Network("Gossip engine future finished.".into()))),
Poll::Pending => {},
}
@@ -513,18 +502,14 @@ fn incoming_global<B: BlockT>(
) -> impl Stream<Item = CommunicationIn<B>> {
let process_commit = {
let telemetry = telemetry.clone();
move |
msg: FullCommitMessage<B>,
mut notification: sc_network_gossip::TopicNotification,
gossip_engine: &Arc<Mutex<GossipEngine<B>>>,
gossip_validator: &Arc<GossipValidator<B>>,
voters: &VoterSet<AuthorityId>,
| {
move |msg: FullCommitMessage<B>,
mut notification: sc_network_gossip::TopicNotification,
gossip_engine: &Arc<Mutex<GossipEngine<B>>>,
gossip_validator: &Arc<GossipValidator<B>>,
voters: &VoterSet<AuthorityId>| {
if voters.len().get() <= TELEMETRY_VOTERS_LIMIT {
let precommits_signed_by: Vec<String> =
msg.message.auth_data.iter().map(move |(_, a)| {
format!("{}", a)
}).collect();
msg.message.auth_data.iter().map(move |(_, a)| format!("{}", a)).collect();
telemetry!(
telemetry;
@@ -547,7 +532,7 @@ fn incoming_global<B: BlockT>(
gossip_engine.lock().report(who, cost);
}
return None;
return None
}
let round = msg.round;
@@ -570,13 +555,13 @@ fn incoming_global<B: BlockT>(
);
gossip_engine.lock().gossip_message(topic, notification.message.clone(), false);
}
},
voter::CommitProcessingOutcome::Bad(_) => {
// report peer and do not gossip.
if let Some(who) = notification.sender.take() {
gossip_engine.lock().report(who, cost::INVALID_COMMIT);
}
}
},
};
let cb = voter::Callback::Work(Box::new(cb));
@@ -585,27 +570,21 @@ fn incoming_global<B: BlockT>(
}
};
let process_catch_up = move |
msg: FullCatchUpMessage<B>,
mut notification: sc_network_gossip::TopicNotification,
gossip_engine: &Arc<Mutex<GossipEngine<B>>>,
gossip_validator: &Arc<GossipValidator<B>>,
voters: &VoterSet<AuthorityId>,
| {
let process_catch_up = move |msg: FullCatchUpMessage<B>,
mut notification: sc_network_gossip::TopicNotification,
gossip_engine: &Arc<Mutex<GossipEngine<B>>>,
gossip_validator: &Arc<GossipValidator<B>>,
voters: &VoterSet<AuthorityId>| {
let gossip_validator = gossip_validator.clone();
let gossip_engine = gossip_engine.clone();
if let Err(cost) = check_catch_up::<B>(
&msg.message,
voters,
msg.set_id,
telemetry.clone(),
) {
if let Err(cost) = check_catch_up::<B>(&msg.message, voters, msg.set_id, telemetry.clone())
{
if let Some(who) = notification.sender {
gossip_engine.lock().report(who, cost);
}
return None;
return None
}
let cb = move |outcome| {
@@ -624,7 +603,10 @@ fn incoming_global<B: BlockT>(
Some(voter::CommunicationIn::CatchUp(msg.message, cb))
};
gossip_engine.clone().lock().messages_for(topic)
gossip_engine
.clone()
.lock()
.messages_for(topic)
.filter_map(|notification| {
// this could be optimized by decoding piecewise.
let decoded = GossipMessage::<B>::decode(&mut &notification.message[..]);
@@ -642,7 +624,7 @@ fn incoming_global<B: BlockT>(
_ => {
debug!(target: "afg", "Skipping unknown message type");
None
}
},
})
})
}
@@ -688,15 +670,15 @@ pub(crate) struct OutgoingMessages<Block: BlockT> {
impl<B: BlockT> Unpin for OutgoingMessages<B> {}
impl<Block: BlockT> Sink<Message<Block>> for OutgoingMessages<Block>
{
impl<Block: BlockT> Sink<Message<Block>> for OutgoingMessages<Block> {
type Error = Error;
fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Sink::poll_ready(Pin::new(&mut self.sender), cx)
.map(|elem| { elem.map_err(|e| {
Sink::poll_ready(Pin::new(&mut self.sender), cx).map(|elem| {
elem.map_err(|e| {
Error::Network(format!("Failed to poll_ready channel sender: {:?}", e))
})})
})
})
}
fn start_send(mut self: Pin<&mut Self>, mut msg: Message<Block>) -> Result<(), Self::Error> {
@@ -725,11 +707,13 @@ impl<Block: BlockT> Sink<Message<Block>> for OutgoingMessages<Block>
keystore.local_id().clone(),
self.round,
self.set_id,
).ok_or_else(
|| Error::Signing(format!(
"Failed to sign GRANDPA vote for round {} targetting {:?}", self.round, target_hash
)
.ok_or_else(|| {
Error::Signing(format!(
"Failed to sign GRANDPA vote for round {} targetting {:?}",
self.round, target_hash
))
)?;
})?;
let message = GossipMessage::Vote(VoteMessage::<Block> {
message: signed.clone(),
@@ -762,7 +746,7 @@ impl<Block: BlockT> Sink<Message<Block>> for OutgoingMessages<Block>
// forward the message to the inner sender.
return self.sender.start_send(signed).map_err(|e| {
Error::Network(format!("Failed to start_send on channel sender: {:?}", e))
});
})
};
Ok(())
@@ -773,10 +757,11 @@ impl<Block: BlockT> Sink<Message<Block>> for OutgoingMessages<Block>
}
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Sink::poll_close(Pin::new(&mut self.sender), cx)
.map(|elem| { elem.map_err(|e| {
Sink::poll_close(Pin::new(&mut self.sender), cx).map(|elem| {
elem.map_err(|e| {
Error::Network(format!("Failed to poll_close channel sender: {:?}", e))
})})
})
})
}
}
@@ -799,23 +784,22 @@ fn check_compact_commit<Block: BlockT>(
if let Some(weight) = voters.get(id).map(|info| info.weight()) {
total_weight += weight.get();
if total_weight > full_threshold {
return Err(cost::MALFORMED_COMMIT);
return Err(cost::MALFORMED_COMMIT)
}
} else {
debug!(target: "afg", "Skipping commit containing unknown voter {}", id);
return Err(cost::MALFORMED_COMMIT);
return Err(cost::MALFORMED_COMMIT)
}
}
if total_weight < voters.threshold().get() {
return Err(cost::MALFORMED_COMMIT);
return Err(cost::MALFORMED_COMMIT)
}
// check signatures on all contained precommits.
let mut buf = Vec::new();
for (i, (precommit, &(ref sig, ref id))) in msg.precommits.iter()
.zip(&msg.auth_data)
.enumerate()
for (i, (precommit, &(ref sig, ref id))) in
msg.precommits.iter().zip(&msg.auth_data).enumerate()
{
use crate::communication::gossip::Misbehavior;
use finality_grandpa::Message as GrandpaMessage;
@@ -839,9 +823,10 @@ fn check_compact_commit<Block: BlockT>(
signatures_checked: i as i32,
blocks_loaded: 0,
equivocations_caught: 0,
}.cost();
}
.cost();
return Err(cost);
return Err(cost)
}
}
@@ -863,7 +848,7 @@ fn check_catch_up<Block: BlockT>(
// check total weight is not out of range for a set of votes.
fn check_weight<'a>(
voters: &'a VoterSet<AuthorityId>,
votes: impl Iterator<Item=&'a AuthorityId>,
votes: impl Iterator<Item = &'a AuthorityId>,
full_threshold: u64,
) -> Result<(), ReputationChange> {
let mut total_weight = 0;
@@ -872,32 +857,24 @@ fn check_catch_up<Block: BlockT>(
if let Some(weight) = voters.get(&id).map(|info| info.weight()) {
total_weight += weight.get();
if total_weight > full_threshold {
return Err(cost::MALFORMED_CATCH_UP);
return Err(cost::MALFORMED_CATCH_UP)
}
} else {
debug!(target: "afg", "Skipping catch up message containing unknown voter {}", id);
return Err(cost::MALFORMED_CATCH_UP);
return Err(cost::MALFORMED_CATCH_UP)
}
}
if total_weight < voters.threshold().get() {
return Err(cost::MALFORMED_CATCH_UP);
return Err(cost::MALFORMED_CATCH_UP)
}
Ok(())
}
check_weight(
voters,
msg.prevotes.iter().map(|vote| &vote.id),
full_threshold,
)?;
check_weight(voters, msg.prevotes.iter().map(|vote| &vote.id), full_threshold)?;
check_weight(
voters,
msg.precommits.iter().map(|vote| &vote.id),
full_threshold,
)?;
check_weight(voters, msg.precommits.iter().map(|vote| &vote.id), full_threshold)?;
fn check_signatures<'a, B, I>(
messages: I,
@@ -906,9 +883,10 @@ fn check_catch_up<Block: BlockT>(
mut signatures_checked: usize,
buf: &mut Vec<u8>,
telemetry: Option<TelemetryHandle>,
) -> Result<usize, ReputationChange> where
) -> Result<usize, ReputationChange>
where
B: BlockT,
I: Iterator<Item=(Message<B>, &'a AuthorityId, &'a AuthoritySignature)>,
I: Iterator<Item = (Message<B>, &'a AuthorityId, &'a AuthoritySignature)>,
{
use crate::communication::gossip::Misbehavior;
@@ -916,12 +894,7 @@ fn check_catch_up<Block: BlockT>(
signatures_checked += 1;
if !sp_finality_grandpa::check_message_signature_with_buffer(
&msg,
id,
sig,
round,
set_id,
buf,
&msg, id, sig, round, set_id, buf,
) {
debug!(target: "afg", "Bad catch up message signature {}", id);
telemetry!(
@@ -933,9 +906,10 @@ fn check_catch_up<Block: BlockT>(
let cost = Misbehavior::BadCatchUpMessage {
signatures_checked: signatures_checked as i32,
}.cost();
}
.cost();
return Err(cost);
return Err(cost)
}
}
@@ -959,7 +933,11 @@ fn check_catch_up<Block: BlockT>(
// check signatures on all contained precommits.
let _ = check_signatures::<Block, _>(
msg.precommits.iter().map(|vote| {
(finality_grandpa::Message::Precommit(vote.precommit.clone()), &vote.id, &vote.signature)
(
finality_grandpa::Message::Precommit(vote.precommit.clone()),
&vote.id,
&vote.signature,
)
}),
msg.round_number,
set_id.0,
@@ -1009,9 +987,12 @@ impl<Block: BlockT> Sink<(RoundNumber, Commit<Block>)> for CommitsOut<Block> {
Poll::Ready(Ok(()))
}
fn start_send(self: Pin<&mut Self>, input: (RoundNumber, Commit<Block>)) -> Result<(), Self::Error> {
fn start_send(
self: Pin<&mut Self>,
input: (RoundNumber, Commit<Block>),
) -> Result<(), Self::Error> {
if !self.is_voter {
return Ok(());
return Ok(())
}
let (round, commit) = input;
@@ -1024,7 +1005,9 @@ impl<Block: BlockT> Sink<(RoundNumber, Commit<Block>)> for CommitsOut<Block> {
"target_number" => ?commit.target_number,
"target_hash" => ?commit.target_hash,
);
let (precommits, auth_data) = commit.precommits.into_iter()
let (precommits, auth_data) = commit
.precommits
.into_iter()
.map(|signed| (signed.precommit, (signed.signature, signed.id)))
.unzip();
@@ -1032,7 +1015,7 @@ impl<Block: BlockT> Sink<(RoundNumber, Commit<Block>)> for CommitsOut<Block> {
target_hash: commit.target_hash,
target_number: commit.target_number,
precommits,
auth_data
auth_data,
};
let message = GossipMessage::Commit(FullCommitMessage::<Block> {
@@ -18,15 +18,19 @@
//! Periodic rebroadcast of neighbor packets.
use futures::{future::FutureExt as _, prelude::*, ready, stream::Stream};
use futures_timer::Delay;
use futures::{future::{FutureExt as _}, prelude::*, ready, stream::Stream};
use log::debug;
use std::{pin::Pin, task::{Context, Poll}, time::Duration};
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use std::{
pin::Pin,
task::{Context, Poll},
time::Duration,
};
use super::gossip::{GossipMessage, NeighborPacket};
use sc_network::PeerId;
use sp_runtime::traits::{NumberFor, Block as BlockT};
use super::gossip::{NeighborPacket, GossipMessage};
use sp_runtime::traits::{Block as BlockT, NumberFor};
// How often to rebroadcast, in cases where no new packets are created.
const REBROADCAST_AFTER: Duration = Duration::from_secs(2 * 60);
@@ -34,7 +38,7 @@ const REBROADCAST_AFTER: Duration = Duration::from_secs(2 * 60);
/// A sender used to send neighbor packets to a background job.
#[derive(Clone)]
pub(super) struct NeighborPacketSender<B: BlockT>(
TracingUnboundedSender<(Vec<PeerId>, NeighborPacket<NumberFor<B>>)>
TracingUnboundedSender<(Vec<PeerId>, NeighborPacket<NumberFor<B>>)>,
);
impl<B: BlockT> NeighborPacketSender<B> {
@@ -63,24 +67,20 @@ pub(super) struct NeighborPacketWorker<B: BlockT> {
impl<B: BlockT> Unpin for NeighborPacketWorker<B> {}
impl<B: BlockT> NeighborPacketWorker<B> {
pub(super) fn new() -> (Self, NeighborPacketSender<B>){
let (tx, rx) = tracing_unbounded::<(Vec<PeerId>, NeighborPacket<NumberFor<B>>)>
("mpsc_grandpa_neighbor_packet_worker");
pub(super) fn new() -> (Self, NeighborPacketSender<B>) {
let (tx, rx) = tracing_unbounded::<(Vec<PeerId>, NeighborPacket<NumberFor<B>>)>(
"mpsc_grandpa_neighbor_packet_worker",
);
let delay = Delay::new(REBROADCAST_AFTER);
(NeighborPacketWorker {
last: None,
delay,
rx,
}, NeighborPacketSender(tx))
(NeighborPacketWorker { last: None, delay, rx }, NeighborPacketSender(tx))
}
}
impl <B: BlockT> Stream for NeighborPacketWorker<B> {
impl<B: BlockT> Stream for NeighborPacketWorker<B> {
type Item = (Vec<PeerId>, GossipMessage<B>);
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>>
{
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let this = &mut *self;
match this.rx.poll_next_unpin(cx) {
Poll::Ready(None) => return Poll::Ready(None),
@@ -88,8 +88,8 @@ impl <B: BlockT> Stream for NeighborPacketWorker<B> {
this.delay.reset(REBROADCAST_AFTER);
this.last = Some((to.clone(), packet.clone()));
return Poll::Ready(Some((to, GossipMessage::<B>::from(packet))));
}
return Poll::Ready(Some((to, GossipMessage::<B>::from(packet))))
},
// Don't return yet, maybe the timer fired.
Poll::Pending => {},
};
@@ -104,10 +104,10 @@ impl <B: BlockT> Stream for NeighborPacketWorker<B> {
//
// Note: In case poll_unpin is called after the resetted delay fires again, this
// will drop one tick. Deemed as very unlikely and also not critical.
while let Poll::Ready(()) = this.delay.poll_unpin(cx) {};
while let Poll::Ready(()) = this.delay.poll_unpin(cx) {}
if let Some((ref to, ref packet)) = this.last {
return Poll::Ready(Some((to.clone(), GossipMessage::<B>::from(packet.clone()))));
return Poll::Ready(Some((to.clone(), GossipMessage::<B>::from(packet.clone()))))
}
Poll::Pending
@@ -18,21 +18,26 @@
//! Tests for the communication portion of the GRANDPA crate.
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use super::{
gossip::{self, GossipValidator},
Round, SetId, VoterSet,
};
use crate::{communication::GRANDPA_PROTOCOL_NAME, environment::SharedVoterSetState};
use futures::prelude::*;
use sc_network::{config::Role, Event as NetworkEvent, ObservedRole, PeerId};
use sc_network_test::{Block, Hash};
use sc_network_gossip::Validator;
use std::sync::Arc;
use sp_keyring::Ed25519Keyring;
use parity_scale_codec::Encode;
use sp_runtime::traits::NumberFor;
use std::{borrow::Cow, pin::Pin, task::{Context, Poll}};
use crate::communication::GRANDPA_PROTOCOL_NAME;
use crate::environment::SharedVoterSetState;
use sc_network::{config::Role, Event as NetworkEvent, ObservedRole, PeerId};
use sc_network_gossip::Validator;
use sc_network_test::{Block, Hash};
use sp_finality_grandpa::AuthorityList;
use super::gossip::{self, GossipValidator};
use super::{VoterSet, Round, SetId};
use sp_keyring::Ed25519Keyring;
use sp_runtime::traits::NumberFor;
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use std::{
borrow::Cow,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
#[derive(Debug)]
pub(crate) enum Event {
@@ -79,13 +84,14 @@ impl super::Network<Block> for TestNetwork {
_peers: Vec<sc_network::PeerId>,
_hash: Hash,
_number: NumberFor<Block>,
) {}
) {
}
}
impl sc_network_gossip::ValidatorContext<Block> for TestNetwork {
fn broadcast_topic(&mut self, _: Hash, _: bool) { }
fn broadcast_topic(&mut self, _: Hash, _: bool) {}
fn broadcast_message(&mut self, _: Hash, _: Vec<u8>, _: bool) { }
fn broadcast_message(&mut self, _: Hash, _: Vec<u8>, _: bool) {}
fn send_message(&mut self, who: &sc_network::PeerId, data: Vec<u8>) {
<Self as sc_network_gossip::Network<Block>>::write_notification(
@@ -96,7 +102,7 @@ impl sc_network_gossip::ValidatorContext<Block> for TestNetwork {
);
}
fn send_topic(&mut self, _: &sc_network::PeerId, _: Hash, _: bool) { }
fn send_topic(&mut self, _: &sc_network::PeerId, _: Hash, _: bool) {}
}
pub(crate) struct Tester {
@@ -107,15 +113,17 @@ pub(crate) struct Tester {
impl Tester {
fn filter_network_events<F>(self, mut pred: F) -> impl Future<Output = Self>
where F: FnMut(Event) -> bool
where
F: FnMut(Event) -> bool,
{
let mut s = Some(self);
futures::future::poll_fn(move |cx| loop {
match Stream::poll_next(Pin::new(&mut s.as_mut().unwrap().events), cx) {
Poll::Ready(None) => panic!("concluded early"),
Poll::Ready(Some(item)) => if pred(item) {
return Poll::Ready(s.take().unwrap())
},
Poll::Ready(Some(item)) =>
if pred(item) {
return Poll::Ready(s.take().unwrap())
},
Poll::Pending => return Poll::Pending,
}
})
@@ -145,8 +153,7 @@ fn config() -> crate::Config {
// dummy voter set state
fn voter_set_state() -> SharedVoterSetState<Block> {
use crate::authorities::AuthoritySet;
use crate::environment::VoterSetState;
use crate::{authorities::AuthoritySet, environment::VoterSetState};
use finality_grandpa::round::State as RoundState;
use sp_core::{crypto::Public, H256};
use sp_finality_grandpa::AuthorityId;
@@ -157,20 +164,13 @@ fn voter_set_state() -> SharedVoterSetState<Block> {
let voters = vec![(AuthorityId::from_slice(&[1; 32]), 1)];
let voters = AuthoritySet::genesis(voters).unwrap();
let set_state = VoterSetState::live(
0,
&voters,
base,
);
let set_state = VoterSetState::live(0, &voters, base);
set_state.into()
}
// needs to run in a tokio runtime.
pub(crate) fn make_test_network() -> (
impl Future<Output = Tester>,
TestNetwork,
) {
pub(crate) fn make_test_network() -> (impl Future<Output = Tester>, TestNetwork) {
let (tx, rx) = tracing_unbounded("test");
let net = TestNetwork { sender: tx };
@@ -185,13 +185,7 @@ pub(crate) fn make_test_network() -> (
}
}
let bridge = super::NetworkBridge::new(
net.clone(),
config(),
voter_set_state(),
None,
None,
);
let bridge = super::NetworkBridge::new(net.clone(), config(), voter_set_state(), None, None);
(
futures::future::ready(Tester {
@@ -204,19 +198,16 @@ pub(crate) fn make_test_network() -> (
}
fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList {
keys.iter()
.map(|key| key.clone().public().into())
.map(|id| (id, 1))
.collect()
keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect()
}
struct NoopContext;
impl sc_network_gossip::ValidatorContext<Block> for NoopContext {
fn broadcast_topic(&mut self, _: Hash, _: bool) { }
fn broadcast_message(&mut self, _: Hash, _: Vec<u8>, _: bool) { }
fn send_message(&mut self, _: &sc_network::PeerId, _: Vec<u8>) { }
fn send_topic(&mut self, _: &sc_network::PeerId, _: Hash, _: bool) { }
fn broadcast_topic(&mut self, _: Hash, _: bool) {}
fn broadcast_message(&mut self, _: Hash, _: Vec<u8>, _: bool) {}
fn send_message(&mut self, _: &sc_network::PeerId, _: Vec<u8>) {}
fn send_topic(&mut self, _: &sc_network::PeerId, _: Hash, _: bool) {}
}
#[test]
@@ -232,9 +223,12 @@ fn good_commit_leads_to_relay() {
let target_hash: Hash = [1; 32].into();
let target_number = 500;
let precommit = finality_grandpa::Precommit { target_hash: target_hash.clone(), target_number };
let precommit =
finality_grandpa::Precommit { target_hash: target_hash.clone(), target_number };
let payload = sp_finality_grandpa::localized_payload(
round, set_id, &finality_grandpa::Message::Precommit(precommit.clone())
round,
set_id,
&finality_grandpa::Message::Precommit(precommit.clone()),
);
let mut precommits = Vec::new();
@@ -247,24 +241,21 @@ fn good_commit_leads_to_relay() {
auth_data.push((signature, public[i].0.clone()))
}
finality_grandpa::CompactCommit {
target_hash,
target_number,
precommits,
auth_data,
}
finality_grandpa::CompactCommit { target_hash, target_number, precommits, auth_data }
};
let encoded_commit = gossip::GossipMessage::<Block>::Commit(gossip::FullCommitMessage {
round: Round(round),
set_id: SetId(set_id),
message: commit,
}).encode();
})
.encode();
let id = sc_network::PeerId::random();
let global_topic = super::global_topic::<Block>(set_id);
let test = make_test_network().0
let test = make_test_network()
.0
.then(move |tester| {
// register a peer.
tester.gossip_validator.new_peer(&mut NoopContext, &id, ObservedRole::Full);
@@ -272,7 +263,8 @@ fn good_commit_leads_to_relay() {
})
.then(move |(tester, id)| {
// start round, dispatch commit, and wait for broadcast.
let (commits_in, _) = tester.net_handle.global_communication(SetId(1), voter_set, false);
let (commits_in, _) =
tester.net_handle.global_communication(SetId(1), voter_set, false);
{
let (action, ..) = tester.gossip_validator.do_validate(&id, &encoded_commit[..]);
@@ -301,7 +293,10 @@ fn good_commit_leads_to_relay() {
let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived {
remote: sender_id.clone(),
messages: vec![(GRANDPA_PROTOCOL_NAME.into(), commit_to_send.clone().into())],
messages: vec![(
GRANDPA_PROTOCOL_NAME.into(),
commit_to_send.clone().into(),
)],
});
// Add a random peer which will be the recipient of this message
@@ -316,13 +311,11 @@ fn good_commit_leads_to_relay() {
// Announce its local set has being on the current set id through a neighbor
// packet, otherwise it won't be eligible to receive the commit
let _ = {
let update = gossip::VersionedNeighborPacket::V1(
gossip::NeighborPacket {
round: Round(round),
set_id: SetId(set_id),
commit_finalized_height: 1,
}
);
let update = gossip::VersionedNeighborPacket::V1(gossip::NeighborPacket {
round: Round(round),
set_id: SetId(set_id),
commit_finalized_height: 1,
});
let msg = gossip::GossipMessage::<Block>::Neighbor(update);
@@ -333,31 +326,27 @@ fn good_commit_leads_to_relay() {
};
true
}
},
_ => false,
});
// when the commit comes in, we'll tell the callback it was good.
let handle_commit = commits_in.into_future()
.map(|(item, _)| {
match item.unwrap() {
finality_grandpa::voter::CommunicationIn::Commit(_, _, mut callback) => {
callback.run(finality_grandpa::voter::CommitProcessingOutcome::good());
},
_ => panic!("commit expected"),
}
});
let handle_commit = commits_in.into_future().map(|(item, _)| match item.unwrap() {
finality_grandpa::voter::CommunicationIn::Commit(_, _, mut callback) => {
callback.run(finality_grandpa::voter::CommitProcessingOutcome::good());
},
_ => panic!("commit expected"),
});
// once the message is sent and commit is "handled" we should have
// a repropagation event coming from the network.
let fut = future::join(send_message, handle_commit).then(move |(tester, ())| {
tester.filter_network_events(move |event| match event {
Event::WriteNotification(_, data) => {
data == encoded_commit
}
_ => false,
let fut = future::join(send_message, handle_commit)
.then(move |(tester, ())| {
tester.filter_network_events(move |event| match event {
Event::WriteNotification(_, data) => data == encoded_commit,
_ => false,
})
})
})
.map(|_| ());
// Poll both the future sending and handling the commit, as well as the underlying
@@ -382,9 +371,12 @@ fn bad_commit_leads_to_report() {
let target_hash: Hash = [1; 32].into();
let target_number = 500;
let precommit = finality_grandpa::Precommit { target_hash: target_hash.clone(), target_number };
let precommit =
finality_grandpa::Precommit { target_hash: target_hash.clone(), target_number };
let payload = sp_finality_grandpa::localized_payload(
round, set_id, &finality_grandpa::Message::Precommit(precommit.clone())
round,
set_id,
&finality_grandpa::Message::Precommit(precommit.clone()),
);
let mut precommits = Vec::new();
@@ -397,24 +389,21 @@ fn bad_commit_leads_to_report() {
auth_data.push((signature, public[i].0.clone()))
}
finality_grandpa::CompactCommit {
target_hash,
target_number,
precommits,
auth_data,
}
finality_grandpa::CompactCommit { target_hash, target_number, precommits, auth_data }
};
let encoded_commit = gossip::GossipMessage::<Block>::Commit(gossip::FullCommitMessage {
round: Round(round),
set_id: SetId(set_id),
message: commit,
}).encode();
})
.encode();
let id = sc_network::PeerId::random();
let global_topic = super::global_topic::<Block>(set_id);
let test = make_test_network().0
let test = make_test_network()
.0
.map(move |tester| {
// register a peer.
tester.gossip_validator.new_peer(&mut NoopContext, &id, ObservedRole::Full);
@@ -422,7 +411,8 @@ fn bad_commit_leads_to_report() {
})
.then(move |(tester, id)| {
// start round, dispatch commit, and wait for broadcast.
let (commits_in, _) = tester.net_handle.global_communication(SetId(1), voter_set, false);
let (commits_in, _) =
tester.net_handle.global_communication(SetId(1), voter_set, false);
{
let (action, ..) = tester.gossip_validator.do_validate(&id, &encoded_commit[..]);
@@ -449,35 +439,35 @@ fn bad_commit_leads_to_report() {
});
let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived {
remote: sender_id.clone(),
messages: vec![(GRANDPA_PROTOCOL_NAME.into(), commit_to_send.clone().into())],
messages: vec![(
GRANDPA_PROTOCOL_NAME.into(),
commit_to_send.clone().into(),
)],
});
true
}
},
_ => false,
});
// when the commit comes in, we'll tell the callback it was bad.
let handle_commit = commits_in.into_future()
.map(|(item, _)| {
match item.unwrap() {
finality_grandpa::voter::CommunicationIn::Commit(_, _, mut callback) => {
callback.run(finality_grandpa::voter::CommitProcessingOutcome::bad());
},
_ => panic!("commit expected"),
}
});
let handle_commit = commits_in.into_future().map(|(item, _)| match item.unwrap() {
finality_grandpa::voter::CommunicationIn::Commit(_, _, mut callback) => {
callback.run(finality_grandpa::voter::CommitProcessingOutcome::bad());
},
_ => panic!("commit expected"),
});
// once the message is sent and commit is "handled" we should have
// a report event coming from the network.
let fut = future::join(send_message, handle_commit).then(move |(tester, ())| {
tester.filter_network_events(move |event| match event {
Event::Report(who, cost_benefit) => {
who == id && cost_benefit == super::cost::INVALID_COMMIT
}
_ => false,
let fut = future::join(send_message, handle_commit)
.then(move |(tester, ())| {
tester.filter_network_events(move |event| match event {
Event::Report(who, cost_benefit) =>
who == id && cost_benefit == super::cost::INVALID_COMMIT,
_ => false,
})
})
})
.map(|_| ());
// Poll both the future sending and handling the commit, as well as the underlying
@@ -508,7 +498,8 @@ fn peer_with_higher_view_leads_to_catch_up_request() {
set_id: SetId(0),
round: Round(10),
commit_finalized_height: 50,
}).encode(),
})
.encode(),
);
// neighbor packets are always discard
@@ -518,27 +509,23 @@ fn peer_with_higher_view_leads_to_catch_up_request() {
}
// a catch up request should be sent to the peer for round - 1
tester.filter_network_events(move |event| match event {
Event::WriteNotification(peer, message) => {
assert_eq!(
peer,
id,
);
tester
.filter_network_events(move |event| match event {
Event::WriteNotification(peer, message) => {
assert_eq!(peer, id,);
assert_eq!(
message,
gossip::GossipMessage::<Block>::CatchUpRequest(
gossip::CatchUpRequestMessage {
set_id: SetId(0),
round: Round(9),
}
).encode(),
);
assert_eq!(
message,
gossip::GossipMessage::<Block>::CatchUpRequest(
gossip::CatchUpRequestMessage { set_id: SetId(0), round: Round(9) }
)
.encode(),
);
true
},
_ => false,
})
true
},
_ => false,
})
.map(|_| ())
});
@@ -16,12 +16,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::collections::{BTreeMap, HashMap};
use std::iter::FromIterator;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Arc;
use std::time::Duration;
use std::{
collections::{BTreeMap, HashMap},
iter::FromIterator,
marker::PhantomData,
pin::Pin,
sync::Arc,
time::Duration,
};
use finality_grandpa::{
round::State as RoundState, voter, voter_set::VoterSet, BlockNumberOps, Error as GrandpaError,
@@ -44,8 +46,10 @@ use sp_finality_grandpa::{
AuthorityId, AuthoritySignature, Equivocation, EquivocationProof, GrandpaApi, RoundNumber,
SetId, GRANDPA_ENGINE_ID,
};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero},
};
use crate::{
authorities::{AuthoritySet, SharedAuthoritySet},
@@ -105,13 +109,11 @@ impl<Block: BlockT> Encode for CompletedRounds<Block> {
impl<Block: BlockT> parity_scale_codec::EncodeLike for CompletedRounds<Block> {}
impl<Block: BlockT> Decode for CompletedRounds<Block> {
fn decode<I: parity_scale_codec::Input>(value: &mut I) -> Result<Self, parity_scale_codec::Error> {
fn decode<I: parity_scale_codec::Input>(
value: &mut I,
) -> Result<Self, parity_scale_codec::Error> {
<(Vec<CompletedRound<Block>>, SetId, Vec<AuthorityId>)>::decode(value)
.map(|(rounds, set_id, voters)| CompletedRounds {
rounds,
set_id,
voters,
})
.map(|(rounds, set_id, voters)| CompletedRounds { rounds, set_id, voters })
}
}
@@ -121,9 +123,7 @@ impl<Block: BlockT> CompletedRounds<Block> {
genesis: CompletedRound<Block>,
set_id: SetId,
voters: &AuthoritySet<Block::Hash, NumberFor<Block>>,
)
-> CompletedRounds<Block>
{
) -> CompletedRounds<Block> {
let mut rounds = Vec::with_capacity(NUM_LAST_COMPLETED_ROUNDS);
rounds.push(genesis);
@@ -137,13 +137,14 @@ impl<Block: BlockT> CompletedRounds<Block> {
}
/// Iterate over all completed rounds.
pub fn iter(&self) -> impl Iterator<Item=&CompletedRound<Block>> {
pub fn iter(&self) -> impl Iterator<Item = &CompletedRound<Block>> {
self.rounds.iter().rev()
}
/// Returns the last (latest) completed round.
pub fn last(&self) -> &CompletedRound<Block> {
self.rounds.first()
self.rounds
.first()
.expect("inner is never empty; always contains at least genesis; qed")
}
@@ -152,10 +153,11 @@ impl<Block: BlockT> CompletedRounds<Block> {
pub fn push(&mut self, completed_round: CompletedRound<Block>) {
use std::cmp::Reverse;
match self.rounds.binary_search_by_key(
&Reverse(completed_round.number),
|completed_round| Reverse(completed_round.number),
) {
match self
.rounds
.binary_search_by_key(&Reverse(completed_round.number), |completed_round| {
Reverse(completed_round.number)
}) {
Ok(idx) => self.rounds[idx] = completed_round,
Err(idx) => self.rounds.insert(idx, completed_round),
};
@@ -215,37 +217,31 @@ impl<Block: BlockT> VoterSetState<Block> {
let mut current_rounds = CurrentRounds::new();
current_rounds.insert(1, HasVoted::No);
VoterSetState::Live {
completed_rounds,
current_rounds,
}
VoterSetState::Live { completed_rounds, current_rounds }
}
/// Returns the last completed rounds.
pub(crate) fn completed_rounds(&self) -> CompletedRounds<Block> {
match self {
VoterSetState::Live { completed_rounds, .. } =>
completed_rounds.clone(),
VoterSetState::Paused { completed_rounds } =>
completed_rounds.clone(),
VoterSetState::Live { completed_rounds, .. } => completed_rounds.clone(),
VoterSetState::Paused { completed_rounds } => completed_rounds.clone(),
}
}
/// Returns the last completed round.
pub(crate) fn last_completed_round(&self) -> CompletedRound<Block> {
match self {
VoterSetState::Live { completed_rounds, .. } =>
completed_rounds.last().clone(),
VoterSetState::Paused { completed_rounds } =>
completed_rounds.last().clone(),
VoterSetState::Live { completed_rounds, .. } => completed_rounds.last().clone(),
VoterSetState::Paused { completed_rounds } => completed_rounds.last().clone(),
}
}
/// Returns the voter set state validating that it includes the given round
/// in current rounds and that the voter isn't paused.
pub fn with_current_round(&self, round: RoundNumber)
-> Result<(&CompletedRounds<Block>, &CurrentRounds<Block>), Error>
{
pub fn with_current_round(
&self,
round: RoundNumber,
) -> Result<(&CompletedRounds<Block>, &CurrentRounds<Block>), Error> {
if let VoterSetState::Live { completed_rounds, current_rounds } = self {
if current_rounds.contains_key(&round) {
Ok((completed_rounds, current_rounds))
@@ -284,10 +280,9 @@ impl<Block: BlockT> HasVoted<Block> {
/// Returns the proposal we should vote with (if any.)
pub fn propose(&self) -> Option<&PrimaryPropose<Block>> {
match self {
HasVoted::Yes(_, Vote::Propose(propose)) =>
Some(propose),
HasVoted::Yes(_, Vote::Prevote(propose, _)) | HasVoted::Yes(_, Vote::Precommit(propose, _, _)) =>
propose.as_ref(),
HasVoted::Yes(_, Vote::Propose(propose)) => Some(propose),
HasVoted::Yes(_, Vote::Prevote(propose, _)) |
HasVoted::Yes(_, Vote::Precommit(propose, _, _)) => propose.as_ref(),
_ => None,
}
}
@@ -295,8 +290,8 @@ impl<Block: BlockT> HasVoted<Block> {
/// Returns the prevote we should vote with (if any.)
pub fn prevote(&self) -> Option<&Prevote<Block>> {
match self {
HasVoted::Yes(_, Vote::Prevote(_, prevote)) | HasVoted::Yes(_, Vote::Precommit(_, prevote, _)) =>
Some(prevote),
HasVoted::Yes(_, Vote::Prevote(_, prevote)) |
HasVoted::Yes(_, Vote::Precommit(_, prevote, _)) => Some(prevote),
_ => None,
}
}
@@ -304,8 +299,7 @@ impl<Block: BlockT> HasVoted<Block> {
/// Returns the precommit we should vote with (if any.)
pub fn precommit(&self) -> Option<&Precommit<Block>> {
match self {
HasVoted::Yes(_, Vote::Precommit(_, _, precommit)) =>
Some(precommit),
HasVoted::Yes(_, Vote::Precommit(_, _, precommit)) => Some(precommit),
_ => None,
}
}
@@ -376,21 +370,21 @@ impl<Block: BlockT> SharedVoterSetState<Block> {
/// Return vote status information for the current round.
pub(crate) fn has_voted(&self, round: RoundNumber) -> HasVoted<Block> {
match &*self.inner.read() {
VoterSetState::Live { current_rounds, .. } => {
current_rounds.get(&round).and_then(|has_voted| match has_voted {
HasVoted::Yes(id, vote) =>
Some(HasVoted::Yes(id.clone(), vote.clone())),
VoterSetState::Live { current_rounds, .. } => current_rounds
.get(&round)
.and_then(|has_voted| match has_voted {
HasVoted::Yes(id, vote) => Some(HasVoted::Yes(id.clone(), vote.clone())),
_ => None,
})
.unwrap_or(HasVoted::No)
},
.unwrap_or(HasVoted::No),
_ => HasVoted::No,
}
}
// NOTE: not exposed outside of this module intentionally.
fn with<F, R>(&self, f: F) -> R
where F: FnOnce(&mut VoterSetState<Block>) -> R
where
F: FnOnce(&mut VoterSetState<Block>) -> R,
{
f(&mut *self.inner.write())
}
@@ -452,8 +446,9 @@ impl<BE, Block: BlockT, C, N: NetworkT<Block>, SC, VR> Environment<BE, Block, C,
/// Updates the voter set state using the given closure. The write lock is
/// held during evaluation of the closure and the environment's voter set
/// state is set to its result if successful.
pub(crate) fn update_voter_set_state<F>(&self, f: F) -> Result<(), Error> where
F: FnOnce(&VoterSetState<Block>) -> Result<Option<VoterSetState<Block>>, Error>
pub(crate) fn update_voter_set_state<F>(&self, f: F) -> Result<(), Error>
where
F: FnOnce(&VoterSetState<Block>) -> Result<Option<VoterSetState<Block>>, Error>,
{
self.voter_set_state.with(|voter_set_state| {
if let Some(set_state) = f(&voter_set_state)? {
@@ -461,7 +456,9 @@ impl<BE, Block: BlockT, C, N: NetworkT<Block>, SC, VR> Environment<BE, Block, C,
if let Some(metrics) = self.metrics.as_ref() {
if let VoterSetState::Live { completed_rounds, .. } = voter_set_state {
let highest = completed_rounds.rounds.iter()
let highest = completed_rounds
.rounds
.iter()
.map(|round| round.number)
.max()
.expect("There is always one completed round (genesis); qed");
@@ -497,7 +494,7 @@ where
if *equivocation.offender() == local_id {
return Err(Error::Safety(
"Refraining from sending equivocation report for our own equivocation.".into(),
));
))
}
}
@@ -520,11 +517,8 @@ where
// find the hash of the latest block in the current set
let current_set_latest_hash = match next_change {
Some((_, n)) if n.is_zero() => {
return Err(Error::Safety(
"Authority set change signalled at genesis.".to_string(),
))
}
Some((_, n)) if n.is_zero() =>
return Err(Error::Safety("Authority set change signalled at genesis.".to_string())),
// the next set starts at `n` so the current one lasts until `n - 1`. if
// `n` is later than the best block, then the current set is still live
// at best block.
@@ -538,14 +532,15 @@ where
// its parent block is the last block in the current set
*header.parent_hash()
}
},
// there is no pending change, the latest block for the current set is
// the best block.
None => best_block_hash,
};
// generate key ownership proof at that block
let key_owner_proof = match self.client
let key_owner_proof = match self
.client
.runtime_api()
.generate_key_ownership_proof(
&BlockId::Hash(current_set_latest_hash),
@@ -557,15 +552,12 @@ where
Some(proof) => proof,
None => {
debug!(target: "afg", "Equivocation offender is not part of the authority set.");
return Ok(());
}
return Ok(())
},
};
// submit equivocation report at **best** block
let equivocation_proof = EquivocationProof::new(
authority_set.set_id,
equivocation,
);
let equivocation_proof = EquivocationProof::new(authority_set.set_id, equivocation);
self.client
.runtime_api()
@@ -608,7 +600,9 @@ pub(crate) fn ancestry<Block: BlockT, Client>(
where
Client: HeaderMetadata<Block, Error = sp_blockchain::Error>,
{
if base == block { return Err(GrandpaError::NotDescendent) }
if base == block {
return Err(GrandpaError::NotDescendent)
}
let tree_route_res = sp_blockchain::tree_route(&**client, block, base);
@@ -618,22 +612,17 @@ where
debug!(target: "afg", "Encountered error computing ancestry between block {:?} and base {:?}: {:?}",
block, base, e);
return Err(GrandpaError::NotDescendent);
}
return Err(GrandpaError::NotDescendent)
},
};
if tree_route.common_block().hash != base {
return Err(GrandpaError::NotDescendent);
return Err(GrandpaError::NotDescendent)
}
// skip one because our ancestry is meant to start from the parent of `block`,
// and `tree_route` includes it.
Ok(tree_route
.retracted()
.iter()
.skip(1)
.map(|e| e.hash)
.collect())
Ok(tree_route.retracted().iter().skip(1).map(|e| e.hash).collect())
}
impl<B, Block, C, N, SC, VR> voter::Environment<Block::Hash, NumberFor<Block>>
@@ -699,7 +688,7 @@ where
// before activating the new set. the `authority_set` is updated immediately thus
// we restrict the voter based on that.
if set_id != authority_set.set_id() {
return Ok(None);
return Ok(None)
}
best_chain_containing(block, client, authority_set, select_chain, voting_rule)
@@ -718,13 +707,12 @@ where
let local_id = local_authority_id(&self.voters, self.config.keystore.as_ref());
let has_voted = match self.voter_set_state.has_voted(round) {
HasVoted::Yes(id, vote) => {
HasVoted::Yes(id, vote) =>
if local_id.as_ref().map(|k| k == &id).unwrap_or(false) {
HasVoted::Yes(id, vote)
} else {
HasVoted::No
}
},
},
HasVoted::No => HasVoted::No,
};
@@ -756,14 +744,17 @@ where
// schedule incoming messages from the network to be held until
// corresponding blocks are imported.
let incoming = Box::pin(UntilVoteTargetImported::new(
self.client.import_notification_stream(),
self.network.clone(),
self.client.clone(),
incoming,
"round",
None,
).map_err(Into::into));
let incoming = Box::pin(
UntilVoteTargetImported::new(
self.client.import_notification_stream(),
self.network.clone(),
self.client.clone(),
incoming,
"round",
None,
)
.map_err(Into::into),
);
// schedule network message cleanup when sink drops.
let outgoing = Box::pin(outgoing.sink_err_into());
@@ -789,18 +780,20 @@ where
self.update_voter_set_state(|voter_set_state| {
let (completed_rounds, current_rounds) = voter_set_state.with_current_round(round)?;
let current_round = current_rounds.get(&round)
let current_round = current_rounds
.get(&round)
.expect("checked in with_current_round that key exists; qed.");
if !current_round.can_propose() {
// we've already proposed in this round (in a previous run),
// ignore the given vote and don't update the voter set
// state
return Ok(None);
return Ok(None)
}
let mut current_rounds = current_rounds.clone();
let current_round = current_rounds.get_mut(&round)
let current_round = current_rounds
.get_mut(&round)
.expect("checked previously that key exists; qed.");
*current_round = HasVoted::Yes(local_id, Vote::Propose(propose));
@@ -849,7 +842,7 @@ where
// we've already prevoted in this round (in a previous run),
// ignore the given vote and don't update the voter set
// state
return Ok(None);
return Ok(None)
}
// report to telemetry and prometheus
@@ -858,7 +851,8 @@ where
let propose = current_round.propose();
let mut current_rounds = current_rounds.clone();
let current_round = current_rounds.get_mut(&round)
let current_round = current_rounds
.get_mut(&round)
.expect("checked previously that key exists; qed.");
*current_round = HasVoted::Yes(local_id, Vote::Prevote(propose.cloned(), prevote));
@@ -911,7 +905,7 @@ where
// we've already precommitted in this round (in a previous run),
// ignore the given vote and don't update the voter set
// state
return Ok(None);
return Ok(None)
}
// report to telemetry and prometheus
@@ -922,12 +916,13 @@ where
HasVoted::Yes(_, Vote::Prevote(_, prevote)) => prevote,
_ => {
let msg = "Voter precommitting before prevoting.";
return Err(Error::Safety(msg.to_string()));
}
return Err(Error::Safety(msg.to_string()))
},
};
let mut current_rounds = current_rounds.clone();
let current_round = current_rounds.get_mut(&round)
let current_round = current_rounds
.get_mut(&round)
.expect("checked previously that key exists; qed.");
*current_round = HasVoted::Yes(
@@ -973,7 +968,7 @@ where
(completed_rounds, current_rounds)
} else {
let msg = "Voter acting while in paused state.";
return Err(Error::Safety(msg.to_string()));
return Err(Error::Safety(msg.to_string()))
};
let mut completed_rounds = completed_rounds.clone();
@@ -998,10 +993,7 @@ where
current_rounds.insert(round + 1, HasVoted::No);
}
let set_state = VoterSetState::<Block>::Live {
completed_rounds,
current_rounds,
};
let set_state = VoterSetState::<Block>::Live { completed_rounds, current_rounds };
crate::aux_schema::write_voter_set_state(&*self.client, &set_state)?;
@@ -1038,21 +1030,21 @@ where
(completed_rounds, current_rounds)
} else {
let msg = "Voter acting while in paused state.";
return Err(Error::Safety(msg.to_string()));
return Err(Error::Safety(msg.to_string()))
};
let mut completed_rounds = completed_rounds.clone();
if let Some(already_completed) = completed_rounds.rounds
.iter_mut().find(|r| r.number == round)
if let Some(already_completed) =
completed_rounds.rounds.iter_mut().find(|r| r.number == round)
{
let n_existing_votes = already_completed.votes.len();
// the interface of Environment guarantees that the previous `historical_votes`
// from `completable` is a prefix of what is passed to `concluded`.
already_completed.votes.extend(
historical_votes.seen().iter().skip(n_existing_votes).cloned()
);
already_completed
.votes
.extend(historical_votes.seen().iter().skip(n_existing_votes).cloned());
already_completed.state = state;
crate::aux_schema::write_concluded_round(&*self.client, &already_completed)?;
}
@@ -1161,8 +1153,8 @@ where
block,
);
return Ok(None);
}
return Ok(None)
},
};
// we refuse to vote beyond the current limit number where transitions are scheduled to occur.
@@ -1195,7 +1187,7 @@ where
}
if *target_header.number() == target_number {
break;
break
}
target_header = client
@@ -1230,15 +1222,15 @@ where
restricted_number < target_header.number()
})
.or_else(|| Some((target_header.hash(), *target_header.number())))
}
},
Ok(None) => {
debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block);
None
}
},
Err(e) => {
debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e);
None
}
},
};
Ok(result)
@@ -1281,20 +1273,22 @@ where
status.finalized_number,
);
return Ok(());
return Ok(())
}
// FIXME #1483: clone only when changed
let old_authority_set = authority_set.clone();
let update_res: Result<_, Error> = client.lock_import_and_run(|import_op| {
let status = authority_set.apply_standard_changes(
hash,
number,
&is_descendent_of::<Block, _>(&*client, None),
initial_sync,
None,
).map_err(|e| Error::Safety(e.to_string()))?;
let status = authority_set
.apply_standard_changes(
hash,
number,
&is_descendent_of::<Block, _>(&*client, None),
initial_sync,
None,
)
.map_err(|e| Error::Safety(e.to_string()))?;
// send a justification notification if a sender exists and in case of error log it.
fn notify_justification<Block: BlockT>(
@@ -1327,17 +1321,15 @@ where
if !justification_required {
if let Some(justification_period) = justification_period {
let last_finalized_number = client.info().finalized_number;
justification_required =
(!last_finalized_number.is_zero() || number - last_finalized_number == justification_period) &&
(last_finalized_number / justification_period != number / justification_period);
justification_required = (!last_finalized_number.is_zero() ||
number - last_finalized_number == justification_period) &&
(last_finalized_number / justification_period !=
number / justification_period);
}
}
let justification = GrandpaJustification::from_commit(
&client,
round_number,
commit,
)?;
let justification =
GrandpaJustification::from_commit(&client, round_number, commit)?;
(justification_required, justification)
},
@@ -1369,25 +1361,22 @@ where
"number" => ?number, "hash" => ?hash,
);
crate::aux_schema::update_best_justification(
&justification,
|insert| apply_aux(import_op, insert, &[]),
)?;
crate::aux_schema::update_best_justification(&justification, |insert| {
apply_aux(import_op, insert, &[])
})?;
let new_authorities = if let Some((canon_hash, canon_number)) = status.new_set_block {
// the authority set has changed.
let (new_id, set_ref) = authority_set.current();
if set_ref.len() > 16 {
afg_log!(initial_sync,
afg_log!(
initial_sync,
"👴 Applying GRANDPA set change to new set with {} authorities",
set_ref.len(),
);
} else {
afg_log!(initial_sync,
"👴 Applying GRANDPA set change to new set {:?}",
set_ref,
);
afg_log!(initial_sync, "👴 Applying GRANDPA set change to new set {:?}", set_ref,);
}
telemetry!(
@@ -1419,7 +1408,7 @@ where
warn!(target: "afg", "Failed to write updated authority set to disk. Bailing.");
warn!(target: "afg", "Node is in a potentially inconsistent state.");
return Err(e.into());
return Err(e.into())
}
}
@@ -1433,6 +1422,6 @@ where
*authority_set = old_authority_set;
Err(CommandOrError::Error(e))
}
},
}
}
@@ -39,19 +39,20 @@
use log::{trace, warn};
use std::sync::Arc;
use parity_scale_codec::{Encode, Decode};
use parity_scale_codec::{Decode, Encode};
use sc_client_api::backend::Backend;
use sp_blockchain::{Backend as BlockchainBackend, HeaderBackend};
use sp_finality_grandpa::GRANDPA_ENGINE_ID;
use sp_runtime::{
generic::BlockId,
traits::{NumberFor, Block as BlockT, Header as HeaderT, One},
traits::{Block as BlockT, Header as HeaderT, NumberFor, One},
};
use sc_client_api::backend::Backend;
use crate::{
SharedAuthoritySet, best_justification,
authorities::{AuthoritySetChangeId, AuthoritySetChanges},
best_justification,
justification::GrandpaJustification,
SharedAuthoritySet,
};
const MAX_UNKNOWN_HEADERS: usize = 100_000;
@@ -76,10 +77,7 @@ where
backend: Arc<B>,
shared_authority_set: Option<SharedAuthoritySet<Block::Hash, NumberFor<Block>>>,
) -> Self {
FinalityProofProvider {
backend,
shared_authority_set,
}
FinalityProofProvider { backend, shared_authority_set }
}
/// Create new finality proof provider for the service using:
@@ -113,14 +111,10 @@ where
{
changes
} else {
return Ok(None);
return Ok(None)
};
prove_finality(
&*self.backend,
authority_set_changes,
block,
)
prove_finality(&*self.backend, authority_set_changes, block)
}
}
@@ -166,11 +160,10 @@ where
if info.finalized_number < block {
let err = format!(
"Requested finality proof for descendant of #{} while we only have finalized #{}.",
block,
info.finalized_number,
block, info.finalized_number,
);
trace!(target: "afg", "{}", &err);
return Err(FinalityProofError::BlockNotYetFinalized);
return Err(FinalityProofError::BlockNotYetFinalized)
}
let (justification, just_block) = match authority_set_changes.get_set_id(block) {
@@ -185,9 +178,9 @@ where
"No justification found for the latest finalized block. \
Returning empty proof.",
);
return Ok(None);
return Ok(None)
}
}
},
AuthoritySetChangeId::Set(_, last_block_for_set) => {
let last_block_for_set_id = BlockId::Number(last_block_for_set);
let justification = if let Some(grandpa_justification) = backend
@@ -203,10 +196,10 @@ where
Returning empty proof.",
block,
);
return Ok(None);
return Ok(None)
};
(justification, last_block_for_set)
}
},
AuthoritySetChangeId::Unknown => {
warn!(
target: "afg",
@@ -214,8 +207,8 @@ where
You need to resync to populate AuthoritySetChanges properly.",
block,
);
return Err(FinalityProofError::BlockNotInAuthoritySetChanges);
}
return Err(FinalityProofError::BlockNotInAuthoritySetChanges)
},
};
// Collect all headers from the requested block until the last block of the set
@@ -224,7 +217,7 @@ where
let mut current = block + One::one();
loop {
if current > just_block || headers.len() >= MAX_UNKNOWN_HEADERS {
break;
break
}
headers.push(backend.blockchain().expect_header(BlockId::Number(current))?);
current += One::one();
@@ -245,9 +238,7 @@ where
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::{
authorities::AuthoritySetChanges, BlockNumberOps, ClientError, SetId,
};
use crate::{authorities::AuthoritySetChanges, BlockNumberOps, ClientError, SetId};
use futures::executor::block_on;
use sc_block_builder::BlockBuilderProvider;
use sc_client_api::{apply_aux, LockImportRun};
@@ -276,8 +267,9 @@ pub(crate) mod tests {
let proof = super::FinalityProof::<Block::Header>::decode(&mut &remote_proof[..])
.map_err(|_| ClientError::BadJustification("failed to decode finality proof".into()))?;
let justification: GrandpaJustification<Block> = Decode::decode(&mut &proof.justification[..])
.map_err(|_| ClientError::JustificationDecode)?;
let justification: GrandpaJustification<Block> =
Decode::decode(&mut &proof.justification[..])
.map_err(|_| ClientError::JustificationDecode)?;
justification.verify(current_set_id, &current_authorities)?;
Ok(proof)
@@ -321,13 +313,13 @@ pub(crate) mod tests {
}
fn store_best_justification(client: &TestClient, just: &GrandpaJustification<Block>) {
client.lock_import_and_run(|import_op| {
crate::aux_schema::update_best_justification(
just,
|insert| apply_aux(import_op, insert, &[]),
)
})
.unwrap();
client
.lock_import_and_run(|import_op| {
crate::aux_schema::update_best_justification(just, |insert| {
apply_aux(import_op, insert, &[])
})
})
.unwrap();
}
#[test]
@@ -336,11 +328,7 @@ pub(crate) mod tests {
let authority_set_changes = AuthoritySetChanges::empty();
// The last finalized block is 4, so we cannot provide further justifications.
let proof_of_5 = prove_finality(
&*backend,
authority_set_changes,
5,
);
let proof_of_5 = prove_finality(&*backend, authority_set_changes, 5);
assert!(matches!(proof_of_5, Err(FinalityProofError::BlockNotYetFinalized)));
}
@@ -353,12 +341,7 @@ pub(crate) mod tests {
// Block 4 is finalized without justification
// => we can't prove finality of 3
let proof_of_3 = prove_finality(
&*backend,
authority_set_changes,
3,
)
.unwrap();
let proof_of_3 = prove_finality(&*backend, authority_set_changes, 3).unwrap();
assert_eq!(proof_of_3, None);
}
@@ -406,14 +389,15 @@ pub(crate) mod tests {
1,
vec![(AuthorityId::from_slice(&[3u8; 32]), 1u64)],
finality_proof.encode(),
).unwrap_err();
)
.unwrap_err();
}
fn create_commit<S, Id>(
block: Block,
round: u64,
set_id: SetId,
auth: &[Ed25519Keyring]
auth: &[Ed25519Keyring],
) -> finality_grandpa::Commit<H256, u64, S, Id>
where
Id: From<sp_core::ed25519::Public>,
@@ -481,11 +465,7 @@ pub(crate) mod tests {
let mut authority_set_changes = AuthoritySetChanges::empty();
authority_set_changes.append(1, 8);
let proof_of_6 = prove_finality(
&*backend,
authority_set_changes,
6,
);
let proof_of_6 = prove_finality(&*backend, authority_set_changes, 6);
assert!(matches!(proof_of_6, Err(FinalityProofError::BlockNotInAuthoritySetChanges)));
}
@@ -499,11 +479,9 @@ pub(crate) mod tests {
let commit = create_commit(block8.clone(), round, 1, &[Ed25519Keyring::Alice]);
let grandpa_just8 = GrandpaJustification::from_commit(&client, round, commit).unwrap();
client.finalize_block(
BlockId::Number(8),
Some((ID, grandpa_just8.encode().clone()))
)
.unwrap();
client
.finalize_block(BlockId::Number(8), Some((ID, grandpa_just8.encode().clone())))
.unwrap();
// Authority set change at block 8, so the justification stored there will be used in the
// FinalityProof for block 6
@@ -512,13 +490,7 @@ pub(crate) mod tests {
authority_set_changes.append(1, 8);
let proof_of_6: FinalityProof = Decode::decode(
&mut &prove_finality(
&*backend,
authority_set_changes.clone(),
6,
)
.unwrap()
.unwrap()[..],
&mut &prove_finality(&*backend, authority_set_changes.clone(), 6).unwrap().unwrap()[..],
)
.unwrap();
assert_eq!(
@@ -540,10 +512,7 @@ pub(crate) mod tests {
let mut authority_set_changes = AuthoritySetChanges::empty();
authority_set_changes.append(0, 5);
assert!(matches!(
prove_finality(&*backend, authority_set_changes, 6),
Ok(None),
));
assert!(matches!(prove_finality(&*backend, authority_set_changes, 6), Ok(None),));
}
#[test]
@@ -563,13 +532,7 @@ pub(crate) mod tests {
authority_set_changes.append(0, 5);
let proof_of_6: FinalityProof = Decode::decode(
&mut &prove_finality(
&*backend,
authority_set_changes,
6,
)
.unwrap()
.unwrap()[..],
&mut &prove_finality(&*backend, authority_set_changes, 6).unwrap().unwrap()[..],
)
.unwrap();
assert_eq!(
+51 -62
View File
@@ -31,9 +31,11 @@ use sp_consensus::{
ImportResult, JustificationImport, SelectChain,
};
use sp_finality_grandpa::{ConsensusLog, ScheduledChange, SetId, GRANDPA_ENGINE_ID};
use sp_runtime::generic::{BlockId, OpaqueDigestItemId};
use sp_runtime::traits::{Block as BlockT, DigestFor, Header as HeaderT, NumberFor, Zero};
use sp_runtime::Justification;
use sp_runtime::{
generic::{BlockId, OpaqueDigestItemId},
traits::{Block as BlockT, DigestFor, Header as HeaderT, NumberFor, Zero},
Justification,
};
use sp_utils::mpsc::TracingUnboundedSender;
use crate::{
@@ -98,12 +100,8 @@ where
let chain_info = self.inner.info();
// request justifications for all pending changes for which change blocks have already been imported
let pending_changes: Vec<_> = self
.authority_set
.inner()
.pending_changes()
.cloned()
.collect();
let pending_changes: Vec<_> =
self.authority_set.inner().pending_changes().cloned().collect();
for pending_change in pending_changes {
if pending_change.delay_kind == DelayKind::Finalized &&
@@ -241,7 +239,7 @@ where
) -> Option<PendingChange<Block::Hash, NumberFor<Block>>> {
// check for forced authority set hard forks
if let Some(change) = self.authority_set_hard_forks.get(&hash) {
return Some(change.clone());
return Some(change.clone())
}
// check for forced change.
@@ -252,7 +250,7 @@ where
canon_height: *header.number(),
canon_hash: hash,
delay_kind: DelayKind::Best { median_last_finalized },
});
})
}
// check normal scheduled change.
@@ -295,10 +293,9 @@ where
fn consume(
mut self,
) -> Option<(AuthoritySet<H, N>, SharedDataLocked<'a, AuthoritySet<H, N>>)> {
self.old.take().map(|old| (
old,
self.guard.take().expect("only taken on deconstruction; qed"),
))
self.old
.take()
.map(|old| (old, self.guard.take().expect("only taken on deconstruction; qed")))
}
}
@@ -311,20 +308,14 @@ where
}
let number = *(block.header.number());
let maybe_change = self.check_new_change(
&block.header,
hash,
);
let maybe_change = self.check_new_change(&block.header, hash);
// returns a function for checking whether a block is a descendent of another
// consistent with querying client directly after importing the block.
let parent_hash = *block.header.parent_hash();
let is_descendent_of = is_descendent_of(&*self.inner, Some((hash, parent_hash)));
let mut guard = InnerGuard {
guard: Some(self.authority_set.inner_locked()),
old: None,
};
let mut guard = InnerGuard { guard: Some(self.authority_set.inner_locked()), old: None };
// whether to pause the old authority set -- happens after import
// of a forced change block.
@@ -339,10 +330,10 @@ where
do_pause = true;
}
guard.as_mut().add_pending_change(
change,
&is_descendent_of,
).map_err(|e| ConsensusError::ClientImport(e.to_string()))?;
guard
.as_mut()
.add_pending_change(change, &is_descendent_of)
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?;
}
let applied_changes = {
@@ -389,7 +380,9 @@ where
AppliedChanges::Forced(new_authorities)
} else {
let did_standard = guard.as_mut().enacts_standard_change(hash, number, &is_descendent_of)
let did_standard = guard
.as_mut()
.enacts_standard_change(hash, number, &is_descendent_of)
.map_err(|e| ConsensusError::ClientImport(e.to_string()))
.map_err(ConsensusError::from)?;
@@ -413,19 +406,17 @@ where
crate::aux_schema::update_authority_set::<Block, _, _>(
authorities,
authorities_change,
|insert| block.auxiliary.extend(
insert.iter().map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
)
|insert| {
block
.auxiliary
.extend(insert.iter().map(|(k, v)| (k.to_vec(), Some(v.to_vec()))))
},
);
}
let just_in_case = just_in_case.map(|(o, i)| (o, i.release_mutex()));
Ok(PendingSetChanges {
just_in_case,
applied_changes,
do_pause,
})
Ok(PendingSetChanges { just_in_case, applied_changes, do_pause })
}
}
@@ -459,7 +450,7 @@ where
// Strip justifications when re-importing an existing block.
let _justifications = block.justifications.take();
return (&*self.inner).import_block(block, new_cache).await
}
},
Ok(BlockStatus::Unknown) => {},
Err(e) => return Err(ConsensusError::ClientImport(e.to_string())),
}
@@ -483,7 +474,7 @@ where
r,
);
pending_changes.revert();
return Ok(r);
return Ok(r)
},
Err(e) => {
debug!(
@@ -492,7 +483,7 @@ where
e,
);
pending_changes.revert();
return Err(ConsensusError::ClientImport(e.to_string()));
return Err(ConsensusError::ClientImport(e.to_string()))
},
}
};
@@ -501,9 +492,9 @@ where
// Send the pause signal after import but BEFORE sending a `ChangeAuthorities` message.
if do_pause {
let _ = self.send_voter_commands.unbounded_send(
VoterCommand::Pause("Forced change scheduled after inactivity".to_string())
);
let _ = self.send_voter_commands.unbounded_send(VoterCommand::Pause(
"Forced change scheduled after inactivity".to_string(),
));
}
let needs_justification = applied_changes.needs_justification();
@@ -521,7 +512,8 @@ where
// they should import the block and discard the justification, and they will
// then request a justification from sync if it's necessary (which they should
// then be able to successfully validate).
let _ = self.send_voter_commands.unbounded_send(VoterCommand::ChangeAuthorities(new));
let _ =
self.send_voter_commands.unbounded_send(VoterCommand::ChangeAuthorities(new));
// we must clear all pending justifications requests, presumably they won't be
// finalized hence why this forced changes was triggered
@@ -537,8 +529,8 @@ where
_ => {},
}
let grandpa_justification = justifications
.and_then(|just| just.into_justification(GRANDPA_ENGINE_ID));
let grandpa_justification =
justifications.and_then(|just| just.into_justification(GRANDPA_ENGINE_ID));
match grandpa_justification {
Some(justification) => {
@@ -559,7 +551,7 @@ where
}
});
},
None => {
None =>
if needs_justification {
debug!(
target: "afg",
@@ -568,8 +560,7 @@ where
);
imported_aux.needs_justification = true;
}
}
},
}
Ok(ImportResult::Imported(imported_aux))
@@ -616,14 +607,9 @@ impl<Backend, Block: BlockT, Client, SC> GrandpaBlockImport<Backend, Block, Clie
{
let mut authority_set = authority_set.inner();
authority_set.pending_standard_changes = authority_set
.pending_standard_changes
.clone()
.map(&mut |hash, _, original| {
authority_set_hard_forks
.get(&hash)
.cloned()
.unwrap_or(original)
authority_set.pending_standard_changes =
authority_set.pending_standard_changes.clone().map(&mut |hash, _, original| {
authority_set_hard_forks.get(&hash).cloned().unwrap_or(original)
});
}
@@ -664,7 +650,7 @@ where
// justification import pipeline similar to what we do for `BlockImport`. In the
// meantime we'll just drop the justification, since this is only used for BEEFY which
// is still WIP.
return Ok(());
return Ok(())
}
let justification = GrandpaJustification::decode_and_verify_finalizes(
@@ -693,7 +679,8 @@ where
match result {
Err(CommandOrError::VoterCommand(command)) => {
afg_log!(initial_sync,
afg_log!(
initial_sync,
"👴 Imported justification for block #{} that triggers \
command {}, signaling voter.",
number,
@@ -703,7 +690,7 @@ where
// send the command to the voter
let _ = self.send_voter_commands.unbounded_send(command);
},
Err(CommandOrError::Error(e)) => {
Err(CommandOrError::Error(e)) =>
return Err(match e {
Error::Grandpa(error) => ConsensusError::ClientImport(error.to_string()),
Error::Network(error) => ConsensusError::ClientImport(error),
@@ -713,10 +700,12 @@ where
Error::Signing(error) => ConsensusError::ClientImport(error),
Error::Timer(error) => ConsensusError::ClientImport(error.to_string()),
Error::RuntimeApi(error) => ConsensusError::ClientImport(error.to_string()),
});
},
}),
Ok(_) => {
assert!(!enacts_change, "returns Ok when no authority set change should be enacted; qed;");
assert!(
!enacts_change,
"returns Ok when no authority set change should be enacted; qed;"
);
},
}
@@ -16,8 +16,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use finality_grandpa::{voter_set::VoterSet, Error as GrandpaError};
use parity_scale_codec::{Decode, Encode};
@@ -52,7 +54,8 @@ impl<Block: BlockT> GrandpaJustification<Block> {
client: &Arc<C>,
round: u64,
commit: Commit<Block>,
) -> Result<GrandpaJustification<Block>, Error> where
) -> Result<GrandpaJustification<Block>, Error>
where
C: HeaderBackend<Block>,
{
let mut votes_ancestries_hashes = HashSet::new();
@@ -66,12 +69,14 @@ impl<Block: BlockT> GrandpaJustification<Block> {
for signed in commit.precommits.iter() {
let mut current_hash = signed.precommit.target_hash;
loop {
if current_hash == commit.target_hash { break; }
if current_hash == commit.target_hash {
break
}
match client.header(BlockId::Hash(current_hash))? {
Some(current_header) => {
if *current_header.number() <= commit.target_number {
return error();
return error()
}
let parent_hash = *current_header.parent_hash();
@@ -95,20 +100,20 @@ impl<Block: BlockT> GrandpaJustification<Block> {
finalized_target: (Block::Hash, NumberFor<Block>),
set_id: u64,
voters: &VoterSet<AuthorityId>,
) -> Result<GrandpaJustification<Block>, ClientError> where
) -> Result<GrandpaJustification<Block>, ClientError>
where
NumberFor<Block>: finality_grandpa::BlockNumberOps,
{
let justification = GrandpaJustification::<Block>::decode(&mut &*encoded)
.map_err(|_| ClientError::JustificationDecode)?;
if (justification.commit.target_hash, justification.commit.target_number) != finalized_target {
if (justification.commit.target_hash, justification.commit.target_number) !=
finalized_target
{
let msg = "invalid commit target in grandpa justification".to_string();
Err(ClientError::BadJustification(msg))
} else {
justification
.verify_with_voter_set(set_id, voters)
.map(|_| justification)
justification.verify_with_voter_set(set_id, voters).map(|_| justification)
}
}
@@ -117,9 +122,8 @@ impl<Block: BlockT> GrandpaJustification<Block> {
where
NumberFor<Block>: finality_grandpa::BlockNumberOps,
{
let voters = VoterSet::new(authorities.iter().cloned()).ok_or(ClientError::Consensus(
sp_consensus::Error::InvalidAuthoritiesSet,
))?;
let voters = VoterSet::new(authorities.iter().cloned())
.ok_or(ClientError::Consensus(sp_consensus::Error::InvalidAuthoritiesSet))?;
self.verify_with_voter_set(set_id, &voters)
}
@@ -137,16 +141,12 @@ impl<Block: BlockT> GrandpaJustification<Block> {
let ancestry_chain = AncestryChain::<Block>::new(&self.votes_ancestries);
match finality_grandpa::validate_commit(
&self.commit,
voters,
&ancestry_chain,
) {
match finality_grandpa::validate_commit(&self.commit, voters, &ancestry_chain) {
Ok(ref result) if result.ghost().is_some() => {},
_ => {
let msg = "invalid commit in grandpa justification".to_string();
return Err(ClientError::BadJustification(msg));
}
return Err(ClientError::BadJustification(msg))
},
}
let mut buf = Vec::new();
@@ -161,11 +161,12 @@ impl<Block: BlockT> GrandpaJustification<Block> {
&mut buf,
) {
return Err(ClientError::BadJustification(
"invalid signature for precommit in grandpa justification".to_string()));
"invalid signature for precommit in grandpa justification".to_string(),
))
}
if self.commit.target_hash == signed.precommit.target_hash {
continue;
continue
}
match ancestry_chain.ancestry(self.commit.target_hash, signed.precommit.target_hash) {
@@ -176,21 +177,21 @@ impl<Block: BlockT> GrandpaJustification<Block> {
visited_hashes.insert(hash);
}
},
_ => {
_ =>
return Err(ClientError::BadJustification(
"invalid precommit ancestry proof in grandpa justification".to_string()));
},
"invalid precommit ancestry proof in grandpa justification".to_string(),
)),
}
}
let ancestry_hashes = self.votes_ancestries
.iter()
.map(|h: &Block::Header| h.hash())
.collect();
let ancestry_hashes =
self.votes_ancestries.iter().map(|h: &Block::Header| h.hash()).collect();
if visited_hashes != ancestry_hashes {
return Err(ClientError::BadJustification(
"invalid precommit ancestries in grandpa justification with unused headers".to_string()));
"invalid precommit ancestries in grandpa justification with unused headers"
.to_string(),
))
}
Ok(())
@@ -211,24 +212,28 @@ struct AncestryChain<Block: BlockT> {
impl<Block: BlockT> AncestryChain<Block> {
fn new(ancestry: &[Block::Header]) -> AncestryChain<Block> {
let ancestry: HashMap<_, _> = ancestry
.iter()
.cloned()
.map(|h: Block::Header| (h.hash(), h))
.collect();
let ancestry: HashMap<_, _> =
ancestry.iter().cloned().map(|h: Block::Header| (h.hash(), h)).collect();
AncestryChain { ancestry }
}
}
impl<Block: BlockT> finality_grandpa::Chain<Block::Hash, NumberFor<Block>> for AncestryChain<Block> where
NumberFor<Block>: finality_grandpa::BlockNumberOps
impl<Block: BlockT> finality_grandpa::Chain<Block::Hash, NumberFor<Block>> for AncestryChain<Block>
where
NumberFor<Block>: finality_grandpa::BlockNumberOps,
{
fn ancestry(&self, base: Block::Hash, block: Block::Hash) -> Result<Vec<Block::Hash>, GrandpaError> {
fn ancestry(
&self,
base: Block::Hash,
block: Block::Hash,
) -> Result<Vec<Block::Hash>, GrandpaError> {
let mut route = Vec::new();
let mut current_hash = block;
loop {
if current_hash == base { break; }
if current_hash == base {
break
}
match self.ancestry.get(&current_hash) {
Some(current_header) => {
current_hash = *current_header.parent_hash();
+140 -163
View File
@@ -56,41 +56,39 @@
#![warn(missing_docs)]
use futures::{
prelude::*,
StreamExt,
};
use futures::{prelude::*, StreamExt};
use log::{debug, error, info};
use parity_scale_codec::{Decode, Encode};
use parking_lot::RwLock;
use prometheus_endpoint::{PrometheusError, Registry};
use sc_client_api::{
backend::{AuxStore, Backend},
LockImportRun, BlockchainEvents, CallExecutor,
ExecutionStrategy, Finalizer, TransactionFor, ExecutorProvider,
BlockchainEvents, CallExecutor, ExecutionStrategy, ExecutorProvider, Finalizer, LockImportRun,
TransactionFor,
};
use parity_scale_codec::{Decode, Encode};
use prometheus_endpoint::{PrometheusError, Registry};
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO};
use sp_api::ProvideRuntimeApi;
use sp_blockchain::{HeaderBackend, Error as ClientError, HeaderMetadata};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{NumberFor, Block as BlockT, DigestFor, Zero};
use sp_consensus::{SelectChain, BlockImport};
use sp_core::{
crypto::Public,
};
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
use sp_application_crypto::AppKey;
use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata};
use sp_consensus::{BlockImport, SelectChain};
use sp_core::crypto::Public;
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, DigestFor, NumberFor, Zero},
};
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver};
use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_INFO, CONSENSUS_DEBUG};
use parking_lot::RwLock;
use finality_grandpa::Error as GrandpaError;
use finality_grandpa::{voter, voter_set::VoterSet};
pub use finality_grandpa::BlockNumberOps;
use finality_grandpa::{voter, voter_set::VoterSet, Error as GrandpaError};
use std::{fmt, io};
use std::sync::Arc;
use std::time::Duration;
use std::pin::Pin;
use std::task::{Poll, Context};
use std::{
fmt, io,
pin::Pin,
sync::Arc,
task::{Context, Poll},
time::Duration,
};
// utility logging macro that takes as first argument a conditional to
// decide whether to log under debug or info level (useful to restrict
@@ -123,6 +121,7 @@ mod voting_rule;
pub use authorities::{AuthoritySet, AuthoritySetChanges, SharedAuthoritySet};
pub use aux_schema::best_justification;
pub use finality_grandpa::voter::report;
pub use finality_proof::{FinalityProof, FinalityProofError, FinalityProofProvider};
pub use import::{find_forced_change, find_scheduled_change, GrandpaBlockImport};
pub use justification::GrandpaJustification;
@@ -132,13 +131,12 @@ pub use voting_rule::{
BeforeBestBlockBy, ThreeQuartersOfTheUnfinalizedChain, VotingRule, VotingRuleResult,
VotingRulesBuilder,
};
pub use finality_grandpa::voter::report;
use aux_schema::PersistentData;
use communication::{Network as NetworkT, NetworkBridge};
use environment::{Environment, VoterSetState};
use until_imported::UntilGlobalMessageBlocksImported;
use sp_finality_grandpa::{AuthorityList, AuthoritySignature, SetId};
use until_imported::UntilGlobalMessageBlocksImported;
// Re-export these two because it's just so damn convenient.
pub use sp_finality_grandpa::{AuthorityId, AuthorityPair, GrandpaApi, ScheduledChange};
@@ -159,7 +157,8 @@ pub type SignedMessage<Block> = finality_grandpa::SignedMessage<
>;
/// A primary propose message for this chain's block type.
pub type PrimaryPropose<Block> = finality_grandpa::PrimaryPropose<<Block as BlockT>::Hash, NumberFor<Block>>;
pub type PrimaryPropose<Block> =
finality_grandpa::PrimaryPropose<<Block as BlockT>::Hash, NumberFor<Block>>;
/// A prevote message for this chain's block type.
pub type Prevote<Block> = finality_grandpa::Prevote<<Block as BlockT>::Hash, NumberFor<Block>>;
/// A precommit message for this chain's block type.
@@ -198,22 +197,14 @@ type CommunicationIn<Block> = finality_grandpa::voter::CommunicationIn<
/// Global communication input stream for commits and catch up messages, with
/// the hash type not being derived from the block, useful for forcing the hash
/// to some type (e.g. `H256`) when the compiler can't do the inference.
type CommunicationInH<Block, H> = finality_grandpa::voter::CommunicationIn<
H,
NumberFor<Block>,
AuthoritySignature,
AuthorityId,
>;
type CommunicationInH<Block, H> =
finality_grandpa::voter::CommunicationIn<H, NumberFor<Block>, AuthoritySignature, AuthorityId>;
/// Global communication sink for commits with the hash type not being derived
/// from the block, useful for forcing the hash to some type (e.g. `H256`) when
/// the compiler can't do the inference.
type CommunicationOutH<Block, H> = finality_grandpa::voter::CommunicationOut<
H,
NumberFor<Block>,
AuthoritySignature,
AuthorityId,
>;
type CommunicationOutH<Block, H> =
finality_grandpa::voter::CommunicationOut<H, NumberFor<Block>, AuthoritySignature, AuthorityId>;
/// Shared voter state for querying.
pub struct SharedVoterState {
@@ -223,18 +214,14 @@ pub struct SharedVoterState {
impl SharedVoterState {
/// Create a new empty `SharedVoterState` instance.
pub fn empty() -> Self {
Self {
inner: Arc::new(RwLock::new(None)),
}
Self { inner: Arc::new(RwLock::new(None)) }
}
fn reset(
&self,
voter_state: Box<dyn voter::VoterState<AuthorityId> + Sync + Send>,
) -> Option<()> {
let mut shared_voter_state = self
.inner
.try_write_for(Duration::from_secs(1))?;
let mut shared_voter_state = self.inner.try_write_for(Duration::from_secs(1))?;
*shared_voter_state = Some(voter_state);
Some(())
@@ -323,7 +310,8 @@ pub(crate) trait BlockStatus<Block: BlockT> {
fn block_number(&self, hash: Block::Hash) -> Result<Option<NumberFor<Block>>, Error>;
}
impl<Block: BlockT, Client> BlockStatus<Block> for Arc<Client> where
impl<Block: BlockT, Client> BlockStatus<Block> for Arc<Client>
where
Client: HeaderBackend<Block>,
NumberFor<Block>: BlockNumberOps,
{
@@ -337,24 +325,36 @@ impl<Block: BlockT, Client> BlockStatus<Block> for Arc<Client> where
/// Ideally this would be a trait alias, we're not there yet.
/// tracking issue <https://github.com/rust-lang/rust/issues/41517>
pub trait ClientForGrandpa<Block, BE>:
LockImportRun<Block, BE> + Finalizer<Block, BE> + AuxStore
+ HeaderMetadata<Block, Error = sp_blockchain::Error> + HeaderBackend<Block>
+ BlockchainEvents<Block> + ProvideRuntimeApi<Block> + ExecutorProvider<Block>
LockImportRun<Block, BE>
+ Finalizer<Block, BE>
+ AuxStore
+ HeaderMetadata<Block, Error = sp_blockchain::Error>
+ HeaderBackend<Block>
+ BlockchainEvents<Block>
+ ProvideRuntimeApi<Block>
+ ExecutorProvider<Block>
+ BlockImport<Block, Transaction = TransactionFor<BE, Block>, Error = sp_consensus::Error>
where
BE: Backend<Block>,
Block: BlockT,
{}
where
BE: Backend<Block>,
Block: BlockT,
{
}
impl<Block, BE, T> ClientForGrandpa<Block, BE> for T
where
BE: Backend<Block>,
Block: BlockT,
T: LockImportRun<Block, BE> + Finalizer<Block, BE> + AuxStore
+ HeaderMetadata<Block, Error = sp_blockchain::Error> + HeaderBackend<Block>
+ BlockchainEvents<Block> + ProvideRuntimeApi<Block> + ExecutorProvider<Block>
+ BlockImport<Block, Transaction = TransactionFor<BE, Block>, Error = sp_consensus::Error>,
{}
where
BE: Backend<Block>,
Block: BlockT,
T: LockImportRun<Block, BE>
+ Finalizer<Block, BE>
+ AuxStore
+ HeaderMetadata<Block, Error = sp_blockchain::Error>
+ HeaderBackend<Block>
+ BlockchainEvents<Block>
+ ProvideRuntimeApi<Block>
+ ExecutorProvider<Block>
+ BlockImport<Block, Transaction = TransactionFor<BE, Block>, Error = sp_consensus::Error>,
{
}
/// Something that one can ask to do a block sync request.
pub(crate) trait BlockSyncRequester<Block: BlockT> {
@@ -364,14 +364,25 @@ pub(crate) trait BlockSyncRequester<Block: BlockT> {
/// If the given vector of peers is empty then the underlying implementation
/// should make a best effort to fetch the block from any peers it is
/// connected to (NOTE: this assumption will change in the future #3629).
fn set_sync_fork_request(&self, peers: Vec<sc_network::PeerId>, hash: Block::Hash, number: NumberFor<Block>);
fn set_sync_fork_request(
&self,
peers: Vec<sc_network::PeerId>,
hash: Block::Hash,
number: NumberFor<Block>,
);
}
impl<Block, Network> BlockSyncRequester<Block> for NetworkBridge<Block, Network> where
impl<Block, Network> BlockSyncRequester<Block> for NetworkBridge<Block, Network>
where
Block: BlockT,
Network: NetworkT<Block>,
{
fn set_sync_fork_request(&self, peers: Vec<sc_network::PeerId>, hash: Block::Hash, number: NumberFor<Block>) {
fn set_sync_fork_request(
&self,
peers: Vec<sc_network::PeerId>,
hash: Block::Hash,
number: NumberFor<Block>,
) {
NetworkBridge::set_sync_fork_request(self, peers, hash, number)
}
}
@@ -391,7 +402,7 @@ pub(crate) enum VoterCommand<H, N> {
/// Pause the voter for given reason.
Pause(String),
/// New authorities.
ChangeAuthorities(NewAuthoritySet<H, N>)
ChangeAuthorities(NewAuthoritySet<H, N>),
}
impl<H, N> fmt::Display for VoterCommand<H, N> {
@@ -436,7 +447,7 @@ impl<H, N> From<VoterCommand<H, N>> for CommandOrError<H, N> {
}
}
impl<H: fmt::Debug, N: fmt::Debug> ::std::error::Error for CommandOrError<H, N> { }
impl<H: fmt::Debug, N: fmt::Debug> ::std::error::Error for CommandOrError<H, N> {}
impl<H, N> fmt::Display for CommandOrError<H, N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -476,8 +487,10 @@ pub trait GenesisAuthoritySetProvider<Block: BlockT> {
fn get(&self) -> Result<AuthorityList, ClientError>;
}
impl<Block: BlockT, E> GenesisAuthoritySetProvider<Block> for Arc<dyn ExecutorProvider<Block, Executor = E>>
where E: CallExecutor<Block>,
impl<Block: BlockT, E> GenesisAuthoritySetProvider<Block>
for Arc<dyn ExecutorProvider<Block, Executor = E>>
where
E: CallExecutor<Block>,
{
fn get(&self) -> Result<AuthorityList, ClientError> {
// This implementation uses the Grandpa runtime API instead of reading directly from the
@@ -492,10 +505,12 @@ impl<Block: BlockT, E> GenesisAuthoritySetProvider<Block> for Arc<dyn ExecutorPr
None,
)
.and_then(|call_result| {
Decode::decode(&mut &call_result[..])
.map_err(|err| ClientError::CallResultDecode(
"failed to decode GRANDPA authorities set proof", err
))
Decode::decode(&mut &call_result[..]).map_err(|err| {
ClientError::CallResultDecode(
"failed to decode GRANDPA authorities set proof",
err,
)
})
})
}
}
@@ -507,13 +522,7 @@ pub fn block_import<BE, Block: BlockT, Client, SC>(
genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
select_chain: SC,
telemetry: Option<TelemetryHandle>,
) -> Result<
(
GrandpaBlockImport<BE, Block, Client, SC>,
LinkHalf<Block, Client, SC>,
),
ClientError,
>
) -> Result<(GrandpaBlockImport<BE, Block, Client, SC>, LinkHalf<Block, Client, SC>), ClientError>
where
SC: SelectChain<Block>,
BE: Backend<Block> + 'static,
@@ -539,13 +548,7 @@ pub fn block_import_with_authority_set_hard_forks<BE, Block: BlockT, Client, SC>
select_chain: SC,
authority_set_hard_forks: Vec<(SetId, (Block::Hash, NumberFor<Block>), AuthorityList)>,
telemetry: Option<TelemetryHandle>,
) -> Result<
(
GrandpaBlockImport<BE, Block, Client, SC>,
LinkHalf<Block, Client, SC>,
),
ClientError,
>
) -> Result<(GrandpaBlockImport<BE, Block, Client, SC>, LinkHalf<Block, Client, SC>), ClientError>
where
SC: SelectChain<Block>,
BE: Backend<Block> + 'static,
@@ -554,11 +557,8 @@ where
let chain_info = client.info();
let genesis_hash = chain_info.genesis_hash;
let persistent_data = aux_schema::load_persistent(
&*client,
genesis_hash,
<NumberFor<Block>>::zero(),
{
let persistent_data =
aux_schema::load_persistent(&*client, genesis_hash, <NumberFor<Block>>::zero(), {
let telemetry = telemetry.clone();
move || {
let authorities = genesis_authorities_provider.get()?;
@@ -570,13 +570,11 @@ where
);
Ok(authorities)
}
},
)?;
})?;
let (voter_commands_tx, voter_commands_rx) = tracing_unbounded("mpsc_grandpa_voter_command");
let (justification_sender, justification_stream) =
GrandpaJustificationStream::channel();
let (justification_sender, justification_stream) = GrandpaJustificationStream::channel();
// create pending change objects with 0 delay and enacted on finality
// (i.e. standard changes) for each authority set hard fork.
@@ -646,11 +644,8 @@ where
let is_voter = local_authority_id(voters, keystore).is_some();
// verification stream
let (global_in, global_out) = network.global_communication(
communication::SetId(set_id),
voters.clone(),
is_voter,
);
let (global_in, global_out) =
network.global_communication(communication::SetId(set_id), voters.clone(), is_voter);
// block commit and catch up messages until relevant blocks are imported.
let global_in = UntilGlobalMessageBlocksImported::new(
@@ -758,23 +753,18 @@ where
);
let conf = config.clone();
let telemetry_task = if let Some(telemetry_on_connect) = telemetry
.as_ref()
.map(|x| x.on_connect_stream())
{
let authorities = persistent_data.authority_set.clone();
let telemetry = telemetry.clone();
let events = telemetry_on_connect
.for_each(move |_| {
let telemetry_task =
if let Some(telemetry_on_connect) = telemetry.as_ref().map(|x| x.on_connect_stream()) {
let authorities = persistent_data.authority_set.clone();
let telemetry = telemetry.clone();
let events = telemetry_on_connect.for_each(move |_| {
let current_authorities = authorities.current_authorities();
let set_id = authorities.set_id();
let authority_id = local_authority_id(&current_authorities, conf.keystore.as_ref())
.unwrap_or_default();
let authorities = current_authorities
.iter()
.map(|(id, _)| id.to_string())
.collect::<Vec<_>>();
let authorities =
current_authorities.iter().map(|(id, _)| id.to_string()).collect::<Vec<_>>();
let authorities = serde_json::to_string(&authorities).expect(
"authorities is always at least an empty vector; \
@@ -792,10 +782,10 @@ where
future::ready(())
});
future::Either::Left(events)
} else {
future::Either::Right(future::pending())
};
future::Either::Left(events)
} else {
future::Either::Right(future::pending())
};
let voter_work = VoterWork::new(
client,
@@ -819,8 +809,7 @@ where
});
// Make sure that `telemetry_task` doesn't accidentally finish and kill grandpa.
let telemetry_task = telemetry_task
.then(|_| future::pending::<()>());
let telemetry_task = telemetry_task.then(|_| future::pending::<()>());
Ok(future::select(voter_work, telemetry_task).map(drop))
}
@@ -842,7 +831,9 @@ impl Metrics {
/// Future that powers the voter.
#[must_use]
struct VoterWork<B, Block: BlockT, C, N: NetworkT<Block>, SC, VR> {
voter: Pin<Box<dyn Future<Output = Result<(), CommandOrError<Block::Hash, NumberFor<Block>>>> + Send>>,
voter: Pin<
Box<dyn Future<Output = Result<(), CommandOrError<Block::Hash, NumberFor<Block>>>> + Send>,
>,
shared_voter_state: SharedVoterState,
env: Arc<Environment<B, Block, C, N, SC, VR>>,
voter_commands_rx: TracingUnboundedReceiver<VoterCommand<Block::Hash, NumberFor<Block>>>,
@@ -881,7 +872,7 @@ where
Some(Err(e)) => {
debug!(target: "afg", "Failed to register metrics: {:?}", e);
None
}
},
None => None,
};
@@ -937,12 +928,7 @@ where
let chain_info = self.env.client.info();
let authorities = self
.env
.voters
.iter()
.map(|(id, _)| id.to_string())
.collect::<Vec<_>>();
let authorities = self.env.voters.iter().map(|(id, _)| id.to_string()).collect::<Vec<_>>();
let authorities = serde_json::to_string(&authorities).expect(
"authorities is always at least an empty vector; elements are always of type string; qed.",
@@ -961,10 +947,7 @@ where
match &*self.env.voter_set_state.read() {
VoterSetState::Live { completed_rounds, .. } => {
let last_finalized = (
chain_info.finalized_hash,
chain_info.finalized_number,
);
let last_finalized = (chain_info.finalized_hash, chain_info.finalized_number);
let global_comms = global_communication(
self.env.set_id,
@@ -997,20 +980,18 @@ where
self.voter = Box::pin(voter);
},
VoterSetState::Paused { .. } =>
self.voter = Box::pin(future::pending()),
VoterSetState::Paused { .. } => self.voter = Box::pin(future::pending()),
};
}
fn handle_voter_command(
&mut self,
command: VoterCommand<Block::Hash, NumberFor<Block>>
command: VoterCommand<Block::Hash, NumberFor<Block>>,
) -> Result<(), Error> {
match command {
VoterCommand::ChangeAuthorities(new) => {
let voters: Vec<String> = new.authorities.iter().map(move |(a, _)| {
format!("{}", a)
}).collect();
let voters: Vec<String> =
new.authorities.iter().map(move |(a, _)| format!("{}", a)).collect();
telemetry!(
self.telemetry;
CONSENSUS_INFO;
@@ -1034,14 +1015,12 @@ where
Ok(Some(set_state))
})?;
let voters = Arc::new(VoterSet::new(new.authorities.into_iter())
.expect(
"new authorities come from pending change; \
let voters = Arc::new(VoterSet::new(new.authorities.into_iter()).expect(
"new authorities come from pending change; \
pending change comes from `AuthoritySet`; \
`AuthoritySet` validates authorities is non-empty and weights are non-zero; \
qed."
)
);
qed.",
));
self.env = Arc::new(Environment {
voters,
@@ -1061,7 +1040,7 @@ where
self.rebuild_voter();
Ok(())
}
},
VoterCommand::Pause(reason) => {
info!(target: "afg", "Pausing old validator set: {}", reason);
@@ -1076,7 +1055,7 @@ where
self.rebuild_voter();
Ok(())
}
},
}
}
}
@@ -1096,37 +1075,35 @@ where
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
match Future::poll(Pin::new(&mut self.voter), cx) {
Poll::Pending => {}
Poll::Pending => {},
Poll::Ready(Ok(())) => {
// voters don't conclude naturally
return Poll::Ready(
Err(Error::Safety("finality-grandpa inner voter has concluded.".into()))
)
}
return Poll::Ready(Err(Error::Safety(
"finality-grandpa inner voter has concluded.".into(),
)))
},
Poll::Ready(Err(CommandOrError::Error(e))) => {
// return inner observer error
return Poll::Ready(Err(e))
}
},
Poll::Ready(Err(CommandOrError::VoterCommand(command))) => {
// some command issued internally
self.handle_voter_command(command)?;
cx.waker().wake_by_ref();
}
},
}
match Stream::poll_next(Pin::new(&mut self.voter_commands_rx), cx) {
Poll::Pending => {}
Poll::Pending => {},
Poll::Ready(None) => {
// the `voter_commands_rx` stream should never conclude since it's never closed.
return Poll::Ready(
Err(Error::Safety("`voter_commands_rx` was closed.".into()))
)
}
return Poll::Ready(Err(Error::Safety("`voter_commands_rx` was closed.".into())))
},
Poll::Ready(Some(command)) => {
// some command issued externally
self.handle_voter_command(command)?;
cx.waker().wake_by_ref();
}
},
}
Future::poll(Pin::new(&mut self.network), cx)
@@ -1142,10 +1119,10 @@ fn local_authority_id(
) -> Option<AuthorityId> {
keystore.and_then(|keystore| {
voters
.iter()
.find(|(p, _)| {
SyncCryptoStore::has_keys(&**keystore, &[(p.to_raw_vec(), AuthorityId::ID)])
})
.map(|(p, _)| p.clone())
.iter()
.find(|(p, _)| {
SyncCryptoStore::has_keys(&**keystore, &[(p.to_raw_vec(), AuthorityId::ID)])
})
.map(|(p, _)| p.clone())
})
}
@@ -16,14 +16,13 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::sync::Arc;
use parking_lot::Mutex;
use std::sync::Arc;
use sp_runtime::traits::Block as BlockT;
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use crate::justification::GrandpaJustification;
use crate::Error;
use crate::{justification::GrandpaJustification, Error};
// Stream of justifications returned when subscribing.
type JustificationStream<Block> = TracingUnboundedReceiver<GrandpaJustification<Block>>;
@@ -41,16 +40,14 @@ type SharedJustificationSenders<Block> = Arc<Mutex<Vec<JustificationSender<Block
/// at the end of a Grandpa round.
#[derive(Clone)]
pub struct GrandpaJustificationSender<Block: BlockT> {
subscribers: SharedJustificationSenders<Block>
subscribers: SharedJustificationSenders<Block>,
}
impl<Block: BlockT> GrandpaJustificationSender<Block> {
/// The `subscribers` should be shared with a corresponding
/// `GrandpaJustificationStream`.
fn new(subscribers: SharedJustificationSenders<Block>) -> Self {
Self {
subscribers,
}
Self { subscribers }
}
/// Send out a notification to all subscribers that a new justification
@@ -83,7 +80,7 @@ impl<Block: BlockT> GrandpaJustificationSender<Block> {
/// so it can be used to add more subscriptions.
#[derive(Clone)]
pub struct GrandpaJustificationStream<Block: BlockT> {
subscribers: SharedJustificationSenders<Block>
subscribers: SharedJustificationSenders<Block>,
}
impl<Block: BlockT> GrandpaJustificationStream<Block> {
@@ -100,9 +97,7 @@ impl<Block: BlockT> GrandpaJustificationStream<Block> {
/// The `subscribers` should be shared with a corresponding
/// `GrandpaJustificationSender`.
fn new(subscribers: SharedJustificationSenders<Block>) -> Self {
Self {
subscribers,
}
Self { subscribers }
}
/// Subscribe to a channel through which justifications are sent
@@ -16,10 +16,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::marker::{PhantomData, Unpin};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::{
marker::{PhantomData, Unpin},
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use finality_grandpa::{voter, voter_set::VoterSet, BlockNumberOps, Error as GrandpaError};
use futures::prelude::*;
@@ -95,14 +97,14 @@ where
},
voter::CommunicationIn::CatchUp(..) => {
// ignore catch up messages
return future::ok(last_finalized_number);
return future::ok(last_finalized_number)
},
};
// if the commit we've received targets a block lower or equal to the last
// finalized, ignore it and continue with the current state
if commit.target_number <= last_finalized_number {
return future::ok(last_finalized_number);
return future::ok(last_finalized_number)
}
let validation_result = match finality_grandpa::validate_commit(
@@ -201,11 +203,9 @@ where
telemetry.clone(),
);
let observer_work = observer_work
.map_ok(|_| ())
.map_err(|e| {
warn!("GRANDPA Observer failed: {:?}", e);
});
let observer_work = observer_work.map_ok(|_| ()).map_err(|e| {
warn!("GRANDPA Observer failed: {:?}", e);
});
Ok(observer_work.map(drop))
}
@@ -213,7 +213,8 @@ where
/// Future that powers the observer.
#[must_use]
struct ObserverWork<B: BlockT, BE, Client, N: NetworkT<B>> {
observer: Pin<Box<dyn Future<Output = Result<(), CommandOrError<B::Hash, NumberFor<B>>>> + Send>>,
observer:
Pin<Box<dyn Future<Output = Result<(), CommandOrError<B::Hash, NumberFor<B>>>> + Send>>,
client: Arc<Client>,
network: NetworkBridge<B, N>,
persistent_data: PersistentData<B>,
@@ -285,11 +286,13 @@ where
let network = self.network.clone();
let voters = voters.clone();
move |round| network.note_round(
crate::communication::Round(round),
crate::communication::SetId(set_id),
&*voters,
)
move |round| {
network.note_round(
crate::communication::Round(round),
crate::communication::SetId(set_id),
&*voters,
)
}
};
// create observer for the current set
@@ -337,7 +340,8 @@ where
set_state
},
}.into();
}
.into();
self.rebuild_observer();
Ok(())
@@ -356,33 +360,33 @@ where
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
match Future::poll(Pin::new(&mut self.observer), cx) {
Poll::Pending => {}
Poll::Pending => {},
Poll::Ready(Ok(())) => {
// observer commit stream doesn't conclude naturally; this could reasonably be an error.
return Poll::Ready(Ok(()))
}
},
Poll::Ready(Err(CommandOrError::Error(e))) => {
// return inner observer error
return Poll::Ready(Err(e))
}
},
Poll::Ready(Err(CommandOrError::VoterCommand(command))) => {
// some command issued internally
self.handle_voter_command(command)?;
cx.waker().wake_by_ref();
}
},
}
match Stream::poll_next(Pin::new(&mut self.voter_commands_rx), cx) {
Poll::Pending => {}
Poll::Pending => {},
Poll::Ready(None) => {
// the `voter_commands_rx` stream should never conclude since it's never closed.
return Poll::Ready(Ok(()))
}
},
Poll::Ready(Some(command)) => {
// some command issued externally
self.handle_voter_command(command)?;
cx.waker().wake_by_ref();
}
},
}
Future::poll(Pin::new(&mut self.network), cx)
@@ -393,12 +397,15 @@ where
mod tests {
use super::*;
use crate::{
aux_schema,
communication::tests::{make_test_network, Event},
};
use assert_matches::assert_matches;
use sp_utils::mpsc::tracing_unbounded;
use crate::{aux_schema, communication::tests::{Event, make_test_network}};
use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt};
use sc_network::PeerId;
use sp_blockchain::HeaderBackend as _;
use sp_utils::mpsc::tracing_unbounded;
use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt};
use futures::executor;
@@ -426,12 +433,9 @@ mod tests {
let voters = vec![(sp_keyring::Ed25519Keyring::Alice.public().into(), 1)];
let persistent_data = aux_schema::load_persistent(
&*backend,
client.info().genesis_hash,
0,
|| Ok(voters),
).unwrap();
let persistent_data =
aux_schema::load_persistent(&*backend, client.info().genesis_hash, 0, || Ok(voters))
.unwrap();
let (_tx, voter_command_rx) = tracing_unbounded("");
+258 -257
View File
@@ -21,31 +21,37 @@
use super::*;
use assert_matches::assert_matches;
use environment::HasVoted;
use sc_network_test::{
Block, BlockImportAdapter, Hash, PassThroughVerifier, Peer, PeersClient, PeersFullClient,
TestClient, TestNetFactory, FullPeerConfig,
};
use sc_network::config::{ProtocolConfig, Role};
use parking_lot::{RwLock, Mutex};
use futures_timer::Delay;
use futures::executor::block_on;
use tokio::runtime::{Runtime, Handle};
use sp_keyring::Ed25519Keyring;
use sp_blockchain::Result;
use futures_timer::Delay;
use parking_lot::{Mutex, RwLock};
use sc_network::config::{ProtocolConfig, Role};
use sc_network_test::{
Block, BlockImportAdapter, FullPeerConfig, Hash, PassThroughVerifier, Peer, PeersClient,
PeersFullClient, TestClient, TestNetFactory,
};
use sp_api::{ApiRef, ProvideRuntimeApi};
use substrate_test_runtime_client::runtime::BlockNumber;
use sp_blockchain::Result;
use sp_consensus::{
BlockOrigin, ForkChoiceStrategy, ImportedAux, BlockImportParams, ImportResult, BlockImport,
import_queue::BoxJustificationImport,
import_queue::BoxJustificationImport, BlockImport, BlockImportParams, BlockOrigin,
ForkChoiceStrategy, ImportResult, ImportedAux,
};
use std::{collections::{HashMap, HashSet}, pin::Pin};
use sp_runtime::{Justifications, traits::{Block as BlockT, Header as HeaderT}};
use sp_runtime::generic::{BlockId, DigestItem};
use sp_core::H256;
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
use sp_finality_grandpa::{
GRANDPA_ENGINE_ID, AuthorityList, EquivocationProof, GrandpaApi, OpaqueKeyOwnershipProof,
AuthorityList, EquivocationProof, GrandpaApi, OpaqueKeyOwnershipProof, GRANDPA_ENGINE_ID,
};
use sp_keyring::Ed25519Keyring;
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::{
generic::{BlockId, DigestItem},
traits::{Block as BlockT, Header as HeaderT},
Justifications,
};
use std::{
collections::{HashMap, HashSet},
pin::Pin,
};
use substrate_test_runtime_client::runtime::BlockNumber;
use tokio::runtime::{Handle, Runtime};
use authorities::AuthoritySet;
use sc_block_builder::BlockBuilderProvider;
@@ -61,7 +67,7 @@ type GrandpaBlockImport = crate::GrandpaBlockImport<
substrate_test_runtime_client::Backend,
Block,
PeersFullClient,
LongestChain<substrate_test_runtime_client::Backend, Block>
LongestChain<substrate_test_runtime_client::Backend, Block>,
>;
struct GrandpaTestNet {
@@ -71,10 +77,8 @@ struct GrandpaTestNet {
impl GrandpaTestNet {
fn new(test_config: TestApi, n_authority: usize, n_full: usize) -> Self {
let mut net = GrandpaTestNet {
peers: Vec::with_capacity(n_authority + n_full),
test_config,
};
let mut net =
GrandpaTestNet { peers: Vec::with_capacity(n_authority + n_full), test_config };
for _ in 0..n_authority {
net.add_authority_peer();
@@ -105,10 +109,7 @@ impl TestNetFactory for GrandpaTestNet {
/// Create new test network with peers and given config.
fn from_config(_config: &ProtocolConfig) -> Self {
GrandpaTestNet {
peers: Vec::new(),
test_config: Default::default(),
}
GrandpaTestNet { peers: Vec::new(), test_config: Default::default() }
}
fn default_config() -> ProtocolConfig {
@@ -133,13 +134,10 @@ impl TestNetFactory for GrandpaTestNet {
PassThroughVerifier::new(false) // use non-instant finality.
}
fn make_block_import(&self, client: PeersClient)
-> (
BlockImportAdapter<Self::BlockImport>,
Option<BoxJustificationImport<Block>>,
PeerData,
)
{
fn make_block_import(
&self,
client: PeersClient,
) -> (BlockImportAdapter<Self::BlockImport>, Option<BoxJustificationImport<Block>>, PeerData) {
match client {
PeersClient::Full(ref client, ref backend) => {
let (import, link) = block_import(
@@ -147,7 +145,8 @@ impl TestNetFactory for GrandpaTestNet {
&self.test_config,
LongestChain::new(backend.clone()),
None,
).expect("Could not create block import for fresh peer.");
)
.expect("Could not create block import for fresh peer.");
let justification_import = Box::new(import.clone());
(
BlockImportAdapter::new(import),
@@ -181,9 +180,7 @@ pub(crate) struct TestApi {
impl TestApi {
pub fn new(genesis_authorities: AuthorityList) -> Self {
TestApi {
genesis_authorities,
}
TestApi { genesis_authorities }
}
}
@@ -235,21 +232,24 @@ fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList {
fn create_keystore(authority: Ed25519Keyring) -> (SyncCryptoStorePtr, tempfile::TempDir) {
let keystore_path = tempfile::tempdir().expect("Creates keystore path");
let keystore = Arc::new(LocalKeystore::open(keystore_path.path(), None)
.expect("Creates keystore"));
let keystore =
Arc::new(LocalKeystore::open(keystore_path.path(), None).expect("Creates keystore"));
SyncCryptoStore::ed25519_generate_new(&*keystore, GRANDPA, Some(&authority.to_seed()))
.expect("Creates authority key");
(keystore, keystore_path)
}
fn block_until_complete(future: impl Future + Unpin, net: &Arc<Mutex<GrandpaTestNet>>, runtime: &mut Runtime) {
fn block_until_complete(
future: impl Future + Unpin,
net: &Arc<Mutex<GrandpaTestNet>>,
runtime: &mut Runtime,
) {
let drive_to_completion = futures::future::poll_fn(|cx| {
net.lock().poll(cx); Poll::<()>::Pending
net.lock().poll(cx);
Poll::<()>::Pending
});
runtime.block_on(
future::select(future, drive_to_completion)
);
runtime.block_on(future::select(future, drive_to_completion));
}
// Spawns grandpa voters. Returns a future to spawn on the runtime.
@@ -264,11 +264,9 @@ fn initialize_grandpa(
let (net_service, link) = {
// temporary needed for some reason
let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(
net.peers[peer_id].network_service().clone(),
link,
)
let link =
net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(net.peers[peer_id].network_service().clone(), link)
};
let grandpa_params = GrandpaParams {
@@ -288,9 +286,10 @@ fn initialize_grandpa(
shared_voter_state: SharedVoterState::empty(),
telemetry: None,
};
let voter = run_grandpa_voter(grandpa_params).expect("all in order with client and network");
let voter =
run_grandpa_voter(grandpa_params).expect("all in order with client and network");
fn assert_send<T: Send>(_: &T) { }
fn assert_send<T: Send>(_: &T) {}
assert_send(&voter);
voters.push(voter);
@@ -307,8 +306,9 @@ fn run_to_completion_with<F>(
net: Arc<Mutex<GrandpaTestNet>>,
peers: &[Ed25519Keyring],
with: F,
) -> u64 where
F: FnOnce(Handle) -> Option<Pin<Box<dyn Future<Output = ()>>>>
) -> u64
where
F: FnOnce(Handle) -> Option<Pin<Box<dyn Future<Output = ()>>>>,
{
let mut wait_for = Vec::new();
@@ -322,20 +322,19 @@ fn run_to_completion_with<F>(
let highest_finalized = highest_finalized.clone();
let client = net.lock().peers[peer_id].client().clone();
wait_for.push(
Box::pin(
client.finality_notification_stream()
.take_while(move |n| {
let mut highest_finalized = highest_finalized.write();
if *n.header.number() > *highest_finalized {
*highest_finalized = *n.header.number();
}
future::ready(n.header.number() < &blocks)
})
.collect::<Vec<_>>()
.map(|_| ())
)
);
wait_for.push(Box::pin(
client
.finality_notification_stream()
.take_while(move |n| {
let mut highest_finalized = highest_finalized.write();
if *n.header.number() > *highest_finalized {
*highest_finalized = *n.header.number();
}
future::ready(n.header.number() < &blocks)
})
.collect::<Vec<_>>()
.map(|_| ()),
));
}
// wait for all finalized on each.
@@ -350,7 +349,7 @@ fn run_to_completion(
runtime: &mut Runtime,
blocks: u64,
net: Arc<Mutex<GrandpaTestNet>>,
peers: &[Ed25519Keyring]
peers: &[Ed25519Keyring],
) -> u64 {
run_to_completion_with(runtime, blocks, net, peers, |_| None)
}
@@ -386,8 +385,7 @@ fn finalize_3_voters_no_observers() {
net.block_until_sync();
for i in 0..3 {
assert_eq!(net.peer(i).client().info().best_number, 20,
"Peer #{} failed to sync", i);
assert_eq!(net.peer(i).client().info().best_number, 20, "Peer #{} failed to sync", i);
}
let net = Arc::new(Mutex::new(net));
@@ -395,7 +393,12 @@ fn finalize_3_voters_no_observers() {
// normally there's no justification for finalized blocks
assert!(
net.lock().peer(0).client().justifications(&BlockId::Number(20)).unwrap().is_none(),
net.lock()
.peer(0)
.client()
.justifications(&BlockId::Number(20))
.unwrap()
.is_none(),
"Extra justification for block#1",
);
}
@@ -425,7 +428,7 @@ fn finalize_3_voters_1_full_observer() {
observer_enabled: true,
telemetry: None,
},
link: link,
link,
network: net_service,
voting_rule: (),
prometheus_registry: None,
@@ -444,9 +447,10 @@ fn finalize_3_voters_1_full_observer() {
for peer_id in 0..4 {
let client = net.lock().peers[peer_id].client().clone();
finality_notifications.push(
client.finality_notification_stream()
client
.finality_notification_stream()
.take_while(|n| future::ready(n.header.number() < &20))
.for_each(move |_| future::ready(()))
.for_each(move |_| future::ready(())),
);
}
@@ -458,9 +462,8 @@ fn finalize_3_voters_1_full_observer() {
// all peers should have stored the justification for the best finalized block #20
for peer_id in 0..4 {
let client = net.lock().peers[peer_id].client().as_full().unwrap();
let justification = crate::aux_schema::best_justification::<_, Block>(&*client)
.unwrap()
.unwrap();
let justification =
crate::aux_schema::best_justification::<_, Block>(&*client).unwrap().unwrap();
assert_eq!(justification.commit.target_number, 20);
}
@@ -469,27 +472,16 @@ fn finalize_3_voters_1_full_observer() {
#[test]
fn transition_3_voters_twice_1_full_observer() {
sp_tracing::try_init_simple();
let peers_a = &[
Ed25519Keyring::Alice,
Ed25519Keyring::Bob,
Ed25519Keyring::Charlie,
];
let peers_a = &[Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
let peers_b = &[
Ed25519Keyring::Dave,
Ed25519Keyring::Eve,
Ed25519Keyring::Ferdie,
];
let peers_b = &[Ed25519Keyring::Dave, Ed25519Keyring::Eve, Ed25519Keyring::Ferdie];
let peers_c = &[
Ed25519Keyring::Alice,
Ed25519Keyring::Eve,
Ed25519Keyring::Two,
];
let peers_c = &[Ed25519Keyring::Alice, Ed25519Keyring::Eve, Ed25519Keyring::Two];
let observer = &[Ed25519Keyring::One];
let all_peers = peers_a.iter()
let all_peers = peers_a
.iter()
.chain(peers_b)
.chain(peers_c)
.chain(observer)
@@ -511,11 +503,9 @@ fn transition_3_voters_twice_1_full_observer() {
let (net_service, link) = {
let net = net.lock();
let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(
net.peers[peer_id].network_service().clone(),
link,
)
let link =
net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(net.peers[peer_id].network_service().clone(), link)
};
let grandpa_params = GrandpaParams {
@@ -536,7 +526,8 @@ fn transition_3_voters_twice_1_full_observer() {
telemetry: None,
};
voters.push(run_grandpa_voter(grandpa_params).expect("all in order with client and network"));
voters
.push(run_grandpa_voter(grandpa_params).expect("all in order with client and network"));
}
net.lock().peer(0).push_blocks(1, false);
@@ -544,10 +535,10 @@ fn transition_3_voters_twice_1_full_observer() {
for (i, peer) in net.lock().peers().iter().enumerate() {
let full_client = peer.client().as_full().expect("only full clients are used in test");
assert_eq!(full_client.chain_info().best_number, 1,
"Peer #{} failed to sync", i);
assert_eq!(full_client.chain_info().best_number, 1, "Peer #{} failed to sync", i);
let set: AuthoritySet<Hash, BlockNumber> = crate::aux_schema::load_authorities(&*full_client).unwrap();
let set: AuthoritySet<Hash, BlockNumber> =
crate::aux_schema::load_authorities(&*full_client).unwrap();
assert_eq!(set.current(), (0, make_ids(peers_a).as_slice()));
assert_eq!(set.pending_changes().count(), 0);
@@ -559,7 +550,8 @@ fn transition_3_voters_twice_1_full_observer() {
let peers_c = peers_c.clone();
// wait for blocks to be finalized before generating new ones
let block_production = client.finality_notification_stream()
let block_production = client
.finality_notification_stream()
.take_while(|n| future::ready(n.header.number() < &30))
.for_each(move |n| {
match n.header.number() {
@@ -571,10 +563,10 @@ fn transition_3_voters_twice_1_full_observer() {
// generate transition at block 15, applied at 20.
net.lock().peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
let mut block = builder.build().unwrap().block;
add_scheduled_change(&mut block, ScheduledChange {
next_authorities: make_ids(peers_b),
delay: 4,
});
add_scheduled_change(
&mut block,
ScheduledChange { next_authorities: make_ids(peers_b), delay: 4 },
);
block
});
@@ -585,10 +577,10 @@ fn transition_3_voters_twice_1_full_observer() {
// add more until we have 30.
net.lock().peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
let mut block = builder.build().unwrap().block;
add_scheduled_change(&mut block, ScheduledChange {
next_authorities: make_ids(&peers_c),
delay: 0,
});
add_scheduled_change(
&mut block,
ScheduledChange { next_authorities: make_ids(&peers_c), delay: 0 },
);
block
});
@@ -612,16 +604,18 @@ fn transition_3_voters_twice_1_full_observer() {
for (peer_id, _) in all_peers.into_iter().enumerate() {
let client = net.lock().peers[peer_id].client().clone();
finality_notifications.push(
client.finality_notification_stream()
client
.finality_notification_stream()
.take_while(|n| future::ready(n.header.number() < &30))
.for_each(move |_| future::ready(()))
.map(move |()| {
let full_client = client.as_full().expect("only full clients are used in test");
let set: AuthoritySet<Hash, BlockNumber> = crate::aux_schema::load_authorities(&*full_client).unwrap();
let set: AuthoritySet<Hash, BlockNumber> =
crate::aux_schema::load_authorities(&*full_client).unwrap();
assert_eq!(set.current(), (2, make_ids(peers_c).as_slice()));
assert_eq!(set.pending_changes().count(), 0);
})
}),
);
}
@@ -648,7 +642,13 @@ fn justification_is_generated_periodically() {
// when block#32 (justification_period) is finalized, justification
// is required => generated
for i in 0..3 {
assert!(net.lock().peer(i).client().justifications(&BlockId::Number(32)).unwrap().is_some());
assert!(net
.lock()
.peer(i)
.client()
.justifications(&BlockId::Number(32))
.unwrap()
.is_some());
}
}
@@ -670,10 +670,10 @@ fn sync_justifications_on_change_blocks() {
// at block 21 we do add a transition which is instant
net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
let mut block = builder.build().unwrap().block;
add_scheduled_change(&mut block, ScheduledChange {
next_authorities: make_ids(peers_b),
delay: 0,
});
add_scheduled_change(
&mut block,
ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 },
);
block
});
@@ -682,8 +682,7 @@ fn sync_justifications_on_change_blocks() {
net.block_until_sync();
for i in 0..4 {
assert_eq!(net.peer(i).client().info().best_number, 25,
"Peer #{} failed to sync", i);
assert_eq!(net.peer(i).client().info().best_number, 25, "Peer #{} failed to sync", i);
}
let net = Arc::new(Mutex::new(net));
@@ -693,12 +692,25 @@ fn sync_justifications_on_change_blocks() {
// the first 3 peers are grandpa voters and therefore have already finalized
// block 21 and stored a justification
for i in 0..3 {
assert!(net.lock().peer(i).client().justifications(&BlockId::Number(21)).unwrap().is_some());
assert!(net
.lock()
.peer(i)
.client()
.justifications(&BlockId::Number(21))
.unwrap()
.is_some());
}
// the last peer should get the justification by syncing from other peers
futures::executor::block_on(futures::future::poll_fn(move |cx| {
if net.lock().peer(3).client().justifications(&BlockId::Number(21)).unwrap().is_none() {
if net
.lock()
.peer(3)
.client()
.justifications(&BlockId::Number(21))
.unwrap()
.is_none()
{
net.lock().poll(cx);
Poll::Pending
} else {
@@ -717,8 +729,12 @@ fn finalizes_multiple_pending_changes_in_order() {
let peers_c = &[Ed25519Keyring::Dave, Ed25519Keyring::Alice, Ed25519Keyring::Bob];
let all_peers = &[
Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie,
Ed25519Keyring::Dave, Ed25519Keyring::Eve, Ed25519Keyring::Ferdie,
Ed25519Keyring::Alice,
Ed25519Keyring::Bob,
Ed25519Keyring::Charlie,
Ed25519Keyring::Dave,
Ed25519Keyring::Eve,
Ed25519Keyring::Ferdie,
];
let genesis_voters = make_ids(peers_a);
@@ -735,10 +751,10 @@ fn finalizes_multiple_pending_changes_in_order() {
// at block 21 we do add a transition which is instant
net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
let mut block = builder.build().unwrap().block;
add_scheduled_change(&mut block, ScheduledChange {
next_authorities: make_ids(peers_b),
delay: 0,
});
add_scheduled_change(
&mut block,
ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 },
);
block
});
@@ -748,10 +764,10 @@ fn finalizes_multiple_pending_changes_in_order() {
// at block 26 we add another which is enacted at block 30
net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
let mut block = builder.build().unwrap().block;
add_scheduled_change(&mut block, ScheduledChange {
next_authorities: make_ids(peers_c),
delay: 4,
});
add_scheduled_change(
&mut block,
ScheduledChange { next_authorities: make_ids(peers_c), delay: 4 },
);
block
});
@@ -762,8 +778,7 @@ fn finalizes_multiple_pending_changes_in_order() {
// all peers imported both change blocks
for i in 0..6 {
assert_eq!(net.peer(i).client().info().best_number, 30,
"Peer #{} failed to sync", i);
assert_eq!(net.peer(i).client().info().best_number, 30, "Peer #{} failed to sync", i);
}
let net = Arc::new(Mutex::new(net));
@@ -794,16 +809,17 @@ fn force_change_to_new_set() {
let mut block = builder.build().unwrap().block;
// add a forced transition at block 12.
add_forced_change(&mut block, 0, ScheduledChange {
next_authorities: voters.clone(),
delay: 10,
});
add_forced_change(
&mut block,
0,
ScheduledChange { next_authorities: voters.clone(), delay: 10 },
);
// add a normal transition too to ensure that forced changes take priority.
add_scheduled_change(&mut block, ScheduledChange {
next_authorities: make_ids(genesis_authorities),
delay: 5,
});
add_scheduled_change(
&mut block,
ScheduledChange { next_authorities: make_ids(genesis_authorities), delay: 5 },
);
block
});
@@ -812,11 +828,11 @@ fn force_change_to_new_set() {
net.lock().block_until_sync();
for (i, peer) in net.lock().peers().iter().enumerate() {
assert_eq!(peer.client().info().best_number, 26,
"Peer #{} failed to sync", i);
assert_eq!(peer.client().info().best_number, 26, "Peer #{} failed to sync", i);
let full_client = peer.client().as_full().expect("only full clients are used in test");
let set: AuthoritySet<Hash, BlockNumber> = crate::aux_schema::load_authorities(&*full_client).unwrap();
let set: AuthoritySet<Hash, BlockNumber> =
crate::aux_schema::load_authorities(&*full_client).unwrap();
assert_eq!(set.current(), (1, voters.as_slice()));
assert_eq!(set.pending_changes().count(), 0);
@@ -841,12 +857,14 @@ fn allows_reimporting_change_blocks() {
let (mut block_import, ..) = net.make_block_import(client.clone());
let full_client = client.as_full().unwrap();
let builder = full_client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap();
let builder = full_client
.new_block_at(&BlockId::Number(0), Default::default(), false)
.unwrap();
let mut block = builder.build().unwrap().block;
add_scheduled_change(&mut block, ScheduledChange {
next_authorities: make_ids(peers_b),
delay: 0,
});
add_scheduled_change(
&mut block,
ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 },
);
let block = || {
let block = block.clone();
@@ -886,13 +904,15 @@ fn test_bad_justification() {
let (mut block_import, ..) = net.make_block_import(client.clone());
let full_client = client.as_full().expect("only full clients are used in test");
let builder = full_client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap();
let builder = full_client
.new_block_at(&BlockId::Number(0), Default::default(), false)
.unwrap();
let mut block = builder.build().unwrap().block;
add_scheduled_change(&mut block, ScheduledChange {
next_authorities: make_ids(peers_b),
delay: 0,
});
add_scheduled_change(
&mut block,
ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 },
);
let block = || {
let block = block.clone();
@@ -923,8 +943,8 @@ fn test_bad_justification() {
#[test]
fn voter_persists_its_votes() {
use std::sync::atomic::{AtomicUsize, Ordering};
use futures::future;
use std::sync::atomic::{AtomicUsize, Ordering};
sp_tracing::try_init_simple();
let mut runtime = Runtime::new().unwrap();
@@ -959,8 +979,7 @@ fn voter_persists_its_votes() {
let set_state = {
let bob_client = net.peer(1).client().clone();
let (_, _, link) = net
.make_block_import(bob_client);
let (_, _, link) = net.make_block_import(bob_client);
let LinkHalf { persistent_data, .. } = link.lock().take().unwrap();
let PersistentData { set_state, .. } = persistent_data;
set_state
@@ -983,10 +1002,7 @@ fn voter_persists_its_votes() {
let (net_service, link) = {
// temporary needed for some reason
let link = net.peers[0].data.lock().take().expect("link initialized at startup; qed");
(
net.peers[0].network_service().clone(),
link,
)
(net.peers[0].network_service().clone(), link)
};
let grandpa_params = GrandpaParams {
@@ -1026,8 +1042,7 @@ fn voter_persists_its_votes() {
// read the persisted state after aborting alice_voter1.
let alice_client = net.peer(0).client().clone();
let (_block_import, _, link) = net
.make_block_import(alice_client);
let (_block_import, _, link) = net.make_block_import(alice_client);
let link = link.lock().take().unwrap();
let grandpa_params = GrandpaParams {
@@ -1064,8 +1079,7 @@ fn voter_persists_its_votes() {
net.peer(0).push_blocks(20, false);
net.block_until_sync();
assert_eq!(net.peer(0).client().info().best_number, 20,
"Peer #{} failed to sync", 0);
assert_eq!(net.peer(0).client().info().best_number, 20, "Peer #{} failed to sync", 0);
let net = Arc::new(Mutex::new(net));
@@ -1113,12 +1127,13 @@ fn voter_persists_its_votes() {
// we push 20 more blocks to alice's chain
net.lock().peer(0).push_blocks(20, false);
let interval = futures::stream::unfold(Delay::new(Duration::from_millis(200)), |delay|
Box::pin(async move {
delay.await;
Some(((), Delay::new(Duration::from_millis(200))))
})
);
let interval =
futures::stream::unfold(Delay::new(Duration::from_millis(200)), |delay| {
Box::pin(async move {
delay.await;
Some(((), Delay::new(Duration::from_millis(200))))
})
});
interval
.take_while(move |_| {
@@ -1135,17 +1150,19 @@ fn voter_persists_its_votes() {
runtime_handle.spawn(alice_voter2(peers, net.clone()));
// and we push our own prevote for block 30
let prevote = finality_grandpa::Prevote {
target_number: 30,
target_hash: block_30_hash,
};
let prevote =
finality_grandpa::Prevote { target_number: 30, target_hash: block_30_hash };
// One should either be calling `Sink::send` or `Sink::start_send` followed
// by `Sink::poll_complete` to make sure items are being flushed. Given that
// we send in a loop including a delay until items are received, this can be
// ignored for the sake of reduced complexity.
Pin::new(&mut *round_tx.lock()).start_send(finality_grandpa::Message::Prevote(prevote)).unwrap();
} else if state.compare_exchange(1, 2, Ordering::SeqCst, Ordering::SeqCst).unwrap() == 1 {
Pin::new(&mut *round_tx.lock())
.start_send(finality_grandpa::Message::Prevote(prevote))
.unwrap();
} else if state.compare_exchange(1, 2, Ordering::SeqCst, Ordering::SeqCst).unwrap() ==
1
{
// the next message we receive should be our own prevote
let prevote = match signed.message {
finality_grandpa::Message::Prevote(prevote) => prevote,
@@ -1155,11 +1172,12 @@ fn voter_persists_its_votes() {
// targeting block 30
assert!(prevote.target_number == 30);
// after alice restarts it should send its previous prevote
// therefore we won't ever receive it again since it will be a
// known message on the gossip layer
} else if state.compare_exchange(2, 3, Ordering::SeqCst, Ordering::SeqCst).unwrap() == 2 {
// after alice restarts it should send its previous prevote
// therefore we won't ever receive it again since it will be a
// known message on the gossip layer
} else if state.compare_exchange(2, 3, Ordering::SeqCst, Ordering::SeqCst).unwrap() ==
2
{
// we then receive a precommit from alice for block 15
// even though we casted a prevote for block 30
let precommit = match signed.message {
@@ -1202,13 +1220,13 @@ fn finalize_3_voters_1_light_observer() {
},
net.peers[3].data.lock().take().expect("link initialized at startup; qed"),
net.peers[3].network_service().clone(),
).unwrap();
)
.unwrap();
net.peer(0).push_blocks(20, false);
net.block_until_sync();
for i in 0..4 {
assert_eq!(net.peer(i).client().info().best_number, 20,
"Peer #{} failed to sync", i);
assert_eq!(net.peer(i).client().info().best_number, 20, "Peer #{} failed to sync", i);
}
let net = Arc::new(Mutex::new(net));
@@ -1231,7 +1249,11 @@ fn voter_catches_up_to_latest_round_when_behind() {
let net = Arc::new(Mutex::new(net));
let mut finality_notifications = Vec::new();
let voter = |keystore, peer_id, link, net: Arc<Mutex<GrandpaTestNet>>| -> Pin<Box<dyn Future<Output = ()> + Send>> {
let voter = |keystore,
peer_id,
link,
net: Arc<Mutex<GrandpaTestNet>>|
-> Pin<Box<dyn Future<Output = ()> + Send>> {
let grandpa_params = GrandpaParams {
config: Config {
gossip_duration: TEST_GOSSIP_DURATION,
@@ -1259,17 +1281,16 @@ fn voter_catches_up_to_latest_round_when_behind() {
for (peer_id, key) in peers.iter().enumerate() {
let (client, link) = {
let net = net.lock();
let link = net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(
net.peers[peer_id].client().clone(),
link,
)
let link =
net.peers[peer_id].data.lock().take().expect("link initialized at startup; qed");
(net.peers[peer_id].client().clone(), link)
};
finality_notifications.push(
client.finality_notification_stream()
client
.finality_notification_stream()
.take_while(|n| future::ready(n.header.number() < &50))
.for_each(move |_| future::ready(()))
.for_each(move |_| future::ready(())),
);
let (keystore, keystore_path) = create_keystore(*key);
@@ -1324,11 +1345,10 @@ fn voter_catches_up_to_latest_round_when_behind() {
};
let drive_to_completion = futures::future::poll_fn(|cx| {
net.lock().poll(cx); Poll::<()>::Pending
net.lock().poll(cx);
Poll::<()>::Pending
});
runtime.block_on(
future::select(test, drive_to_completion)
);
runtime.block_on(future::select(test, drive_to_completion));
}
type TestEnvironment<N, VR> = Environment<
@@ -1350,11 +1370,7 @@ where
N: NetworkT<Block>,
VR: VotingRule<Block, TestClient>,
{
let PersistentData {
ref authority_set,
ref set_state,
..
} = link.persistent_data;
let PersistentData { ref authority_set, ref set_state, .. } = link.persistent_data;
let config = Config {
gossip_duration: TEST_GOSSIP_DURATION,
@@ -1366,13 +1382,8 @@ where
telemetry: None,
};
let network = NetworkBridge::new(
network_service.clone(),
config.clone(),
set_state.clone(),
None,
None,
);
let network =
NetworkBridge::new(network_service.clone(), config.clone(), set_state.clone(), None, None);
Environment {
authority_set: authority_set.clone(),
@@ -1428,25 +1439,28 @@ fn grandpa_environment_respects_voting_rules() {
// the unrestricted environment should just return the best block
assert_eq!(
block_on(unrestricted_env.best_chain_containing(
peer.client().info().finalized_hash
)).unwrap().unwrap().1,
block_on(unrestricted_env.best_chain_containing(peer.client().info().finalized_hash))
.unwrap()
.unwrap()
.1,
21,
);
// both the other environments should return block 16, which is 3/4 of the
// way in the unfinalized chain
assert_eq!(
block_on(three_quarters_env.best_chain_containing(
peer.client().info().finalized_hash
)).unwrap().unwrap().1,
block_on(three_quarters_env.best_chain_containing(peer.client().info().finalized_hash))
.unwrap()
.unwrap()
.1,
16,
);
assert_eq!(
block_on(default_env.best_chain_containing(
peer.client().info().finalized_hash
)).unwrap().unwrap().1,
block_on(default_env.best_chain_containing(peer.client().info().finalized_hash))
.unwrap()
.unwrap()
.1,
16,
);
@@ -1455,18 +1469,20 @@ fn grandpa_environment_respects_voting_rules() {
// the 3/4 environment should propose block 21 for voting
assert_eq!(
block_on(three_quarters_env.best_chain_containing(
peer.client().info().finalized_hash
)).unwrap().unwrap().1,
block_on(three_quarters_env.best_chain_containing(peer.client().info().finalized_hash))
.unwrap()
.unwrap()
.1,
21,
);
// while the default environment will always still make sure we don't vote
// on the best block (2 behind)
assert_eq!(
block_on(default_env.best_chain_containing(
peer.client().info().finalized_hash
)).unwrap().unwrap().1,
block_on(default_env.best_chain_containing(peer.client().info().finalized_hash))
.unwrap()
.unwrap()
.1,
19,
);
@@ -1477,9 +1493,10 @@ fn grandpa_environment_respects_voting_rules() {
// best block, there's a hard rule that we can't cast any votes lower than
// the given base (#21).
assert_eq!(
block_on(default_env.best_chain_containing(
peer.client().info().finalized_hash
)).unwrap().unwrap().1,
block_on(default_env.best_chain_containing(peer.client().info().finalized_hash))
.unwrap()
.unwrap()
.1,
21,
);
}
@@ -1518,9 +1535,7 @@ fn grandpa_environment_never_overwrites_round_voter_state() {
assert_eq!(get_current_round(2), None);
// after completing round 1 we should start tracking round 2
environment
.completed(1, round_state(), base(), &historical_votes())
.unwrap();
environment.completed(1, round_state(), base(), &historical_votes()).unwrap();
assert_eq!(get_current_round(2).unwrap(), HasVoted::No);
@@ -1530,10 +1545,8 @@ fn grandpa_environment_never_overwrites_round_voter_state() {
let info = peer.client().info();
let prevote = finality_grandpa::Prevote {
target_hash: info.best_hash,
target_number: info.best_number,
};
let prevote =
finality_grandpa::Prevote { target_hash: info.best_hash, target_number: info.best_number };
// we prevote for round 2 which should lead to us updating the voter state
environment.prevoted(2, prevote.clone()).unwrap();
@@ -1545,9 +1558,7 @@ fn grandpa_environment_never_overwrites_round_voter_state() {
// if we report round 1 as completed again we should not overwrite the
// voter state for round 2
environment
.completed(1, round_state(), base(), &historical_votes())
.unwrap();
environment.completed(1, round_state(), base(), &historical_votes()).unwrap();
assert_matches!(get_current_round(2).unwrap(), HasVoted::Yes(_, _));
}
@@ -1566,7 +1577,9 @@ fn imports_justification_for_regular_blocks_on_import() {
let (mut block_import, ..) = net.make_block_import(client.clone());
let full_client = client.as_full().expect("only full clients are used in test");
let builder = full_client.new_block_at(&BlockId::Number(0), Default::default(), false).unwrap();
let builder = full_client
.new_block_at(&BlockId::Number(0), Default::default(), false)
.unwrap();
let block = builder.build().unwrap().block;
let block_hash = block.hash();
@@ -1597,11 +1610,7 @@ fn imports_justification_for_regular_blocks_on_import() {
precommits: vec![precommit],
};
GrandpaJustification::from_commit(
&full_client,
round,
commit,
).unwrap()
GrandpaJustification::from_commit(&full_client, round, commit).unwrap()
};
// we import the block with justification attached
@@ -1622,9 +1631,7 @@ fn imports_justification_for_regular_blocks_on_import() {
);
// the justification should be imported and available from the client
assert!(
client.justifications(&BlockId::Hash(block_hash)).unwrap().is_some(),
);
assert!(client.justifications(&BlockId::Hash(block_hash)).unwrap().is_some(),);
}
#[test]
@@ -1644,10 +1651,7 @@ fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() {
};
let signed_prevote = {
let prevote = finality_grandpa::Prevote {
target_hash: H256::random(),
target_number: 1,
};
let prevote = finality_grandpa::Prevote { target_hash: H256::random(), target_number: 1 };
let signed = alice.sign(&[]).into();
(prevote, signed)
@@ -1667,10 +1671,7 @@ fn grandpa_environment_doesnt_send_equivocation_reports_for_itself() {
// reporting the equivocation should fail since the offender is a local
// authority (i.e. we have keys in our keystore for the given id)
let equivocation_proof = sp_finality_grandpa::Equivocation::Prevote(equivocation.clone());
assert!(matches!(
environment.report_equivocation(equivocation_proof),
Err(Error::Safety(_))
));
assert!(matches!(environment.report_equivocation(equivocation_proof), Err(Error::Safety(_))));
// if we set the equivocation offender to another id for which we don't have
// keys it should work
@@ -23,32 +23,31 @@
//! This is used for votes and commit messages currently.
use super::{
BlockStatus as BlockStatusT,
BlockSyncRequester as BlockSyncRequesterT,
CommunicationIn,
Error,
BlockStatus as BlockStatusT, BlockSyncRequester as BlockSyncRequesterT, CommunicationIn, Error,
SignedMessage,
};
use log::{debug, warn};
use sp_utils::mpsc::TracingUnboundedReceiver;
use futures::prelude::*;
use futures::stream::{Fuse, StreamExt};
use futures_timer::Delay;
use finality_grandpa::voter;
use parking_lot::Mutex;
use prometheus_endpoint::{
Gauge, U64, PrometheusError, register, Registry,
use futures::{
prelude::*,
stream::{Fuse, StreamExt},
};
use futures_timer::Delay;
use log::{debug, warn};
use parking_lot::Mutex;
use prometheus_endpoint::{register, Gauge, PrometheusError, Registry, U64};
use sc_client_api::{BlockImportNotification, ImportNotifications};
use sp_finality_grandpa::AuthorityId;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use sp_utils::mpsc::TracingUnboundedReceiver;
use std::collections::{HashMap, VecDeque};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Duration;
use std::{
collections::{HashMap, VecDeque},
pin::Pin,
sync::Arc,
task::{Context, Poll},
time::Duration,
};
use wasm_timer::Instant;
const LOG_PENDING_INTERVAL: Duration = Duration::from_secs(15);
@@ -84,7 +83,6 @@ pub(crate) enum DiscardWaitOrReady<Block: BlockT, W, R> {
}
/// Prometheus metrics for the `UntilImported` queue.
//
// At a given point in time there can be more than one `UntilImported` queue. One can not register a
// metric twice, thus queues need to share the same Prometheus metrics instead of instantiating
// their own ones.
@@ -101,10 +99,13 @@ pub(crate) struct Metrics {
impl Metrics {
pub(crate) fn register(registry: &Registry) -> Result<Self, PrometheusError> {
Ok(Self {
global_waiting_messages: register(Gauge::new(
"finality_grandpa_until_imported_waiting_messages_number",
"Number of finality grandpa messages waiting within the until imported queue.",
)?, registry)?,
global_waiting_messages: register(
Gauge::new(
"finality_grandpa_until_imported_waiting_messages_number",
"Number of finality grandpa messages waiting within the until imported queue.",
)?,
registry,
)?,
local_waiting_messages: 0,
})
}
@@ -120,7 +121,6 @@ impl Metrics {
}
}
impl Clone for Metrics {
fn clone(&self) -> Self {
Metrics {
@@ -136,8 +136,7 @@ impl Drop for Metrics {
fn drop(&mut self) {
// Reduce the global counter by the amount of messages that were still left in the dropped
// queue.
self.global_waiting_messages
.sub(self.local_waiting_messages)
self.global_waiting_messages.sub(self.local_waiting_messages)
}
}
@@ -200,11 +199,12 @@ where
// used in the event of missed import notifications
const CHECK_PENDING_INTERVAL: Duration = Duration::from_secs(5);
let check_pending = futures::stream::unfold(Delay::new(CHECK_PENDING_INTERVAL), |delay|
let check_pending = futures::stream::unfold(Delay::new(CHECK_PENDING_INTERVAL), |delay| {
Box::pin(async move {
delay.await;
Some((Ok(()), Delay::new(CHECK_PENDING_INTERVAL)))
}));
})
});
UntilImported {
import_notifications: import_notifications.fuse(),
@@ -220,7 +220,9 @@ where
}
}
impl<Block, BStatus, BSyncRequester, I, M> Stream for UntilImported<Block, BStatus, BSyncRequester, I, M> where
impl<Block, BStatus, BSyncRequester, I, M> Stream
for UntilImported<Block, BStatus, BSyncRequester, I, M>
where
Block: BlockT,
BStatus: BlockStatusT<Block>,
BSyncRequester: BlockSyncRequesterT<Block>,
@@ -257,7 +259,7 @@ impl<Block, BStatus, BSyncRequester, I, M> Stream for UntilImported<Block, BStat
if let Some(metrics) = &mut this.metrics {
metrics.waiting_messages_inc();
}
}
},
Poll::Pending => break,
}
}
@@ -269,12 +271,12 @@ impl<Block, BStatus, BSyncRequester, I, M> Stream for UntilImported<Block, BStat
// new block imported. queue up all messages tied to that hash.
if let Some((_, _, messages)) = this.pending.remove(&notification.hash) {
let canon_number = *notification.header.number();
let ready_messages = messages.into_iter()
.filter_map(|m| m.wait_completed(canon_number));
let ready_messages =
messages.into_iter().filter_map(|m| m.wait_completed(canon_number));
this.ready.extend(ready_messages);
}
}
}
},
Poll::Pending => break,
}
}
@@ -286,7 +288,9 @@ impl<Block, BStatus, BSyncRequester, I, M> Stream for UntilImported<Block, BStat
if update_interval {
let mut known_keys = Vec::new();
for (&block_hash, &mut (block_number, ref mut last_log, ref v)) in this.pending.iter_mut() {
for (&block_hash, &mut (block_number, ref mut last_log, ref v)) in
this.pending.iter_mut()
{
if let Some(number) = this.status_check.block_number(block_hash)? {
known_keys.push((block_hash, number));
} else {
@@ -318,8 +322,8 @@ impl<Block, BStatus, BSyncRequester, I, M> Stream for UntilImported<Block, BStat
for (known_hash, canon_number) in known_keys {
if let Some((_, _, pending_messages)) = this.pending.remove(&known_hash) {
let ready_messages = pending_messages.into_iter()
.filter_map(|m| m.wait_completed(canon_number));
let ready_messages =
pending_messages.into_iter().filter_map(|m| m.wait_completed(canon_number));
this.ready.extend(ready_messages);
}
@@ -363,9 +367,9 @@ impl<Block: BlockT> BlockUntilImported<Block> for SignedMessage<Block> {
if let Some(number) = status_check.block_number(target_hash)? {
if number != target_number {
warn_authority_wrong_target(target_hash, msg.id);
return Ok(DiscardWaitOrReady::Discard);
return Ok(DiscardWaitOrReady::Discard)
} else {
return Ok(DiscardWaitOrReady::Ready(msg));
return Ok(DiscardWaitOrReady::Ready(msg))
}
}
@@ -386,13 +390,8 @@ impl<Block: BlockT> BlockUntilImported<Block> for SignedMessage<Block> {
/// Helper type definition for the stream which waits until vote targets for
/// signed messages are imported.
pub(crate) type UntilVoteTargetImported<Block, BlockStatus, BlockSyncRequester, I> = UntilImported<
Block,
BlockStatus,
BlockSyncRequester,
I,
SignedMessage<Block>,
>;
pub(crate) type UntilVoteTargetImported<Block, BlockStatus, BlockSyncRequester, I> =
UntilImported<Block, BlockStatus, BlockSyncRequester, I, SignedMessage<Block>>;
/// This blocks a global message import, i.e. a commit or catch up messages,
/// until all blocks referenced in its votes are known.
@@ -445,19 +444,18 @@ impl<Block: BlockT> BlockUntilImported<Block> for BlockGlobalMessage<Block> {
if let Some(number) = status_check.block_number(target_hash)? {
entry.insert(KnownOrUnknown::Known(number));
number
} else {
entry.insert(KnownOrUnknown::Unknown(perceived_number));
perceived_number
}
}
},
};
if canon_number != perceived_number {
// invalid global message: messages targeting wrong number
// or at least different from other vote in same global
// message.
return Ok(false);
return Ok(false)
}
Ok(true)
@@ -466,23 +464,24 @@ impl<Block: BlockT> BlockUntilImported<Block> for BlockGlobalMessage<Block> {
match input {
voter::CommunicationIn::Commit(_, ref commit, ..) => {
// add known hashes from all precommits.
let precommit_targets = commit.precommits
.iter()
.map(|c| (c.target_number, c.target_hash));
let precommit_targets =
commit.precommits.iter().map(|c| (c.target_number, c.target_hash));
for (target_number, target_hash) in precommit_targets {
if !query_known(target_hash, target_number)? {
return Ok(DiscardWaitOrReady::Discard);
return Ok(DiscardWaitOrReady::Discard)
}
}
},
voter::CommunicationIn::CatchUp(ref catch_up, ..) => {
// add known hashes from all prevotes and precommits.
let prevote_targets = catch_up.prevotes
let prevote_targets = catch_up
.prevotes
.iter()
.map(|s| (s.prevote.target_number, s.prevote.target_hash));
let precommit_targets = catch_up.precommits
let precommit_targets = catch_up
.precommits
.iter()
.map(|s| (s.precommit.target_number, s.precommit.target_hash));
@@ -490,29 +489,39 @@ impl<Block: BlockT> BlockUntilImported<Block> for BlockGlobalMessage<Block> {
for (target_number, target_hash) in targets {
if !query_known(target_hash, target_number)? {
return Ok(DiscardWaitOrReady::Discard);
return Ok(DiscardWaitOrReady::Discard)
}
}
},
};
}
let unknown_hashes = checked_hashes.into_iter().filter_map(|(hash, num)| match num {
KnownOrUnknown::Unknown(number) => Some((hash, number)),
KnownOrUnknown::Known(_) => None,
}).collect::<Vec<_>>();
let unknown_hashes = checked_hashes
.into_iter()
.filter_map(|(hash, num)| match num {
KnownOrUnknown::Unknown(number) => Some((hash, number)),
KnownOrUnknown::Known(_) => None,
})
.collect::<Vec<_>>();
if unknown_hashes.is_empty() {
// none of the hashes in the global message were unknown.
// we can just return the message directly.
return Ok(DiscardWaitOrReady::Ready(input));
return Ok(DiscardWaitOrReady::Ready(input))
}
let locked_global = Arc::new(Mutex::new(Some(input)));
let items_to_await = unknown_hashes.into_iter().map(|(hash, target_number)| {
(hash, target_number, BlockGlobalMessage { inner: locked_global.clone(), target_number })
}).collect();
let items_to_await = unknown_hashes
.into_iter()
.map(|(hash, target_number)| {
(
hash,
target_number,
BlockGlobalMessage { inner: locked_global.clone(), target_number },
)
})
.collect();
// schedule waits for all unknown messages.
// when the last one of these has `wait_completed` called on it,
@@ -525,7 +534,7 @@ impl<Block: BlockT> BlockUntilImported<Block> for BlockGlobalMessage<Block> {
// Delete the inner message so it won't ever be forwarded. Future calls to
// `wait_completed` on the same `inner` will ignore it.
*self.inner.lock() = None;
return None;
return None
}
match Arc::try_unwrap(self.inner) {
@@ -542,25 +551,20 @@ impl<Block: BlockT> BlockUntilImported<Block> for BlockGlobalMessage<Block> {
/// A stream which gates off incoming global messages, i.e. commit and catch up
/// messages, until all referenced block hashes have been imported.
pub(crate) type UntilGlobalMessageBlocksImported<Block, BlockStatus, BlockSyncRequester, I> = UntilImported<
Block,
BlockStatus,
BlockSyncRequester,
I,
BlockGlobalMessage<Block>,
>;
pub(crate) type UntilGlobalMessageBlocksImported<Block, BlockStatus, BlockSyncRequester, I> =
UntilImported<Block, BlockStatus, BlockSyncRequester, I, BlockGlobalMessage<Block>>;
#[cfg(test)]
mod tests {
use super::*;
use crate::{CatchUp, CompactCommit};
use substrate_test_runtime_client::runtime::{Block, Hash, Header};
use sp_consensus::BlockOrigin;
use sc_client_api::BlockImportNotification;
use finality_grandpa::Precommit;
use futures::future::Either;
use futures_timer::Delay;
use sc_client_api::BlockImportNotification;
use sp_consensus::BlockOrigin;
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
use finality_grandpa::Precommit;
use substrate_test_runtime_client::runtime::{Block, Hash, Header};
#[derive(Clone)]
struct TestChainState {
@@ -571,10 +575,8 @@ mod tests {
impl TestChainState {
fn new() -> (Self, ImportNotifications<Block>) {
let (tx, rx) = tracing_unbounded("test");
let state = TestChainState {
sender: tx,
known_blocks: Arc::new(Mutex::new(HashMap::new())),
};
let state =
TestChainState { sender: tx, known_blocks: Arc::new(Mutex::new(HashMap::new())) };
(state, rx)
}
@@ -588,13 +590,15 @@ mod tests {
let number = header.number().clone();
self.known_blocks.lock().insert(hash, number);
self.sender.unbounded_send(BlockImportNotification {
hash,
origin: BlockOrigin::File,
header,
is_new_best: false,
tree_route: None,
}).unwrap();
self.sender
.unbounded_send(BlockImportNotification {
hash,
origin: BlockOrigin::File,
header,
is_new_best: false,
tree_route: None,
})
.unwrap();
}
}
@@ -615,14 +619,17 @@ mod tests {
impl Default for TestBlockSyncRequester {
fn default() -> Self {
TestBlockSyncRequester {
requests: Arc::new(Mutex::new(Vec::new())),
}
TestBlockSyncRequester { requests: Arc::new(Mutex::new(Vec::new())) }
}
}
impl BlockSyncRequesterT<Block> for TestBlockSyncRequester {
fn set_sync_fork_request(&self, _peers: Vec<sc_network::PeerId>, hash: Hash, number: NumberFor<Block>) {
fn set_sync_fork_request(
&self,
_peers: Vec<sc_network::PeerId>,
hash: Hash,
number: NumberFor<Block>,
) {
self.requests.lock().push((hash, number));
}
}
@@ -639,7 +646,7 @@ mod tests {
// unwrap the commit from `CommunicationIn` returning its fields in a tuple,
// panics if the given message isn't a commit
fn unapply_commit(msg: CommunicationIn<Block>) -> (u64, CompactCommit::<Block>) {
fn unapply_commit(msg: CommunicationIn<Block>) -> (u64, CompactCommit<Block>) {
match msg {
voter::CommunicationIn::Commit(round, commit, ..) => (round, commit),
_ => panic!("expected commit"),
@@ -658,7 +665,8 @@ mod tests {
fn message_all_dependencies_satisfied<F>(
msg: CommunicationIn<Block>,
enact_dependencies: F,
) -> CommunicationIn<Block> where
) -> CommunicationIn<Block>
where
F: FnOnce(&TestChainState),
{
let (chain_state, import_notifications) = TestChainState::new();
@@ -688,7 +696,8 @@ mod tests {
fn blocking_message_on_dependencies<F>(
msg: CommunicationIn<Block>,
enact_dependencies: F,
) -> CommunicationIn<Block> where
) -> CommunicationIn<Block>
where
F: FnOnce(&TestChainState),
{
let (chain_state, import_notifications) = TestChainState::new();
@@ -710,16 +719,17 @@ mod tests {
// NOTE: needs to be cloned otherwise it is moved to the stream and
// dropped too early.
let inner_chain_state = chain_state.clone();
let work = future::select(until_imported.into_future(), Delay::new(Duration::from_millis(100)))
.then(move |res| match res {
Either::Left(_) => panic!("timeout should have fired first"),
Either::Right((_, until_imported)) => {
// timeout fired. push in the headers.
enact_dependencies(&inner_chain_state);
let work =
future::select(until_imported.into_future(), Delay::new(Duration::from_millis(100)))
.then(move |res| match res {
Either::Left(_) => panic!("timeout should have fired first"),
Either::Right((_, until_imported)) => {
// timeout fired. push in the headers.
enact_dependencies(&inner_chain_state);
until_imported
}
});
until_imported
},
});
futures::executor::block_on(work).0.unwrap().unwrap()
}
@@ -734,37 +744,22 @@ mod tests {
target_hash: h1.hash(),
target_number: 5,
precommits: vec![
Precommit {
target_hash: h2.hash(),
target_number: 6,
},
Precommit {
target_hash: h3.hash(),
target_number: 7,
},
Precommit { target_hash: h2.hash(), target_number: 6 },
Precommit { target_hash: h3.hash(), target_number: 7 },
],
auth_data: Vec::new(), // not used
};
let unknown_commit = || voter::CommunicationIn::Commit(
0,
unknown_commit.clone(),
voter::Callback::Blank,
);
let unknown_commit =
|| voter::CommunicationIn::Commit(0, unknown_commit.clone(), voter::Callback::Blank);
let res = blocking_message_on_dependencies(
unknown_commit(),
|chain_state| {
chain_state.import_header(h1);
chain_state.import_header(h2);
chain_state.import_header(h3);
},
);
let res = blocking_message_on_dependencies(unknown_commit(), |chain_state| {
chain_state.import_header(h1);
chain_state.import_header(h2);
chain_state.import_header(h3);
});
assert_eq!(
unapply_commit(res),
unapply_commit(unknown_commit()),
);
assert_eq!(unapply_commit(res), unapply_commit(unknown_commit()),);
}
#[test]
@@ -777,37 +772,22 @@ mod tests {
target_hash: h1.hash(),
target_number: 5,
precommits: vec![
Precommit {
target_hash: h2.hash(),
target_number: 6,
},
Precommit {
target_hash: h3.hash(),
target_number: 7,
},
Precommit { target_hash: h2.hash(), target_number: 6 },
Precommit { target_hash: h3.hash(), target_number: 7 },
],
auth_data: Vec::new(), // not used
};
let known_commit = || voter::CommunicationIn::Commit(
0,
known_commit.clone(),
voter::Callback::Blank,
);
let known_commit =
|| voter::CommunicationIn::Commit(0, known_commit.clone(), voter::Callback::Blank);
let res = message_all_dependencies_satisfied(
known_commit(),
|chain_state| {
chain_state.import_header(h1);
chain_state.import_header(h2);
chain_state.import_header(h3);
},
);
let res = message_all_dependencies_satisfied(known_commit(), |chain_state| {
chain_state.import_header(h1);
chain_state.import_header(h2);
chain_state.import_header(h3);
});
assert_eq!(
unapply_commit(res),
unapply_commit(known_commit()),
);
assert_eq!(unapply_commit(res), unapply_commit(known_commit()),);
}
#[test]
@@ -816,37 +796,27 @@ mod tests {
let h2 = make_header(6);
let h3 = make_header(7);
let signed_prevote = |header: &Header| {
finality_grandpa::SignedPrevote {
id: Default::default(),
signature: Default::default(),
prevote: finality_grandpa::Prevote {
target_hash: header.hash(),
target_number: *header.number(),
},
}
let signed_prevote = |header: &Header| finality_grandpa::SignedPrevote {
id: Default::default(),
signature: Default::default(),
prevote: finality_grandpa::Prevote {
target_hash: header.hash(),
target_number: *header.number(),
},
};
let signed_precommit = |header: &Header| {
finality_grandpa::SignedPrecommit {
id: Default::default(),
signature: Default::default(),
precommit: finality_grandpa::Precommit {
target_hash: header.hash(),
target_number: *header.number(),
},
}
let signed_precommit = |header: &Header| finality_grandpa::SignedPrecommit {
id: Default::default(),
signature: Default::default(),
precommit: finality_grandpa::Precommit {
target_hash: header.hash(),
target_number: *header.number(),
},
};
let prevotes = vec![
signed_prevote(&h1),
signed_prevote(&h3),
];
let prevotes = vec![signed_prevote(&h1), signed_prevote(&h3)];
let precommits = vec![
signed_precommit(&h1),
signed_precommit(&h2),
];
let precommits = vec![signed_precommit(&h1), signed_precommit(&h2)];
let unknown_catch_up = finality_grandpa::CatchUp {
round_number: 1,
@@ -856,24 +826,16 @@ mod tests {
base_number: *h1.number(),
};
let unknown_catch_up = || voter::CommunicationIn::CatchUp(
unknown_catch_up.clone(),
voter::Callback::Blank,
);
let unknown_catch_up =
|| voter::CommunicationIn::CatchUp(unknown_catch_up.clone(), voter::Callback::Blank);
let res = blocking_message_on_dependencies(
unknown_catch_up(),
|chain_state| {
chain_state.import_header(h1);
chain_state.import_header(h2);
chain_state.import_header(h3);
},
);
let res = blocking_message_on_dependencies(unknown_catch_up(), |chain_state| {
chain_state.import_header(h1);
chain_state.import_header(h2);
chain_state.import_header(h3);
});
assert_eq!(
unapply_catch_up(res),
unapply_catch_up(unknown_catch_up()),
);
assert_eq!(unapply_catch_up(res), unapply_catch_up(unknown_catch_up()),);
}
#[test]
@@ -882,37 +844,27 @@ mod tests {
let h2 = make_header(6);
let h3 = make_header(7);
let signed_prevote = |header: &Header| {
finality_grandpa::SignedPrevote {
id: Default::default(),
signature: Default::default(),
prevote: finality_grandpa::Prevote {
target_hash: header.hash(),
target_number: *header.number(),
},
}
let signed_prevote = |header: &Header| finality_grandpa::SignedPrevote {
id: Default::default(),
signature: Default::default(),
prevote: finality_grandpa::Prevote {
target_hash: header.hash(),
target_number: *header.number(),
},
};
let signed_precommit = |header: &Header| {
finality_grandpa::SignedPrecommit {
id: Default::default(),
signature: Default::default(),
precommit: finality_grandpa::Precommit {
target_hash: header.hash(),
target_number: *header.number(),
},
}
let signed_precommit = |header: &Header| finality_grandpa::SignedPrecommit {
id: Default::default(),
signature: Default::default(),
precommit: finality_grandpa::Precommit {
target_hash: header.hash(),
target_number: *header.number(),
},
};
let prevotes = vec![
signed_prevote(&h1),
signed_prevote(&h3),
];
let prevotes = vec![signed_prevote(&h1), signed_prevote(&h3)];
let precommits = vec![
signed_precommit(&h1),
signed_precommit(&h2),
];
let precommits = vec![signed_precommit(&h1), signed_precommit(&h2)];
let unknown_catch_up = finality_grandpa::CatchUp {
round_number: 1,
@@ -922,24 +874,16 @@ mod tests {
base_number: *h1.number(),
};
let unknown_catch_up = || voter::CommunicationIn::CatchUp(
unknown_catch_up.clone(),
voter::Callback::Blank,
);
let unknown_catch_up =
|| voter::CommunicationIn::CatchUp(unknown_catch_up.clone(), voter::Callback::Blank);
let res = message_all_dependencies_satisfied(
unknown_catch_up(),
|chain_state| {
chain_state.import_header(h1);
chain_state.import_header(h2);
chain_state.import_header(h3);
},
);
let res = message_all_dependencies_satisfied(unknown_catch_up(), |chain_state| {
chain_state.import_header(h1);
chain_state.import_header(h2);
chain_state.import_header(h3);
});
assert_eq!(
unapply_catch_up(res),
unapply_catch_up(unknown_catch_up()),
);
assert_eq!(unapply_catch_up(res), unapply_catch_up(unknown_catch_up()),);
}
#[test]
@@ -970,23 +914,14 @@ mod tests {
target_hash: h1.hash(),
target_number: 5,
precommits: vec![
Precommit {
target_hash: h2.hash(),
target_number: 6,
},
Precommit {
target_hash: h3.hash(),
target_number: 7,
},
Precommit { target_hash: h2.hash(), target_number: 6 },
Precommit { target_hash: h3.hash(), target_number: 7 },
],
auth_data: Vec::new(), // not used
};
let unknown_commit = || voter::CommunicationIn::Commit(
0,
unknown_commit.clone(),
voter::Callback::Blank,
);
let unknown_commit =
|| voter::CommunicationIn::Commit(0, unknown_commit.clone(), voter::Callback::Blank);
// we send the commit message and spawn the until_imported stream
global_tx.unbounded_send(unknown_commit()).unwrap();
@@ -1002,7 +937,7 @@ mod tests {
if block_sync_requests.contains(&(h2.hash(), *h2.number())) &&
block_sync_requests.contains(&(h3.hash(), *h3.number()))
{
return Poll::Ready(());
return Poll::Ready(())
}
// NOTE: nothing in this function is future-aware (i.e nothing gets registered to wake
@@ -1016,10 +951,12 @@ mod tests {
// the `until_imported` stream doesn't request the blocks immediately,
// but it should request them after a small timeout
let timeout = Delay::new(Duration::from_secs(60));
let test = future::select(assert, timeout).map(|res| match res {
Either::Left(_) => {},
Either::Right(_) => panic!("timed out waiting for block sync request"),
}).map(drop);
let test = future::select(assert, timeout)
.map(|res| match res {
Either::Left(_) => {},
Either::Right(_) => panic!("timed out waiting for block sync request"),
})
.map(drop);
futures::executor::block_on(test);
}
@@ -1035,10 +972,8 @@ mod tests {
base_number: *header.number(),
};
let catch_up = voter::CommunicationIn::CatchUp(
unknown_catch_up.clone(),
voter::Callback::Blank,
);
let catch_up =
voter::CommunicationIn::CatchUp(unknown_catch_up.clone(), voter::Callback::Blank);
Arc::new(Mutex::new(Some(catch_up)))
}
@@ -1047,15 +982,10 @@ mod tests {
fn block_global_message_wait_completed_return_when_all_awaited() {
let msg_inner = test_catch_up();
let waiting_block_1 = BlockGlobalMessage::<Block> {
inner: msg_inner.clone(),
target_number: 1,
};
let waiting_block_1 =
BlockGlobalMessage::<Block> { inner: msg_inner.clone(), target_number: 1 };
let waiting_block_2 = BlockGlobalMessage::<Block> {
inner: msg_inner,
target_number: 2,
};
let waiting_block_2 = BlockGlobalMessage::<Block> { inner: msg_inner, target_number: 2 };
// waiting_block_2 is still waiting for block 2, thus this should return `None`.
assert!(waiting_block_1.wait_completed(1).is_none());
@@ -1069,15 +999,10 @@ mod tests {
fn block_global_message_wait_completed_return_none_on_block_number_missmatch() {
let msg_inner = test_catch_up();
let waiting_block_1 = BlockGlobalMessage::<Block> {
inner: msg_inner.clone(),
target_number: 1,
};
let waiting_block_1 =
BlockGlobalMessage::<Block> { inner: msg_inner.clone(), target_number: 1 };
let waiting_block_2 = BlockGlobalMessage::<Block> {
inner: msg_inner,
target_number: 2,
};
let waiting_block_2 = BlockGlobalMessage::<Block> { inner: msg_inner, target_number: 2 };
// Calling wait_completed with wrong block number should yield None.
assert!(waiting_block_1.wait_completed(1234).is_none());
@@ -22,15 +22,15 @@
//! restrictions that are taken into account by the GRANDPA environment when
//! selecting a finality target to vote on.
use std::future::Future;
use std::sync::Arc;
use std::pin::Pin;
use std::{future::Future, pin::Pin, sync::Arc};
use dyn_clone::DynClone;
use sc_client_api::blockchain::HeaderBackend;
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{Block as BlockT, Header, NumberFor, One, Zero};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Header, NumberFor, One, Zero},
};
/// A future returned by a `VotingRule` to restrict a given vote, if any restriction is necessary.
pub type VotingRuleResult<Block> =
@@ -63,7 +63,8 @@ where
) -> VotingRuleResult<Block>;
}
impl<Block, B> VotingRule<Block, B> for () where
impl<Block, B> VotingRule<Block, B> for ()
where
Block: BlockT,
B: HeaderBackend<Block>,
{
@@ -83,7 +84,8 @@ impl<Block, B> VotingRule<Block, B> for () where
/// behind the best block.
#[derive(Clone)]
pub struct BeforeBestBlockBy<N>(N);
impl<Block, B> VotingRule<Block, B> for BeforeBestBlockBy<NumberFor<Block>> where
impl<Block, B> VotingRule<Block, B> for BeforeBestBlockBy<NumberFor<Block>>
where
Block: BlockT,
B: HeaderBackend<Block>,
{
@@ -97,7 +99,7 @@ impl<Block, B> VotingRule<Block, B> for BeforeBestBlockBy<NumberFor<Block>> wher
use sp_arithmetic::traits::Saturating;
if current_target.number().is_zero() {
return Box::pin(async { None });
return Box::pin(async { None })
}
// find the target number restricted by this rule
@@ -105,17 +107,13 @@ impl<Block, B> VotingRule<Block, B> for BeforeBestBlockBy<NumberFor<Block>> wher
// our current target is already lower than this rule would restrict
if target_number >= *current_target.number() {
return Box::pin(async { None });
return Box::pin(async { None })
}
let current_target = current_target.clone();
// find the block at the given target height
Box::pin(std::future::ready(find_target(
&*backend,
target_number.clone(),
&current_target,
)))
Box::pin(std::future::ready(find_target(&*backend, target_number.clone(), &current_target)))
}
}
@@ -125,7 +123,8 @@ impl<Block, B> VotingRule<Block, B> for BeforeBestBlockBy<NumberFor<Block>> wher
#[derive(Clone)]
pub struct ThreeQuartersOfTheUnfinalizedChain;
impl<Block, B> VotingRule<Block, B> for ThreeQuartersOfTheUnfinalizedChain where
impl<Block, B> VotingRule<Block, B> for ThreeQuartersOfTheUnfinalizedChain
where
Block: BlockT,
B: HeaderBackend<Block>,
{
@@ -150,15 +149,11 @@ impl<Block, B> VotingRule<Block, B> for ThreeQuartersOfTheUnfinalizedChain where
// our current target is already lower than this rule would restrict
if target_number >= *current_target.number() {
return Box::pin(async { None });
return Box::pin(async { None })
}
// find the block at the given target height
Box::pin(std::future::ready(find_target(
&*backend,
target_number,
current_target,
)))
Box::pin(std::future::ready(find_target(&*backend, target_number, current_target)))
}
}
@@ -167,7 +162,8 @@ fn find_target<Block, B>(
backend: &B,
target_number: NumberFor<Block>,
current_header: &Block::Header,
) -> Option<(Block::Hash, NumberFor<Block>)> where
) -> Option<(Block::Hash, NumberFor<Block>)>
where
Block: BlockT,
B: HeaderBackend<Block>,
{
@@ -184,11 +180,13 @@ fn find_target<Block, B>(
}
if *target_header.number() == target_number {
return Some((target_hash, target_number));
return Some((target_hash, target_number))
}
target_hash = *target_header.parent_hash();
target_header = backend.header(BlockId::Hash(target_hash)).ok()?
target_header = backend
.header(BlockId::Hash(target_hash))
.ok()?
.expect("Header known to exist due to the existence of one of its descendents; qed");
}
}
@@ -199,13 +197,12 @@ struct VotingRules<Block, B> {
impl<B, Block> Clone for VotingRules<B, Block> {
fn clone(&self) -> Self {
VotingRules {
rules: self.rules.clone(),
}
VotingRules { rules: self.rules.clone() }
}
}
impl<Block, B> VotingRule<Block, B> for VotingRules<Block, B> where
impl<Block, B> VotingRule<Block, B> for VotingRules<Block, B>
where
Block: BlockT,
B: HeaderBackend<Block> + 'static,
{
@@ -230,8 +227,8 @@ impl<Block, B> VotingRule<Block, B> for VotingRules<Block, B> where
.await
.filter(|(_, restricted_number)| {
// NOTE: we can only restrict votes within the interval [base, target)
restricted_number >= base.number()
&& restricted_number < restricted_target.number()
restricted_number >= base.number() &&
restricted_number < restricted_target.number()
})
.and_then(|(hash, _)| backend.header(BlockId::Hash(hash)).ok())
.and_then(std::convert::identity)
@@ -257,7 +254,8 @@ pub struct VotingRulesBuilder<Block, B> {
rules: Vec<Box<dyn VotingRule<Block, B>>>,
}
impl<Block, B> Default for VotingRulesBuilder<Block, B> where
impl<Block, B> Default for VotingRulesBuilder<Block, B>
where
Block: BlockT,
B: HeaderBackend<Block> + 'static,
{
@@ -268,19 +266,19 @@ impl<Block, B> Default for VotingRulesBuilder<Block, B> where
}
}
impl<Block, B> VotingRulesBuilder<Block, B> where
impl<Block, B> VotingRulesBuilder<Block, B>
where
Block: BlockT,
B: HeaderBackend<Block> + 'static,
{
/// Return a new voting rule builder using the given backend.
pub fn new() -> Self {
VotingRulesBuilder {
rules: Vec::new(),
}
VotingRulesBuilder { rules: Vec::new() }
}
/// Add a new voting rule to the builder.
pub fn add<R>(mut self, rule: R) -> Self where
pub fn add<R>(mut self, rule: R) -> Self
where
R: VotingRule<Block, B> + 'static,
{
self.rules.push(Box::new(rule));
@@ -288,8 +286,9 @@ impl<Block, B> VotingRulesBuilder<Block, B> where
}
/// Add all given voting rules to the builder.
pub fn add_all<I>(mut self, rules: I) -> Self where
I: IntoIterator<Item=Box<dyn VotingRule<Block, B>>>,
pub fn add_all<I>(mut self, rules: I) -> Self
where
I: IntoIterator<Item = Box<dyn VotingRule<Block, B>>>,
{
self.rules.extend(rules);
self
@@ -298,13 +297,12 @@ impl<Block, B> VotingRulesBuilder<Block, B> where
/// Return a new `VotingRule` that applies all of the previously added
/// voting rules in-order.
pub fn build(self) -> impl VotingRule<Block, B> + Clone {
VotingRules {
rules: Arc::new(self.rules),
}
VotingRules { rules: Arc::new(self.rules) }
}
}
impl<Block, B> VotingRule<Block, B> for Box<dyn VotingRule<Block, B>> where
impl<Block, B> VotingRule<Block, B> for Box<dyn VotingRule<Block, B>>
where
Block: BlockT,
B: HeaderBackend<Block>,
Self: Clone,
@@ -358,33 +356,19 @@ mod tests {
fn multiple_voting_rules_cannot_restrict_past_base() {
// setup an aggregate voting rule composed of two voting rules
// where each subtracts 50 blocks from the current target
let rule = VotingRulesBuilder::new()
.add(Subtract(50))
.add(Subtract(50))
.build();
let rule = VotingRulesBuilder::new().add(Subtract(50)).add(Subtract(50)).build();
let mut client = Arc::new(TestClientBuilder::new().build());
for _ in 0..200 {
let block = client
.new_block(Default::default())
.unwrap()
.build()
.unwrap()
.block;
let block = client.new_block(Default::default()).unwrap().build().unwrap().block;
futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap();
}
let genesis = client
.header(&BlockId::Number(0u32.into()))
.unwrap()
.unwrap();
let genesis = client.header(&BlockId::Number(0u32.into())).unwrap().unwrap();
let best = client
.header(&BlockId::Hash(client.info().best_hash))
.unwrap()
.unwrap();
let best = client.header(&BlockId::Hash(client.info().best_hash)).unwrap().unwrap();
let (_, number) =
futures::executor::block_on(rule.restrict_vote(client.clone(), &genesis, &best, &best))
@@ -394,10 +378,7 @@ mod tests {
// which means that we should be voting for block #100
assert_eq!(number, 100);
let block110 = client
.header(&BlockId::Number(110u32.into()))
.unwrap()
.unwrap();
let block110 = client.header(&BlockId::Number(110u32.into())).unwrap().unwrap();
let (_, number) = futures::executor::block_on(rule.restrict_vote(
client.clone(),