node: let others know their address

Include the node's IP address in the Node's announcements.  Source it
from the service's configuration which can assumed to be populated with
default values when available.

Signed-off-by: Slack Coder <slackcoder@server.ky>
This commit is contained in:
Slack Coder 2022-11-07 07:50:09 -05:00
parent f3d867af4d
commit a9b38dc1ae
5 changed files with 91 additions and 53 deletions

View File

@ -14,6 +14,7 @@ type Reactor = nakamoto_net_poll::Reactor<net::TcpStream>;
struct Options {
connect: Vec<Address>,
listen: Vec<net::SocketAddr>,
external_addresses: Vec<Address>,
}
impl Options {
@ -22,6 +23,7 @@ impl Options {
let mut parser = lexopt::Parser::from_env();
let mut connect = Vec::new();
let mut external_addresses = Vec::new();
let mut listen = Vec::new();
while let Some(arg) = parser.next()? {
@ -34,6 +36,10 @@ impl Options {
let addr = parser.value()?.parse()?;
listen.push(addr);
}
Long("external-address") => {
let addr = parser.value()?.parse()?;
external_addresses.push(addr);
}
Long("help") => {
println!("usage: radicle-node [--connect <addr>]..");
process::exit(0);
@ -41,7 +47,11 @@ impl Options {
_ => return Err(arg.unexpected()),
}
}
Ok(Self { connect, listen })
Ok(Self {
connect,
listen,
external_addresses,
})
}
}
@ -66,6 +76,7 @@ fn main() -> anyhow::Result<()> {
let config = client::Config {
service: service::Config {
connect: options.connect,
external_addresses: options.external_addresses,
..service::Config::default()
},
listen: options.listen,

View File

@ -945,29 +945,22 @@ where
}
}
fn next_connections(
rng: &Rng,
sessions: &Sessions,
address_pool: &mut dyn Iterator<Item = (NodeId, address::KnownAddress)>,
) -> Vec<Address> {
fn choose_addresses(&mut self) -> Vec<Address> {
let mut initializing: Vec<Address> = Vec::new();
let mut negotiated: HashMap<NodeId, &Session> = HashMap::new();
for (_, s) in sessions.iter() {
if s.link != Link::Outbound {
for s in self.sessions.values() {
if !s.link.is_outbound() {
continue;
}
match s.state {
session::State::Initial => {
initializing.push(s.addr.into());
}
session::State::Negotiated { .. } => {
let node_id = s
.node_id()
.expect("negotiated sessions must have a node ID");
negotiated.insert(node_id, s);
session::State::Negotiated { id, .. } => {
negotiated.insert(id, s);
}
_ => continue,
};
session::State::Disconnected { .. } => {}
}
}
let wanted = TARGET_OUTBOUND_PEERS
@ -977,33 +970,23 @@ where
return Vec::new();
}
// All nodes are considered equal
let mut address_pool: Vec<_> = address_pool
self.addresses
.entries()
.unwrap()
.filter(|(node_id, s)| {
!initializing.contains(&s.addr) && !negotiated.contains_key(node_id)
})
.take(wanted)
.collect();
let mut next = Vec::new();
loop {
if address_pool.is_empty() {
break;
}
let i = rng.usize(0..address_pool.len());
let (_, addr) = address_pool.swap_remove(i);
next.push(addr.addr);
}
next
.map(|(_, s)| s.addr)
.collect()
}
fn maintain_connections(&mut self) {
let mut address_pool = self
.addresses
.entries()
.expect("address store be accessible");
let next = Self::next_connections(&self.rng, &self.sessions, &mut address_pool);
for addr in next {
let addrs = self.choose_addresses();
if addrs.is_empty() {
debug!("No eligible peers available to connect to");
}
for addr in addrs {
self.reactor.connect(addr.clone());
}
}
@ -1267,7 +1250,7 @@ mod gossip {
pub fn node(timestamp: Timestamp, config: &Config) -> NodeAnnouncement {
let features = node::Features::SEED;
let alias = config.alias();
let addresses = vec![]; // TODO
let addresses = config.external_addresses.clone();
NodeAnnouncement {
features,

View File

@ -46,6 +46,8 @@ pub struct Config {
/// Peers to connect to on startup.
/// Connections to these peers will be maintained.
pub connect: Vec<Address>,
/// Specify the node's public addresses
pub external_addresses: Vec<Address>,
/// Peer-to-peer network.
pub network: Network,
/// Project tracking policy.
@ -62,6 +64,7 @@ impl Default for Config {
fn default() -> Self {
Self {
connect: Vec::default(),
external_addresses: vec![],
network: Network::default(),
project_tracking: ProjectTracking::default(),
remote_tracking: RemoteTracking::default(),

View File

@ -75,7 +75,8 @@ where
let mut rng = fastrand::Rng::new();
let signer = MockSigner::new(&mut rng);
Self::config(name, Config::default(), ip, storage, signer, rng)
let addrs = address::Book::memory().unwrap();
Self::config(name, Config::default(), ip, storage, addrs, signer, rng)
}
}
@ -89,13 +90,13 @@ where
config: Config,
ip: impl Into<net::IpAddr>,
storage: S,
addrs: address::Book,
signer: G,
rng: fastrand::Rng,
) -> Self {
let local_time = LocalTime::now();
let clock = RefClock::from(local_time);
let routing = routing::Table::memory().unwrap();
let addrs = address::Book::memory().unwrap();
let service = Service::new(config, clock, routing, storage, addrs, signer, rng.clone());
let ip = ip.into();
let local_addr = net::SocketAddr::new(ip, rng.u16(..));

View File

@ -4,6 +4,7 @@ use std::sync::Arc;
use crossbeam_channel as chan;
use nakamoto_net as nakamoto;
use crate::address;
use crate::collections::{HashMap, HashSet};
use crate::crypto::test::signer::MockSigner;
use crate::prelude::{LocalDuration, Timestamp};
@ -169,6 +170,7 @@ fn test_persistent_peer_connect() {
config,
[7, 7, 7, 7],
MockStorage::empty(),
address::Book::memory().unwrap(),
MockSigner::new(&mut rng),
rng,
);
@ -235,6 +237,7 @@ fn test_tracking() {
},
[7, 7, 7, 7],
MockStorage::empty(),
address::Book::memory().unwrap(),
MockSigner::default(),
fastrand::Rng::new(),
);
@ -428,10 +431,19 @@ fn test_refs_announcement_relay() {
let bob = {
let mut rng = fastrand::Rng::new();
let addresses = address::Book::memory().unwrap();
let signer = MockSigner::new(&mut rng);
let storage = fixtures::storage(tmp.path().join("bob"), &signer).unwrap();
Peer::config("bob", Config::default(), [9, 9, 9, 9], storage, signer, rng)
Peer::config(
"bob",
Config::default(),
[9, 9, 9, 9],
storage,
addresses,
signer,
rng,
)
};
let bob_inv = bob.inventory().unwrap();
@ -593,6 +605,7 @@ fn test_persistent_peer_reconnect() {
},
[7, 7, 7, 7],
MockStorage::empty(),
address::Book::memory().unwrap(),
MockSigner::default(),
fastrand::Rng::new(),
);
@ -648,21 +661,49 @@ fn test_persistent_peer_reconnect() {
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]
fn test_maintain_connections() {
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty());
let connected = vec![
Peer::new("connected 1", [8, 8, 8, 1], MockStorage::empty()),
Peer::new("connected 2", [8, 8, 8, 2], MockStorage::empty()),
Peer::new("connected 3", [8, 8, 8, 3], 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, 3], MockStorage::empty()),
];
let mut unconnected = vec![
Peer::new("new 1", [9, 9, 9, 1], MockStorage::empty()),
Peer::new("new 2", [9, 9, 9, 2], MockStorage::empty()),
Peer::new("new 3", [9, 9, 9, 3], 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, 3], MockStorage::empty()),
];
let mut address_book = address::Book::memory().unwrap();
for peer in &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() {
alice.connect_to(peer);
}
@ -672,14 +713,10 @@ fn test_maintain_connections() {
"alice should be connected to all peers"
);
for peer in unconnected.iter() {
alice.receive(&connected[0].addr(), peer.node_announcement());
}
for peer in connected.iter() {
alice.disconnected(
&peer.addr(),
&nakamoto::DisconnectReason::Protocol(DisconnectReason::User),
&nakamoto::DisconnectReason::Protocol(DisconnectReason::Error(session::Error::Timeout)),
);
let addr = alice
@ -692,7 +729,10 @@ fn test_maintain_connections() {
assert!(addr != peer.addr());
unconnected.retain(|p| p.addr() != addr);
}
assert!(unconnected.is_empty());
assert!(
unconnected.is_empty(),
"alice should connect to all unconnected peers"
);
}
#[test]