-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(blend): establish new connections, or deny new streams #989
base: blend-drop-conns
Are you sure you want to change the base?
Conversation
b79429d
to
018e6cf
Compare
d9e2d21
to
d276e59
Compare
018e6cf
to
15a6973
Compare
d276e59
to
15ab4af
Compare
nomos-blend/network/src/behaviour.rs
Outdated
if self.should_deny_stream(&peer_id) { | ||
// Notify the corresponding [`ConnectionHandler`] to close the stream. | ||
self.events.push_back(ToSwarm::NotifyHandler { | ||
peer_id, | ||
handler: NotifyHandler::One(connection_id), | ||
event: FromBehaviour::CloseSubstreams, | ||
}); |
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.
This goes before the calls of handle_established_outbound/inbound_connection
right? Anyway, we should check if by the time this event is processed we didn't open a stream already. Because we are opening streams for any in/out-bound connections.
Is that the case?
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.
Since they don't have a proper documentation, I investigated their code.
This ConnectionEstablished
event is triggered AFTER the handle_established_outbound/inbound_connection
is called and the ConnectionHandler
is returned from that.
It means that the FromBehaviour::CloseSubstreams
that I'm scheduling here will be defintely delivered to the ConnectionHandler
. If the ConnectionHandler
already established inbound/outbound substreams, they will be replaced with the Dropped
state, as I implemented in #988. Even if they're not initialized yet, they'll be set as Dropped
and are never going to be initalized.
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.
I still think in this case it is easier to just reject the connection in the handle_stablished_outbound/inbound
from this behaviour anaway. Accepting a connection just to get it closed feels weird. Maybe I'm missing something here.
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.
Okay. That was my initial implementation when I opened this PR, but changed it while having discussions in other PRs. Rejecting the connection itself is the recommended way by libp2p, as far as I understand. However, as I've been saying, if we have to consider the case where multiple behaviours share a connection, things are complicated, and libp2p don't give us a clear approach. We need to decide.
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.
Let's use the way libp2p recommends. I will revert the handle_established_outbound/inbound_connection
to deny the connection.
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.
4680e94 I just updated this PR by using libp2p-allow-block-list
and libp2p-connection-limits
. It would be better to review this PR itself again, but it might be also easy to review the specific commit if you want.
15a6973
to
21cf051
Compare
15ab4af
to
6e56328
Compare
nomos-blend/network/src/peer_sets.rs
Outdated
pub(crate) fn set_malicious(&mut self, peer_id: PeerId) { | ||
self.negotiated_healthy_peers.remove(&peer_id); | ||
self.negotiated_unhealthy_peers.remove(&peer_id); | ||
self.malicious_peers.insert(peer_id); | ||
} |
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.
If when setting a peer as malicious they are removed from healthy and unhealthy; shouldn't it happen the other way around? E.g.: Shouldn't set_unhealthy
remove from malicious_peers
?
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.
Ah, good point. Actually, in the current spec, any peer who has been set as malicious can't be removed from the malicious set. But, yeah, as you said, we should handle the case when the peer is in the malicious set at the moment when set_unhealthy
is called. I will re-think about this state machine and refine it.
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.
I removed this peer_sets.rs
because I found and use libp2p-allow-block-list
and libp2p-connection-limits
in the end. 4680e94
They simplify this PR a lot. Instead of maintaining the malicious_peers
set, now we add malicious peers to the libp2p block list, so that the connections from them or to them can be denied / closed.
It would be better to review this PR itself again, but it might be also easy to review the specific commit if you want.
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.
I'll go over it again, no worries :)
@@ -7,7 +7,7 @@ edition = "2021" | |||
cached = "0.53.1" | |||
futures = "0.3.30" | |||
futures-timer = "3.0.3" | |||
libp2p = "0.53" | |||
libp2p = "0.55" |
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.
To use all functions of libp2p-allow-block-list
, we need to upgrade libp2p to 0.55: libp2p/rust-libp2p@e63975d.
pub fn unsubscribe(&mut self, topic: &str) -> Result<bool, PublishError> { | ||
pub fn unsubscribe(&mut self, topic: &str) -> bool { |
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.
This is because the unsubscribe
API has changed in libp2p v0.55
// TODO: Instead of holding the membership, we just want a way to get the list of addresses. | ||
membership: Membership<PeerId, SphinxMessage>, | ||
rng: R, | ||
peering_degree: usize, |
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.
I'll update this to u16
by rebasing this branch to the #987, after all changes are reviewed completely.
FROM rust:1.82.0-slim-bookworm AS builder | ||
FROM rust:1.84.0-slim-bookworm AS builder |
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.
libp2p v0.55 requires Rust >=1.83.
Why libp2p v0.55? Please see #989 (comment)
1. What does this PR implement?
This PR is the last one of refactoring connection management.
https://www.notion.so/Connection-Management-in-Libp2p-1708f96fb65c8019a6edd2a3b89ff8e2?pvs=4#1768f96fb65c80e58f68ea5300deba40
This PR adds the following actions:
The detailed logic is:
Behaviour
maintains three sets of peers (healthy, unhealthy, and malicious) based on the output of connection monitoring added in the PR refactor(blend): perform conn monitoring in the ConnectionHandler level #987.Behaviour
determines whether new connections need to be established, based on the number of peers in those three sets. If so, theBehaviour
emits an event to theBackend
, so that theBackend
can select random peers and requestSwarm
to dial them.Behaviour
denies the stream of connections, ifmax_peering_degree
reached or if the peer has been detected as malicious. It doesn't deny the connection itself (even though libp2p provides an API for that explicitly), because we want to make our behaviour/handler have control on only streams, not connections.Why
Backend
selects random peers? not byBehaviour
?Backend
because we may have more control and flexibility on theBackend
rather thanBehaviour
.Behaviour
may have a different kind of membership. So, if possible, I want to decoupleBehaviour
with membership.As I noted in Notion, I've found that we don't actually need to define our own ConnectionManager abstraction. However, please feel free to share your opinion if you think it's better to define the abstraction for both Blend and DA. I think, their requirements are quite different.
2. Does the code have enough context to be clearly understood?
Yes
3. Who are the specification authors and who is accountable for this PR?
@youngjoon-lee
4. Is the specification accurate and complete?
Yes
5. Does the implementation introduce changes in the specification?
No
Checklist
Warning
Do not merge the PR if any of the following is missing: