Skip to content

Commit

Permalink
Make threshold configurable for TreeOverlay
Browse files Browse the repository at this point in the history
  • Loading branch information
youngjoon-lee committed Sep 21, 2023
1 parent f57bfc8 commit b58e35b
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 41 deletions.
44 changes: 6 additions & 38 deletions consensus-engine/src/overlay/flat_overlay.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use super::threshold::{apply_threshold, default_leader_super_majority_threshold, deser_fraction};
use super::LeaderSelection;
use crate::overlay::CommitteeMembership;
use crate::{NodeId, Overlay};
use fraction::{Fraction, ToPrimitive};
use fraction::Fraction;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;

const LEADER_SUPER_MAJORITY_THRESHOLD_NUM: u64 = 2;
const LEADER_SUPER_MAJORITY_THRESHOLD_DEN: u64 = 3;

#[derive(Clone, Debug, PartialEq)]
/// Flat overlay with a single committee and round robin leader selection.
pub struct FlatOverlay<L: LeaderSelection, M: CommitteeMembership> {
Expand Down Expand Up @@ -36,12 +34,8 @@ where
Self {
nodes,
leader,
leader_threshold: leader_super_majority_threshold.unwrap_or_else(|| {
Fraction::new(
LEADER_SUPER_MAJORITY_THRESHOLD_NUM,
LEADER_SUPER_MAJORITY_THRESHOLD_DEN,
)
}),
leader_threshold: leader_super_majority_threshold
.unwrap_or_else(default_leader_super_majority_threshold),
_committee_membership: Default::default(),
}
}
Expand Down Expand Up @@ -91,11 +85,7 @@ where
}

fn leader_super_majority_threshold(&self, _id: NodeId) -> usize {
// self.leader_threshold is a tuple of (num, den) where num/den is the super majority threshold
(Fraction::from(self.nodes.len()) * self.leader_threshold)
.floor()
.to_usize()
.unwrap()
apply_threshold(self.nodes.len(), self.leader_threshold)
}

fn update_leader_selection<F, E>(&self, f: F) -> Result<Self, E>
Expand Down Expand Up @@ -125,30 +115,8 @@ pub struct FlatOverlaySettings<L> {
pub nodes: Vec<NodeId>,
/// A fraction representing the threshold in the form `<num>/<den>'
/// Defaults to 2/3
#[serde(with = "deser")]
#[serde(with = "deser_fraction")]
#[serde(skip_serializing_if = "Option::is_none")]
pub leader_super_majority_threshold: Option<Fraction>,
pub leader: L,
}

mod deser {
use fraction::Fraction;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;

pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Fraction>, D::Error>
where
D: Deserializer<'de>,
{
<Option<String>>::deserialize(deserializer)?
.map(|s| FromStr::from_str(&s).map_err(de::Error::custom))
.transpose()
}

pub fn serialize<S>(value: &Option<Fraction>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
value.map(|v| v.to_string()).serialize(serializer)
}
}
2 changes: 2 additions & 0 deletions consensus-engine/src/overlay/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod flat_overlay;
mod leadership;
mod membership;
mod random_beacon;
mod threshold;
mod tree_overlay;

pub use branch_overlay::*;
Expand Down Expand Up @@ -98,6 +99,7 @@ mod tests {
number_of_committees: 1,
leader: RoundRobin::new(),
committee_membership: FisherYatesShuffle::new(ENTROPY),
leader_super_majority_threshold: None,
});
let branch_overlay = BranchOverlay::new(BranchOverlaySettings {
current_leader: nodes[0],
Expand Down
41 changes: 41 additions & 0 deletions consensus-engine/src/overlay/threshold.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use fraction::{Fraction, GenericFraction, ToPrimitive};

const LEADER_SUPER_MAJORITY_THRESHOLD_NUM: u64 = 2;
const LEADER_SUPER_MAJORITY_THRESHOLD_DEN: u64 = 3;

pub fn default_leader_super_majority_threshold() -> GenericFraction<u64> {
Fraction::new(
LEADER_SUPER_MAJORITY_THRESHOLD_NUM,
LEADER_SUPER_MAJORITY_THRESHOLD_DEN,
)
}

pub fn apply_threshold(size: usize, threshold: GenericFraction<u64>) -> usize {
// `threshold` is a tuple of (num, den) where `num/den` is the super majority threshold
(Fraction::from(size) * threshold)
.floor()
.to_usize()
.unwrap()
}

pub mod deser_fraction {
use fraction::Fraction;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;

pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Fraction>, D::Error>
where
D: Deserializer<'de>,
{
<Option<String>>::deserialize(deserializer)?
.map(|s| FromStr::from_str(&s).map_err(de::Error::custom))
.transpose()
}

pub fn serialize<S>(value: &Option<Fraction>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
value.map(|v| v.to_string()).serialize(serializer)
}
}
25 changes: 23 additions & 2 deletions consensus-engine/src/overlay/tree_overlay/overlay.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use super::tree::Tree;
use crate::overlay::threshold::{
apply_threshold, default_leader_super_majority_threshold, deser_fraction,
};
use crate::overlay::CommitteeMembership;
use crate::{overlay::LeaderSelection, Committee, NodeId, Overlay};
use fraction::Fraction;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone)]
Expand All @@ -11,6 +15,11 @@ pub struct TreeOverlaySettings<L: LeaderSelection, M: CommitteeMembership> {
pub number_of_committees: usize,
pub leader: L,
pub committee_membership: M,
/// A fraction representing the threshold in the form `<num>/<den>'
/// Defaults to 2/3
#[serde(with = "deser_fraction")]
#[serde(skip_serializing_if = "Option::is_none")]
pub leader_super_majority_threshold: Option<Fraction>,
}

#[derive(Debug, Clone)]
Expand All @@ -21,6 +30,7 @@ pub struct TreeOverlay<L, M> {
pub(super) carnot_tree: Tree,
pub(super) leader: L,
pub(super) committee_membership: M,
pub(super) leader_threshold: Fraction,
}

impl<L, M> Overlay for TreeOverlay<L, M>
Expand All @@ -40,6 +50,7 @@ where
number_of_committees,
leader,
committee_membership,
leader_super_majority_threshold,
} = settings;

committee_membership.reshape_committees(&mut nodes);
Expand All @@ -52,6 +63,8 @@ where
carnot_tree,
leader,
committee_membership,
leader_threshold: leader_super_majority_threshold
.unwrap_or_else(default_leader_super_majority_threshold),
}
}

Expand Down Expand Up @@ -158,8 +171,7 @@ where
// });
// let root_size = self.root_committee().len();
// let committee_size = root_size + children_size;
let committee_size = self.root_committee().len();
(committee_size * 2 / 3) + 1
apply_threshold(self.root_committee().len(), self.leader_threshold)
}

fn update_leader_selection<F, E>(&self, f: F) -> Result<Self, E>
Expand All @@ -186,6 +198,7 @@ where
number_of_committees: self.number_of_committees,
leader: self.leader.clone(),
committee_membership,
leader_super_majority_threshold: Some(self.leader_threshold),
};
Self::new(settings)
})
Expand All @@ -204,6 +217,7 @@ where
number_of_committees: self.number_of_committees,
leader,
committee_membership,
leader_super_majority_threshold: Some(self.leader_threshold),
})
}

Expand Down Expand Up @@ -234,6 +248,7 @@ mod tests {
number_of_committees: 3,
leader: RoundRobin::new(),
committee_membership: FisherYatesShuffle::new(ENTROPY),
leader_super_majority_threshold: None,
});

assert_eq!(*overlay.leader(), nodes[0]);
Expand All @@ -248,6 +263,7 @@ mod tests {
number_of_committees: 3,
leader: RoundRobin::new(),
committee_membership: FisherYatesShuffle::new(ENTROPY),
leader_super_majority_threshold: None,
});

let leader = overlay.next_leader();
Expand All @@ -265,6 +281,7 @@ mod tests {
number_of_committees: 3,
leader: RoundRobin::new(),
committee_membership: FisherYatesShuffle::new(ENTROPY),
leader_super_majority_threshold: None,
});

let mut expected_root = Committee::new();
Expand All @@ -283,6 +300,7 @@ mod tests {
number_of_committees: 3,
leader: RoundRobin::new(),
committee_membership: FisherYatesShuffle::new(ENTROPY),
leader_super_majority_threshold: None,
});

let mut leaf_committees = overlay
Expand Down Expand Up @@ -313,6 +331,7 @@ mod tests {
number_of_committees: 3,
leader: RoundRobin::new(),
committee_membership: FisherYatesShuffle::new(ENTROPY),
leader_super_majority_threshold: None,
});

assert_eq!(overlay.super_majority_threshold(overlay.nodes[8]), 0);
Expand All @@ -327,6 +346,7 @@ mod tests {
number_of_committees: 3,
leader: RoundRobin::new(),
committee_membership: FisherYatesShuffle::new(ENTROPY),
leader_super_majority_threshold: None,
});

assert_eq!(overlay.super_majority_threshold(overlay.nodes[0]), 3);
Expand All @@ -341,6 +361,7 @@ mod tests {
number_of_committees: 3,
leader: RoundRobin::new(),
committee_membership: FisherYatesShuffle::new(ENTROPY),
leader_super_majority_threshold: None,
});

assert_eq!(
Expand Down
1 change: 1 addition & 0 deletions simulations/src/bin/app/overlay_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub fn to_overlay_node<R: Rng>(
number_of_committees: tree_settings.number_of_committees,
leader: RoundRobin::new(),
committee_membership: RandomBeaconState::initial_sad_from_entropy([0; 32]),
leader_super_majority_threshold: None,
};
Box::new(
CarnotNode::<TreeOverlay<RoundRobin, RandomBeaconState>>::new(
Expand Down
6 changes: 5 additions & 1 deletion tests/src/nodes/nomos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ impl Node for NomosNode {
fn create_node_config(
nodes: Vec<NodeId>,
private_key: [u8; 32],
_threshold: Fraction,
threshold: Fraction,
timeout: Duration,
#[cfg(feature = "libp2p")] mixnet_node_config: Option<MixnetNodeConfig>,
#[cfg(feature = "waku")] _mixnet_node_config: Option<MixnetNodeConfig>,
Expand Down Expand Up @@ -282,6 +282,10 @@ fn create_node_config(
current_leader: [0; 32].into(),
number_of_committees: 1,
committee_membership: RandomBeaconState::initial_sad_from_entropy([0; 32]),
// By setting the leader_threshold to 1 we ensure that all nodes come
// online before progressing. This is only necessary until we add a way
// to recover poast blocks from other nodes.
leader_super_majority_threshold: Some(threshold),
},
timeout,
},
Expand Down

0 comments on commit b58e35b

Please sign in to comment.