Reactor State Dependencies #5801
Replies: 4 comments 2 replies
-
Yeah, the proper fix for this would be #4644, which I think we should tackle separately. A temporary hack like passing a function to the constructor is fine.
This one's going to be a bit more tricky. I'll look into this as I prototype the router and peer store. Most likely we'll need to rewrite this reactor quite significantly with other abstractions or responsibilites.
We'll need to come up with something for height (e.g. additional peer updates), the rest I believe can be replaced by the existing peer updates.
This peer state is a consensus-local concept, and can be replaced by local state tracking e.g. in a map, using peer updates to keep track of peers coming and going. However, this state is also exposed directly via RPC. :( tendermint/rpc/core/consensus.go Line 56 in 56911ee This probably needs the RPC layer to have access to the consensus reactor so it can request this information via a method call.
This can be replaced by something like peer errors (or possibly a broader concept like peer quality). Thanks for gathering this info @alexanderbez! I don't think this sounds too bad, and we should be able to come up with reasonable solutions for most of this -- let's chew on it for a couple of days. |
Beta Was this translation helpful? Give feedback.
-
Nice, thanks for auditing all of these. A few thoughts:
|
Beta Was this translation helpful? Give feedback.
-
Summary of discussion on call about reactors sharing state:
We'll mull on this over the holidays. |
Beta Was this translation helpful? Give feedback.
-
How do we close discussions @marbar3778? |
Beta Was this translation helpful? Give feedback.
-
As we refactor the existing reactors in context of the new p2p design (ref: #5670), we need to address and come up with a clean way to handle cases where reactors depend on external/shared state, as we want reactors to be as isolated as possible and have clear boundary semantics.
Here are the finding I've compiled after reviewing all the reactors. TL;DR if there is any dependency on external/shared state, it is either a peer and/or the p2p switch.
/cc @tessr @erikgrinaker
Reactor State Dependencies
State Sync
The state sync reactor relies on no external or shared state (yay 🎉 ).
Evidence
The evidence reactor relies on the following external or shared state:
The peer height is used to determine what evidence to send to a connected peer. Specifically, if the peer's height is less than or equal to the height of the evidence, then we ignore sending that piece of evidence to the peer.
Removing this state requirement is trivial but it means sending more messages over the wire such that the receiving peer will ignore it.
Blockchain v0
The blockchain v0 reactor relies on the following external or shared state:
The reactor relies on the switch directly to get peers to broadcast messages to during
poolRoutine
. This isn't a problem though because the peer ID is part of theBlockRequest
, so we have all the info we need to send messages to that peer.There is one place where where we need the number of peers, but that is used in a log only which I suppose we can just omit.
Finally, the reactor depends on the switch to call an API on an entirely different reactor:
I'm not clear on how handle this situation. Maybe we can completely remove v0 or a figure out a way to augment the reactor such that we can call this API without needing the switch (e.g. passing a function to the constructor).
Blockchain v1
The blockchain v1 reactor relies on the following external or shared state:
The reactor relies on a p2p switch which is wrapped with a private
switchIO
type. This is somewhat problematic. The reliance on theTrySend
andBroadcast
APIs are not problematic. However, we face the same problem as we do in the blockchain v0 reactor --SwitchToConsensus
.PEX
The pex reactor relies on the following external or shared state:
A call to the peer's
NodeInfo
is made duringAddPeer
so we can add the resultingNetAddress
to the address book. Various other APIs are called such asIsOutbound
,FlushStop
, andSocketAddr
.Various APIs are called on the p2p switch such as
IsDialingOrExistingAddress
,NumPeers
,IsPeerPersistent
,DialPeerWithAddress
, andMaxNumOutboundPeers
.Mempool
The mempool reactor relies on the following external or shared state:
Various APIs are called on the peer in the mempool such as getting the peer's height via
Get
,IsRunning
andQuit
.Consensus
The consensus reactor relies on the following external or shared state:
The consensus reactor uses the peer's state, specifically to call APIs such as
RecordVote
,RecordBlockPart
andSetHasProposalBlockPart
. In fact the reactor also calls methods such asInitPeer
which internally set the peer's state.The reactor uses the switch to get all known peers so it can further call APIs on the peer's state such as
RecordVote
andRecordBlockPart
. In addition, it does peer management on the switch via API calls such asMarkPeerAsGood
andMarkPeerAsGood
.Summary
Across all the reactors, the most common calls we make to external or shared state include direct API calls on the p2p Switch and the peer's state. Some reactors only rely on a peer's height, whereas other reactors mutate peer state directly.
Beta Was this translation helpful? Give feedback.
All reactions