From b2bcd561cf1e2a5088cf600b24c9ee567bfa2e2e Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Fri, 12 Jul 2024 10:52:44 +0100 Subject: [PATCH] radicle: store threshold in Canonical The Canonical type is generally constructed with the threshold, needed for the quorum computation, in scope. To make it easier to use and encapsulate its functionality, it now holds the threshold as an additional field. --- crates/radicle-remote-helper/src/push.rs | 3 ++- crates/radicle/src/git/canonical.rs | 24 ++++++++++++++++-------- crates/radicle/src/storage/git.rs | 5 +++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/crates/radicle-remote-helper/src/push.rs b/crates/radicle-remote-helper/src/push.rs index 41d1785c..eaeccb88 100644 --- a/crates/radicle-remote-helper/src/push.rs +++ b/crates/radicle-remote-helper/src/push.rs @@ -280,6 +280,7 @@ pub fn run( stored, &project, identity.delegates().as_ref(), + identity.threshold(), )?; let converges = canonical::converges( canonical @@ -292,7 +293,7 @@ pub fn run( canonical.modify_vote(me, head.into()); } - match canonical.quorum(identity.threshold(), &working) { + match canonical.quorum(&working) { Ok(canonical_oid) => { // Canonical head is an ancestor of head. let is_ff = head == *canonical_oid diff --git a/crates/radicle/src/git/canonical.rs b/crates/radicle/src/git/canonical.rs index 2f0db2fb..706eec21 100644 --- a/crates/radicle/src/git/canonical.rs +++ b/crates/radicle/src/git/canonical.rs @@ -21,8 +21,10 @@ use super::{lit, Oid, Qualified}; /// /// `Canonical` can then be used for performing calculations about the /// canonicity of the reference, most importantly the [`Canonical::quorum`]. +#[derive(Debug)] pub struct Canonical { tips: BTreeMap, + threshold: usize, } /// Error that can occur when calculation the [`Canonical::quorum`]. @@ -90,6 +92,7 @@ impl Canonical { repo: &S, project: &Project, delegates: &NonEmpty, + threshold: usize, ) -> Result where S: ReadRepository, @@ -98,6 +101,7 @@ impl Canonical { repo, delegates, &lit::refs_heads(project.default_branch()).into(), + threshold, ) } @@ -107,6 +111,7 @@ impl Canonical { repo: &S, delegates: &NonEmpty, name: &Qualified, + threshold: usize, ) -> Result where S: ReadRepository, @@ -127,7 +132,7 @@ impl Canonical { Err(e) => return Err(e), } } - Ok(Canonical { tips }) + Ok(Canonical { tips, threshold }) } /// Return the set of [`Did`]s and their [`Oid`] tip. @@ -171,7 +176,7 @@ impl Canonical { /// /// Also returns an error if `heads` is empty or `threshold` cannot be /// satisified with the number of heads given. - pub fn quorum(&self, threshold: usize, repo: &raw::Repository) -> Result { + pub fn quorum(&self, repo: &raw::Repository) -> Result { let mut candidates = BTreeMap::<_, usize>::new(); // Build a list of candidate commits and count how many "votes" each of them has. @@ -196,11 +201,14 @@ impl Canonical { } } // Keep commits which pass the threshold. - candidates.retain(|_, votes| *votes >= threshold); + candidates.retain(|_, votes| *votes >= self.threshold); - let (mut longest, _) = candidates - .pop_first() - .ok_or(QuorumError::NoCandidates(NoCandidates { threshold }))?; + let (mut longest, _) = + candidates + .pop_first() + .ok_or(QuorumError::NoCandidates(NoCandidates { + threshold: self.threshold, + }))?; // Now that all scores are calculated, figure out what is the longest branch // that passes the threshold. In case of divergence, return an error. @@ -235,7 +243,7 @@ impl Canonical { // | // return Err(QuorumError::Diverging(Diverging { - threshold, + threshold: self.threshold, base: base.into(), longest, head: *head, @@ -271,7 +279,7 @@ mod tests { (did, (*head).into()) }) .collect(); - Canonical { tips }.quorum(threshold, repo) + Canonical { tips, threshold }.quorum(repo) } #[test] diff --git a/crates/radicle/src/storage/git.rs b/crates/radicle/src/storage/git.rs index d6560792..1a49cd7a 100644 --- a/crates/radicle/src/storage/git.rs +++ b/crates/radicle/src/storage/git.rs @@ -752,8 +752,9 @@ impl ReadRepository for Repository { let project = doc.project()?; let branch_ref = git::refs::branch(project.default_branch()); let raw = self.raw(); - let oid = Canonical::default_branch(self, &project, doc.delegates().into())? - .quorum(doc.threshold(), raw)?; + let oid = + Canonical::default_branch(self, &project, doc.delegates().into(), doc.threshold())? + .quorum(raw)?; Ok((branch_ref, oid)) }