grandpa: update to finality-grandpa v0.12.0 (#5853)

* grandpa: update to v0.12.0

* grandpa: fix tests

* grandpa: better validation of authority set invariants

* grandpa: avoid duplicating invalid authority list check

* grandpa: add missing doc

* grandpa: better validation of expect proofs

* grandpa: fix test compilation

* grandpa: fix tests

* grandpa: add test for AuthoritySet invariants

* grandpa: bump finality-grandpa to v0.12.0
This commit is contained in:
André Silva
2020-04-30 21:03:30 +01:00
committed by GitHub
parent 43e8268ae1
commit d2967ba4b6
13 changed files with 238 additions and 90 deletions
+4 -2
View File
@@ -1346,10 +1346,11 @@ dependencies = [
[[package]]
name = "finality-grandpa"
version = "0.11.2"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "024517816630be5204eba201e8d1d405042b1255a5e0e3f298b054fc24d59e1d"
checksum = "9d7907cc24468e29b5d3ea2097e78104492b6650c55f96af1f14e7915dc155ad"
dependencies = [
"either",
"futures 0.3.4",
"futures-timer 2.0.2",
"log",
@@ -6344,6 +6345,7 @@ name = "sc-finality-grandpa"
version = "0.8.0-dev"
dependencies = [
"assert_matches",
"derive_more",
"env_logger 0.7.1",
"finality-grandpa",
"fork-tree",
+3 -2
View File
@@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
derive_more = "0.99.2"
fork-tree = { version = "2.0.0-dev", path = "../../utils/fork-tree" }
futures = "0.3.4"
futures-timer = "3.0.1"
@@ -41,11 +42,11 @@ sp-finality-tracker = { version = "2.0.0-dev", path = "../../primitives/finality
sp-finality-grandpa = { version = "2.0.0-dev", path = "../../primitives/finality-grandpa" }
prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.8.0-dev"}
sc-block-builder = { version = "0.8.0-dev", path = "../block-builder" }
finality-grandpa = { version = "0.11.2", features = ["derive-codec"] }
finality-grandpa = { version = "0.12.0", features = ["derive-codec"] }
pin-project = "0.4.6"
[dev-dependencies]
finality-grandpa = { version = "0.11.2", features = ["derive-codec", "test-helpers"] }
finality-grandpa = { version = "0.12.0", features = ["derive-codec", "test-helpers"] }
sc-network = { version = "0.8.0-dev", path = "../network" }
sc-network-test = { version = "0.8.0-dev", path = "../network/test" }
sp-keyring = { version = "2.0.0-dev", path = "../../primitives/keyring" }
@@ -29,6 +29,15 @@ use std::fmt::Debug;
use std::ops::Add;
use std::sync::Arc;
/// Error type returned on operations on the `AuthoritySet`.
#[derive(Debug, derive_more::Display, derive_more::From)]
pub enum Error<E> {
#[display("Invalid authority set, either empty or with an authority weight set to 0.")]
InvalidAuthoritySet,
#[display(fmt = "Invalid operation in the pending changes tree: {}", _0)]
ForkTree(fork_tree::Error<E>),
}
/// A shared authority set.
pub(crate) struct SharedAuthoritySet<H, N> {
inner: Arc<RwLock<AuthoritySet<H, N>>>,
@@ -64,7 +73,11 @@ where N: Add<Output=N> + Ord + Clone + Debug,
/// Get the current authorities and their weights (for the current set ID).
pub(crate) fn current_authorities(&self) -> VoterSet<AuthorityId> {
self.inner.read().current_authorities.iter().cloned().collect()
VoterSet::new(self.inner.read().current_authorities.iter().cloned()).expect(
"current_authorities is non-empty and weights are non-zero; \
constructor and all mutating operations on `AuthoritySet` ensure this; \
qed.",
)
}
}
@@ -88,7 +101,7 @@ pub(crate) struct Status<H, N> {
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub(crate) struct AuthoritySet<H, N> {
pub(crate) current_authorities: AuthorityList,
pub(crate) set_id: u64,
set_id: u64,
// Tree of pending standard changes across forks. Standard changes are
// enacted on finality and must be enacted (i.e. finalized) in-order across
// a given branch
@@ -96,21 +109,49 @@ pub(crate) struct AuthoritySet<H, N> {
// Pending forced changes across different forks (at most one per fork).
// Forced changes are enacted on block depth (not finality), for this reason
// only one forced change should exist per fork.
pub(crate) pending_forced_changes: Vec<PendingChange<H, N>>,
pending_forced_changes: Vec<PendingChange<H, N>>,
}
impl<H, N> AuthoritySet<H, N>
where H: PartialEq,
N: Ord,
{
// authority sets must be non-empty and all weights must be greater than 0
fn invalid_authority_list(authorities: &AuthorityList) -> bool {
authorities.is_empty() || authorities.iter().any(|(_, w)| *w == 0)
}
/// Get a genesis set with given authorities.
pub(crate) fn genesis(initial: AuthorityList) -> Self {
AuthoritySet {
pub(crate) fn genesis(initial: AuthorityList) -> Option<Self> {
if Self::invalid_authority_list(&initial) {
return None;
}
Some(AuthoritySet {
current_authorities: initial,
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
})
}
/// Create a new authority set.
pub(crate) fn new(
authorities: AuthorityList,
set_id: u64,
pending_standard_changes: ForkTree<H, N, PendingChange<H, N>>,
pending_forced_changes: Vec<PendingChange<H, N>>,
) -> Option<Self> {
if Self::invalid_authority_list(&authorities) {
return None;
}
Some(AuthoritySet {
current_authorities: authorities,
set_id,
pending_standard_changes,
pending_forced_changes,
})
}
/// Get the current set id and a reference to the current authority set.
@@ -128,7 +169,7 @@ where
&mut self,
pending: PendingChange<H, N>,
is_descendent_of: &F,
) -> Result<(), fork_tree::Error<E>> where
) -> Result<(), Error<E>> where
F: Fn(&H, &H) -> Result<bool, E>,
E: std::error::Error,
{
@@ -159,15 +200,16 @@ where
&mut self,
pending: PendingChange<H, N>,
is_descendent_of: &F,
) -> Result<(), fork_tree::Error<E>> where
) -> Result<(), Error<E>> where
F: Fn(&H, &H) -> Result<bool, E>,
E: std::error::Error,
{
for change in self.pending_forced_changes.iter() {
if change.canon_hash == pending.canon_hash ||
is_descendent_of(&change.canon_hash, &pending.canon_hash)?
is_descendent_of(&change.canon_hash, &pending.canon_hash)
.map_err(fork_tree::Error::Client)?
{
return Err(fork_tree::Error::UnfinalizedAncestor);
return Err(fork_tree::Error::UnfinalizedAncestor.into());
}
}
@@ -201,10 +243,14 @@ where
&mut self,
pending: PendingChange<H, N>,
is_descendent_of: &F,
) -> Result<(), fork_tree::Error<E>> where
) -> Result<(), Error<E>> where
F: Fn(&H, &H) -> Result<bool, E>,
E: std::error::Error,
{
if Self::invalid_authority_list(&pending.next_authorities) {
return Err(Error::InvalidAuthoritySet);
}
match pending.delay_kind {
DelayKind::Best { .. } => {
self.add_forced_change(pending, is_descendent_of)
@@ -309,8 +355,8 @@ where
finalized_number: N,
is_descendent_of: &F,
initial_sync: bool,
) -> Result<Status<H, N>, fork_tree::Error<E>>
where F: Fn(&H, &H) -> Result<bool, E>,
) -> Result<Status<H, N>, Error<E>> where
F: Fn(&H, &H) -> Result<bool, E>,
E: std::error::Error,
{
let mut status = Status {
@@ -370,8 +416,8 @@ where
finalized_hash: H,
finalized_number: N,
is_descendent_of: &F,
) -> Result<Option<bool>, fork_tree::Error<E>>
where F: Fn(&H, &H) -> Result<bool, E>,
) -> Result<Option<bool>, Error<E>> where
F: Fn(&H, &H) -> Result<bool, E>,
E: std::error::Error,
{
self.pending_standard_changes.finalizes_any_with_descendent_if(
@@ -379,7 +425,7 @@ where
finalized_number.clone(),
is_descendent_of,
|change| change.effective_number() == finalized_number
)
).map_err(Error::ForkTree)
}
}
@@ -457,8 +503,10 @@ mod tests {
#[test]
fn current_limit_filters_min() {
let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]), 1)];
let mut authorities = AuthoritySet {
current_authorities: Vec::new(),
current_authorities: current_authorities.clone(),
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
@@ -466,7 +514,7 @@ mod tests {
let change = |height| {
PendingChange {
next_authorities: Vec::new(),
next_authorities: current_authorities.clone(),
delay: 0,
canon_height: height,
canon_hash: height.to_string(),
@@ -502,15 +550,17 @@ mod tests {
#[test]
fn changes_iterated_in_pre_order() {
let current_authorities = vec![(AuthorityId::from_slice(&[1; 32]), 1)];
let mut authorities = AuthoritySet {
current_authorities: Vec::new(),
current_authorities: current_authorities.clone(),
set_id: 0,
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
};
let change_a = PendingChange {
next_authorities: Vec::new(),
next_authorities: current_authorities.clone(),
delay: 10,
canon_height: 5,
canon_hash: "hash_a",
@@ -518,7 +568,7 @@ mod tests {
};
let change_b = PendingChange {
next_authorities: Vec::new(),
next_authorities: current_authorities.clone(),
delay: 0,
canon_height: 5,
canon_hash: "hash_b",
@@ -526,7 +576,7 @@ mod tests {
};
let change_c = PendingChange {
next_authorities: Vec::new(),
next_authorities: current_authorities.clone(),
delay: 5,
canon_height: 10,
canon_hash: "hash_c",
@@ -543,7 +593,7 @@ mod tests {
// forced changes are iterated last
let change_d = PendingChange {
next_authorities: Vec::new(),
next_authorities: current_authorities.clone(),
delay: 2,
canon_height: 1,
canon_hash: "hash_d",
@@ -551,7 +601,7 @@ mod tests {
};
let change_e = PendingChange {
next_authorities: Vec::new(),
next_authorities: current_authorities.clone(),
delay: 2,
canon_height: 0,
canon_hash: "hash_e",
@@ -689,7 +739,7 @@ mod tests {
// trying to finalize past `change_c` without finalizing `change_a` first
assert!(matches!(
authorities.apply_standard_changes("hash_d", 40, &is_descendent_of, false),
Err(fork_tree::Error::UnfinalizedAncestor)
Err(Error::ForkTree(fork_tree::Error::UnfinalizedAncestor))
));
let status = authorities.apply_standard_changes(
@@ -871,4 +921,74 @@ mod tests {
}),
);
}
#[test]
fn maintains_authority_list_invariants() {
// empty authority lists are invalid
assert_eq!(AuthoritySet::<(), ()>::genesis(vec![]), None);
assert_eq!(
AuthoritySet::<(), ()>::new(vec![], 0, ForkTree::new(), Vec::new()),
None,
);
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::<(), ()>::new(
invalid_authorities_weight.clone(),
0,
ForkTree::new(),
Vec::new()
),
None,
);
let mut authority_set =
AuthoritySet::<(), u64>::genesis(vec![(AuthorityId::from_slice(&[1; 32]), 5)]).unwrap();
let invalid_change_empty_authorities = PendingChange {
next_authorities: vec![],
delay: 10,
canon_height: 5,
canon_hash: (),
delay_kind: DelayKind::Finalized,
};
// pending change contains an empty authority set
assert!(matches!(
authority_set.add_pending_change(
invalid_change_empty_authorities.clone(),
&static_is_descendent_of(false)
),
Err(Error::InvalidAuthoritySet)
));
let invalid_change_authorities_weight = PendingChange {
next_authorities: invalid_authorities_weight,
delay: 10,
canon_height: 5,
canon_hash: (),
delay_kind: DelayKind::Best {
median_last_finalized: 0,
},
};
// pending change contains an an authority set
// where one authority has weight of 0
assert!(matches!(
authority_set.add_pending_change(
invalid_change_authorities_weight,
&static_is_descendent_of(false)
),
Err(Error::InvalidAuthoritySet)
));
}
}
@@ -97,12 +97,14 @@ where H: Clone + Debug + PartialEq,
}
}
AuthoritySet {
current_authorities: self.current_authorities,
set_id: self.set_id,
pending_forced_changes: Vec::new(),
pending_standard_changes
}
let authority_set = AuthoritySet::new(
self.current_authorities,
self.set_id,
pending_standard_changes,
Vec::new(),
);
authority_set.expect("current_authorities is non-empty and weights are non-zero; qed.")
}
}
@@ -334,7 +336,8 @@ pub(crate) fn load_persistent<Block: BlockT, B, G>(
from genesis on what appears to be first startup.");
let genesis_authorities = genesis_authorities()?;
let genesis_set = AuthoritySet::genesis(genesis_authorities.clone());
let genesis_set = AuthoritySet::genesis(genesis_authorities.clone())
.expect("genesis authorities is non-empty; all weights are non-zero; qed.");
let state = make_genesis_round();
let base = state.prevote_ghost
.expect("state is for completed round; completed rounds must have a prevote ghost; qed.");
@@ -503,12 +506,12 @@ mod test {
assert_eq!(
*authority_set.inner().read(),
AuthoritySet {
current_authorities: authorities.clone(),
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
AuthoritySet::new(
authorities.clone(),
set_id,
},
ForkTree::new(),
Vec::new(),
).unwrap(),
);
let mut current_rounds = CurrentRounds::new();
@@ -547,12 +550,12 @@ mod test {
};
{
let authority_set = AuthoritySet::<H256, u64> {
current_authorities: authorities.clone(),
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
let authority_set = AuthoritySet::<H256, u64>::new(
authorities.clone(),
set_id,
};
ForkTree::new(),
Vec::new(),
).unwrap();
let voter_set_state = V1VoterSetState::Live(round_number, round_state.clone());
@@ -593,12 +596,12 @@ mod test {
assert_eq!(
*authority_set.inner().read(),
AuthoritySet {
current_authorities: authorities.clone(),
pending_standard_changes: ForkTree::new(),
pending_forced_changes: Vec::new(),
AuthoritySet::new(
authorities.clone(),
set_id,
},
ForkTree::new(),
Vec::new(),
).unwrap(),
);
let mut current_rounds = CurrentRounds::new();
@@ -1618,7 +1618,10 @@ mod tests {
use crate::environment::VoterSetState;
let base = (H256::zero(), 0);
let voters = AuthoritySet::genesis(Vec::new());
let voters = vec![(AuthorityId::from_slice(&[1; 32]), 1)];
let voters = AuthoritySet::genesis(voters).unwrap();
let set_state = VoterSetState::live(
0,
&voters,
@@ -258,7 +258,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
// is a no-op if currently in that set.
self.validator.note_set(
set_id,
voters.voters().iter().map(|(v, _)| v.clone()).collect(),
voters.iter().map(|(v, _)| v.clone()).collect(),
|to, neighbor| self.neighbor_sender.send(to, neighbor),
);
@@ -289,7 +289,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
let locals = local_key.and_then(|pair| {
let id = pair.public();
if voters.contains_key(&id) {
if voters.contains(&id) {
Some((pair, id))
} else {
None
@@ -308,12 +308,12 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
}
Ok(GossipMessage::Vote(msg)) => {
// check signature.
if !voters.contains_key(&msg.message.id) {
if !voters.contains(&msg.message.id) {
debug!(target: "afg", "Skipping message from unknown voter {}", msg.message.id);
return future::ready(None);
}
if voters.len() <= TELEMETRY_VOTERS_LIMIT {
if voters.len().get() <= TELEMETRY_VOTERS_LIMIT {
match &msg.message.message {
PrimaryPropose(propose) => {
telemetry!(CONSENSUS_INFO; "afg.received_propose";
@@ -378,7 +378,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
) {
self.validator.note_set(
set_id,
voters.voters().iter().map(|(v, _)| v.clone()).collect(),
voters.iter().map(|(v, _)| v.clone()).collect(),
|to, neighbor| self.neighbor_sender.send(to, neighbor),
);
@@ -476,7 +476,7 @@ fn incoming_global<B: BlockT>(
gossip_validator: &Arc<GossipValidator<B>>,
voters: &VoterSet<AuthorityId>,
| {
if voters.len() <= TELEMETRY_VOTERS_LIMIT {
if voters.len().get() <= TELEMETRY_VOTERS_LIMIT {
let precommits_signed_by: Vec<String> =
msg.message.auth_data.iter().map(move |(_, a)| {
format!("{}", a)
@@ -799,13 +799,13 @@ fn check_compact_commit<Block: BlockT>(
) -> Result<(), ReputationChange> {
// 4f + 1 = equivocations from f voters.
let f = voters.total_weight() - voters.threshold();
let full_threshold = voters.total_weight() + f;
let full_threshold = (f + voters.total_weight()).0;
// check total weight is not out of range.
let mut total_weight = 0;
for (_, ref id) in &msg.auth_data {
if let Some(weight) = voters.info(id).map(|info| info.weight()) {
total_weight += weight;
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);
}
@@ -815,7 +815,7 @@ fn check_compact_commit<Block: BlockT>(
}
}
if total_weight < voters.threshold() {
if total_weight < voters.threshold().get() {
return Err(cost::MALFORMED_COMMIT);
}
@@ -860,7 +860,7 @@ fn check_catch_up<Block: BlockT>(
) -> Result<(), ReputationChange> {
// 4f + 1 = equivocations from f voters.
let f = voters.total_weight() - voters.threshold();
let full_threshold = voters.total_weight() + f;
let full_threshold = (f + voters.total_weight()).0;
// check total weight is not out of range for a set of votes.
fn check_weight<'a>(
@@ -871,8 +871,8 @@ fn check_catch_up<Block: BlockT>(
let mut total_weight = 0;
for id in votes {
if let Some(weight) = voters.info(&id).map(|info| info.weight()) {
total_weight += weight;
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);
}
@@ -882,7 +882,7 @@ fn check_catch_up<Block: BlockT>(
}
}
if total_weight < voters.threshold() {
if total_weight < voters.threshold().get() {
return Err(cost::MALFORMED_CATCH_UP);
}
@@ -29,7 +29,7 @@ use std::{borrow::Cow, pin::Pin, task::{Context, Poll}};
use crate::environment::SharedVoterSetState;
use sp_finality_grandpa::{AuthorityList, GRANDPA_ENGINE_ID};
use super::gossip::{self, GossipValidator};
use super::{AuthorityId, VoterSet, Round, SetId};
use super::{VoterSet, Round, SetId};
#[derive(Debug)]
pub(crate) enum Event {
@@ -142,11 +142,15 @@ fn voter_set_state() -> SharedVoterSetState<Block> {
use crate::authorities::AuthoritySet;
use crate::environment::VoterSetState;
use finality_grandpa::round::State as RoundState;
use sp_core::H256;
use sp_core::{crypto::Public, H256};
use sp_finality_grandpa::AuthorityId;
let state = RoundState::genesis((H256::zero(), 0));
let base = state.prevote_ghost.unwrap();
let voters = AuthoritySet::genesis(Vec::new());
let voters = vec![(AuthorityId::from_slice(&[1; 32]), 1)];
let voters = AuthoritySet::genesis(voters).unwrap();
let set_state = VoterSetState::live(
0,
&voters,
@@ -212,7 +216,7 @@ impl sc_network_gossip::ValidatorContext<Block> for NoopContext {
fn good_commit_leads_to_relay() {
let private = [Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
let public = make_ids(&private[..]);
let voter_set = Arc::new(public.iter().cloned().collect::<VoterSet<AuthorityId>>());
let voter_set = Arc::new(VoterSet::new(public.iter().cloned()).unwrap());
let round = 1;
let set_id = 1;
@@ -360,7 +364,7 @@ fn bad_commit_leads_to_report() {
let _ = env_logger::try_init();
let private = [Ed25519Keyring::Alice, Ed25519Keyring::Bob, Ed25519Keyring::Charlie];
let public = make_ids(&private[..]);
let voter_set = Arc::new(public.iter().cloned().collect::<VoterSet<AuthorityId>>());
let voter_set = Arc::new(VoterSet::new(public.iter().cloned()).unwrap());
let round = 1;
let set_id = 1;
@@ -579,23 +579,23 @@ where
Block: 'static,
B: Backend<Block>,
C: crate::ClientForGrandpa<Block, B> + 'static,
N: NetworkT<Block> + 'static + Send,
N: NetworkT<Block> + 'static + Send + Sync,
SC: SelectChain<Block> + 'static,
VR: VotingRule<Block, C>,
NumberFor<Block>: BlockNumberOps,
{
type Timer = Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send>>;
type Timer = Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + Sync>>;
type Id = AuthorityId;
type Signature = AuthoritySignature;
// regular round message streams
type In = Pin<Box<dyn Stream<
Item = Result<::finality_grandpa::SignedMessage<Block::Hash, NumberFor<Block>, Self::Signature, Self::Id>, Self::Error>
> + Send>>;
> + Send + Sync>>;
type Out = Pin<Box<dyn Sink<
::finality_grandpa::Message<Block::Hash, NumberFor<Block>>,
Error = Self::Error,
> + Send>>;
> + Send + Sync>>;
type Error = CommandOrError<Block::Hash, NumberFor<Block>>;
@@ -54,6 +54,7 @@ use sc_telemetry::{telemetry, CONSENSUS_INFO};
use sp_finality_grandpa::{AuthorityId, AuthorityList, VersionedAuthorityList, GRANDPA_AUTHORITIES_KEY};
use crate::justification::GrandpaJustification;
use crate::VoterSet;
/// Maximum number of fragments that we want to return in a single prove_finality call.
const MAX_FRAGMENTS_IN_PROOF: usize = 8;
@@ -588,7 +589,11 @@ impl<Block: BlockT> ProvableJustification<Block::Header> for GrandpaJustificatio
NumberFor<Block>: BlockNumberOps,
{
fn verify(&self, set_id: u64, authorities: &[(AuthorityId, u64)]) -> ClientResult<()> {
GrandpaJustification::verify(self, set_id, &authorities.iter().cloned().collect())
let authorities = VoterSet::new(authorities.iter().cloned()).ok_or(
ClientError::Consensus(sp_consensus::Error::InvalidAuthoritiesSet),
)?;
GrandpaJustification::verify(self, set_id, &authorities)
}
}
+15 -6
View File
@@ -674,7 +674,7 @@ pub fn run_grandpa_voter<Block: BlockT, BE: 'static, C, N, SC, VR>(
let events = telemetry_on_connect
.for_each(move |_| {
let curr = authorities.current_authorities();
let mut auths = curr.voters().into_iter().map(|(p, _)| p);
let mut auths = curr.iter().map(|(p, _)| p);
let maybe_authority_id = authority_id(&mut auths, &conf.keystore)
.unwrap_or(Default::default());
@@ -682,8 +682,8 @@ pub fn run_grandpa_voter<Block: BlockT, BE: 'static, C, N, SC, VR>(
"authority_id" => maybe_authority_id.to_string(),
"authority_set_id" => ?authorities.set_id(),
"authorities" => {
let authorities: Vec<String> = curr.voters()
.iter().map(|(id, _)| id.to_string()).collect();
let authorities: Vec<String> = curr.iter()
.map(|(id, _)| id.to_string()).collect();
serde_json::to_string(&authorities)
.expect("authorities is always at least an empty vector; elements are always of type string")
}
@@ -823,7 +823,7 @@ where
"authority_id" => authority_id.to_string(),
"authority_set_id" => ?self.env.set_id,
"authorities" => {
let authorities: Vec<String> = self.env.voters.voters()
let authorities: Vec<String> = self.env.voters
.iter().map(|(id, _)| id.to_string()).collect();
serde_json::to_string(&authorities)
.expect("authorities is always at least an empty vector; elements are always of type string")
@@ -894,8 +894,16 @@ where
Ok(Some(set_state))
})?;
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."
)
);
self.env = Arc::new(Environment {
voters: Arc::new(new.authorities.into_iter().collect()),
voters,
set_id: new.set_id,
voter_set_state: self.env.voter_set_state.clone(),
// Fields below are simply transferred and not updated.
@@ -1017,7 +1025,8 @@ fn is_voter(
keystore: &Option<KeyStorePtr>,
) -> Option<AuthorityPair> {
match keystore {
Some(keystore) => voters.voters().iter()
Some(keystore) => voters
.iter()
.find_map(|(p, _)| keystore.read().key_pair::<AuthorityPair>(&p).ok()),
None => None,
}
@@ -409,11 +409,13 @@ mod tests {
(Arc::new(client), backend)
};
let voters = vec![(sp_keyring::Ed25519Keyring::Alice.public().into(), 1)];
let persistent_data = aux_schema::load_persistent(
&*backend,
client.info().genesis_hash,
0,
|| Ok(vec![]),
|| Ok(voters),
).unwrap();
let (_tx, voter_command_rx) = tracing_unbounded("");
@@ -990,7 +990,6 @@ fn test_bad_justification() {
#[test]
fn voter_persists_its_votes() {
use std::iter::FromIterator;
use std::sync::atomic::{AtomicUsize, Ordering};
use futures::future;
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver};
@@ -1145,7 +1144,7 @@ fn voter_persists_its_votes() {
let (round_rx, round_tx) = network.round_communication(
communication::Round(1),
communication::SetId(0),
Arc::new(VoterSet::from_iter(voters)),
Arc::new(VoterSet::new(voters).unwrap()),
Some(peers[1].pair().into()),
HasVoted::No,
);
@@ -147,7 +147,7 @@ pub(crate) struct UntilImported<Block: BlockT, BlockStatus, BlockSyncRequester,
inner: Fuse<I>,
ready: VecDeque<M::Blocked>,
/// Interval at which to check status of each awaited block.
check_pending: Pin<Box<dyn Stream<Item = Result<(), std::io::Error>> + Send>>,
check_pending: Pin<Box<dyn Stream<Item = Result<(), std::io::Error>> + Send + Sync>>,
/// Mapping block hashes to their block number, the point in time it was
/// first encountered (Instant) and a list of GRANDPA messages referencing
/// the block hash.