mirror of
https://seed.radicle.dev/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5.git
synced 2026-11-12 14:40:37 +08:00
node: Start implementing gossip subscriptions
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
use std::io;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use bloomy::BloomFilter;
|
||||
|
||||
use crate::identity::Id;
|
||||
use crate::protocol::wire;
|
||||
|
||||
/// Size in bytes of subscription bloom filter.
|
||||
pub const FILTER_SIZE: usize = 1024 * 16;
|
||||
/// Number of hashes used for bloom filter.
|
||||
pub const FILTER_HASHES: usize = 2;
|
||||
|
||||
/// Subscription filter.
|
||||
/// Nb. This filter doesn't currently support inserting public keys.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Filter(BloomFilter<Id>);
|
||||
|
||||
impl Deref for Filter {
|
||||
type Target = BloomFilter<Id>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Filter {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Filter {
|
||||
fn default() -> Self {
|
||||
Self(BloomFilter::with_size(FILTER_SIZE))
|
||||
}
|
||||
}
|
||||
|
||||
impl wire::Encode for Filter {
|
||||
fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
||||
let mut n = 0;
|
||||
|
||||
n += self.0.as_bytes().encode(writer)?;
|
||||
|
||||
Ok(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl wire::Decode for Filter {
|
||||
fn decode<R: std::io::Read + ?Sized>(reader: &mut R) -> Result<Self, wire::Error> {
|
||||
let bytes: [u8; FILTER_SIZE] = wire::Decode::decode(reader)?;
|
||||
let bf = BloomFilter::from(Vec::from(bytes));
|
||||
|
||||
debug_assert_eq!(bf.hashes(), FILTER_HASHES);
|
||||
|
||||
Ok(Self(bf))
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ use byteorder::{NetworkEndian, ReadBytesExt};
|
||||
use crate::crypto;
|
||||
use crate::git;
|
||||
use crate::identity::Id;
|
||||
use crate::protocol::filter::Filter;
|
||||
use crate::protocol::wire;
|
||||
use crate::protocol::{NodeId, Timestamp, PROTOCOL_VERSION};
|
||||
use crate::storage::refs::Refs;
|
||||
@@ -33,6 +34,7 @@ pub enum MessageType {
|
||||
NodeAnnouncement = 2,
|
||||
InventoryAnnouncement = 4,
|
||||
RefsAnnouncement = 6,
|
||||
Subscribe = 8,
|
||||
}
|
||||
|
||||
impl From<MessageType> for u16 {
|
||||
@@ -50,6 +52,7 @@ impl TryFrom<u16> for MessageType {
|
||||
2 => Ok(MessageType::NodeAnnouncement),
|
||||
4 => Ok(MessageType::InventoryAnnouncement),
|
||||
6 => Ok(MessageType::RefsAnnouncement),
|
||||
8 => Ok(MessageType::Subscribe),
|
||||
_ => Err(other),
|
||||
}
|
||||
}
|
||||
@@ -334,6 +337,10 @@ pub enum Message {
|
||||
git: git::Url,
|
||||
},
|
||||
|
||||
/// Subscribe to gossip messages matching the filter, that are newer than the given
|
||||
/// timestamp.
|
||||
Subscribe { filter: Filter, since: Timestamp },
|
||||
|
||||
/// Node announcing its inventory to the network.
|
||||
/// This should be the whole inventory every time.
|
||||
InventoryAnnouncement {
|
||||
@@ -404,6 +411,7 @@ impl Message {
|
||||
pub fn type_id(&self) -> u16 {
|
||||
match self {
|
||||
Self::Hello { .. } => MessageType::Hello,
|
||||
Self::Subscribe { .. } => MessageType::Subscribe,
|
||||
Self::NodeAnnouncement { .. } => MessageType::NodeAnnouncement,
|
||||
Self::InventoryAnnouncement { .. } => MessageType::InventoryAnnouncement,
|
||||
Self::RefsAnnouncement { .. } => MessageType::RefsAnnouncement,
|
||||
@@ -416,6 +424,7 @@ impl fmt::Debug for Message {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Hello { id, .. } => write!(f, "Hello({})", id),
|
||||
Self::Subscribe { since, .. } => write!(f, "Subscribe({})", since),
|
||||
Self::NodeAnnouncement { node, .. } => write!(f, "NodeAnnouncement({})", node),
|
||||
Self::InventoryAnnouncement { node, message, .. } => {
|
||||
write!(
|
||||
@@ -460,6 +469,10 @@ impl wire::Encode for Message {
|
||||
n += addrs.as_slice().encode(writer)?;
|
||||
n += git.encode(writer)?;
|
||||
}
|
||||
Self::Subscribe { filter, since } => {
|
||||
n += filter.encode(writer)?;
|
||||
n += since.encode(writer)?;
|
||||
}
|
||||
Self::RefsAnnouncement {
|
||||
node,
|
||||
message,
|
||||
@@ -512,6 +525,12 @@ impl wire::Decode for Message {
|
||||
git,
|
||||
})
|
||||
}
|
||||
Ok(MessageType::Subscribe) => {
|
||||
let filter = Filter::decode(reader)?;
|
||||
let since = Timestamp::decode(reader)?;
|
||||
|
||||
Ok(Self::Subscribe { filter, since })
|
||||
}
|
||||
Ok(MessageType::NodeAnnouncement) => {
|
||||
let node = NodeId::decode(reader)?;
|
||||
let message = NodeAnnouncement::decode(reader)?;
|
||||
|
||||
@@ -230,6 +230,9 @@ impl Peer {
|
||||
}
|
||||
log::warn!("Node announcement handling is not implemented");
|
||||
}
|
||||
(PeerState::Negotiated { .. }, Message::Subscribe { .. }) => {
|
||||
log::warn!("Subscribe message handling is not implemented");
|
||||
}
|
||||
(PeerState::Negotiated { .. }, Message::Hello { .. }) => {
|
||||
debug!(
|
||||
"Disconnecting peer {} for sending us a redundant handshake message",
|
||||
|
||||
Reference in New Issue
Block a user