From 6565e1f8aa68a806b41ada27559a54871ca8fbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <andre.beat@gmail.com> Date: Thu, 8 Aug 2019 09:56:49 +0200 Subject: [PATCH] grandpa: track multiple live rounds in voter set state (#3298) * grandpa: track multiple live rounds in voter set state * grandpa: don't assume rounds are completed in-order * grandpa: fix tests * grandpa: don't assume round is being tracked on Environment::completed * grandpa: fix missing import in test --- .../core/finality-grandpa/src/aux_schema.rs | 92 +++---- .../src/communication/gossip.rs | 33 +-- .../src/communication/tests.rs | 20 +- .../core/finality-grandpa/src/environment.rs | 253 ++++++++++++------ substrate/core/finality-grandpa/src/lib.rs | 27 +- .../core/finality-grandpa/src/observer.rs | 24 +- substrate/core/finality-grandpa/src/tests.rs | 1 + 7 files changed, 246 insertions(+), 204 deletions(-) diff --git a/substrate/core/finality-grandpa/src/aux_schema.rs b/substrate/core/finality-grandpa/src/aux_schema.rs index 5f430b17fee..78c1741d519 100644 --- a/substrate/core/finality-grandpa/src/aux_schema.rs +++ b/substrate/core/finality-grandpa/src/aux_schema.rs @@ -30,7 +30,9 @@ use fg_primitives::AuthorityId; use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind}; use crate::consensus_changes::{SharedConsensusChanges, ConsensusChanges}; -use crate::environment::{CompletedRound, CompletedRounds, HasVoted, SharedVoterSetState, VoterSetState}; +use crate::environment::{ + CompletedRound, CompletedRounds, CurrentRounds, HasVoted, SharedVoterSetState, VoterSetState, +}; use crate::NewAuthoritySet; const VERSION_KEY: &[u8] = b"grandpa_schema_version"; @@ -155,6 +157,9 @@ fn migrate_from_version0<Block: BlockT, B, G>( let base = last_round_state.prevote_ghost .expect("state is for completed round; completed rounds must have a prevote ghost; qed."); + let mut current_rounds = CurrentRounds::new(); + current_rounds.insert(last_round_number + 1, HasVoted::No); + let set_state = VoterSetState::Live { completed_rounds: CompletedRounds::new( CompletedRound { @@ -166,7 +171,7 @@ fn migrate_from_version0<Block: BlockT, B, G>( set_id, &new_set, ), - current_round: HasVoted::No, + current_rounds, }; backend.insert_aux(&[(SET_STATE_KEY, set_state.encode().as_slice())], &[])?; @@ -223,9 +228,12 @@ fn migrate_from_version1<Block: BlockT, B, G>( let base = set_state.prevote_ghost .expect("state is for completed round; completed rounds must have a prevote ghost; qed."); + let mut current_rounds = CurrentRounds::new(); + current_rounds.insert(last_round_number + 1, HasVoted::No); + VoterSetState::Live { completed_rounds: completed_rounds(last_round_number, set_state, base), - current_round: HasVoted::No, + current_rounds, } }, None => { @@ -233,10 +241,11 @@ fn migrate_from_version1<Block: BlockT, B, G>( let base = set_state.prevote_ghost .expect("state is for completed round; completed rounds must have a prevote ghost; qed."); - VoterSetState::Live { - completed_rounds: completed_rounds(0, set_state, base), - current_round: HasVoted::No, - } + VoterSetState::live( + set_id, + &set, + base, + ) }, }; @@ -300,19 +309,11 @@ pub(crate) fn load_persistent<Block: BlockT, B, G>( let base = state.prevote_ghost .expect("state is for completed round; completed rounds must have a prevote ghost; qed."); - VoterSetState::Live { - completed_rounds: CompletedRounds::new( - CompletedRound { - number: 0, - votes: Vec::new(), - base, - state, - }, - set.current().0, - &set, - ), - current_round: HasVoted::No, - } + VoterSetState::live( + set.current().0, + &set, + base, + ) } }; @@ -338,19 +339,12 @@ pub(crate) fn load_persistent<Block: BlockT, B, G>( let base = state.prevote_ghost .expect("state is for completed round; completed rounds must have a prevote ghost; qed."); - let genesis_state = VoterSetState::Live { - completed_rounds: CompletedRounds::new( - CompletedRound { - number: 0, - votes: Vec::new(), - state, - base, - }, - 0, - &genesis_set, - ), - current_round: HasVoted::No, - }; + let genesis_state = VoterSetState::live( + 0, + &genesis_set, + base, + ); + backend.insert_aux( &[ (AUTHORITY_SET_KEY, genesis_set.encode().as_slice()), @@ -396,23 +390,11 @@ pub(crate) fn update_authority_set<Block: BlockT, F, R>( // we also overwrite the "last completed round" entry with a blank slate // because from the perspective of the finality gadget, the chain has // reset. - let round_state = RoundState::genesis(( - new_set.canon_hash.clone(), - new_set.canon_number.clone(), - )); - let set_state = VoterSetState::<Block>::Live { - completed_rounds: CompletedRounds::new( - CompletedRound { - number: 0, - state: round_state, - votes: Vec::new(), - base: (new_set.canon_hash, new_set.canon_number), - }, - new_set.set_id, - &set, - ), - current_round: HasVoted::No, - }; + let set_state = VoterSetState::<Block>::live( + new_set.set_id, + &set, + (new_set.canon_hash, new_set.canon_number), + ); let encoded = set_state.encode(); write_aux(&[ @@ -527,6 +509,9 @@ mod test { }, ); + let mut current_rounds = CurrentRounds::new(); + current_rounds.insert(round_number + 1, HasVoted::No); + assert_eq!( &*set_state.read(), &VoterSetState::Live { @@ -540,7 +525,7 @@ mod test { set_id, &*authority_set.inner().read(), ), - current_round: HasVoted::No, + current_rounds, }, ); } @@ -614,6 +599,9 @@ mod test { }, ); + let mut current_rounds = CurrentRounds::new(); + current_rounds.insert(round_number + 1, HasVoted::No); + assert_eq!( &*set_state.read(), &VoterSetState::Live { @@ -627,7 +615,7 @@ mod test { set_id, &*authority_set.inner().read(), ), - current_round: HasVoted::No, + current_rounds, }, ); } diff --git a/substrate/core/finality-grandpa/src/communication/gossip.rs b/substrate/core/finality-grandpa/src/communication/gossip.rs index 5eb912c9576..20a629b6ae3 100644 --- a/substrate/core/finality-grandpa/src/communication/gossip.rs +++ b/substrate/core/finality-grandpa/src/communication/gossip.rs @@ -1248,26 +1248,16 @@ mod tests { // dummy voter set state fn voter_set_state() -> SharedVoterSetState<Block> { use crate::authorities::AuthoritySet; - use crate::environment::{CompletedRound, CompletedRounds, HasVoted, VoterSetState}; - use grandpa::round::State as RoundState; + use crate::environment::VoterSetState; use primitives::H256; - let state = RoundState::genesis((H256::zero(), 0)); - let base = state.prevote_ghost.unwrap(); + let base = (H256::zero(), 0); let voters = AuthoritySet::genesis(Vec::new()); - let set_state = VoterSetState::Live { - completed_rounds: CompletedRounds::new( - CompletedRound { - state, - number: 0, - votes: Vec::new(), - base, - }, - 0, - &voters, - ), - current_round: HasVoted::No, - }; + let set_state = VoterSetState::live( + 0, + &voters, + base, + ); set_state.into() } @@ -1542,16 +1532,19 @@ mod tests { let set_state: SharedVoterSetState<Block> = { let mut completed_rounds = voter_set_state().read().completed_rounds(); - assert!(completed_rounds.push(environment::CompletedRound { + completed_rounds.push(environment::CompletedRound { number: 1, state: grandpa::round::State::genesis(Default::default()), base: Default::default(), votes: Default::default(), - })); + }); + + let mut current_rounds = environment::CurrentRounds::new(); + current_rounds.insert(2, environment::HasVoted::No); let set_state = environment::VoterSetState::<Block>::Live { completed_rounds, - current_round: environment::HasVoted::No, + current_rounds, }; set_state.into() diff --git a/substrate/core/finality-grandpa/src/communication/tests.rs b/substrate/core/finality-grandpa/src/communication/tests.rs index 70e9413cd9c..de5a0840392 100644 --- a/substrate/core/finality-grandpa/src/communication/tests.rs +++ b/substrate/core/finality-grandpa/src/communication/tests.rs @@ -141,26 +141,18 @@ fn config() -> crate::Config { // dummy voter set state fn voter_set_state() -> SharedVoterSetState<Block> { use crate::authorities::AuthoritySet; - use crate::environment::{CompletedRound, CompletedRounds, HasVoted, VoterSetState}; + use crate::environment::VoterSetState; use grandpa::round::State as RoundState; use primitives::H256; let state = RoundState::genesis((H256::zero(), 0)); let base = state.prevote_ghost.unwrap(); let voters = AuthoritySet::genesis(Vec::new()); - let set_state = VoterSetState::Live { - completed_rounds: CompletedRounds::new( - CompletedRound { - state, - number: 0, - votes: Vec::new(), - base, - }, - 0, - &voters, - ), - current_round: HasVoted::No, - }; + let set_state = VoterSetState::live( + 0, + &voters, + base, + ); set_state.into() } diff --git a/substrate/core/finality-grandpa/src/environment.rs b/substrate/core/finality-grandpa/src/environment.rs index 93b176a430e..5761093c5eb 100644 --- a/substrate/core/finality-grandpa/src/environment.rs +++ b/substrate/core/finality-grandpa/src/environment.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see <http://www.gnu.org/licenses/>. -use std::collections::VecDeque; +use std::collections::BTreeMap; use std::iter::FromIterator; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -74,11 +74,12 @@ pub struct CompletedRound<Block: BlockT> { pub votes: Vec<SignedMessage<Block>>, } -// Data about last completed rounds within a single voter set. Stores NUM_LAST_COMPLETED_ROUNDS and always -// contains data about at least one round (genesis). +// Data about last completed rounds within a single voter set. Stores +// NUM_LAST_COMPLETED_ROUNDS and always contains data about at least one round +// (genesis). #[derive(Debug, Clone, PartialEq)] pub struct CompletedRounds<Block: BlockT> { - rounds: VecDeque<CompletedRound<Block>>, + rounds: Vec<CompletedRound<Block>>, set_id: u64, voters: Vec<AuthorityId>, } @@ -117,8 +118,8 @@ impl<Block: BlockT> CompletedRounds<Block> { ) -> CompletedRounds<Block> { - let mut rounds = VecDeque::with_capacity(NUM_LAST_COMPLETED_ROUNDS); - rounds.push_back(genesis); + let mut rounds = Vec::with_capacity(NUM_LAST_COMPLETED_ROUNDS); + rounds.push(genesis); let voters = voters.current().1.iter().map(|(a, _)| a.clone()).collect(); CompletedRounds { rounds, set_id, voters } @@ -131,32 +132,38 @@ impl<Block: BlockT> CompletedRounds<Block> { /// Iterate over all completed rounds. pub fn iter(&self) -> impl Iterator<Item=&CompletedRound<Block>> { - self.rounds.iter() + self.rounds.iter().rev() } /// Returns the last (latest) completed round. pub fn last(&self) -> &CompletedRound<Block> { - self.rounds.back() + self.rounds.first() .expect("inner is never empty; always contains at least genesis; qed") } - /// Push a new completed round, returns false if the given round is older - /// than the last completed round. - pub fn push(&mut self, completed_round: CompletedRound<Block>) -> bool { - if self.last().number >= completed_round.number { - return false; - } + /// Push a new completed round, oldest round is evicted if number of rounds + /// is higher than `NUM_LAST_COMPLETED_ROUNDS`. + 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), + ) { + Ok(idx) => self.rounds[idx] = completed_round, + Err(idx) => self.rounds.insert(idx, completed_round), + }; - if self.rounds.len() == NUM_LAST_COMPLETED_ROUNDS { - self.rounds.pop_front(); + if self.rounds.len() > NUM_LAST_COMPLETED_ROUNDS { + self.rounds.pop(); } - - self.rounds.push_back(completed_round); - - true } } +/// A map with voter status information for currently live rounds, +/// which votes have we cast and what are they. +pub type CurrentRounds<Block> = BTreeMap<u64, HasVoted<Block>>; + /// The state of the current voter set, whether it is currently active or not /// and information related to the previously completed rounds. Current round /// voting status is used when restarting the voter, i.e. it will re-use the @@ -168,8 +175,8 @@ pub enum VoterSetState<Block: BlockT> { Live { /// The previously completed rounds. completed_rounds: CompletedRounds<Block>, - /// Vote status for the current round. - current_round: HasVoted<Block>, + /// Voter status for the currently live rounds. + current_rounds: CurrentRounds<Block>, }, /// The voter is paused, i.e. not casting or importing any votes. Paused { @@ -179,6 +186,35 @@ pub enum VoterSetState<Block: BlockT> { } impl<Block: BlockT> VoterSetState<Block> { + /// Create a new live VoterSetState with round 0 as a completed round using + /// the given genesis state and the given authorities. Round 1 is added as a + /// current round (with state `HasVoted::No`). + pub(crate) fn live( + set_id: u64, + authority_set: &AuthoritySet<Block::Hash, NumberFor<Block>>, + genesis_state: (Block::Hash, NumberFor<Block>), + ) -> VoterSetState<Block> { + let state = RoundState::genesis((genesis_state.0, genesis_state.1)); + let completed_rounds = CompletedRounds::new( + CompletedRound { + number: 0, + state, + base: (genesis_state.0, genesis_state.1), + votes: Vec::new(), + }, + set_id, + authority_set, + ); + + let mut current_rounds = CurrentRounds::new(); + current_rounds.insert(1, HasVoted::No); + + VoterSetState::Live { + completed_rounds, + current_rounds, + } + } + /// Returns the last completed rounds. pub(crate) fn completed_rounds(&self) -> CompletedRounds<Block> { match self { @@ -198,10 +234,28 @@ impl<Block: BlockT> VoterSetState<Block> { 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: u64) + -> Result<(&CompletedRounds<Block>, &CurrentRounds<Block>), Error> + { + if let VoterSetState::Live { completed_rounds, current_rounds } = self { + if current_rounds.contains_key(&round) { + return Ok((completed_rounds, current_rounds)); + } else { + let msg = "Voter acting on a live round we are not tracking."; + return Err(Error::Safety(msg.to_string())); + } + } else { + let msg = "Voter acting while in paused state."; + return Err(Error::Safety(msg.to_string())); + } + } } /// Whether we've voted already during a prior run of the program. -#[derive(Debug, Decode, Encode, PartialEq)] +#[derive(Clone, Debug, Decode, Encode, PartialEq)] pub enum HasVoted<Block: BlockT> { /// Has not voted already in this round. No, @@ -290,10 +344,16 @@ impl<Block: BlockT> SharedVoterSetState<Block> { } /// Return vote status information for the current round. - pub(crate) fn has_voted(&self) -> HasVoted<Block> { + pub(crate) fn has_voted(&self, round: u64) -> HasVoted<Block> { match &*self.inner.read() { - VoterSetState::Live { current_round: HasVoted::Yes(id, vote), .. } => - 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) + }, _ => HasVoted::No, } } @@ -502,7 +562,7 @@ where let local_key = crate::is_voter(&self.voters, &self.config.keystore); - let has_voted = match self.voter_set_state.has_voted() { + let has_voted = match self.voter_set_state.has_voted(round) { HasVoted::Yes(id, vote) => { if local_key.as_ref().map(|k| k.public() == id).unwrap_or(false) { HasVoted::Yes(id, vote) @@ -541,7 +601,7 @@ where } } - fn proposed(&self, _round: u64, propose: PrimaryPropose<Block>) -> Result<(), Self::Error> { + fn proposed(&self, round: u64, propose: PrimaryPropose<Block>) -> Result<(), Self::Error> { let local_id = crate::is_voter(&self.voters, &self.config.keystore); let local_id = match local_id { @@ -550,23 +610,26 @@ where }; self.update_voter_set_state(|voter_set_state| { - let completed_rounds = match voter_set_state { - VoterSetState::Live { completed_rounds, current_round: HasVoted::No } => completed_rounds, - VoterSetState::Live { current_round, .. } 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); - }, - _ => { - let msg = "Voter proposing after prevote/precommit or while paused."; - return Err(Error::Safety(msg.to_string())); - }, - }; + let (completed_rounds, current_rounds) = voter_set_state.with_current_round(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); + } + + let mut current_rounds = current_rounds.clone(); + let current_round = current_rounds.get_mut(&round) + .expect("checked previously that key exists; qed."); + + *current_round = HasVoted::Yes(local_id, Vote::Propose(propose)); let set_state = VoterSetState::<Block>::Live { completed_rounds: completed_rounds.clone(), - current_round: HasVoted::Yes(local_id, Vote::Propose(propose)), + current_rounds, }; #[allow(deprecated)] @@ -578,7 +641,7 @@ where Ok(()) } - fn prevoted(&self, _round: u64, prevote: Prevote<Block>) -> Result<(), Self::Error> { + fn prevoted(&self, round: u64, prevote: Prevote<Block>) -> Result<(), Self::Error> { let local_id = crate::is_voter(&self.voters, &self.config.keystore); let local_id = match local_id { @@ -587,26 +650,28 @@ where }; self.update_voter_set_state(|voter_set_state| { - let (completed_rounds, propose) = match voter_set_state { - VoterSetState::Live { completed_rounds, current_round: HasVoted::No } => - (completed_rounds, None), - VoterSetState::Live { completed_rounds, current_round: HasVoted::Yes(_, Vote::Propose(propose)) } => - (completed_rounds, Some(propose)), - VoterSetState::Live { current_round, .. } if !current_round.can_prevote() => { - // 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); - }, - _ => { - let msg = "Voter prevoting after precommit or while paused."; - return Err(Error::Safety(msg.to_string())); - }, - }; + let (completed_rounds, current_rounds) = voter_set_state.with_current_round(round)?; + let current_round = current_rounds.get(&round) + .expect("checked in with_current_round that key exists; qed."); + + if !current_round.can_prevote() { + // 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); + } + + let propose = current_round.propose(); + + let mut current_rounds = current_rounds.clone(); + 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)); let set_state = VoterSetState::<Block>::Live { completed_rounds: completed_rounds.clone(), - current_round: HasVoted::Yes(local_id, Vote::Prevote(propose.cloned(), prevote)), + current_rounds, }; #[allow(deprecated)] @@ -618,7 +683,7 @@ where Ok(()) } - fn precommitted(&self, _round: u64, precommit: Precommit<Block>) -> Result<(), Self::Error> { + fn precommitted(&self, round: u64, precommit: Precommit<Block>) -> Result<(), Self::Error> { let local_id = crate::is_voter(&self.voters, &self.config.keystore); let local_id = match local_id { @@ -627,24 +692,38 @@ where }; self.update_voter_set_state(|voter_set_state| { - let (completed_rounds, propose, prevote) = match voter_set_state { - VoterSetState::Live { completed_rounds, current_round: HasVoted::Yes(_, Vote::Prevote(propose, prevote)) } => - (completed_rounds, propose, prevote), - VoterSetState::Live { current_round, .. } if !current_round.can_precommit() => { - // 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); - }, + let (completed_rounds, current_rounds) = voter_set_state.with_current_round(round)?; + let current_round = current_rounds.get(&round) + .expect("checked in with_current_round that key exists; qed."); + + if !current_round.can_precommit() { + // 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); + } + + let propose = current_round.propose(); + let prevote = match current_round { + HasVoted::Yes(_, Vote::Prevote(_, prevote)) => prevote, _ => { - let msg = "Voter precommitting while paused."; + let msg = "Voter precommitting before prevoting."; return Err(Error::Safety(msg.to_string())); - } + }, }; + let mut current_rounds = current_rounds.clone(); + let current_round = current_rounds.get_mut(&round) + .expect("checked previously that key exists; qed."); + + *current_round = HasVoted::Yes( + local_id, + Vote::Precommit(propose.cloned(), prevote.clone(), precommit), + ); + let set_state = VoterSetState::<Block>::Live { completed_rounds: completed_rounds.clone(), - current_round: HasVoted::Yes(local_id, Vote::Precommit(propose.clone(), prevote.clone(), precommit)), + current_rounds, }; #[allow(deprecated)] @@ -673,25 +752,37 @@ where ); self.update_voter_set_state(|voter_set_state| { - let mut completed_rounds = voter_set_state.completed_rounds(); + // NOTE: we don't use `with_current_round` here, it is possible that + // we are not currently tracking this round if it is a round we + // caught up to. + let (completed_rounds, current_rounds) = + if let VoterSetState::Live { completed_rounds, current_rounds } = voter_set_state { + (completed_rounds, current_rounds) + } else { + let msg = "Voter acting while in paused state."; + return Err(Error::Safety(msg.to_string())); + }; + + let mut completed_rounds = completed_rounds.clone(); // TODO: Future integration will store the prevote and precommit index. See #2611. let votes = historical_votes.seen().clone(); - // NOTE: the Environment assumes that rounds are *always* completed in-order. - if !completed_rounds.push(CompletedRound { + completed_rounds.push(CompletedRound { number: round, state: state.clone(), base, votes, - }) { - let msg = "Voter completed round that is older than the last completed round."; - return Err(Error::Safety(msg.to_string())); - }; + }); + + // remove the round from live rounds and start tracking the next round + let mut current_rounds = current_rounds.clone(); + current_rounds.remove(&round); + current_rounds.insert(round + 1, HasVoted::No); let set_state = VoterSetState::<Block>::Live { completed_rounds, - current_round: HasVoted::No, + current_rounds, }; #[allow(deprecated)] diff --git a/substrate/core/finality-grandpa/src/lib.rs b/substrate/core/finality-grandpa/src/lib.rs index a0df661f0cf..474d0ae24b4 100644 --- a/substrate/core/finality-grandpa/src/lib.rs +++ b/substrate/core/finality-grandpa/src/lib.rs @@ -75,7 +75,7 @@ use serde_json; use srml_finality_tracker; use grandpa::Error as GrandpaError; -use grandpa::{voter, round::State as RoundState, BlockNumberOps, voter_set::VoterSet}; +use grandpa::{voter, BlockNumberOps, voter_set::VoterSet}; use std::fmt; use std::sync::Arc; @@ -103,7 +103,7 @@ pub use light_import::light_block_import; pub use observer::run_grandpa_observer; use aux_schema::PersistentData; -use environment::{CompletedRound, CompletedRounds, Environment, HasVoted, SharedVoterSetState, VoterSetState}; +use environment::{Environment, SharedVoterSetState, VoterSetState}; use import::GrandpaBlockImport; use until_imported::UntilGlobalMessageBlocksImported; use communication::NetworkBridge; @@ -635,22 +635,11 @@ pub fn run_grandpa_voter<B, E, Block: BlockT<Hash=H256>, N, RA, SC, X>( // start the new authority set using the block where the // set changed (not where the signal happened!) as the base. - let genesis_state = RoundState::genesis((new.canon_hash, new.canon_number)); - - let set_state = VoterSetState::Live { - // always start at round 0 when changing sets. - completed_rounds: CompletedRounds::new( - CompletedRound { - number: 0, - state: genesis_state, - base: (new.canon_hash, new.canon_number), - votes: Vec::new(), - }, - new.set_id, - &*authority_set.inner().read(), - ), - current_round: HasVoted::No, - }; + let set_state = VoterSetState::live( + new.set_id, + &*authority_set.inner().read(), + (new.canon_hash, new.canon_number), + ); #[allow(deprecated)] aux_schema::write_voter_set_state(&**client.backend(), &set_state)?; @@ -763,4 +752,4 @@ fn is_voter( .find_map(|(p, _)| keystore.read().key_pair::<AuthorityPair>(&p).ok()), None => None, } -} \ No newline at end of file +} diff --git a/substrate/core/finality-grandpa/src/observer.rs b/substrate/core/finality-grandpa/src/observer.rs index f347b678b6c..2532ee80982 100644 --- a/substrate/core/finality-grandpa/src/observer.rs +++ b/substrate/core/finality-grandpa/src/observer.rs @@ -20,7 +20,7 @@ use futures::prelude::*; use futures::future::{self, Loop as FutureLoop}; use grandpa::{ - BlockNumberOps, Error as GrandpaError, round::State as RoundState, voter, voter_set::VoterSet + BlockNumberOps, Error as GrandpaError, voter, voter_set::VoterSet }; use log::{debug, info, warn}; @@ -36,7 +36,6 @@ use crate::{ use crate::authorities::SharedAuthoritySet; use crate::communication::NetworkBridge; use crate::consensus_changes::SharedConsensusChanges; -use crate::environment::{CompletedRound, CompletedRounds, HasVoted}; use fg_primitives::AuthorityId; struct ObserverChain<'a, Block: BlockT, B, E, RA>(&'a Client<B, E, Block, RA>); @@ -238,22 +237,11 @@ pub fn run_grandpa_observer<B, E, Block: BlockT<Hash=H256>, N, RA, SC>( VoterCommand::ChangeAuthorities(new) => { // start the new authority set using the block where the // set changed (not where the signal happened!) as the base. - let genesis_state = RoundState::genesis((new.canon_hash, new.canon_number)); - - let set_state = VoterSetState::Live::<Block> { - // always start at round 0 when changing sets. - completed_rounds: CompletedRounds::new( - CompletedRound { - number: 0, - state: genesis_state, - base: (new.canon_hash, new.canon_number), - votes: Vec::new(), - }, - new.set_id, - &*authority_set.inner().read(), - ), - current_round: HasVoted::No, - }; + let set_state = VoterSetState::live( + new.set_id, + &*authority_set.inner().read(), + (new.canon_hash, new.canon_number), + ); #[allow(deprecated)] crate::aux_schema::write_voter_set_state(&**client.backend(), &set_state)?; diff --git a/substrate/core/finality-grandpa/src/tests.rs b/substrate/core/finality-grandpa/src/tests.rs index 45a91b336a1..7c2b024f5cc 100644 --- a/substrate/core/finality-grandpa/src/tests.rs +++ b/substrate/core/finality-grandpa/src/tests.rs @@ -17,6 +17,7 @@ //! Tests and test helpers for GRANDPA. use super::*; +use environment::HasVoted; use network::test::{Block, DummySpecialization, Hash, TestNetFactory, Peer, PeersClient}; use network::test::{PassThroughVerifier}; use network::config::{ProtocolConfig, Roles, BoxFinalityProofRequestBuilder}; -- GitLab