Remove peer timestamp
Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
1fa85f0da3
commit
7169881849
|
|
@ -4,8 +4,9 @@ pub mod filter;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod peer;
|
pub mod peer;
|
||||||
|
|
||||||
|
use std::collections::{BTreeMap, VecDeque};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::{collections::VecDeque, fmt, net, net::IpAddr};
|
use std::{fmt, net, net::IpAddr};
|
||||||
|
|
||||||
use crossbeam_channel as chan;
|
use crossbeam_channel as chan;
|
||||||
use fastrand::Rng;
|
use fastrand::Rng;
|
||||||
|
|
@ -236,7 +237,7 @@ impl<'r, T: WriteStorage<'r>, S: address_book::Store, G: crypto::Signer> Service
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the connected peers.
|
/// Get the connected peers.
|
||||||
pub fn peers(&self) -> &Sessions {
|
pub fn sessions(&self) -> &Sessions {
|
||||||
&self.sessions
|
&self.sessions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -651,6 +652,13 @@ pub struct Lookup {
|
||||||
pub remote: Vec<NodeId>,
|
pub remote: Vec<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information on a peer, that we may or may not be connected to.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct Peer {
|
||||||
|
/// Timestamp of the last message received from peer.
|
||||||
|
pub last_message: Timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
/// Global service state used across peers.
|
/// Global service state used across peers.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Context<S, T, G> {
|
pub struct Context<S, T, G> {
|
||||||
|
|
@ -660,6 +668,8 @@ pub struct Context<S, T, G> {
|
||||||
signer: G,
|
signer: G,
|
||||||
/// Tracks the location of projects.
|
/// Tracks the location of projects.
|
||||||
routing: Routing,
|
routing: Routing,
|
||||||
|
/// Keeps track of peer states.
|
||||||
|
peers: BTreeMap<NodeId, Peer>,
|
||||||
/// Outgoing I/O queue.
|
/// Outgoing I/O queue.
|
||||||
io: VecDeque<Io>,
|
io: VecDeque<Io>,
|
||||||
/// Clock. Tells the time.
|
/// Clock. Tells the time.
|
||||||
|
|
@ -700,6 +710,7 @@ where
|
||||||
signer,
|
signer,
|
||||||
clock,
|
clock,
|
||||||
routing: HashMap::with_hasher(rng.clone().into()),
|
routing: HashMap::with_hasher(rng.clone().into()),
|
||||||
|
peers: BTreeMap::new(),
|
||||||
io: VecDeque::new(),
|
io: VecDeque::new(),
|
||||||
storage,
|
storage,
|
||||||
addrmgr,
|
addrmgr,
|
||||||
|
|
@ -741,12 +752,7 @@ where
|
||||||
fn handshake_messages(&self) -> [Message; 4] {
|
fn handshake_messages(&self) -> [Message; 4] {
|
||||||
let git = self.config.git_url.clone();
|
let git = self.config.git_url.clone();
|
||||||
[
|
[
|
||||||
Message::init(
|
Message::init(self.node_id(), self.config.listen.clone(), git),
|
||||||
self.node_id(),
|
|
||||||
self.timestamp(),
|
|
||||||
self.config.listen.clone(),
|
|
||||||
git,
|
|
||||||
),
|
|
||||||
Message::node(self.node_announcement(), &self.signer),
|
Message::node(self.node_announcement(), &self.signer),
|
||||||
Message::inventory(self.inventory_announcement().unwrap(), &self.signer),
|
Message::inventory(self.inventory_announcement().unwrap(), &self.signer),
|
||||||
Message::subscribe(self.filter(), self.timestamp(), Timestamp::MAX),
|
Message::subscribe(self.filter(), self.timestamp(), Timestamp::MAX),
|
||||||
|
|
|
||||||
|
|
@ -156,13 +156,14 @@ impl InventoryAnnouncement {
|
||||||
|
|
||||||
/// Message payload.
|
/// Message payload.
|
||||||
/// These are the messages peers send to each other.
|
/// These are the messages peers send to each other.
|
||||||
|
///
|
||||||
|
/// "Announcement" messages are messages that are relayed between peers.
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
/// The first message sent to a peer after connection.
|
/// The first message sent to a peer after connection.
|
||||||
Initialize {
|
Initialize {
|
||||||
// TODO: This is currently untrusted.
|
// TODO: This is currently untrusted.
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
timestamp: Timestamp,
|
|
||||||
version: u32,
|
version: u32,
|
||||||
addrs: Vec<Address>,
|
addrs: Vec<Address>,
|
||||||
git: git::Url,
|
git: git::Url,
|
||||||
|
|
@ -205,13 +206,12 @@ pub enum Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
pub fn init(id: NodeId, timestamp: Timestamp, addrs: Vec<Address>, git: git::Url) -> Self {
|
pub fn init(id: NodeId, addrs: Vec<Address>, git: git::Url) -> Self {
|
||||||
Self::Initialize {
|
Self::Initialize {
|
||||||
id,
|
id,
|
||||||
timestamp,
|
|
||||||
version: PROTOCOL_VERSION,
|
version: PROTOCOL_VERSION,
|
||||||
addrs,
|
|
||||||
git,
|
git,
|
||||||
|
addrs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ pub enum SessionError {
|
||||||
WrongMagic(u32),
|
WrongMagic(u32),
|
||||||
#[error("wrong protocol version in message: {0}")]
|
#[error("wrong protocol version in message: {0}")]
|
||||||
WrongVersion(u32),
|
WrongVersion(u32),
|
||||||
#[error("invalid inventory timestamp: {0}")]
|
#[error("invalid announcement timestamp: {0}")]
|
||||||
InvalidTimestamp(u64),
|
InvalidTimestamp(u64),
|
||||||
#[error("peer misbehaved")]
|
#[error("peer misbehaved")]
|
||||||
Misbehavior,
|
Misbehavior,
|
||||||
|
|
@ -47,8 +47,6 @@ pub struct Session {
|
||||||
pub persistent: bool,
|
pub persistent: bool,
|
||||||
/// Peer connection state.
|
/// Peer connection state.
|
||||||
pub state: SessionState,
|
pub state: SessionState,
|
||||||
/// Last known peer time.
|
|
||||||
pub timestamp: Timestamp,
|
|
||||||
/// Peer subscription.
|
/// Peer subscription.
|
||||||
pub subscribe: Option<Subscribe>,
|
pub subscribe: Option<Subscribe>,
|
||||||
|
|
||||||
|
|
@ -64,7 +62,6 @@ impl Session {
|
||||||
addr,
|
addr,
|
||||||
state: SessionState::default(),
|
state: SessionState::default(),
|
||||||
link,
|
link,
|
||||||
timestamp: Timestamp::default(),
|
|
||||||
subscribe: None,
|
subscribe: None,
|
||||||
persistent,
|
persistent,
|
||||||
attempts: 0,
|
attempts: 0,
|
||||||
|
|
@ -110,17 +107,11 @@ impl Session {
|
||||||
SessionState::Initial,
|
SessionState::Initial,
|
||||||
Message::Initialize {
|
Message::Initialize {
|
||||||
id,
|
id,
|
||||||
timestamp,
|
|
||||||
version,
|
version,
|
||||||
addrs,
|
addrs,
|
||||||
git,
|
git,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
let now = ctx.timestamp();
|
|
||||||
|
|
||||||
if timestamp.abs_diff(now) > MAX_TIME_DELTA.as_secs() {
|
|
||||||
return Err(SessionError::InvalidTimestamp(timestamp));
|
|
||||||
}
|
|
||||||
if version != PROTOCOL_VERSION {
|
if version != PROTOCOL_VERSION {
|
||||||
return Err(SessionError::WrongVersion(version));
|
return Err(SessionError::WrongVersion(version));
|
||||||
}
|
}
|
||||||
|
|
@ -154,18 +145,17 @@ impl Session {
|
||||||
signature,
|
signature,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
// FIXME: This is wrong, we are comparing timestamps of different peers.
|
|
||||||
let now = ctx.clock.local_time();
|
let now = ctx.clock.local_time();
|
||||||
let last = self.timestamp;
|
let peer = ctx.peers.entry(node).or_insert_with(Peer::default);
|
||||||
|
|
||||||
// Don't allow messages from too far in the past or future.
|
// Don't allow messages from too far in the future.
|
||||||
if message.timestamp.abs_diff(now.as_secs()) > MAX_TIME_DELTA.as_secs() {
|
if message.timestamp.saturating_sub(now.as_secs()) > MAX_TIME_DELTA.as_secs() {
|
||||||
return Err(SessionError::InvalidTimestamp(message.timestamp));
|
return Err(SessionError::InvalidTimestamp(message.timestamp));
|
||||||
}
|
}
|
||||||
// Discard inventory messages we've already seen, otherwise update
|
// Discard inventory messages we've already seen, otherwise update
|
||||||
// out last seen time.
|
// out last seen time.
|
||||||
if message.timestamp > last {
|
if message.timestamp > peer.last_message {
|
||||||
self.timestamp = message.timestamp;
|
peer.last_message = message.timestamp;
|
||||||
} else {
|
} else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
@ -188,6 +178,8 @@ impl Session {
|
||||||
signature,
|
signature,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
|
// FIXME: Check message timestamp.
|
||||||
|
|
||||||
if message.verify(&node, &signature) {
|
if message.verify(&node, &signature) {
|
||||||
// TODO: Buffer/throttle fetches.
|
// TODO: Buffer/throttle fetches.
|
||||||
// TODO: Check that we're tracking this user as well.
|
// TODO: Check that we're tracking this user as well.
|
||||||
|
|
@ -222,6 +214,8 @@ impl Session {
|
||||||
signature,
|
signature,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
|
// FIXME: Check message timestamp.
|
||||||
|
|
||||||
if !message.verify(&node, &signature) {
|
if !message.verify(&node, &signature) {
|
||||||
return Err(SessionError::Misbehavior);
|
return Err(SessionError::Misbehavior);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,12 +150,7 @@ where
|
||||||
self.service.connected(remote, &local, Link::Inbound);
|
self.service.connected(remote, &local, Link::Inbound);
|
||||||
self.receive(
|
self.receive(
|
||||||
&remote,
|
&remote,
|
||||||
Message::init(
|
Message::init(peer.node_id(), vec![Address::from(remote)], git),
|
||||||
peer.node_id(),
|
|
||||||
self.local_time().as_secs(),
|
|
||||||
vec![Address::from(remote)],
|
|
||||||
git,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut msgs = self.messages(&remote);
|
let mut msgs = self.messages(&remote);
|
||||||
|
|
@ -182,12 +177,7 @@ where
|
||||||
let git = peer.config().git_url.clone();
|
let git = peer.config().git_url.clone();
|
||||||
self.receive(
|
self.receive(
|
||||||
&remote,
|
&remote,
|
||||||
Message::init(
|
Message::init(peer.node_id(), peer.config().listen.clone(), git),
|
||||||
peer.node_id(),
|
|
||||||
self.local_time().as_secs(),
|
|
||||||
peer.config().listen.clone(),
|
|
||||||
git,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ use crate::test::signer::MockSigner;
|
||||||
use crate::test::simulator;
|
use crate::test::simulator;
|
||||||
use crate::test::simulator::{Peer as _, Simulation};
|
use crate::test::simulator::{Peer as _, Simulation};
|
||||||
use crate::test::storage::MockStorage;
|
use crate::test::storage::MockStorage;
|
||||||
|
use crate::LocalTime;
|
||||||
use crate::{client, identity, rad, service, storage, test};
|
use crate::{client, identity, rad, service, storage, test};
|
||||||
use crate::{Link, LocalTime};
|
|
||||||
|
|
||||||
// NOTE
|
// NOTE
|
||||||
//
|
//
|
||||||
|
|
@ -42,7 +42,7 @@ fn test_outbound_connection() {
|
||||||
|
|
||||||
let peers = alice
|
let peers = alice
|
||||||
.service
|
.service
|
||||||
.peers()
|
.sessions()
|
||||||
.negotiated()
|
.negotiated()
|
||||||
.map(|(ip, _)| *ip)
|
.map(|(ip, _)| *ip)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -62,7 +62,7 @@ fn test_inbound_connection() {
|
||||||
|
|
||||||
let peers = alice
|
let peers = alice
|
||||||
.service
|
.service
|
||||||
.peers()
|
.sessions()
|
||||||
.negotiated()
|
.negotiated()
|
||||||
.map(|(ip, _)| *ip)
|
.map(|(ip, _)| *ip)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -103,27 +103,6 @@ fn test_wrong_peer_version() {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_handshake_invalid_timestamp() {
|
|
||||||
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty());
|
|
||||||
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty());
|
|
||||||
let time_delta = MAX_TIME_DELTA.as_secs() + 1;
|
|
||||||
let local = std::net::SocketAddr::new(bob.ip, bob.rng.u16(..));
|
|
||||||
|
|
||||||
alice.initialize();
|
|
||||||
alice.connected(bob.addr(), &local, Link::Inbound);
|
|
||||||
alice.receive(
|
|
||||||
&bob.addr(),
|
|
||||||
Message::init(
|
|
||||||
bob.node_id(),
|
|
||||||
alice.timestamp() - time_delta,
|
|
||||||
vec![],
|
|
||||||
bob.git_url(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
assert_matches!(alice.outbox().next(), Some(Io::Disconnect(addr, _)) if addr == bob.addr());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_wrong_peer_magic() {
|
fn test_wrong_peer_magic() {
|
||||||
|
|
@ -211,7 +190,7 @@ fn test_inventory_relay_bad_timestamp() {
|
||||||
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty());
|
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty());
|
||||||
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty());
|
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty());
|
||||||
let two_hours = 3600 * 2;
|
let two_hours = 3600 * 2;
|
||||||
let timestamp = alice.local_time.as_secs() - two_hours;
|
let timestamp = alice.local_time.as_secs() + two_hours;
|
||||||
|
|
||||||
alice.connect_to(&bob);
|
alice.connect_to(&bob);
|
||||||
alice.receive(
|
alice.receive(
|
||||||
|
|
@ -341,7 +320,7 @@ fn test_persistent_peer_reconnect() {
|
||||||
sim.run_while([&mut alice, &mut bob, &mut eve], |s| !s.is_settled());
|
sim.run_while([&mut alice, &mut bob, &mut eve], |s| !s.is_settled());
|
||||||
|
|
||||||
let ips = alice
|
let ips = alice
|
||||||
.peers()
|
.sessions()
|
||||||
.negotiated()
|
.negotiated()
|
||||||
.map(|(ip, _)| *ip)
|
.map(|(ip, _)| *ip)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
|
||||||
|
|
@ -132,13 +132,11 @@ impl wire::Encode for Message {
|
||||||
match self {
|
match self {
|
||||||
Self::Initialize {
|
Self::Initialize {
|
||||||
id,
|
id,
|
||||||
timestamp,
|
|
||||||
version,
|
version,
|
||||||
addrs,
|
addrs,
|
||||||
git,
|
git,
|
||||||
} => {
|
} => {
|
||||||
n += id.encode(writer)?;
|
n += id.encode(writer)?;
|
||||||
n += timestamp.encode(writer)?;
|
|
||||||
n += version.encode(writer)?;
|
n += version.encode(writer)?;
|
||||||
n += addrs.as_slice().encode(writer)?;
|
n += addrs.as_slice().encode(writer)?;
|
||||||
n += git.encode(writer)?;
|
n += git.encode(writer)?;
|
||||||
|
|
@ -191,14 +189,12 @@ impl wire::Decode for Message {
|
||||||
match MessageType::try_from(type_id) {
|
match MessageType::try_from(type_id) {
|
||||||
Ok(MessageType::Initialize) => {
|
Ok(MessageType::Initialize) => {
|
||||||
let id = NodeId::decode(reader)?;
|
let id = NodeId::decode(reader)?;
|
||||||
let timestamp = Timestamp::decode(reader)?;
|
|
||||||
let version = u32::decode(reader)?;
|
let version = u32::decode(reader)?;
|
||||||
let addrs = Vec::<Address>::decode(reader)?;
|
let addrs = Vec::<Address>::decode(reader)?;
|
||||||
let git = git::Url::decode(reader)?;
|
let git = git::Url::decode(reader)?;
|
||||||
|
|
||||||
Ok(Self::Initialize {
|
Ok(Self::Initialize {
|
||||||
id,
|
id,
|
||||||
timestamp,
|
|
||||||
version,
|
version,
|
||||||
addrs,
|
addrs,
|
||||||
git,
|
git,
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,18 @@ impl std::hash::Hash for PublicKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for PublicKey {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
self.0.as_ref().partial_cmp(other.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for PublicKey {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.0.as_ref().cmp(other.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for PublicKey {
|
impl fmt::Display for PublicKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.to_human())
|
write!(f, "{}", self.to_human())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue