node: announce node only when accessible

Avoid redundantly emitting Node Announcements about it's publicly
available addresses when it has none.

Signed-off-by: Slack Coder <slackcoder@server.ky>
This commit is contained in:
Slack Coder 2022-11-07 08:54:46 -05:00
parent a9b38dc1ae
commit 503a618743
3 changed files with 60 additions and 42 deletions

View File

@ -314,6 +314,16 @@ where
todo!() todo!()
} }
/// Get the address book instance.
pub fn addresses(&self) -> &A {
&self.addresses
}
/// Get the mutable address book instance.
pub fn addresses_mut(&mut self) -> &mut A {
&mut self.addresses
}
/// Get the storage instance. /// Get the storage instance.
pub fn storage(&self) -> &S { pub fn storage(&self) -> &S {
&self.storage &self.storage
@ -1228,7 +1238,7 @@ mod gossip {
storage: &S, storage: &S,
signer: &G, signer: &G,
config: &Config, config: &Config,
) -> [Message; 4] { ) -> Vec<Message> {
let inventory = match storage.inventory() { let inventory = match storage.inventory() {
Ok(i) => i, Ok(i) => i,
Err(e) => { Err(e) => {
@ -1239,27 +1249,37 @@ mod gossip {
} }
}; };
[ let mut msgs = vec![
Message::init(*signer.public_key(), config.listen.clone()), Message::init(*signer.public_key(), config.listen.clone()),
Message::node(gossip::node(timestamp, config), signer),
Message::inventory(gossip::inventory(timestamp, inventory), signer), Message::inventory(gossip::inventory(timestamp, inventory), signer),
Message::subscribe(config.filter(), timestamp, Timestamp::MAX), Message::subscribe(config.filter(), timestamp, Timestamp::MAX),
] ];
if let Some(m) = gossip::node(timestamp, config) {
msgs.push(Message::node(m, signer));
};
msgs
} }
pub fn node(timestamp: Timestamp, config: &Config) -> NodeAnnouncement { pub fn node(timestamp: Timestamp, config: &Config) -> Option<NodeAnnouncement> {
let features = node::Features::SEED; let features = node::Features::SEED;
let alias = config.alias(); let alias = config.alias();
let addresses = config.external_addresses.clone(); let addresses = config.external_addresses.clone();
NodeAnnouncement { if addresses.is_empty() {
features, return None;
timestamp,
alias,
addresses,
nonce: 0,
} }
.solve()
Some(
NodeAnnouncement {
features,
timestamp,
alias,
addresses,
nonce: 0,
}
.solve(),
)
} }
pub fn inventory(timestamp: Timestamp, inventory: Vec<Id>) -> InventoryAnnouncement { pub fn inventory(timestamp: Timestamp, inventory: Vec<Id>) -> InventoryAnnouncement {

View File

@ -7,6 +7,7 @@ use std::ops::{Deref, DerefMut};
use log::*; use log::*;
use crate::address; use crate::address;
use crate::address::Store;
use crate::clock::{RefClock, Timestamp}; use crate::clock::{RefClock, Timestamp};
use crate::crypto::test::signer::MockSigner; use crate::crypto::test::signer::MockSigner;
use crate::crypto::Signer; use crate::crypto::Signer;
@ -125,6 +126,26 @@ where
simulator::Peer::addr(self).into() simulator::Peer::addr(self).into()
} }
pub fn import_addresses<P>(&mut self, peers: P)
where
P: AsRef<[Self]>,
{
let timestamp = self.timestamp();
for peer in peers.as_ref() {
let known_address = address::KnownAddress::new(peer.address(), address::Source::Peer);
self.service
.addresses_mut()
.insert(
&peer.node_id(),
radicle::node::Features::default(),
peer.name,
timestamp,
Some(known_address),
)
.unwrap();
}
}
pub fn timestamp(&self) -> Timestamp { pub fn timestamp(&self) -> Timestamp {
self.service.clock().timestamp() self.service.clock().timestamp()
} }

View File

@ -661,49 +661,24 @@ fn test_persistent_peer_reconnect() {
assert_matches!(alice.outbox().next(), None); assert_matches!(alice.outbox().next(), None);
} }
fn add_peer<A: address::Store>(address_book: &mut A, peer: &Peer<MockStorage, MockSigner>) {
let known_address = address::KnownAddress::new(peer.address(), address::Source::Peer);
address_book
.insert(
&peer.node_id(),
radicle::node::Features::NONE,
peer.name,
LocalTime::now().as_secs(),
Some(known_address),
)
.unwrap();
}
#[test] #[test]
fn test_maintain_connections() { fn test_maintain_connections() {
// Peers alice starts out connected to.
let connected = vec![ let connected = vec![
Peer::new("connected", [8, 8, 8, 1], MockStorage::empty()), Peer::new("connected", [8, 8, 8, 1], MockStorage::empty()),
Peer::new("connected", [8, 8, 8, 2], MockStorage::empty()), Peer::new("connected", [8, 8, 8, 2], MockStorage::empty()),
Peer::new("connected", [8, 8, 8, 3], MockStorage::empty()), Peer::new("connected", [8, 8, 8, 3], MockStorage::empty()),
]; ];
// Peers alice will connect to once the others disconnect.
let mut unconnected = vec![ let mut unconnected = vec![
Peer::new("unconnected", [9, 9, 9, 1], MockStorage::empty()), Peer::new("unconnected", [9, 9, 9, 1], MockStorage::empty()),
Peer::new("unconnected", [9, 9, 9, 2], MockStorage::empty()), Peer::new("unconnected", [9, 9, 9, 2], MockStorage::empty()),
Peer::new("unconnected", [9, 9, 9, 3], MockStorage::empty()), Peer::new("unconnected", [9, 9, 9, 3], MockStorage::empty()),
]; ];
let mut address_book = address::Book::memory().unwrap(); let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty());
for peer in &unconnected { alice.import_addresses(&unconnected);
add_peer(&mut address_book, peer);
}
let mut alice = Peer::config(
"alice",
Config {
project_tracking: ProjectTracking::Allowed(HashSet::default()),
..Config::default()
},
[7, 7, 7, 7],
MockStorage::empty(),
address_book,
MockSigner::default(),
fastrand::Rng::new(),
);
for peer in connected.iter() { for peer in connected.iter() {
alice.connect_to(peer); alice.connect_to(peer);
} }
@ -713,10 +688,12 @@ fn test_maintain_connections() {
"alice should be connected to all peers" "alice should be connected to all peers"
); );
// A transient error such as this will cause Alice to attempt a reconnection.
let error = Arc::new(io::Error::from(io::ErrorKind::ConnectionReset));
for peer in connected.iter() { for peer in connected.iter() {
alice.disconnected( alice.disconnected(
&peer.addr(), &peer.addr(),
&nakamoto::DisconnectReason::Protocol(DisconnectReason::Error(session::Error::Timeout)), &nakamoto::DisconnectReason::ConnectionError(error.clone()),
); );
let addr = alice let addr = alice