From 6533334fdcbc7d923ee3ede01209205cfb3752fa Mon Sep 17 00:00:00 2001 From: pls148 <184445976+pls148@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:03:00 -0800 Subject: [PATCH] Add epoch to threshold functions to allow dynamically sized committees --- .../traits/election/randomized_committee.rs | 6 ++-- .../election/randomized_committee_members.rs | 14 ++++---- .../src/traits/election/static_committee.rs | 6 ++-- .../static_committee_leader_two_views.rs | 6 ++-- crates/testing/src/helpers.rs | 2 +- crates/types/src/simple_certificate.rs | 35 +++++++++++++------ crates/types/src/traits/election.rs | 6 ++-- crates/types/src/vote.rs | 9 +++-- 8 files changed, 51 insertions(+), 33 deletions(-) diff --git a/crates/hotshot/src/traits/election/randomized_committee.rs b/crates/hotshot/src/traits/election/randomized_committee.rs index 89a36f9030..3747ef731f 100644 --- a/crates/hotshot/src/traits/election/randomized_committee.rs +++ b/crates/hotshot/src/traits/election/randomized_committee.rs @@ -163,17 +163,17 @@ impl Membership for RandomizedCommittee { } /// Get the voting success threshold for the committee - fn success_threshold(&self) -> NonZeroU64 { + fn success_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(((self.stake_table.len() as u64 * 2) / 3) + 1).unwrap() } /// Get the voting failure threshold for the committee - fn failure_threshold(&self) -> NonZeroU64 { + fn failure_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(((self.stake_table.len() as u64) / 3) + 1).unwrap() } /// Get the voting upgrade threshold for the committee - fn upgrade_threshold(&self) -> NonZeroU64 { + fn upgrade_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(max( (self.stake_table.len() as u64 * 9) / 10, ((self.stake_table.len() as u64 * 2) / 3) + 1, diff --git a/crates/hotshot/src/traits/election/randomized_committee_members.rs b/crates/hotshot/src/traits/election/randomized_committee_members.rs index ec0ef1231b..1bd3d1d54d 100644 --- a/crates/hotshot/src/traits/election/randomized_committee_members.rs +++ b/crates/hotshot/src/traits/election/randomized_committee_members.rs @@ -11,7 +11,6 @@ use std::{ num::NonZeroU64, }; -use ethereum_types::U256; use hotshot_types::{ traits::{ election::Membership, @@ -21,6 +20,7 @@ use hotshot_types::{ }, PeerConfig, }; +use primitive_types::U256; use rand::{rngs::StdRng, Rng}; use utils::anytrace::Result; @@ -231,20 +231,20 @@ impl Membership } /// Get the voting success threshold for the committee - fn success_threshold(&self) -> NonZeroU64 { - let len = self.stake_table.len() / 2; // Divide by two as we are flipping between odds and evens + fn success_threshold(&self, epoch: ::Epoch) -> NonZeroU64 { + let len = self.total_nodes(epoch); NonZeroU64::new(((len as u64 * 2) / 3) + 1).unwrap() } /// Get the voting failure threshold for the committee - fn failure_threshold(&self) -> NonZeroU64 { - let len = self.stake_table.len() / 2; // Divide by two as we are flipping between odds and evens + fn failure_threshold(&self, epoch: ::Epoch) -> NonZeroU64 { + let len = self.total_nodes(epoch); NonZeroU64::new(((len as u64) / 3) + 1).unwrap() } /// Get the voting upgrade threshold for the committee - fn upgrade_threshold(&self) -> NonZeroU64 { - let len = self.stake_table.len() / 2; // Divide by two as we are flipping between odds and evens + fn upgrade_threshold(&self, epoch: ::Epoch) -> NonZeroU64 { + let len = self.total_nodes(epoch); NonZeroU64::new(max((len as u64 * 9) / 10, ((len as u64 * 2) / 3) + 1)).unwrap() } } diff --git a/crates/hotshot/src/traits/election/static_committee.rs b/crates/hotshot/src/traits/election/static_committee.rs index 200ed530dd..f21d07748a 100644 --- a/crates/hotshot/src/traits/election/static_committee.rs +++ b/crates/hotshot/src/traits/election/static_committee.rs @@ -156,17 +156,17 @@ impl Membership for StaticCommittee { } /// Get the voting success threshold for the committee - fn success_threshold(&self) -> NonZeroU64 { + fn success_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(((self.stake_table.len() as u64 * 2) / 3) + 1).unwrap() } /// Get the voting failure threshold for the committee - fn failure_threshold(&self) -> NonZeroU64 { + fn failure_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(((self.stake_table.len() as u64) / 3) + 1).unwrap() } /// Get the voting upgrade threshold for the committee - fn upgrade_threshold(&self) -> NonZeroU64 { + fn upgrade_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(max( (self.stake_table.len() as u64 * 9) / 10, ((self.stake_table.len() as u64 * 2) / 3) + 1, diff --git a/crates/hotshot/src/traits/election/static_committee_leader_two_views.rs b/crates/hotshot/src/traits/election/static_committee_leader_two_views.rs index 922a815e68..c3b132fa5c 100644 --- a/crates/hotshot/src/traits/election/static_committee_leader_two_views.rs +++ b/crates/hotshot/src/traits/election/static_committee_leader_two_views.rs @@ -157,17 +157,17 @@ impl Membership for StaticCommitteeLeaderForTwoViews NonZeroU64 { + fn success_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(((self.stake_table.len() as u64 * 2) / 3) + 1).unwrap() } /// Get the voting failure threshold for the committee - fn failure_threshold(&self) -> NonZeroU64 { + fn failure_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(((self.stake_table.len() as u64) / 3) + 1).unwrap() } /// Get the voting upgrade threshold for the committee - fn upgrade_threshold(&self) -> NonZeroU64 { + fn upgrade_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { NonZeroU64::new(((self.stake_table.len() as u64 * 9) / 10) + 1).unwrap() } } diff --git a/crates/testing/src/helpers.rs b/crates/testing/src/helpers.rs index d27c5fe165..64c8c9ee63 100644 --- a/crates/testing/src/helpers.rs +++ b/crates/testing/src/helpers.rs @@ -223,7 +223,7 @@ pub async fn build_assembled_sig< let real_qc_pp: ::QcParams = ::public_parameter( stake_table.clone(), - U256::from(CERT::threshold(membership)), + U256::from(CERT::threshold(membership, epoch)), ); let total_nodes = stake_table.len(); let signers = bitvec![1; total_nodes]; diff --git a/crates/types/src/simple_certificate.rs b/crates/types/src/simple_certificate.rs index 17fd4aa1c2..0ebb90edd6 100644 --- a/crates/types/src/simple_certificate.rs +++ b/crates/types/src/simple_certificate.rs @@ -37,7 +37,10 @@ use crate::{ /// Trait which allows use to inject different threshold calculations into a Certificate type pub trait Threshold { /// Calculate a threshold based on the membership - fn threshold>(membership: &MEMBERSHIP) -> u64; + fn threshold>( + membership: &MEMBERSHIP, + epoch: ::Epoch, + ) -> u64; } /// Defines a threshold which is 2f + 1 (Amount needed for Quorum) @@ -45,8 +48,11 @@ pub trait Threshold { pub struct SuccessThreshold {} impl Threshold for SuccessThreshold { - fn threshold>(membership: &MEMBERSHIP) -> u64 { - membership.success_threshold().into() + fn threshold>( + membership: &MEMBERSHIP, + epoch: ::Epoch, + ) -> u64 { + membership.success_threshold(epoch).into() } } @@ -55,8 +61,11 @@ impl Threshold for SuccessThreshold { pub struct OneHonestThreshold {} impl Threshold for OneHonestThreshold { - fn threshold>(membership: &MEMBERSHIP) -> u64 { - membership.failure_threshold().into() + fn threshold>( + membership: &MEMBERSHIP, + epoch: ::Epoch, + ) -> u64 { + membership.failure_threshold(epoch).into() } } @@ -65,8 +74,11 @@ impl Threshold for OneHonestThreshold { pub struct UpgradeThreshold {} impl Threshold for UpgradeThreshold { - fn threshold>(membership: &MEMBERSHIP) -> u64 { - membership.upgrade_threshold().into() + fn threshold>( + membership: &MEMBERSHIP, + epoch: ::Epoch, + ) -> u64 { + membership.upgrade_threshold(epoch).into() } } @@ -156,7 +168,7 @@ impl> } let real_qc_pp = ::public_parameter( membership.stake_table(epoch), - U256::from(Self::threshold(membership)), + U256::from(Self::threshold(membership, epoch)), ); let Ok(commit) = self.data_commitment(upgrade_lock).await else { return false; @@ -167,8 +179,11 @@ impl> self.signatures.as_ref().unwrap(), ) } - fn threshold>(membership: &MEMBERSHIP) -> u64 { - THRESHOLD::threshold(membership) + fn threshold>( + membership: &MEMBERSHIP, + epoch: ::Epoch, + ) -> u64 { + THRESHOLD::threshold(membership, epoch) } fn data(&self) -> &Self::Voteable { &self.data diff --git a/crates/types/src/traits/election.rs b/crates/types/src/traits/election.rs index aa313fc64a..d54fb6908c 100644 --- a/crates/types/src/traits/election.rs +++ b/crates/types/src/traits/election.rs @@ -89,11 +89,11 @@ pub trait Membership: Clone + Debug + Send + Sync { fn total_nodes(&self, epoch: TYPES::Epoch) -> usize; /// Returns the threshold for a specific `Membership` implementation - fn success_threshold(&self) -> NonZeroU64; + fn success_threshold(&self, epoch: TYPES::Epoch) -> NonZeroU64; /// Returns the threshold for a specific `Membership` implementation - fn failure_threshold(&self) -> NonZeroU64; + fn failure_threshold(&self, epoch: TYPES::Epoch) -> NonZeroU64; /// Returns the threshold required to upgrade the network protocol - fn upgrade_threshold(&self) -> NonZeroU64; + fn upgrade_threshold(&self, epoch: TYPES::Epoch) -> NonZeroU64; } diff --git a/crates/types/src/vote.rs b/crates/types/src/vote.rs index 6291599004..c2a49f4973 100644 --- a/crates/types/src/vote.rs +++ b/crates/types/src/vote.rs @@ -80,7 +80,10 @@ pub trait Certificate: HasViewNumber { ) -> impl std::future::Future; /// Returns the amount of stake needed to create this certificate // TODO: Make this a static ratio of the total stake of `Membership` - fn threshold>(membership: &MEMBERSHIP) -> u64; + fn threshold>( + membership: &MEMBERSHIP, + epoch: ::Epoch, + ) -> u64; /// Get the commitment which was voted on fn data(&self) -> &Self::Voteable; /// Get the vote commitment which the votes commit to @@ -199,12 +202,12 @@ impl< *total_stake_casted += stake_table_entry.stake(); total_vote_map.insert(key, (vote.signature(), vote_commitment)); - if *total_stake_casted >= CERT::threshold(membership).into() { + if *total_stake_casted >= CERT::threshold(membership, epoch).into() { // Assemble QC let real_qc_pp: <::SignatureKey as SignatureKey>::QcParams = ::public_parameter( stake_table, - U256::from(CERT::threshold(membership)), + U256::from(CERT::threshold(membership, epoch)), ); let real_qc_sig = ::assemble(