Skip to content
Snippets Groups Projects
Commit abaaaaff authored by Max Inden's avatar Max Inden Committed by André Silva
Browse files

core/finality-grandpa: Minor refactorings (#3825)

* core/finality-grandpa: Improve code comments

* core/finality-grandpa: Rename VoteOrPrecommit to PrevoteOrPrecommit

According to the Grandpa paper [1]:

> A vote is a block hash, together with some metadata such as round
number and the type of vote, such as prevote or precommit, all signed
with a voter’s private key.

To reduce confusion this patch makes the code consistent with the
research paper.

[1] https://github.com/w3f/consensus/blob/master/pdf/grandpa.pdf

* core/finality-grandpa: Add comment for NetworkStream concept

* core/finality-grandpa: Improve round_communication doc comment

* core/finality-grandpa: Rename PrevoteOrPrecommit to Vote

* core/finality-grandpa: Represent NetworkStream state machine as enum

* core/finality-grandpa: Improve KeepTopics comment
parent 31eebdf3
Branches
No related merge requests found
...@@ -52,7 +52,7 @@ pub type AuthorityWeight = u64; ...@@ -52,7 +52,7 @@ pub type AuthorityWeight = u64;
/// The index of an authority. /// The index of an authority.
pub type AuthorityIndex = u64; pub type AuthorityIndex = u64;
/// The identifier of a GRANDPA set. /// The monotonic identifier of a GRANDPA set of authorities.
pub type SetId = u64; pub type SetId = u64;
/// The round indicator. /// The round indicator.
......
...@@ -183,7 +183,13 @@ impl<N: Ord> View<N> { ...@@ -183,7 +183,13 @@ impl<N: Ord> View<N> {
const KEEP_RECENT_ROUNDS: usize = 3; const KEEP_RECENT_ROUNDS: usize = 3;
/// Tracks topics we keep messages for. /// Tracks gossip topics that we are keeping messages for. We keep topics of:
///
/// - the last `KEEP_RECENT_ROUNDS` complete GRANDPA rounds,
///
/// - the topic for the current and next round,
///
/// - and a global topic for commit and catch-up messages.
struct KeepTopics<B: BlockT> { struct KeepTopics<B: BlockT> {
current_set: SetId, current_set: SetId,
rounds: VecDeque<(Round, SetId)>, rounds: VecDeque<(Round, SetId)>,
...@@ -256,7 +262,7 @@ fn neighbor_topics<B: BlockT>(view: &View<NumberFor<B>>) -> Vec<B::Hash> { ...@@ -256,7 +262,7 @@ fn neighbor_topics<B: BlockT>(view: &View<NumberFor<B>>) -> Vec<B::Hash> {
#[derive(Debug, Encode, Decode)] #[derive(Debug, Encode, Decode)]
pub(super) enum GossipMessage<Block: BlockT> { pub(super) enum GossipMessage<Block: BlockT> {
/// Grandpa message with round and set info. /// Grandpa message with round and set info.
VoteOrPrecommit(VoteOrPrecommitMessage<Block>), Vote(VoteMessage<Block>),
/// Grandpa commit message with round and set info. /// Grandpa commit message with round and set info.
Commit(FullCommitMessage<Block>), Commit(FullCommitMessage<Block>),
/// A neighbor packet. Not repropagated. /// A neighbor packet. Not repropagated.
...@@ -273,9 +279,9 @@ impl<Block: BlockT> From<NeighborPacket<NumberFor<Block>>> for GossipMessage<Blo ...@@ -273,9 +279,9 @@ impl<Block: BlockT> From<NeighborPacket<NumberFor<Block>>> for GossipMessage<Blo
} }
} }
/// Network level message with topic information. /// Network level vote message with topic information.
#[derive(Debug, Encode, Decode)] #[derive(Debug, Encode, Decode)]
pub(super) struct VoteOrPrecommitMessage<Block: BlockT> { pub(super) struct VoteMessage<Block: BlockT> {
/// The round this message is from. /// The round this message is from.
pub(super) round: Round, pub(super) round: Round,
/// The voter set ID this message is from. /// The voter set ID this message is from.
...@@ -612,7 +618,7 @@ impl<Block: BlockT> Inner<Block> { ...@@ -612,7 +618,7 @@ impl<Block: BlockT> Inner<Block> {
cost::PAST_REJECTION cost::PAST_REJECTION
} }
fn validate_round_message(&self, who: &PeerId, full: &VoteOrPrecommitMessage<Block>) fn validate_round_message(&self, who: &PeerId, full: &VoteMessage<Block>)
-> Action<Block::Hash> -> Action<Block::Hash>
{ {
match self.consider_vote(full.round, full.set_id) { match self.consider_vote(full.round, full.set_id) {
...@@ -1003,7 +1009,7 @@ impl<Block: BlockT> GossipValidator<Block> { ...@@ -1003,7 +1009,7 @@ impl<Block: BlockT> GossipValidator<Block> {
let action = { let action = {
match GossipMessage::<Block>::decode(&mut data) { match GossipMessage::<Block>::decode(&mut data) {
Ok(GossipMessage::VoteOrPrecommit(ref message)) Ok(GossipMessage::Vote(ref message))
=> self.inner.write().validate_round_message(who, message), => self.inner.write().validate_round_message(who, message),
Ok(GossipMessage::Commit(ref message)) => self.inner.write().validate_commit_message(who, message), Ok(GossipMessage::Commit(ref message)) => self.inner.write().validate_commit_message(who, message),
Ok(GossipMessage::Neighbor(update)) => { Ok(GossipMessage::Neighbor(update)) => {
...@@ -1163,7 +1169,7 @@ impl<Block: BlockT> network_gossip::Validator<Block> for GossipValidator<Block> ...@@ -1163,7 +1169,7 @@ impl<Block: BlockT> network_gossip::Validator<Block> for GossipValidator<Block>
Ok(GossipMessage::Neighbor(_)) => false, Ok(GossipMessage::Neighbor(_)) => false,
Ok(GossipMessage::CatchUpRequest(_)) => false, Ok(GossipMessage::CatchUpRequest(_)) => false,
Ok(GossipMessage::CatchUp(_)) => false, Ok(GossipMessage::CatchUp(_)) => false,
Ok(GossipMessage::VoteOrPrecommit(_)) => false, // should not be the case. Ok(GossipMessage::Vote(_)) => false, // should not be the case.
} }
}) })
} }
...@@ -1478,7 +1484,7 @@ mod tests { ...@@ -1478,7 +1484,7 @@ mod tests {
val.note_round(Round(1), |_, _| {}); val.note_round(Round(1), |_, _| {});
let inner = val.inner.read(); let inner = val.inner.read();
let unknown_voter = inner.validate_round_message(&peer, &VoteOrPrecommitMessage { let unknown_voter = inner.validate_round_message(&peer, &VoteMessage {
round: Round(1), round: Round(1),
set_id: SetId(set_id), set_id: SetId(set_id),
message: SignedMessage::<Block> { message: SignedMessage::<Block> {
...@@ -1491,7 +1497,7 @@ mod tests { ...@@ -1491,7 +1497,7 @@ mod tests {
} }
}); });
let bad_sig = inner.validate_round_message(&peer, &VoteOrPrecommitMessage { let bad_sig = inner.validate_round_message(&peer, &VoteMessage {
round: Round(1), round: Round(1),
set_id: SetId(set_id), set_id: SetId(set_id),
message: SignedMessage::<Block> { message: SignedMessage::<Block> {
......
...@@ -48,7 +48,7 @@ use crate::{ ...@@ -48,7 +48,7 @@ use crate::{
}; };
use crate::environment::HasVoted; use crate::environment::HasVoted;
use gossip::{ use gossip::{
GossipMessage, FullCatchUpMessage, FullCommitMessage, VoteOrPrecommitMessage, GossipValidator GossipMessage, FullCatchUpMessage, FullCommitMessage, VoteMessage, GossipValidator
}; };
use fg_primitives::{ use fg_primitives::{
AuthorityPair, AuthorityId, AuthoritySignature, SetId as SetIdNumber, RoundNumber, AuthorityPair, AuthorityId, AuthoritySignature, SetId as SetIdNumber, RoundNumber,
...@@ -148,12 +148,21 @@ impl<B, S, H> Network<B> for Arc<NetworkService<B, S, H>> where ...@@ -148,12 +148,21 @@ impl<B, S, H> Network<B> for Arc<NetworkService<B, S, H>> where
type In = NetworkStream; type In = NetworkStream;
fn messages_for(&self, topic: B::Hash) -> Self::In { fn messages_for(&self, topic: B::Hash) -> Self::In {
// Given that one can only communicate with the Substrate network via the `NetworkService` via message-passing,
// and given that methods on the network consensus gossip are not exposed but only reachable by passing a
// closure into `with_gossip` on the `NetworkService` this function needs to make use of the `NetworkStream`
// construction.
//
// We create a oneshot channel and pass the sender within a closure to the network. At some point in the future
// the network passes the message channel back through the oneshot channel. But the consumer of this function
// expects a stream, not a stream within a oneshot. This complexity is abstracted within `NetworkStream`,
// waiting for the oneshot to resolve and from there on acting like a normal message channel.
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.with_gossip(move |gossip, _| { self.with_gossip(move |gossip, _| {
let inner_rx = gossip.messages_for(GRANDPA_ENGINE_ID, topic); let inner_rx = gossip.messages_for(GRANDPA_ENGINE_ID, topic);
let _ = tx.send(inner_rx); let _ = tx.send(inner_rx);
}); });
NetworkStream { outer: rx, inner: None } NetworkStream::PollingOneshot(rx)
} }
fn register_validator(&self, validator: Arc<dyn network_gossip::Validator<B>>) { fn register_validator(&self, validator: Arc<dyn network_gossip::Validator<B>>) {
...@@ -202,10 +211,18 @@ impl<B, S, H> Network<B> for Arc<NetworkService<B, S, H>> where ...@@ -202,10 +211,18 @@ impl<B, S, H> Network<B> for Arc<NetworkService<B, S, H>> where
} }
} }
/// A stream used by NetworkBridge in its implementation of Network. /// A stream used by NetworkBridge in its implementation of Network. Given a oneshot that eventually returns a channel
pub struct NetworkStream { /// which eventually returns messages, instead of:
inner: Option<mpsc::UnboundedReceiver<network_gossip::TopicNotification>>, ///
outer: oneshot::Receiver<mpsc::UnboundedReceiver<network_gossip::TopicNotification>> /// 1. polling the oneshot until it returns a message channel
///
/// 2. polling the message channel for messages
///
/// `NetworkStream` combines the two steps into one, requiring a consumer to only poll `NetworkStream` to retrieve
/// messages directly.
pub enum NetworkStream {
PollingOneshot(oneshot::Receiver<mpsc::UnboundedReceiver<network_gossip::TopicNotification>>),
PollingTopicNotifications(mpsc::UnboundedReceiver<network_gossip::TopicNotification>),
} }
impl Stream for NetworkStream { impl Stream for NetworkStream {
...@@ -213,17 +230,21 @@ impl Stream for NetworkStream { ...@@ -213,17 +230,21 @@ impl Stream for NetworkStream {
type Error = (); type Error = ();
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if let Some(ref mut inner) = self.inner { match self {
return inner.poll(); NetworkStream::PollingOneshot(oneshot) => {
} match oneshot.poll() {
match self.outer.poll() { Ok(futures::Async::Ready(mut stream)) => {
Ok(futures::Async::Ready(mut inner)) => { let poll_result = stream.poll();
let poll_result = inner.poll(); *self = NetworkStream::PollingTopicNotifications(stream);
self.inner = Some(inner); poll_result
poll_result },
Ok(futures::Async::NotReady) => Ok(futures::Async::NotReady),
Err(_) => Err(())
}
},
NetworkStream::PollingTopicNotifications(stream) => {
stream.poll()
}, },
Ok(futures::Async::NotReady) => Ok(futures::Async::NotReady),
Err(_) => Err(())
} }
} }
} }
...@@ -275,8 +296,8 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> { ...@@ -275,8 +296,8 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
validator.note_round(Round(round.number), |_, _| {}); validator.note_round(Round(round.number), |_, _| {});
for signed in round.votes.iter() { for signed in round.votes.iter() {
let message = gossip::GossipMessage::VoteOrPrecommit( let message = gossip::GossipMessage::Vote(
gossip::VoteOrPrecommitMessage::<B> { gossip::VoteMessage::<B> {
message: signed.clone(), message: signed.clone(),
round: Round(round.number), round: Round(round.number),
set_id: SetId(set_id), set_id: SetId(set_id),
...@@ -341,7 +362,8 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> { ...@@ -341,7 +362,8 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
); );
} }
/// Get the round messages for a round in the current set ID. These are signature-checked. /// Get a stream of signature-checked round messages from the network as well as a sink for round messages to the
/// network all within the current set.
pub(crate) fn round_communication( pub(crate) fn round_communication(
&self, &self,
round: Round, round: Round,
...@@ -379,7 +401,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> { ...@@ -379,7 +401,7 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> {
}) })
.and_then(move |msg| { .and_then(move |msg| {
match msg { match msg {
GossipMessage::VoteOrPrecommit(msg) => { GossipMessage::Vote(msg) => {
// check signature. // check signature.
if !voters.contains_key(&msg.message.id) { if !voters.contains_key(&msg.message.id) {
debug!(target: "afg", "Skipping message from unknown voter {}", msg.message.id); debug!(target: "afg", "Skipping message from unknown voter {}", msg.message.id);
...@@ -707,7 +729,7 @@ impl<Block: BlockT, N: Network<Block>> Sink for OutgoingMessages<Block, N> ...@@ -707,7 +729,7 @@ impl<Block: BlockT, N: Network<Block>> Sink for OutgoingMessages<Block, N>
id: local_id.clone(), id: local_id.clone(),
}; };
let message = GossipMessage::VoteOrPrecommit(VoteOrPrecommitMessage::<Block> { let message = GossipMessage::Vote(VoteMessage::<Block> {
message: signed.clone(), message: signed.clone(),
round: Round(self.round), round: Round(self.round),
set_id: SetId(self.set_id), set_id: SetId(self.set_id),
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment