-
Notifications
You must be signed in to change notification settings - Fork 2.7k
core/finality-grandpa: Gossip synced blocks via neighbor packets #3755
Conversation
andresilva
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried to answer all the questions I found :)
| pub type AuthorityIndex = u64; | ||
|
|
||
| /// The identifier of a GRANDPA set. | ||
| // TODO: Explain what a set is. A set of notes participating in the grandpa process? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A set is a given stable set of authorities, in this case it is identified by a monotonic id.
| pub type SetId = u64; | ||
|
|
||
| /// The round indicator. | ||
| // TODO: Explain what a round is and how it relates to a set. A round in which each participant within the set votes? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A round is a voting round of the GRANDPA protocol, rounds exist in the context of a given set, i.e. they validate with the authorities assigned to the given set id.
| const KEEP_RECENT_ROUNDS: usize = 3; | ||
|
|
||
| /// Tracks topics we keep messages for. | ||
| // TODO: What is a topic? What is a KeepTopic? Maybe more of a TopicsToKeep? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A topic is an identifier for gossip messages, you subscribe to a given topic and you get messages for it. At the beginning of each round a new topic is created named something like "{SET_ID}-{ROUND_ID}". And there's also a global topic (per set) for commit and catch up messages.
IIRC this data structure is used to keep track of what topics we are currently interested in. It is used in this context to validate messages we might get from other peers and also to inform them about our current status (neighbor packet).
| /// Network level message with topic information. | ||
| #[derive(Debug, Encode, Decode)] | ||
| // TODO: Are both *prevote* and *precommit* *vote* messages? If so, this would need to be called | ||
| // PrevoteOrPrecommitMessage, right? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this can be renamed to PrevoteOrPrecommitMessage to be more explicit.
| #[derive(Debug, Encode, Decode)] | ||
| pub(super) enum VersionedNeighborPacket<N> { | ||
| pub(super) enum VersionedNeighborPacket<Block: BlockT> { | ||
| // TODO: Should we be updating this version given that this effort is a breaking change? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we should add a new variant here V2 wrapping the new neighbor packet type. In principle I think it should be possible to make this backwards-compatible (but I didn't think it through tbqh.)
| inner: parking_lot::RwLock<Inner<Block>>, | ||
| // TODO: The name `GossipValidator` seems confusing, as it does more than validating (e.g. constructing new messages). | ||
| pub(super) struct GossipValidator<Block: BlockT, Client> { | ||
| // TODO: Why does all of core/grandpa need to be Sync, hence the RwLock? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's multiple components of substrate that will need to interact with GRANDPA. The network gets a GossipValidator, the import pipeline gets a GrandpaBlockImport, and there's also the GrandpaVoter which is running in some future.
| /// A stream of input messages for a topic. | ||
| type In: Stream<Item=network_gossip::TopicNotification,Error=()>; | ||
|
|
||
| // TODO: Why are the topics block hashes? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The topics in our gossip system are hashes, they didn't need to be restricted to the same hashing as we used for blocks but that's what we have for now.
| } | ||
|
|
||
| /// Get the round messages for a round in the current set ID. These are signature-checked. | ||
| // TODO: Why is the doc comment 'Get' when this function returns a Sink? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The doc is incomplete, this gives you both a sink and stream that should provide you with IO infrastructure for the round (to get and send messages).
|
|
||
| // TODO: Adding a block in a function called 'validate' seems missleading. | ||
| // | ||
| // TODO: Is it save to give these vote and commit messages any attention at this point? Do they need to be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point we have already done checked that the message is well-formed and the signature is valid. Any further validation will only happen once we have the full ancestry of the block imported now.
|
|
||
| // TODO: This is very complex. If I understood correctly we are passing a closure to the network in which we pass a | ||
| // stream back via a oneshot. The other end of the oneshot is embedded in the `NetworkStream`, which retrieves the | ||
| // actual stream from the oneshot and polls it from now on. Couldn't `gossip.messages_for` return a stream? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I don't remember of the top of my head why we do this.
|
Closing in favor of #3800. I will follow up on the comments in future pull requests. Thanks for the help @andresilva. |
Goal
In order to participate in the Grandpa gossip process a Grandpa voter needs
to know:
Which blocks are relevant for the current round.
Where to retrieve these relevant blocks from.
Grandpa voters already exchange neighbor packets with each other in an
epidemic fashion. This pull request extends the neighbor packet by a set of
block hashes which:
The node has imported.
Have been mentioned by Grandpa prevote or precommit messages.
Within the current Grandpa round.
Listening to these extended neighbor packets a node can pass the information
down to the network sync service enabled through
#3633.
This is part two of #3629.
Possible (current) solution
In order for a component within
core/finality-grandpa/srcto be able toachieve the above goal it would need to:
(1) Receive prevote and precommit messages to keep track of the mentioned
block hashes.
(2) Somehow know whether a given block is available locally (is synced).
(3) Have access to a sink to send out the neighbor packets.
This pull request uses
core/finality-grandpa/src/communication/gossip::GossipValidatoras it hasaccess to (1) and (3) and is already the component sending out
NeighborPackets. We pass down aClient(stripped down version viaBlockStatustrait) throughNetworkBridgeinto theGossipValidatorthusalso achieving (2).
Pull request status
For now this pull request is only a draft. I am opening it up at this point
to ease architectural discussions and to ask questions marked with
TODO.What do people think of the approach of extending the
GossipValidator? Doesthis stretch the responsibilities of a network validator a bit too much given
that the new logic is proactive?