Skip to content
This repository has been archived by the owner on Jun 25, 2021. It is now read-only.

Commit

Permalink
feat: use supermajority agreement + increase elder size to 7
Browse files Browse the repository at this point in the history
  • Loading branch information
madadam committed Mar 22, 2021
1 parent b0d10b6 commit b729a87
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 19 deletions.
19 changes: 13 additions & 6 deletions src/consensus/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
use crate::{
crypto::{self, Digest256, Keypair, PublicKey, Signature, Verifier},
error::Result,
majority,
messages::{Message, Variant},
node::Node,
peer::Peer,
routing::command::{self, Command},
section::{EldersInfo, SectionKeyShare},
supermajority,
};
use bls_dkg::key_gen::{message::Message as DkgMessage, KeyGen};
use hex_fmt::HexFmt;
Expand Down Expand Up @@ -139,7 +139,7 @@ impl DkgVoter {
}];
}

let threshold = majority(elders_info.elders.len()) - 1;
let threshold = supermajority(elders_info.elders.len()) - 1;
let participants = elders_info
.elders
.values()
Expand Down Expand Up @@ -481,10 +481,10 @@ impl DkgFailureProofSet {
}
}

// Check whether we have proofs from a majority of the participants. The contained proofs are
// assumed valid.
// Check whether we have enough proofs to reach agreement on the failure. The contained proofs
// are assumed valid.
fn has_agreement(&self, elders_info: &EldersInfo) -> bool {
self.0.len() >= majority(elders_info.elders.len())
has_failure_agreement(elders_info.elders.len(), self.0.len())
}

pub fn verify(&self, elders_info: &EldersInfo, generation: u64) -> bool {
Expand All @@ -500,10 +500,17 @@ impl DkgFailureProofSet {
.filter(|proof| proof.public_key.verify(&hash, &proof.signature).is_ok())
.count();

votes >= majority(elders_info.elders.len())
has_failure_agreement(elders_info.elders.len(), votes)
}
}

// Check whether we have enough proofs to reach agreement on the failure. We only need
// `N - supermajority(N) + 1` proofs, because that already makes a supermajority agreement on a
// successful outcome impossible.
fn has_failure_agreement(num_participants: usize, num_votes: usize) -> bool {
num_votes > num_participants - supermajority(num_participants)
}

// Create a value whose signature serves as the proof that a failure of a DKG session with the given
// `dkg_key` was observed.
fn failure_proof_hash(dkg_key: &DkgKey) -> Digest256 {
Expand Down
33 changes: 24 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,23 +107,38 @@ pub const RECOMMENDED_SECTION_SIZE: usize = 2 * ELDER_SIZE;
/// Number of elders per section.
pub const ELDER_SIZE: usize = 7;

/// Number of votes required to agree
/// with a strict majority (i.e. > 50%)
/// Number of votes required to agree with a supermajority (i.e. > 2/3)
#[inline]
pub(crate) const fn majority(num_possible_voters: usize) -> usize {
1 + (num_possible_voters / 2)
pub(crate) const fn supermajority(num_possible_voters: usize) -> usize {
1 + num_possible_voters * 2 / 3
}

#[cfg(test)]
mod tests {
use super::majority;
use super::supermajority;
use proptest::prelude::*;

#[test]
fn supermajority_of_small_group() {
assert_eq!(supermajority(0), 1);
assert_eq!(supermajority(1), 1);
assert_eq!(supermajority(2), 2);
assert_eq!(supermajority(3), 3);
assert_eq!(supermajority(4), 3);
assert_eq!(supermajority(5), 4);
assert_eq!(supermajority(6), 5);
assert_eq!(supermajority(7), 5);
assert_eq!(supermajority(8), 6);
assert_eq!(supermajority(9), 7);
}

proptest! {
#[test]
fn proptest_strict_majority(a in any::<usize>()) {
let maj = majority(a);
let maj_double = maj * 2;
assert!(maj_double == a + 1 || maj_double == a + 2);
fn proptest_supermajority(a in 0usize..10000) {
let n = 3 * a;
assert_eq!(supermajority(n), 2 * a + 1);
assert_eq!(supermajority(n + 1), 2 * a + 1);
assert_eq!(supermajority(n + 2), 2 * a + 2);
}
}
}
5 changes: 2 additions & 3 deletions src/routing/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use crate::{
consensus::{test_utils::*, Proven, Vote},
crypto,
event::Event,
majority,
messages::{JoinRequest, Message, PlainMessage, ResourceProofResponse, Variant, VerifyStatus},
network::Network,
node::Node,
Expand All @@ -24,7 +23,7 @@ use crate::{
test_utils::*, EldersInfo, MemberInfo, PeerState, Section, SectionChain, SectionKeyShare,
MIN_AGE,
},
ELDER_SIZE,
supermajority, ELDER_SIZE,
};
use anyhow::Result;
use assert_matches::assert_matches;
Expand Down Expand Up @@ -1451,7 +1450,7 @@ async fn relocation_of_non_elder() -> Result<()> {
relocation(RelocatedPeerRole::NonElder).await
}

const THRESHOLD: usize = majority(ELDER_SIZE) - 1;
const THRESHOLD: usize = supermajority(ELDER_SIZE) - 1;

#[allow(dead_code)]
enum RelocatedPeerRole {
Expand Down
2 changes: 1 addition & 1 deletion src/section/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ impl Section {

if expected_names == current_names {
vec![]
} else if expected_names.len() < crate::majority(current_names.len()) {
} else if expected_names.len() < crate::supermajority(current_names.len()) {
warn!("ignore attempt to reduce the number of elders too much");
vec![]
} else {
Expand Down

0 comments on commit b729a87

Please sign in to comment.