diff --git a/crates/example-types/src/node_types.rs b/crates/example-types/src/node_types.rs index a3ff669ab3..c5e5c6a3a9 100644 --- a/crates/example-types/src/node_types.rs +++ b/crates/example-types/src/node_types.rs @@ -52,7 +52,7 @@ impl NodeType for TestTypes { type Transaction = TestTransaction; type ValidatedState = TestValidatedState; type InstanceState = TestInstanceState; - type Membership = GeneralStaticCommittee; + type Membership = GeneralStaticCommittee; type BuilderSignatureKey = BuilderKey; } @@ -81,8 +81,7 @@ impl NodeType for TestConsecutiveLeaderTypes { type Transaction = TestTransaction; type ValidatedState = TestValidatedState; type InstanceState = TestInstanceState; - type Membership = - StaticCommitteeLeaderForTwoViews; + type Membership = StaticCommitteeLeaderForTwoViews; type BuilderSignatureKey = BuilderKey; } diff --git a/crates/examples/infra/mod.rs b/crates/examples/infra/mod.rs index 20b0ed8a56..0f37e713aa 100755 --- a/crates/examples/infra/mod.rs +++ b/crates/examples/infra/mod.rs @@ -377,32 +377,34 @@ pub trait RunDa< // Get KeyPair for certificate Aggregation let pk = config.config.my_own_validator_config.public_key.clone(); let sk = config.config.my_own_validator_config.private_key.clone(); - let known_nodes_with_stake = config.config.known_nodes_with_stake.clone(); let network = self.network(); + let all_nodes = config.config.known_nodes_with_stake.clone(); + let da_nodes = config.config.known_da_nodes.clone(); + // Create the quorum membership from all nodes - let quorum_membership = ::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake.clone(), + let quorum_membership = ::Membership::new( + all_nodes.clone(), + all_nodes.clone(), Topic::Global, + #[cfg(feature = "fixed-leader-election")] config.config.fixed_leader_for_gpuvid, ); // Create the quorum membership from all nodes, specifying the committee // as the known da nodes - let da_membership = ::Membership::create_election( - known_nodes_with_stake.clone(), - config.config.known_da_nodes.clone(), + let da_membership = ::Membership::new( + all_nodes.clone(), + da_nodes, Topic::Da, + #[cfg(feature = "fixed-leader-election")] config.config.fixed_leader_for_gpuvid, ); let memberships = Memberships { quorum_membership: quorum_membership.clone(), da_membership, - vid_membership: quorum_membership.clone(), - view_sync_membership: quorum_membership, }; let marketplace_config = MarketplaceConfig { diff --git a/crates/hotshot/src/lib.rs b/crates/hotshot/src/lib.rs index 3a1a2cd086..2fd7cde872 100644 --- a/crates/hotshot/src/lib.rs +++ b/crates/hotshot/src/lib.rs @@ -90,14 +90,10 @@ pub struct MarketplaceConfig> { /// Bundle of all the memberships a consensus instance uses #[derive(Clone)] pub struct Memberships { - /// Quorum Membership + /// The entire quorum pub quorum_membership: TYPES::Membership, - /// DA + /// The DA nodes pub da_membership: TYPES::Membership, - /// VID - pub vid_membership: TYPES::Membership, - /// View Sync - pub view_sync_membership: TYPES::Membership, } /// Holds the state needed to participate in `HotShot` consensus diff --git a/crates/hotshot/src/tasks/mod.rs b/crates/hotshot/src/tasks/mod.rs index 9bab74694a..5db94d0e14 100644 --- a/crates/hotshot/src/tasks/mod.rs +++ b/crates/hotshot/src/tasks/mod.rs @@ -495,8 +495,6 @@ where let network = Arc::clone(&handle.network); let quorum_membership = handle.memberships.quorum_membership.clone(); let da_membership = handle.memberships.da_membership.clone(); - let vid_membership = handle.memberships.vid_membership.clone(); - let view_sync_membership = handle.memberships.view_sync_membership.clone(); self.add_network_event_task( handle, @@ -507,7 +505,7 @@ where self.add_network_event_task( handle, Arc::clone(&network), - quorum_membership, + quorum_membership.clone(), network::upgrade_filter, ); self.add_network_event_task( @@ -519,13 +517,13 @@ where self.add_network_event_task( handle, Arc::clone(&network), - view_sync_membership, + quorum_membership.clone(), network::view_sync_filter, ); self.add_network_event_task( handle, Arc::clone(&network), - vid_membership, + quorum_membership, network::vid_filter, ); } @@ -577,8 +575,6 @@ pub fn add_network_event_tasks, V: let network = Arc::clone(&handle.network); let quorum_membership = handle.memberships.quorum_membership.clone(); let da_membership = handle.memberships.da_membership.clone(); - let vid_membership = handle.memberships.vid_membership.clone(); - let view_sync_membership = handle.memberships.view_sync_membership.clone(); add_network_event_task( handle, @@ -589,7 +585,7 @@ pub fn add_network_event_tasks, V: add_network_event_task( handle, Arc::clone(&network), - quorum_membership, + quorum_membership.clone(), network::upgrade_filter, ); add_network_event_task( @@ -601,13 +597,13 @@ pub fn add_network_event_tasks, V: add_network_event_task( handle, Arc::clone(&network), - view_sync_membership, + quorum_membership.clone(), network::view_sync_filter, ); add_network_event_task( handle, Arc::clone(&network), - vid_membership, + quorum_membership, network::vid_filter, ); } diff --git a/crates/hotshot/src/tasks/task_state.rs b/crates/hotshot/src/tasks/task_state.rs index 8ce9d19236..ab7f68fdc4 100644 --- a/crates/hotshot/src/tasks/task_state.rs +++ b/crates/hotshot/src/tasks/task_state.rs @@ -120,7 +120,7 @@ impl, V: Versions> CreateTaskState cur_view: handle.cur_view().await, vote_collector: None, network: Arc::clone(&handle.hotshot.network), - membership: handle.hotshot.memberships.vid_membership.clone().into(), + membership: handle.hotshot.memberships.quorum_membership.clone().into(), public_key: handle.public_key().clone(), private_key: handle.private_key().clone(), id: handle.hotshot.id, @@ -161,12 +161,7 @@ impl, V: Versions> CreateTaskState current_view: cur_view, next_view: cur_view, network: Arc::clone(&handle.hotshot.network), - membership: handle - .hotshot - .memberships - .view_sync_membership - .clone() - .into(), + membership: handle.hotshot.memberships.quorum_membership.clone().into(), public_key: handle.public_key().clone(), private_key: handle.private_key().clone(), num_timeouts_tracked: 0, diff --git a/crates/hotshot/src/traits/election/static_committee.rs b/crates/hotshot/src/traits/election/static_committee.rs index 842c2378c6..01b56be103 100644 --- a/crates/hotshot/src/traits/election/static_committee.rs +++ b/crates/hotshot/src/traits/election/static_committee.rs @@ -4,74 +4,126 @@ // You should have received a copy of the MIT License // along with the HotShot repository. If not, see . -use std::{marker::PhantomData, num::NonZeroU64}; +use std::collections::BTreeMap; +use std::num::NonZeroU64; use ethereum_types::U256; -// use ark_bls12_381::Parameters as Param381; -use hotshot_types::traits::signature_key::StakeTableEntryType; use hotshot_types::{ - signature_key::BLSPubKey, traits::{ - election::Membership, network::Topic, node_implementation::NodeType, - signature_key::SignatureKey, + election::Membership, + network::Topic, + node_implementation::NodeType, + signature_key::{SignatureKey, StakeTableEntryType}, }, PeerConfig, }; #[cfg(feature = "randomized-leader-election")] use rand::{rngs::StdRng, Rng}; -use tracing::debug; - -/// Dummy implementation of [`Membership`] #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct GeneralStaticCommittee { - /// All the nodes participating and their stake - all_nodes_with_stake: Vec, - /// The nodes on the static committee and their stake - committee_nodes_with_stake: Vec, - /// builder nodes - committee_nodes_without_stake: Vec, - /// the number of fixed leader for gpuvid + +/// The static committee election +pub struct GeneralStaticCommittee { + /// The nodes eligible for leadership. + /// NOTE: This is currently a hack because the DA leader needs to be the quorum + /// leader but without voting rights. + eligible_leaders: Vec<::StakeTableEntry>, + + /// The nodes on the committee and their stake + stake_table: Vec<::StakeTableEntry>, + + /// The nodes on the committee and their stake, indexed by public key + indexed_stake_table: + BTreeMap::StakeTableEntry>, + + // /// The members of the committee + // committee_members: BTreeSet, + #[cfg(feature = "fixed-leader-election")] + /// The number of fixed leaders for gpuvid fixed_leader_for_gpuvid: usize, - /// Node type phantom - _type_phantom: PhantomData, /// The network topic of the committee committee_topic: Topic, } /// static committee using a vrf kp -pub type StaticCommittee = GeneralStaticCommittee; - -impl GeneralStaticCommittee { - /// Creates a new dummy elector - #[must_use] - pub fn new( - _nodes: &[PUBKEY], - nodes_with_stake: Vec, - nodes_without_stake: Vec, - fixed_leader_for_gpuvid: usize, +pub type StaticCommittee = GeneralStaticCommittee; + +impl Membership for GeneralStaticCommittee { + /// Create a new election + fn new( + eligible_leaders: Vec::SignatureKey>>, + committee_members: Vec::SignatureKey>>, committee_topic: Topic, + #[cfg(feature = "fixed-leader-election")] fixed_leader_for_gpuvid: usize, ) -> Self { + // For each eligible leader, get the stake table entry + let eligible_leaders: Vec<::StakeTableEntry> = + eligible_leaders + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // For each member, get the stake table entry + let members: Vec<::StakeTableEntry> = + committee_members + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // Index the stake table by public key + let indexed_stake_table: BTreeMap< + TYPES::SignatureKey, + ::StakeTableEntry, + > = members + .iter() + .map(|entry| (TYPES::SignatureKey::public_key(entry), entry.clone())) + .collect(); + Self { - all_nodes_with_stake: nodes_with_stake.clone(), - committee_nodes_with_stake: nodes_with_stake, - committee_nodes_without_stake: nodes_without_stake, - fixed_leader_for_gpuvid, - _type_phantom: PhantomData, + eligible_leaders, + stake_table: members, + indexed_stake_table, committee_topic, + #[cfg(feature = "fixed-leader-election")] + fixed_leader_for_gpuvid, } } -} -impl Membership - for GeneralStaticCommittee -where - TYPES: NodeType, -{ - /// Clone the public key and corresponding stake table for current elected committee - fn committee_qc_stake_table(&self) -> Vec { - self.committee_nodes_with_stake.clone() + /// Get the stake table for the current view + fn stake_table( + &self, + ) -> Vec<<::SignatureKey as SignatureKey>::StakeTableEntry> { + self.stake_table.clone() + } + + /// Get all members of the committee for the current view + fn committee_members( + &self, + _view_number: ::Time, + ) -> std::collections::BTreeSet<::SignatureKey> { + self.stake_table + .iter() + .map(TYPES::SignatureKey::public_key) + .collect() + } + + /// Get the stake table entry for a public key + fn stake( + &self, + pub_key: &::SignatureKey, + ) -> Option<::StakeTableEntry> { + // Only return the stake if it is above zero + self.indexed_stake_table.get(pub_key).cloned() + } + + /// Check if a node has stake in the committee + fn has_stake(&self, pub_key: &::SignatureKey) -> bool { + self.indexed_stake_table + .get(pub_key) + .is_some_and(|x| x.stake() > U256::zero()) } /// Get the network topic for the committee @@ -84,152 +136,53 @@ where feature = "fixed-leader-election" )))] /// Index the vector of public keys with the current view number - fn leader(&self, view_number: TYPES::Time) -> PUBKEY { - let index = usize::try_from(*view_number % self.all_nodes_with_stake.len() as u64).unwrap(); - let res = self.all_nodes_with_stake[index].clone(); + fn leader(&self, view_number: TYPES::Time) -> TYPES::SignatureKey { + let index = usize::try_from(*view_number % self.eligible_leaders.len() as u64).unwrap(); + let res = self.eligible_leaders[index].clone(); TYPES::SignatureKey::public_key(&res) } #[cfg(feature = "fixed-leader-election")] /// Only get leader in fixed set /// Index the fixed vector (first fixed_leader_for_gpuvid element) of public keys with the current view number - fn leader(&self, view_number: TYPES::Time) -> PUBKEY { + fn leader(&self, view_number: TYPES::Time) -> TYPES::SignatureKey { if self.fixed_leader_for_gpuvid <= 0 - || self.fixed_leader_for_gpuvid > self.all_nodes_with_stake.len() + || self.fixed_leader_for_gpuvid > self.eligible_leaders.len() { panic!("fixed_leader_for_gpuvid is not set correctly."); } let index = usize::try_from(*view_number % self.fixed_leader_for_gpuvid as u64).unwrap(); - let res = self.all_nodes_with_stake[index].clone(); + let res = self.eligible_leaders[index].clone(); TYPES::SignatureKey::public_key(&res) } #[cfg(feature = "randomized-leader-election")] /// Index the vector of public keys with a random number generated using the current view number as a seed - fn leader(&self, view_number: TYPES::Time) -> PUBKEY { + fn leader(&self, view_number: TYPES::Time) -> TYPES::SignatureKey { let mut rng: StdRng = rand::SeedableRng::seed_from_u64(*view_number); let randomized_view_number: usize = rng.gen(); - let index = randomized_view_number % self.nodes_with_stake.len(); - let res = self.all_nodes_with_stake[index].clone(); + let index = randomized_view_number % self.eligible_leaders.len(); + let res = self.eligible_leaders[index].clone(); TYPES::SignatureKey::public_key(&res) } - fn has_stake(&self, pub_key: &PUBKEY) -> bool { - let entry = pub_key.stake_table_entry(1u64); - self.committee_nodes_with_stake.contains(&entry) - } - - fn stake( - &self, - pub_key: &::SignatureKey, - ) -> Option<::StakeTableEntry> { - let entry = pub_key.stake_table_entry(1u64); - if self.committee_nodes_with_stake.contains(&entry) { - Some(entry) - } else { - None - } - } - - fn create_election( - mut all_nodes: Vec>, - committee_members: Vec>, - committee_topic: Topic, - fixed_leader_for_gpuvid: usize, - ) -> Self { - let mut committee_nodes_with_stake = Vec::new(); - let mut committee_nodes_without_stake = Vec::new(); - - // Iterate over committee members - for entry in committee_members - .iter() - .map(|entry| entry.stake_table_entry.clone()) - { - if entry.stake() > U256::from(0) { - // Positive stake - committee_nodes_with_stake.push(entry); - } else { - // Zero stake - committee_nodes_without_stake.push(PUBKEY::public_key(&entry)); - } - } - - // Retain all nodes with stake - all_nodes.retain(|entry| entry.stake_table_entry.stake() > U256::from(0)); - - debug!( - "Election Membership Size: {}", - committee_nodes_with_stake.len() - ); - - Self { - all_nodes_with_stake: all_nodes - .into_iter() - .map(|entry| entry.stake_table_entry) - .collect(), - committee_nodes_with_stake, - committee_nodes_without_stake, - fixed_leader_for_gpuvid, - _type_phantom: PhantomData, - committee_topic, - } - } - + /// Get the total number of nodes in the committee fn total_nodes(&self) -> usize { - self.committee_nodes_with_stake.len() + self.stake_table.len() } + /// Get the voting success threshold for the committee fn success_threshold(&self) -> NonZeroU64 { - NonZeroU64::new(((self.committee_nodes_with_stake.len() as u64 * 2) / 3) + 1).unwrap() + 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 { - NonZeroU64::new(((self.committee_nodes_with_stake.len() as u64) / 3) + 1).unwrap() + NonZeroU64::new(((self.stake_table.len() as u64) / 3) + 1).unwrap() } + /// Get the voting upgrade threshold for the committee fn upgrade_threshold(&self) -> NonZeroU64 { - NonZeroU64::new(((self.committee_nodes_with_stake.len() as u64 * 9) / 10) + 1).unwrap() - } - - fn staked_committee( - &self, - _view_number: ::Time, - ) -> std::collections::BTreeSet<::SignatureKey> { - self.committee_nodes_with_stake - .iter() - .map(|node| ::SignatureKey::public_key(node)) - .collect() - } - - fn non_staked_committee( - &self, - _view_number: ::Time, - ) -> std::collections::BTreeSet<::SignatureKey> { - self.committee_nodes_without_stake.iter().cloned().collect() - } - - fn whole_committee( - &self, - view_number: ::Time, - ) -> std::collections::BTreeSet<::SignatureKey> { - let mut committee = self.staked_committee(view_number); - committee.extend(self.non_staked_committee(view_number)); - committee - } -} - -impl GeneralStaticCommittee -where - TYPES: NodeType, -{ - #[allow(clippy::must_use_candidate)] - /// get the non-staked builder nodes - pub fn non_staked_nodes_count(&self) -> usize { - self.committee_nodes_without_stake.len() - } - #[allow(clippy::must_use_candidate)] - /// get all the non-staked nodes - pub fn non_staked_nodes(&self) -> Vec { - self.committee_nodes_without_stake.clone() + NonZeroU64::new(((self.stake_table.len() as u64 * 9) / 10) + 1).unwrap() } } 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 d114a5d904..2f88c5ba4d 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 @@ -1,202 +1,159 @@ -use std::{marker::PhantomData, num::NonZeroU64}; +// Copyright (c) 2021-2024 Espresso Systems (espressosys.com) +// This file is part of the HotShot repository. + +// You should have received a copy of the MIT License +// along with the HotShot repository. If not, see . + +use std::collections::BTreeMap; +use std::num::NonZeroU64; use ethereum_types::U256; -// use ark_bls12_381::Parameters as Param381; -use hotshot_types::traits::signature_key::StakeTableEntryType; use hotshot_types::{ - signature_key::BLSPubKey, traits::{ - election::Membership, network::Topic, node_implementation::NodeType, - signature_key::SignatureKey, + election::Membership, + network::Topic, + node_implementation::NodeType, + signature_key::{SignatureKey, StakeTableEntryType}, }, PeerConfig, }; -use tracing::debug; - -/// Dummy implementation of [`Membership`] #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub struct StaticCommitteeLeaderForTwoViews { - /// All the nodes participating and their stake - all_nodes_with_stake: Vec, - /// The nodes on the static committee and their stake - committee_nodes_with_stake: Vec, - /// builder nodes - committee_nodes_without_stake: Vec, - /// the number of fixed leader for gpuvid + +/// The static committee election +pub struct StaticCommitteeLeaderForTwoViews { + /// The nodes eligible for leadership. + /// NOTE: This is currently a hack because the DA leader needs to be the quorum + /// leader but without voting rights. + eligible_leaders: Vec<::StakeTableEntry>, + + /// The nodes on the committee and their stake + stake_table: Vec<::StakeTableEntry>, + + /// The nodes on the committee and their stake, indexed by public key + indexed_stake_table: + BTreeMap::StakeTableEntry>, + + // /// The members of the committee + // committee_members: BTreeSet, + #[cfg(feature = "fixed-leader-election")] + /// The number of fixed leaders for gpuvid fixed_leader_for_gpuvid: usize, - /// Node type phantom - _type_phantom: PhantomData, /// The network topic of the committee committee_topic: Topic, } /// static committee using a vrf kp -pub type StaticCommittee = StaticCommitteeLeaderForTwoViews; - -impl StaticCommitteeLeaderForTwoViews { - /// Creates a new dummy elector - #[must_use] - pub fn new( - _nodes: &[PUBKEY], - nodes_with_stake: Vec, - nodes_without_stake: Vec, - fixed_leader_for_gpuvid: usize, +pub type StaticCommittee = StaticCommitteeLeaderForTwoViews; + +impl Membership for StaticCommitteeLeaderForTwoViews { + /// Create a new election + fn new( + eligible_leaders: Vec::SignatureKey>>, + committee_members: Vec::SignatureKey>>, committee_topic: Topic, + #[cfg(feature = "fixed-leader-election")] fixed_leader_for_gpuvid: usize, ) -> Self { + // For each eligible leader, get the stake table entry + let eligible_leaders: Vec<::StakeTableEntry> = + eligible_leaders + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // For each member, get the stake table entry + let members: Vec<::StakeTableEntry> = + committee_members + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // Index the stake table by public key + let indexed_stake_table: BTreeMap< + TYPES::SignatureKey, + ::StakeTableEntry, + > = members + .iter() + .map(|entry| (TYPES::SignatureKey::public_key(entry), entry.clone())) + .collect(); + Self { - all_nodes_with_stake: nodes_with_stake.clone(), - committee_nodes_with_stake: nodes_with_stake, - committee_nodes_without_stake: nodes_without_stake, - fixed_leader_for_gpuvid, - _type_phantom: PhantomData, + eligible_leaders, + stake_table: members, + indexed_stake_table, committee_topic, + #[cfg(feature = "fixed-leader-election")] + fixed_leader_for_gpuvid, } } -} - -impl Membership - for StaticCommitteeLeaderForTwoViews -where - TYPES: NodeType, -{ - /// Clone the public key and corresponding stake table for current elected committee - fn committee_qc_stake_table(&self) -> Vec { - self.committee_nodes_with_stake.clone() - } - - /// Get the network topic for the committee - fn committee_topic(&self) -> Topic { - self.committee_topic.clone() - } - /// Index the vector of public keys with the current view number - fn leader(&self, view_number: TYPES::Time) -> PUBKEY { - // two connsecutive views will have same index starting with even number. - // eg 0->1, 2->3 ... 10->11 etc - let index = - usize::try_from((*view_number / 2) % self.all_nodes_with_stake.len() as u64).unwrap(); - let res = self.all_nodes_with_stake[index].clone(); - TYPES::SignatureKey::public_key(&res) + /// Get the stake table for the current view + fn stake_table( + &self, + ) -> Vec<<::SignatureKey as SignatureKey>::StakeTableEntry> { + self.stake_table.clone() } - fn has_stake(&self, pub_key: &PUBKEY) -> bool { - let entry = pub_key.stake_table_entry(1u64); - self.committee_nodes_with_stake.contains(&entry) + /// Get all members of the committee for the current view + fn committee_members( + &self, + _view_number: ::Time, + ) -> std::collections::BTreeSet<::SignatureKey> { + self.stake_table + .iter() + .map(TYPES::SignatureKey::public_key) + .collect() } + /// Get the stake table entry for a public key fn stake( &self, pub_key: &::SignatureKey, ) -> Option<::StakeTableEntry> { - let entry = pub_key.stake_table_entry(1u64); - if self.committee_nodes_with_stake.contains(&entry) { - Some(entry) - } else { - None - } + // Only return the stake if it is above zero + self.indexed_stake_table.get(pub_key).cloned() } - fn create_election( - mut all_nodes: Vec>, - committee_members: Vec>, - committee_topic: Topic, - fixed_leader_for_gpuvid: usize, - ) -> Self { - let mut committee_nodes_with_stake = Vec::new(); - let mut committee_nodes_without_stake = Vec::new(); - - // Iterate over committee members - for entry in committee_members - .iter() - .map(|entry| entry.stake_table_entry.clone()) - { - if entry.stake() > U256::from(0) { - // Positive stake - committee_nodes_with_stake.push(entry); - } else { - // Zero stake - committee_nodes_without_stake.push(PUBKEY::public_key(&entry)); - } - } - - // Retain all nodes with stake - all_nodes.retain(|entry| entry.stake_table_entry.stake() > U256::from(0)); + /// Check if a node has stake in the committee + fn has_stake(&self, pub_key: &::SignatureKey) -> bool { + self.indexed_stake_table + .get(pub_key) + .is_some_and(|x| x.stake() > U256::zero()) + } - debug!( - "Election Membership Size: {}", - committee_nodes_with_stake.len() - ); + /// Get the network topic for the committee + fn committee_topic(&self) -> Topic { + self.committee_topic.clone() + } - Self { - all_nodes_with_stake: all_nodes - .into_iter() - .map(|entry| entry.stake_table_entry) - .collect(), - committee_nodes_with_stake, - committee_nodes_without_stake, - fixed_leader_for_gpuvid, - _type_phantom: PhantomData, - committee_topic, - } + /// Index the vector of public keys with the current view number + fn leader(&self, view_number: TYPES::Time) -> TYPES::SignatureKey { + let index = + usize::try_from((*view_number / 2) % self.eligible_leaders.len() as u64).unwrap(); + let res = self.eligible_leaders[index].clone(); + TYPES::SignatureKey::public_key(&res) } + /// Get the total number of nodes in the committee fn total_nodes(&self) -> usize { - self.committee_nodes_with_stake.len() + self.stake_table.len() } + /// Get the voting success threshold for the committee fn success_threshold(&self) -> NonZeroU64 { - NonZeroU64::new(((self.committee_nodes_with_stake.len() as u64 * 2) / 3) + 1).unwrap() + 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 { - NonZeroU64::new(((self.committee_nodes_with_stake.len() as u64) / 3) + 1).unwrap() + NonZeroU64::new(((self.stake_table.len() as u64) / 3) + 1).unwrap() } + /// Get the voting upgrade threshold for the committee fn upgrade_threshold(&self) -> NonZeroU64 { - NonZeroU64::new(((self.committee_nodes_with_stake.len() as u64 * 9) / 10) + 1).unwrap() - } - - fn staked_committee( - &self, - _view_number: ::Time, - ) -> std::collections::BTreeSet<::SignatureKey> { - self.committee_nodes_with_stake - .iter() - .map(|node| ::SignatureKey::public_key(node)) - .collect() - } - - fn non_staked_committee( - &self, - _view_number: ::Time, - ) -> std::collections::BTreeSet<::SignatureKey> { - self.committee_nodes_without_stake.iter().cloned().collect() - } - - fn whole_committee( - &self, - view_number: ::Time, - ) -> std::collections::BTreeSet<::SignatureKey> { - let mut committee = self.staked_committee(view_number); - committee.extend(self.non_staked_committee(view_number)); - committee - } -} - -impl StaticCommitteeLeaderForTwoViews -where - TYPES: NodeType, -{ - #[allow(clippy::must_use_candidate)] - /// get the non-staked builder nodes - pub fn non_staked_nodes_count(&self) -> usize { - self.committee_nodes_without_stake.len() - } - #[allow(clippy::must_use_candidate)] - /// get all the non-staked nodes - pub fn non_staked_nodes(&self) -> Vec { - self.committee_nodes_without_stake.clone() + NonZeroU64::new(((self.stake_table.len() as u64 * 9) / 10) + 1).unwrap() } } diff --git a/crates/orchestrator/run-config.toml b/crates/orchestrator/run-config.toml index e0672d0164..ae5cfe59ad 100644 --- a/crates/orchestrator/run-config.toml +++ b/crates/orchestrator/run-config.toml @@ -56,10 +56,8 @@ enable_registration_verification = true [config] num_nodes_with_stake = 10 -num_nodes_without_stake = 0 start_threshold = [8, 10] staked_da_nodes = 10 -non_staked_da_nodes = 0 fixed_leader_for_gpuvid = 1 next_view_timeout = 30000 timeout_ratio = [11, 10] diff --git a/crates/orchestrator/src/config.rs b/crates/orchestrator/src/config.rs index 514eda8e96..0464c1bd5f 100644 --- a/crates/orchestrator/src/config.rs +++ b/crates/orchestrator/src/config.rs @@ -499,8 +499,6 @@ pub struct HotShotConfigFile { pub start_threshold: (u64, u64), /// Total number of staked nodes in the network pub num_nodes_with_stake: NonZeroUsize, - /// Total number of non-staked nodes in the network - pub num_nodes_without_stake: usize, #[serde(skip)] /// My own public key, secret key, stake value pub my_own_validator_config: ValidatorConfig, @@ -515,8 +513,6 @@ pub struct HotShotConfigFile { pub known_nodes_without_stake: Vec, /// Number of staking DA nodes pub staked_da_nodes: usize, - /// Number of non-staking DA nodes - pub non_staked_da_nodes: usize, /// Number of fixed leaders for GPU VID pub fixed_leader_for_gpuvid: usize, /// Base duration for next-view timeout, in milliseconds @@ -641,13 +637,11 @@ impl From> for HotShotConfig { execution_type: ExecutionType::Continuous, start_threshold: val.start_threshold, num_nodes_with_stake: val.num_nodes_with_stake, - num_nodes_without_stake: val.num_nodes_without_stake, known_da_nodes: val.known_da_nodes, known_nodes_with_stake: val.known_nodes_with_stake, known_nodes_without_stake: val.known_nodes_without_stake, my_own_validator_config: val.my_own_validator_config, da_staked_committee_size: val.staked_da_nodes, - da_non_staked_committee_size: val.non_staked_da_nodes, fixed_leader_for_gpuvid: val.fixed_leader_for_gpuvid, next_view_timeout: val.next_view_timeout, view_sync_timeout: val.view_sync_timeout, @@ -720,13 +714,11 @@ impl Default for HotShotConfigFile { Self { num_nodes_with_stake: NonZeroUsize::new(10).unwrap(), start_threshold: (1, 1), - num_nodes_without_stake: 0, my_own_validator_config: ValidatorConfig::default(), known_nodes_with_stake: gen_known_nodes_with_stake, known_nodes_without_stake: vec![], staked_da_nodes, known_da_nodes, - non_staked_da_nodes: 0, fixed_leader_for_gpuvid: 1, next_view_timeout: 10000, view_sync_timeout: Duration::from_millis(1000), diff --git a/crates/orchestrator/staging-config.toml b/crates/orchestrator/staging-config.toml index 7290ced3b0..417a19f10b 100644 --- a/crates/orchestrator/staging-config.toml +++ b/crates/orchestrator/staging-config.toml @@ -44,9 +44,7 @@ builder = "Simple" [config] start_threshold = [ 8, 10 ] num_nodes_with_stake = 10 -num_nodes_without_stake = 0 staked_da_nodes = 10 -non_staked_da_nodes = 0 fixed_leader_for_gpuvid = 1 next_view_timeout = 15_000 timeout_ratio = [ 11, 10 ] diff --git a/crates/task-impls/src/consensus/mod.rs b/crates/task-impls/src/consensus/mod.rs index 2e8507cd93..c4b7291bc3 100644 --- a/crates/task-impls/src/consensus/mod.rs +++ b/crates/task-impls/src/consensus/mod.rs @@ -159,7 +159,7 @@ impl, V: Versions> ConsensusTaskSt .validate(&disperse.signature, payload_commitment.as_ref()) { let mut validated = false; - for da_member in self.da_membership.staked_committee(view) { + for da_member in self.da_membership.committee_members(view) { if da_member.validate(&disperse.signature, payload_commitment.as_ref()) { validated = true; break; diff --git a/crates/task-impls/src/network.rs b/crates/task-impls/src/network.rs index 1ea7a3cc1d..7102179585 100644 --- a/crates/task-impls/src/network.rs +++ b/crates/task-impls/src/network.rs @@ -547,7 +547,7 @@ impl< kind: message_kind, }; let view = message.kind.view_number(); - let committee = membership.whole_committee(view); + let committee = membership.committee_members(view); let committee_topic = membership.committee_topic(); let net = Arc::clone(&self.channel); let storage = Arc::clone(&self.storage); diff --git a/crates/task-impls/src/quorum_vote/mod.rs b/crates/task-impls/src/quorum_vote/mod.rs index 67a28f1da4..bd7e04d993 100644 --- a/crates/task-impls/src/quorum_vote/mod.rs +++ b/crates/task-impls/src/quorum_vote/mod.rs @@ -603,7 +603,7 @@ impl, V: Versions> QuorumVoteTaskS .validate(&disperse.signature, payload_commitment.as_ref()) { let mut validated = false; - for da_member in self.da_membership.staked_committee(view) { + for da_member in self.da_membership.committee_members(view) { if da_member.validate(&disperse.signature, payload_commitment.as_ref()) { validated = true; break; diff --git a/crates/task-impls/src/request.rs b/crates/task-impls/src/request.rs index abe40ef702..d7d2c0b8ff 100644 --- a/crates/task-impls/src/request.rs +++ b/crates/task-impls/src/request.rs @@ -213,7 +213,7 @@ impl> NetworkRequestState = self .da_membership - .whole_committee(view) + .committee_members(view) .into_iter() .collect(); // Randomize the recipients so all replicas don't overload the same 1 recipients diff --git a/crates/testing/src/helpers.rs b/crates/testing/src/helpers.rs index 54d6039f33..a5a992784c 100644 --- a/crates/testing/src/helpers.rs +++ b/crates/testing/src/helpers.rs @@ -79,35 +79,25 @@ pub async fn build_system_handle< .await .unwrap(); - let known_nodes_with_stake = config.known_nodes_with_stake.clone(); let private_key = config.my_own_validator_config.private_key.clone(); let public_key = config.my_own_validator_config.public_key.clone(); - let _known_nodes_without_stake = config.known_nodes_without_stake.clone(); + let all_nodes = config.known_nodes_with_stake.clone(); + let da_nodes = config.known_da_nodes.clone(); let memberships = Memberships { - quorum_membership: TYPES::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake.clone(), + quorum_membership: TYPES::Membership::new( + all_nodes.clone(), + all_nodes.clone(), Topic::Global, + #[cfg(feature = "fixed-leader-election")] config.fixed_leader_for_gpuvid, ), - da_membership: TYPES::Membership::create_election( - known_nodes_with_stake.clone(), - config.known_da_nodes.clone(), + da_membership: TYPES::Membership::new( + all_nodes, + da_nodes, Topic::Da, - config.fixed_leader_for_gpuvid, - ), - vid_membership: TYPES::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake.clone(), - Topic::Global, - config.fixed_leader_for_gpuvid, - ), - view_sync_membership: TYPES::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake, - Topic::Global, + #[cfg(feature = "fixed-leader-election")] config.fixed_leader_for_gpuvid, ), }; @@ -207,7 +197,7 @@ pub async fn build_assembled_sig< view: TYPES::Time, upgrade_lock: &UpgradeLock, ) -> ::QcType { - let stake_table = membership.committee_qc_stake_table(); + let stake_table = membership.stake_table(); let real_qc_pp: ::QcParams = ::public_parameter( stake_table.clone(), @@ -264,7 +254,7 @@ pub fn vid_scheme_from_view_number( membership: &TYPES::Membership, view_number: TYPES::Time, ) -> VidSchemeType { - let num_storage_nodes = membership.staked_committee(view_number).len(); + let num_storage_nodes = membership.committee_members(view_number).len(); vid_scheme(num_storage_nodes) } diff --git a/crates/testing/src/test_builder.rs b/crates/testing/src/test_builder.rs index 098d12512d..3ff40a68ff 100644 --- a/crates/testing/src/test_builder.rs +++ b/crates/testing/src/test_builder.rs @@ -60,8 +60,6 @@ pub struct TimingData { pub struct TestDescription, V: Versions> { /// Total number of staked nodes in the test pub num_nodes_with_stake: usize, - /// Total number of non-staked nodes in the test - pub num_nodes_without_stake: usize, /// nodes available at start pub start_nodes: usize, /// Whether to skip initializing nodes that will start late, which will catch up later with @@ -71,8 +69,6 @@ pub struct TestDescription, V: Ver pub num_bootstrap_nodes: usize, /// Size of the staked DA committee for the test pub da_staked_committee_size: usize, - /// Size of the non-staked DA committee for the test - pub da_non_staked_committee_size: usize, /// overall safety property description pub overall_safety_properties: OverallSafetyPropertiesDescription, /// spinning properties @@ -239,12 +235,10 @@ impl, V: Versions> TestDescription #[allow(clippy::redundant_field_names)] pub fn default_stress() -> Self { let num_nodes_with_stake = 100; - let num_nodes_without_stake = 0; Self { num_bootstrap_nodes: num_nodes_with_stake, num_nodes_with_stake, - num_nodes_without_stake, start_nodes: num_nodes_with_stake, overall_safety_properties: OverallSafetyPropertiesDescription:: { num_successful_views: 50, @@ -272,13 +266,11 @@ impl, V: Versions> TestDescription #[allow(clippy::redundant_field_names)] pub fn default_multiple_rounds() -> Self { let num_nodes_with_stake = 10; - let num_nodes_without_stake = 0; TestDescription:: { // TODO: remove once we have fixed the DHT timeout issue // https://github.com/EspressoSystems/HotShot/issues/2088 num_bootstrap_nodes: num_nodes_with_stake, num_nodes_with_stake, - num_nodes_without_stake, start_nodes: num_nodes_with_stake, overall_safety_properties: OverallSafetyPropertiesDescription:: { num_successful_views: 20, @@ -304,10 +296,8 @@ impl, V: Versions> TestDescription #[allow(clippy::redundant_field_names)] pub fn default_more_nodes() -> Self { let num_nodes_with_stake = 20; - let num_nodes_without_stake = 0; Self { num_nodes_with_stake, - num_nodes_without_stake, start_nodes: num_nodes_with_stake, num_bootstrap_nodes: num_nodes_with_stake, // The first 14 (i.e., 20 - f) nodes are in the DA committee and we may shutdown the @@ -342,16 +332,13 @@ impl, V: Versions> Default #[allow(clippy::redundant_field_names)] fn default() -> Self { let num_nodes_with_stake = 6; - let num_nodes_without_stake = 0; Self { timing_data: TimingData::default(), num_nodes_with_stake, - num_nodes_without_stake, start_nodes: num_nodes_with_stake, skip_late: false, num_bootstrap_nodes: num_nodes_with_stake, da_staked_committee_size: num_nodes_with_stake, - da_non_staked_committee_size: num_nodes_without_stake, spinning_properties: SpinningTaskDescription { node_changes: vec![], }, @@ -404,7 +391,6 @@ where num_bootstrap_nodes, timing_data, da_staked_committee_size, - da_non_staked_committee_size, unreliable_network, .. } = self.clone(); @@ -446,13 +432,11 @@ where num_nodes_with_stake: NonZeroUsize::new(num_nodes_with_stake).unwrap(), // Currently making this zero for simplicity known_da_nodes, - num_nodes_without_stake: 0, num_bootstrap: num_bootstrap_nodes, known_nodes_with_stake, known_nodes_without_stake: vec![], my_own_validator_config, da_staked_committee_size, - da_non_staked_committee_size, fixed_leader_for_gpuvid: 1, next_view_timeout: 500, view_sync_timeout: Duration::from_millis(250), diff --git a/crates/testing/src/test_runner.rs b/crates/testing/src/test_runner.rs index e616e270c8..0f6faffae3 100644 --- a/crates/testing/src/test_runner.rs +++ b/crates/testing/src/test_runner.rs @@ -394,7 +394,6 @@ where ) -> Vec { let mut results = vec![]; let config = self.launcher.resource_generator.config.clone(); - let known_nodes_with_stake = config.known_nodes_with_stake.clone(); let (mut builder_tasks, builder_urls) = self.init_builders::().await; self.add_servers(builder_urls.clone()).await; @@ -412,29 +411,22 @@ where self.next_node_id += 1; tracing::debug!("launch node {}", i); + let all_nodes = config.known_nodes_with_stake.clone(); + let da_nodes = config.known_da_nodes.clone(); + let memberships = Memberships { - quorum_membership: ::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake.clone(), + quorum_membership: ::Membership::new( + all_nodes.clone(), + all_nodes.clone(), Topic::Global, + #[cfg(feature = "fixed-leader-election")] config.fixed_leader_for_gpuvid, ), - da_membership: ::Membership::create_election( - known_nodes_with_stake.clone(), - config.known_da_nodes.clone(), + da_membership: ::Membership::new( + all_nodes, + da_nodes, Topic::Da, - config.fixed_leader_for_gpuvid, - ), - vid_membership: ::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake.clone(), - Topic::Global, - config.fixed_leader_for_gpuvid, - ), - view_sync_membership: ::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake.clone(), - Topic::Global, + #[cfg(feature = "fixed-leader-election")] config.fixed_leader_for_gpuvid, ), }; diff --git a/crates/testing/tests/tests_1/network_task.rs b/crates/testing/tests/tests_1/network_task.rs index 0b97676722..322640b054 100644 --- a/crates/testing/tests/tests_1/network_task.rs +++ b/crates/testing/tests/tests_1/network_task.rs @@ -56,12 +56,14 @@ async fn test_network_task() { let consensus = handle.hotshot.consensus(); let config = launcher.resource_generator.config.clone(); let public_key = config.my_own_validator_config.public_key; - let known_nodes_with_stake = config.known_nodes_with_stake.clone(); - let membership = ::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake, + let all_nodes = config.known_nodes_with_stake.clone(); + + let membership = ::Membership::new( + all_nodes.clone(), + all_nodes, Topic::Global, + #[cfg(feature = "fixed-leader-election")] config.fixed_leader_for_gpuvid, ); let network_state: NetworkEventTaskState, _> = @@ -135,13 +137,14 @@ async fn test_network_storage_fail() { storage.write().await.should_return_err = true; let config = launcher.resource_generator.config.clone(); let public_key = config.my_own_validator_config.public_key; - let known_nodes_with_stake = config.known_nodes_with_stake.clone(); + let all_nodes = config.known_nodes_with_stake.clone(); let upgrade_lock = UpgradeLock::::new(); - let membership = ::Membership::create_election( - known_nodes_with_stake.clone(), - known_nodes_with_stake, + let membership = ::Membership::new( + all_nodes.clone(), + all_nodes, Topic::Global, + #[cfg(feature = "fixed-leader-election")] config.fixed_leader_for_gpuvid, ); let network_state: NetworkEventTaskState, _> = diff --git a/crates/testing/tests/tests_3/memory_network.rs b/crates/testing/tests/tests_3/memory_network.rs index 03a9abe2d1..0ecbbccc50 100644 --- a/crates/testing/tests/tests_3/memory_network.rs +++ b/crates/testing/tests/tests_3/memory_network.rs @@ -60,7 +60,7 @@ impl NodeType for Test { type Transaction = TestTransaction; type ValidatedState = TestValidatedState; type InstanceState = TestInstanceState; - type Membership = GeneralStaticCommittee; + type Membership = GeneralStaticCommittee; type BuilderSignatureKey = BuilderKey; } diff --git a/crates/types/src/data.rs b/crates/types/src/data.rs index 03d30ca817..88071936f7 100644 --- a/crates/types/src/data.rs +++ b/crates/types/src/data.rs @@ -177,7 +177,7 @@ impl VidDisperse { membership: &TYPES::Membership, ) -> Self { let shares = membership - .staked_committee(view_number) + .committee_members(view_number) .iter() .map(|node| (node.clone(), vid_disperse.shares.remove(0))) .collect(); diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 6206497700..1a9ff34b6c 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -176,8 +176,6 @@ pub struct HotShotConfig { /// Total number of nodes in the network // Earlier it was total_nodes pub num_nodes_with_stake: NonZeroUsize, - /// Number of nodes without stake - pub num_nodes_without_stake: usize, /// List of known node's public keys and stake value for certificate aggregation, serving as public parameter pub known_nodes_with_stake: Vec>, /// All public keys known to be DA nodes @@ -188,8 +186,6 @@ pub struct HotShotConfig { pub my_own_validator_config: ValidatorConfig, /// List of DA committee (staking)nodes for static DA committee pub da_staked_committee_size: usize, - /// List of DA committee nodes (non-staking)nodes for static DA committee - pub da_non_staked_committee_size: usize, /// Number of fixed leaders for GPU VID, normally it will be 0, it's only used when running GPU VID pub fixed_leader_for_gpuvid: usize, /// Base duration for next-view timeout, in milliseconds diff --git a/crates/types/src/simple_certificate.rs b/crates/types/src/simple_certificate.rs index 3208d69203..5d87393ea7 100644 --- a/crates/types/src/simple_certificate.rs +++ b/crates/types/src/simple_certificate.rs @@ -154,7 +154,7 @@ impl> return true; } let real_qc_pp = ::public_parameter( - membership.committee_qc_stake_table(), + membership.stake_table(), U256::from(Self::threshold(membership)), ); let Ok(commit) = self.date_commitment(upgrade_lock).await else { diff --git a/crates/types/src/traits/election.rs b/crates/types/src/traits/election.rs index f6caa02da9..d21f1a82bf 100644 --- a/crates/types/src/traits/election.rs +++ b/crates/types/src/traits/election.rs @@ -5,63 +5,29 @@ // along with the HotShot repository. If not, see . //! The election trait, used to decide which node is the leader and determine if a vote is valid. - -// Needed to avoid the non-binding `let` warning. -#![allow(clippy::let_underscore_untyped)] - -use std::{collections::BTreeSet, fmt::Debug, hash::Hash, num::NonZeroU64}; - -use snafu::Snafu; - use super::{network::Topic, node_implementation::NodeType}; use crate::{traits::signature_key::SignatureKey, PeerConfig}; - -/// Error for election problems -#[derive(Snafu, Debug)] -pub enum ElectionError { - /// stub error to be filled in - StubError, - /// Math error doing something - /// NOTE: it would be better to make Election polymorphic over - /// the election error and then have specific math errors - MathError, -} +use std::{collections::BTreeSet, fmt::Debug, hash::Hash, num::NonZeroU64}; /// A protocol for determining membership in and participating in a committee. pub trait Membership: Clone + Debug + Eq + PartialEq + Send + Sync + Hash + 'static { - /// create an election - /// TODO may want to move this to a testableelection trait - fn create_election( - all_nodes: Vec>, + /// Create a committee + fn new( + // Note: eligible_leaders is currently a hack because the DA leader == the quorum leader + // but they should not have voting power. + eligible_leaders: Vec>, committee_members: Vec>, committee_topic: Topic, - fixed_leader_for_gpuvid: usize, + #[cfg(feature = "fixed-leader-election")] fixed_leader_for_gpuvid: usize, ) -> Self; - /// Clone the public key and corresponding stake table for current elected committee - fn committee_qc_stake_table( - &self, - ) -> Vec<::StakeTableEntry>; - - /// The leader of the committee for view `view_number`. - fn leader(&self, view_number: TYPES::Time) -> TYPES::SignatureKey; - - /// The staked members of the committee for view `view_number`. - fn staked_committee(&self, view_number: TYPES::Time) -> BTreeSet; - - /// The non-staked members of the committee for view `view_number`. - fn non_staked_committee(&self, view_number: TYPES::Time) -> BTreeSet; + /// Get all participants in the committee (including their stake) + fn stake_table(&self) -> Vec<::StakeTableEntry>; - /// Get whole (staked + non-staked) committee for view `view_number`. - fn whole_committee(&self, view_number: TYPES::Time) -> BTreeSet; - - /// Get the network topic for the committee - fn committee_topic(&self) -> Topic; - - /// Check if a key has stake - fn has_stake(&self, pub_key: &TYPES::SignatureKey) -> bool; + /// Get all participants in the committee for a specific view + fn committee_members(&self, view_number: TYPES::Time) -> BTreeSet; /// Get the stake table entry for a public key, returns `None` if the /// key is not in the table @@ -70,6 +36,15 @@ pub trait Membership: pub_key: &TYPES::SignatureKey, ) -> Option<::StakeTableEntry>; + /// See if a node has stake in the committee + fn has_stake(&self, pub_key: &TYPES::SignatureKey) -> bool; + + /// The leader of the committee for view `view_number`. + fn leader(&self, view_number: TYPES::Time) -> TYPES::SignatureKey; + + /// Get the network topic for the committee + fn committee_topic(&self) -> Topic; + /// Returns the number of total nodes in the committee fn total_nodes(&self) -> usize; diff --git a/crates/types/src/vote.rs b/crates/types/src/vote.rs index 83b0898c24..0123ba0085 100644 --- a/crates/types/src/vote.rs +++ b/crates/types/src/vote.rs @@ -161,7 +161,7 @@ impl< let Some(stake_table_entry) = membership.stake(&key) else { return Either::Left(()); }; - let stake_table = membership.committee_qc_stake_table(); + let stake_table = membership.stake_table(); let Some(vote_node_id) = stake_table .iter() .position(|x| *x == stake_table_entry.clone())