Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
radicle: Announcer with replication factor of 0
Fintan Halpenny committed 8 months ago
commit 685c84e5989ecdfb8ff87fa70c855d10f5305bf6
parent 4307eb35b5f8ddac2a704de0c3475e2df072b359
1 file changed +61 -2
modified crates/radicle/src/node/sync/announce.rs
@@ -182,14 +182,21 @@ impl Announcer {
    }

    fn is_target_reached(&self) -> Option<SuccessfulOutcome> {
+
        // It should not be possible to construct a target that has no preferred
+
        // seeds and set the target to 0
+
        debug_assert!(self.target.has_preferred_seeds() || self.target.has_replication_factor());
+

        let SuccessCounts { preferred, synced } = self.success_counts();
-
        if !self.target.preferred_seeds.is_empty() && preferred >= self.target.preferred_seeds.len()
-
        {
+
        if self.target.has_preferred_seeds() && preferred >= self.target.preferred_seeds.len() {
            Some(SuccessfulOutcome::PreferredNodes {
                preferred: self.target.preferred_seeds.len(),
                total_nodes_synced: synced,
            })
        } else {
+
            // The only target to hit is preferred seeds
+
            if !self.target.has_replication_factor() {
+
                return None;
+
            }
            let replicas = self.target.replicas();
            let min = replicas.lower_bound();
            match replicas.upper_bound() {
@@ -526,6 +533,16 @@ impl Target {
    pub fn replicas(&self) -> &ReplicationFactor {
        &self.replicas
    }
+

+
    /// Check if the target has preferred seeds
+
    pub fn has_preferred_seeds(&self) -> bool {
+
        !self.preferred_seeds.is_empty()
+
    }
+

+
    /// Check that lower bound of the replication is greater than `0`
+
    pub fn has_replication_factor(&self) -> bool {
+
        self.replicas.lower_bound() != 0
+
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -913,6 +930,48 @@ mod test {
    }

    #[test]
+
    fn announcer_with_replication_factor_zero_and_preferred_seeds() {
+
        let local = arbitrary::gen::<NodeId>(0);
+
        let seeds = arbitrary::set::<NodeId>(5..=5);
+

+
        let preferred_seeds = seeds.iter().take(2).copied().collect::<BTreeSet<_>>();
+
        let unsynced = seeds.iter().skip(2).copied().collect::<BTreeSet<_>>();
+

+
        // Zero replication factor but with preferred seeds should work
+
        let config = AnnouncerConfig::public(
+
            local,
+
            // Zero replication factor
+
            ReplicationFactor::must_reach(0),
+
            preferred_seeds.clone(),
+
            BTreeSet::new(),
+
            unsynced,
+
        );
+

+
        let mut announcer = Announcer::new(config).unwrap();
+

+
        // Should succeed immediately when we sync with all preferred seeds
+
        for &node in &preferred_seeds {
+
            let duration = time::Duration::from_secs(1);
+
            match announcer.synced_with(node, duration) {
+
                ControlFlow::Continue(_) => {} // Continue until all preferred are synced
+
                ControlFlow::Break(success) => {
+
                    assert_eq!(
+
                        success.outcome(),
+
                        SuccessfulOutcome::PreferredNodes {
+
                            preferred: preferred_seeds.len(),
+
                            total_nodes_synced: preferred_seeds.len()
+
                        },
+
                        "Should succeed with preferred seeds even with zero replication factor"
+
                    );
+
                    return;
+
                }
+
            }
+
        }
+

+
        panic!("Should have succeeded with preferred seeds");
+
    }
+

+
    #[test]
    fn cannot_construct_announcer() {
        let local = arbitrary::gen::<NodeId>(0);
        let seeds = arbitrary::set::<NodeId>(10..=10);