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:
parent
f3d867af4d
commit
a9b38dc1ae
|
|
@ -14,6 +14,7 @@ type Reactor = nakamoto_net_poll::Reactor<net::TcpStream>;
|
||||||
struct Options {
|
struct Options {
|
||||||
connect: Vec<Address>,
|
connect: Vec<Address>,
|
||||||
listen: Vec<net::SocketAddr>,
|
listen: Vec<net::SocketAddr>,
|
||||||
|
external_addresses: Vec<Address>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
|
|
@ -22,6 +23,7 @@ impl Options {
|
||||||
|
|
||||||
let mut parser = lexopt::Parser::from_env();
|
let mut parser = lexopt::Parser::from_env();
|
||||||
let mut connect = Vec::new();
|
let mut connect = Vec::new();
|
||||||
|
let mut external_addresses = Vec::new();
|
||||||
let mut listen = Vec::new();
|
let mut listen = Vec::new();
|
||||||
|
|
||||||
while let Some(arg) = parser.next()? {
|
while let Some(arg) = parser.next()? {
|
||||||
|
|
@ -34,6 +36,10 @@ impl Options {
|
||||||
let addr = parser.value()?.parse()?;
|
let addr = parser.value()?.parse()?;
|
||||||
listen.push(addr);
|
listen.push(addr);
|
||||||
}
|
}
|
||||||
|
Long("external-address") => {
|
||||||
|
let addr = parser.value()?.parse()?;
|
||||||
|
external_addresses.push(addr);
|
||||||
|
}
|
||||||
Long("help") => {
|
Long("help") => {
|
||||||
println!("usage: radicle-node [--connect <addr>]..");
|
println!("usage: radicle-node [--connect <addr>]..");
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
|
|
@ -41,7 +47,11 @@ impl Options {
|
||||||
_ => return Err(arg.unexpected()),
|
_ => 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 {
|
let config = client::Config {
|
||||||
service: service::Config {
|
service: service::Config {
|
||||||
connect: options.connect,
|
connect: options.connect,
|
||||||
|
external_addresses: options.external_addresses,
|
||||||
..service::Config::default()
|
..service::Config::default()
|
||||||
},
|
},
|
||||||
listen: options.listen,
|
listen: options.listen,
|
||||||
|
|
|
||||||
|
|
@ -945,29 +945,22 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_connections(
|
fn choose_addresses(&mut self) -> Vec<Address> {
|
||||||
rng: &Rng,
|
|
||||||
sessions: &Sessions,
|
|
||||||
address_pool: &mut dyn Iterator<Item = (NodeId, address::KnownAddress)>,
|
|
||||||
) -> Vec<Address> {
|
|
||||||
let mut initializing: Vec<Address> = Vec::new();
|
let mut initializing: Vec<Address> = Vec::new();
|
||||||
let mut negotiated: HashMap<NodeId, &Session> = HashMap::new();
|
let mut negotiated: HashMap<NodeId, &Session> = HashMap::new();
|
||||||
for (_, s) in sessions.iter() {
|
for s in self.sessions.values() {
|
||||||
if s.link != Link::Outbound {
|
if !s.link.is_outbound() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match s.state {
|
match s.state {
|
||||||
session::State::Initial => {
|
session::State::Initial => {
|
||||||
initializing.push(s.addr.into());
|
initializing.push(s.addr.into());
|
||||||
}
|
}
|
||||||
session::State::Negotiated { .. } => {
|
session::State::Negotiated { id, .. } => {
|
||||||
let node_id = s
|
negotiated.insert(id, s);
|
||||||
.node_id()
|
|
||||||
.expect("negotiated sessions must have a node ID");
|
|
||||||
negotiated.insert(node_id, s);
|
|
||||||
}
|
}
|
||||||
_ => continue,
|
session::State::Disconnected { .. } => {}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let wanted = TARGET_OUTBOUND_PEERS
|
let wanted = TARGET_OUTBOUND_PEERS
|
||||||
|
|
@ -977,33 +970,23 @@ where
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
// All nodes are considered equal
|
self.addresses
|
||||||
let mut address_pool: Vec<_> = address_pool
|
.entries()
|
||||||
|
.unwrap()
|
||||||
.filter(|(node_id, s)| {
|
.filter(|(node_id, s)| {
|
||||||
!initializing.contains(&s.addr) && !negotiated.contains_key(node_id)
|
!initializing.contains(&s.addr) && !negotiated.contains_key(node_id)
|
||||||
})
|
})
|
||||||
.take(wanted)
|
.take(wanted)
|
||||||
.collect();
|
.map(|(_, s)| s.addr)
|
||||||
|
.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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maintain_connections(&mut self) {
|
fn maintain_connections(&mut self) {
|
||||||
let mut address_pool = self
|
let addrs = self.choose_addresses();
|
||||||
.addresses
|
if addrs.is_empty() {
|
||||||
.entries()
|
debug!("No eligible peers available to connect to");
|
||||||
.expect("address store be accessible");
|
}
|
||||||
let next = Self::next_connections(&self.rng, &self.sessions, &mut address_pool);
|
for addr in addrs {
|
||||||
for addr in next {
|
|
||||||
self.reactor.connect(addr.clone());
|
self.reactor.connect(addr.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1267,7 +1250,7 @@ mod gossip {
|
||||||
pub fn node(timestamp: Timestamp, config: &Config) -> NodeAnnouncement {
|
pub fn node(timestamp: Timestamp, config: &Config) -> NodeAnnouncement {
|
||||||
let features = node::Features::SEED;
|
let features = node::Features::SEED;
|
||||||
let alias = config.alias();
|
let alias = config.alias();
|
||||||
let addresses = vec![]; // TODO
|
let addresses = config.external_addresses.clone();
|
||||||
|
|
||||||
NodeAnnouncement {
|
NodeAnnouncement {
|
||||||
features,
|
features,
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ pub struct Config {
|
||||||
/// Peers to connect to on startup.
|
/// Peers to connect to on startup.
|
||||||
/// Connections to these peers will be maintained.
|
/// Connections to these peers will be maintained.
|
||||||
pub connect: Vec<Address>,
|
pub connect: Vec<Address>,
|
||||||
|
/// Specify the node's public addresses
|
||||||
|
pub external_addresses: Vec<Address>,
|
||||||
/// Peer-to-peer network.
|
/// Peer-to-peer network.
|
||||||
pub network: Network,
|
pub network: Network,
|
||||||
/// Project tracking policy.
|
/// Project tracking policy.
|
||||||
|
|
@ -62,6 +64,7 @@ impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
connect: Vec::default(),
|
connect: Vec::default(),
|
||||||
|
external_addresses: vec![],
|
||||||
network: Network::default(),
|
network: Network::default(),
|
||||||
project_tracking: ProjectTracking::default(),
|
project_tracking: ProjectTracking::default(),
|
||||||
remote_tracking: RemoteTracking::default(),
|
remote_tracking: RemoteTracking::default(),
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,8 @@ where
|
||||||
let mut rng = fastrand::Rng::new();
|
let mut rng = fastrand::Rng::new();
|
||||||
let signer = MockSigner::new(&mut rng);
|
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,
|
config: Config,
|
||||||
ip: impl Into<net::IpAddr>,
|
ip: impl Into<net::IpAddr>,
|
||||||
storage: S,
|
storage: S,
|
||||||
|
addrs: address::Book,
|
||||||
signer: G,
|
signer: G,
|
||||||
rng: fastrand::Rng,
|
rng: fastrand::Rng,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let local_time = LocalTime::now();
|
let local_time = LocalTime::now();
|
||||||
let clock = RefClock::from(local_time);
|
let clock = RefClock::from(local_time);
|
||||||
let routing = routing::Table::memory().unwrap();
|
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 service = Service::new(config, clock, routing, storage, addrs, signer, rng.clone());
|
||||||
let ip = ip.into();
|
let ip = ip.into();
|
||||||
let local_addr = net::SocketAddr::new(ip, rng.u16(..));
|
let local_addr = net::SocketAddr::new(ip, rng.u16(..));
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||||
use crossbeam_channel as chan;
|
use crossbeam_channel as chan;
|
||||||
use nakamoto_net as nakamoto;
|
use nakamoto_net as nakamoto;
|
||||||
|
|
||||||
|
use crate::address;
|
||||||
use crate::collections::{HashMap, HashSet};
|
use crate::collections::{HashMap, HashSet};
|
||||||
use crate::crypto::test::signer::MockSigner;
|
use crate::crypto::test::signer::MockSigner;
|
||||||
use crate::prelude::{LocalDuration, Timestamp};
|
use crate::prelude::{LocalDuration, Timestamp};
|
||||||
|
|
@ -169,6 +170,7 @@ fn test_persistent_peer_connect() {
|
||||||
config,
|
config,
|
||||||
[7, 7, 7, 7],
|
[7, 7, 7, 7],
|
||||||
MockStorage::empty(),
|
MockStorage::empty(),
|
||||||
|
address::Book::memory().unwrap(),
|
||||||
MockSigner::new(&mut rng),
|
MockSigner::new(&mut rng),
|
||||||
rng,
|
rng,
|
||||||
);
|
);
|
||||||
|
|
@ -235,6 +237,7 @@ fn test_tracking() {
|
||||||
},
|
},
|
||||||
[7, 7, 7, 7],
|
[7, 7, 7, 7],
|
||||||
MockStorage::empty(),
|
MockStorage::empty(),
|
||||||
|
address::Book::memory().unwrap(),
|
||||||
MockSigner::default(),
|
MockSigner::default(),
|
||||||
fastrand::Rng::new(),
|
fastrand::Rng::new(),
|
||||||
);
|
);
|
||||||
|
|
@ -428,10 +431,19 @@ fn test_refs_announcement_relay() {
|
||||||
|
|
||||||
let bob = {
|
let bob = {
|
||||||
let mut rng = fastrand::Rng::new();
|
let mut rng = fastrand::Rng::new();
|
||||||
|
let addresses = address::Book::memory().unwrap();
|
||||||
let signer = MockSigner::new(&mut rng);
|
let signer = MockSigner::new(&mut rng);
|
||||||
let storage = fixtures::storage(tmp.path().join("bob"), &signer).unwrap();
|
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();
|
let bob_inv = bob.inventory().unwrap();
|
||||||
|
|
||||||
|
|
@ -593,6 +605,7 @@ fn test_persistent_peer_reconnect() {
|
||||||
},
|
},
|
||||||
[7, 7, 7, 7],
|
[7, 7, 7, 7],
|
||||||
MockStorage::empty(),
|
MockStorage::empty(),
|
||||||
|
address::Book::memory().unwrap(),
|
||||||
MockSigner::default(),
|
MockSigner::default(),
|
||||||
fastrand::Rng::new(),
|
fastrand::Rng::new(),
|
||||||
);
|
);
|
||||||
|
|
@ -648,21 +661,49 @@ 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() {
|
||||||
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty());
|
|
||||||
|
|
||||||
let connected = vec![
|
let connected = vec![
|
||||||
Peer::new("connected 1", [8, 8, 8, 1], MockStorage::empty()),
|
Peer::new("connected", [8, 8, 8, 1], MockStorage::empty()),
|
||||||
Peer::new("connected 2", [8, 8, 8, 2], MockStorage::empty()),
|
Peer::new("connected", [8, 8, 8, 2], MockStorage::empty()),
|
||||||
Peer::new("connected 3", [8, 8, 8, 3], MockStorage::empty()),
|
Peer::new("connected", [8, 8, 8, 3], MockStorage::empty()),
|
||||||
];
|
];
|
||||||
let mut unconnected = vec![
|
let mut unconnected = vec![
|
||||||
Peer::new("new 1", [9, 9, 9, 1], MockStorage::empty()),
|
Peer::new("unconnected", [9, 9, 9, 1], MockStorage::empty()),
|
||||||
Peer::new("new 2", [9, 9, 9, 2], MockStorage::empty()),
|
Peer::new("unconnected", [9, 9, 9, 2], MockStorage::empty()),
|
||||||
Peer::new("new 3", [9, 9, 9, 3], 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() {
|
for peer in connected.iter() {
|
||||||
alice.connect_to(peer);
|
alice.connect_to(peer);
|
||||||
}
|
}
|
||||||
|
|
@ -672,14 +713,10 @@ fn test_maintain_connections() {
|
||||||
"alice should be connected to all peers"
|
"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() {
|
for peer in connected.iter() {
|
||||||
alice.disconnected(
|
alice.disconnected(
|
||||||
&peer.addr(),
|
&peer.addr(),
|
||||||
&nakamoto::DisconnectReason::Protocol(DisconnectReason::User),
|
&nakamoto::DisconnectReason::Protocol(DisconnectReason::Error(session::Error::Timeout)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let addr = alice
|
let addr = alice
|
||||||
|
|
@ -692,7 +729,10 @@ fn test_maintain_connections() {
|
||||||
assert!(addr != peer.addr());
|
assert!(addr != peer.addr());
|
||||||
unconnected.retain(|p| p.addr() != addr);
|
unconnected.retain(|p| p.addr() != addr);
|
||||||
}
|
}
|
||||||
assert!(unconnected.is_empty());
|
assert!(
|
||||||
|
unconnected.is_empty(),
|
||||||
|
"alice should connect to all unconnected peers"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue