protocols/gossipsub: Add message signing and verification configuration (#1583)

This adds optional message signing and verification to the gossipsub protocol as
per the libp2p specifications.

In addition this commit:

- Removes the LruCache received cache and simply uses the memcache in it's
  place.

- Send subscriptions to all peers

- Prevent invalid messages from being gossiped

- Send grafts when subscriptions are added to the mesh

Co-authored-by: Max Inden <mail@max-inden.de>
Co-authored-by: Rüdiger Klaehn <rklaehn@protonmail.com>
Co-authored-by: Rüdiger Klaehn <rklaehn@gmail.com>
This commit is contained in:
Age Manning
2020-08-03 18:13:43 +10:00
committed by GitHub
parent d0ad105433
commit d8ad7bddf5
14 changed files with 1358 additions and 568 deletions

View File

@ -19,6 +19,7 @@
// DEALINGS IN THE SOFTWARE.
use crate::behaviour::GossipsubRpc;
use crate::config::ValidationMode;
use crate::protocol::{GossipsubCodec, ProtocolConfig};
use futures::prelude::*;
use futures_codec::Framed;
@ -50,6 +51,10 @@ pub struct GossipsubHandler {
/// Queue of values that we want to send to the remote.
send_queue: SmallVec<[GossipsubRpc; 16]>,
/// Flag indicating that an outbound substream is being established to prevent duplicate
/// requests.
outbound_substream_establishing: bool,
/// Flag determining whether to maintain the connection to the peer.
keep_alive: KeepAlive,
}
@ -80,26 +85,20 @@ enum OutboundSubstreamState {
impl GossipsubHandler {
/// Builds a new `GossipsubHandler`.
pub fn new(protocol_id: impl Into<Cow<'static, [u8]>>, max_transmit_size: usize) -> Self {
pub fn new(
protocol_id: impl Into<Cow<'static, [u8]>>,
max_transmit_size: usize,
validation_mode: ValidationMode,
) -> Self {
GossipsubHandler {
listen_protocol: SubstreamProtocol::new(ProtocolConfig::new(
protocol_id,
max_transmit_size,
validation_mode,
)),
inbound_substream: None,
outbound_substream: None,
send_queue: SmallVec::new(),
keep_alive: KeepAlive::Yes,
}
}
}
impl Default for GossipsubHandler {
fn default() -> Self {
GossipsubHandler {
listen_protocol: SubstreamProtocol::new(ProtocolConfig::default()),
inbound_substream: None,
outbound_substream: None,
outbound_substream_establishing: false,
send_queue: SmallVec::new(),
keep_alive: KeepAlive::Yes,
}
@ -132,6 +131,7 @@ impl ProtocolsHandler for GossipsubHandler {
substream: <Self::OutboundProtocol as OutboundUpgrade<NegotiatedSubstream>>::Output,
message: Self::OutboundOpenInfo,
) {
self.outbound_substream_establishing = false;
// Should never establish a new outbound substream if one already exists.
// If this happens, an outbound message is not sent.
if self.outbound_substream.is_some() {
@ -154,6 +154,7 @@ impl ProtocolsHandler for GossipsubHandler {
<Self::OutboundProtocol as OutboundUpgrade<NegotiatedSubstream>>::Error,
>,
) {
self.outbound_substream_establishing = false;
// Ignore upgrade errors for now.
// If a peer doesn't support this protocol, this will just ignore them, but not disconnect
// them.
@ -175,9 +176,13 @@ impl ProtocolsHandler for GossipsubHandler {
>,
> {
// determine if we need to create the stream
if !self.send_queue.is_empty() && self.outbound_substream.is_none() {
if !self.send_queue.is_empty()
&& self.outbound_substream.is_none()
&& !self.outbound_substream_establishing
{
let message = self.send_queue.remove(0);
self.send_queue.shrink_to_fit();
self.outbound_substream_establishing = true;
return Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
protocol: self.listen_protocol.clone(),
info: message,
@ -198,9 +203,21 @@ impl ProtocolsHandler for GossipsubHandler {
return Poll::Ready(ProtocolsHandlerEvent::Custom(message));
}
Poll::Ready(Some(Err(e))) => {
debug!("Inbound substream error while awaiting input: {:?}", e);
self.inbound_substream =
Some(InboundSubstreamState::Closing(substream));
match e.kind() {
std::io::ErrorKind::InvalidData => {
// Invalid message, ignore it and reset to waiting
warn!("Invalid message received. Error: {}", e);
self.inbound_substream =
Some(InboundSubstreamState::WaitingInput(substream));
}
_ => {
// More serious errors, close this side of the stream. If the
// peer is still around, they will re-establish their
// connection
self.inbound_substream =
Some(InboundSubstreamState::Closing(substream));
}
}
}
// peer closed the stream
Poll::Ready(None) => {
@ -242,7 +259,7 @@ impl ProtocolsHandler for GossipsubHandler {
break;
}
Some(InboundSubstreamState::Poisoned) => {
panic!("Error occurred during inbound stream processing")
unreachable!("Error occurred during inbound stream processing")
}
}
}
@ -338,7 +355,7 @@ impl ProtocolsHandler for GossipsubHandler {
break;
}
Some(OutboundSubstreamState::Poisoned) => {
panic!("Error occurred during outbound stream processing")
unreachable!("Error occurred during outbound stream processing")
}
}
}