From 31de71c3458ae4f82b682b0f241b6255a13bc8ca Mon Sep 17 00:00:00 2001 From: Federico Franzoni <8609060+fed-franz@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:46:25 +0200 Subject: [PATCH 1/3] consensus: Update Majority and Supermajority definitions Remove the definition of the two constants as multipliers and define majority and supermajority as functions. This eliminates the risk of computing the supermajority of 2/3 with the `0.67` multiplier, which could yield a wrong result of 2/3+1. --- consensus/src/config.rs | 50 ++++++++++++++++++--------------- consensus/src/user/committee.rs | 11 +++----- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/consensus/src/config.rs b/consensus/src/config.rs index 746e1b9586..a9d6d7518d 100644 --- a/consensus/src/config.rs +++ b/consensus/src/config.rs @@ -9,19 +9,10 @@ use std::time::Duration; /// Maximum number of iterations Consensus runs per a single round. pub const CONSENSUS_MAX_ITER: u8 = 50; -/// Percentage number that determines quorums. -pub const SUPERMAJORITY_THRESHOLD: f64 = 0.67; -pub const MAJORITY_THRESHOLD: f64 = 0.5; - /// Total credits of steps committees pub const PROPOSAL_COMMITTEE_CREDITS: usize = 1; pub const VALIDATION_COMMITTEE_CREDITS: usize = 64; -pub const VALIDATION_COMMITTEE_QUORUM: f64 = - VALIDATION_COMMITTEE_CREDITS as f64 * SUPERMAJORITY_THRESHOLD; - pub const RATIFICATION_COMMITTEE_CREDITS: usize = 64; -pub const RATIFICATION_COMMITTEE_QUORUM: f64 = - RATIFICATION_COMMITTEE_CREDITS as f64 * SUPERMAJORITY_THRESHOLD; pub const DEFAULT_BLOCK_GAS_LIMIT: u64 = 5 * 1_000_000_000; @@ -35,32 +26,45 @@ pub const MAX_STEP_TIMEOUT: Duration = Duration::from_secs(40); pub const TIMEOUT_INCREASE: Duration = Duration::from_secs(2); pub const MINIMUM_BLOCK_TIME: u64 = 10; -/// Returns delta between full quorum and super_majority -pub fn validation_extra() -> usize { - VALIDATION_COMMITTEE_CREDITS - validation_committee_quorum() +// Returns `floor(value/2) + 1` +pub fn majority(value: usize) -> usize { + value / 2 + 1 } -pub fn ratification_extra() -> usize { - RATIFICATION_COMMITTEE_CREDITS - ratification_committee_quorum() +// Returns `ceil( value/3*2 )` +pub fn supermajority(value: usize) -> usize { + let sm = value as f32 / 3.0 * 2.0; + sm.ceil() as usize +} + +/// Returns the quorum of a Ratification committee +pub fn ratification_quorum() -> usize { + supermajority(RATIFICATION_COMMITTEE_CREDITS) } -/// Returns ceil of RATIFICATION_COMMITTEE_QUORUM -pub fn ratification_committee_quorum() -> usize { - RATIFICATION_COMMITTEE_QUORUM.ceil() as usize +/// Returns the quorum of a Validation committee +pub fn validation_quorum() -> usize { + supermajority(VALIDATION_COMMITTEE_CREDITS) } -/// Returns ceil of VALIDATION_COMMITTEE_QUORUM -pub fn validation_committee_quorum() -> usize { - VALIDATION_COMMITTEE_QUORUM.ceil() as usize +/// Returns the number of credits beyond the quorum for a Validation committee +pub fn validation_extra() -> usize { + VALIDATION_COMMITTEE_CREDITS - validation_quorum() +} + +/// Returns the number of credits beyond the quorum for a Ratification committee +pub fn ratification_extra() -> usize { + RATIFICATION_COMMITTEE_CREDITS - ratification_quorum() } #[cfg(test)] mod tests { use super::*; #[test] - fn test_quorum_consts() { - assert_eq!(validation_committee_quorum(), 43); - assert_eq!(ratification_committee_quorum(), 43); + fn test_quorums() { + assert_eq!(majority(VALIDATION_COMMITTEE_CREDITS), 33); + assert_eq!(validation_quorum(), 43); + assert_eq!(ratification_quorum(), 43); assert_eq!(validation_extra(), 21); assert_eq!(ratification_extra(), 21); } diff --git a/consensus/src/user/committee.rs b/consensus/src/user/committee.rs index 125efe0395..269c6405f0 100644 --- a/consensus/src/user/committee.rs +++ b/consensus/src/user/committee.rs @@ -8,7 +8,7 @@ use crate::user::provisioners::Provisioners; use crate::user::sortition; use super::cluster::Cluster; -use crate::config; +use crate::config::{majority, supermajority}; use node_data::bls::{PublicKey, PublicKeyBytes}; use std::collections::{BTreeMap, HashMap}; use std::fmt; @@ -36,13 +36,10 @@ impl Committee { pub fn new(provisioners: &Provisioners, cfg: &sortition::Config) -> Self { // Generate committee using deterministic sortition. let extracted = provisioners.create_committee(cfg); - let committee_credits = cfg.committee_credits() as f64; + let committee_credits = cfg.committee_credits(); - let super_majority = (committee_credits - * config::SUPERMAJORITY_THRESHOLD) - .ceil() as usize; - let majority = - (committee_credits * config::MAJORITY_THRESHOLD) as usize + 1; + let majority = majority(committee_credits); + let super_majority = supermajority(committee_credits); // Turn the raw vector into a hashmap where we map a pubkey to its // occurrences. From 3c5aebacbbd816bfa2cd2691da095275e1860c0c Mon Sep 17 00:00:00 2001 From: Federico Franzoni <8609060+fed-franz@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:49:17 +0200 Subject: [PATCH 2/3] rusk: update quorum functions --- rusk/src/lib/node/rusk.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rusk/src/lib/node/rusk.rs b/rusk/src/lib/node/rusk.rs index 32cfcc2de3..3288d1fc75 100644 --- a/rusk/src/lib/node/rusk.rs +++ b/rusk/src/lib/node/rusk.rs @@ -16,9 +16,9 @@ use tracing::{debug, info, warn}; use dusk_bytes::{DeserializableSlice, Serializable}; use dusk_consensus::config::{ - ratification_committee_quorum, ratification_extra, - validation_committee_quorum, validation_extra, - RATIFICATION_COMMITTEE_CREDITS, VALIDATION_COMMITTEE_CREDITS, + ratification_extra, ratification_quorum, validation_extra, + validation_quorum, RATIFICATION_COMMITTEE_CREDITS, + VALIDATION_COMMITTEE_CREDITS, }; use dusk_consensus::operations::{CallParams, VerificationOutput, Voter}; use execution_core::{ @@ -773,7 +773,7 @@ fn calc_generator_extra_reward( let reward_per_quota = generator_extra_reward / (validation_extra() + ratification_extra()) as u64; - let sum = ratification_committee_quorum() + validation_committee_quorum(); + let sum = ratification_quorum() + validation_quorum(); credits.saturating_sub(sum as u64) * reward_per_quota } From 09e48467acdfa101eaa101e72d846bea5344f4ed Mon Sep 17 00:00:00 2001 From: Federico Franzoni <8609060+fed-franz@users.noreply.github.com> Date: Tue, 20 Aug 2024 15:20:34 +0200 Subject: [PATCH 3/3] consensus: add majority tests --- consensus/src/config.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/consensus/src/config.rs b/consensus/src/config.rs index a9d6d7518d..e40188930f 100644 --- a/consensus/src/config.rs +++ b/consensus/src/config.rs @@ -60,6 +60,17 @@ pub fn ratification_extra() -> usize { #[cfg(test)] mod tests { use super::*; + + #[test] + fn test_majorities() { + assert_eq!(majority(4), 3); + assert_eq!(majority(11), 6); + assert_eq!(majority(99), 50); + assert_eq!(supermajority(3), 2); + assert_eq!(supermajority(9), 6); + assert_eq!(supermajority(51), 34); + } + #[test] fn test_quorums() { assert_eq!(majority(VALIDATION_COMMITTEE_CREDITS), 33);