Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
node: let others know their address
Slack Coder committed 3 years ago
commit a9b38dc1aecf0ebe9f84489f359cc8650dbf4d74
parent f3d867af4d4192fab694404f9c4ba9f0e2fe1cb4
5 files changed +91 -53
modified radicle-node/src/main.rs
@@ -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,
modified radicle-node/src/service.rs
@@ -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,
modified radicle-node/src/service/config.rs
@@ -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(),
modified radicle-node/src/test/peer.rs
@@ -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(..));
modified radicle-node/src/tests.rs
@@ -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]