hotshot_types/traits/
election.rs1use std::{collections::BTreeSet, fmt::Debug, sync::Arc};
9
10use alloy::primitives::U256;
11use async_lock::RwLock;
12use hotshot_utils::anytrace::Result;
13
14use super::node_implementation::NodeType;
15use crate::{
16 data::Leaf2, drb::DrbResult, stake_table::HSStakeTable,
17 traits::signature_key::StakeTableEntryType, PeerConfig,
18};
19
20pub trait Membership<TYPES: NodeType>: Debug + Send + Sync {
22 type Error: std::fmt::Display;
24 fn new(
26 stake_committee_members: Vec<PeerConfig<TYPES>>,
29 da_committee_members: Vec<PeerConfig<TYPES>>,
30 ) -> Self;
31
32 fn total_stake(&self, epoch: Option<TYPES::Epoch>) -> U256 {
33 self.stake_table(epoch)
34 .iter()
35 .fold(U256::ZERO, |acc, entry| {
36 acc + entry.stake_table_entry.stake()
37 })
38 }
39
40 fn total_da_stake(&self, epoch: Option<TYPES::Epoch>) -> U256 {
41 self.da_stake_table(epoch)
42 .iter()
43 .fold(U256::ZERO, |acc, entry| {
44 acc + entry.stake_table_entry.stake()
45 })
46 }
47
48 fn stake_table(&self, epoch: Option<TYPES::Epoch>) -> HSStakeTable<TYPES>;
50
51 fn da_stake_table(&self, epoch: Option<TYPES::Epoch>) -> HSStakeTable<TYPES>;
53
54 fn committee_members(
56 &self,
57 view_number: TYPES::View,
58 epoch: Option<TYPES::Epoch>,
59 ) -> BTreeSet<TYPES::SignatureKey>;
60
61 fn da_committee_members(
63 &self,
64 view_number: TYPES::View,
65 epoch: Option<TYPES::Epoch>,
66 ) -> BTreeSet<TYPES::SignatureKey>;
67
68 fn stake(
71 &self,
72 pub_key: &TYPES::SignatureKey,
73 epoch: Option<TYPES::Epoch>,
74 ) -> Option<PeerConfig<TYPES>>;
75
76 fn da_stake(
79 &self,
80 pub_key: &TYPES::SignatureKey,
81 epoch: Option<TYPES::Epoch>,
82 ) -> Option<PeerConfig<TYPES>>;
83
84 fn has_stake(&self, pub_key: &TYPES::SignatureKey, epoch: Option<TYPES::Epoch>) -> bool;
86
87 fn has_da_stake(&self, pub_key: &TYPES::SignatureKey, epoch: Option<TYPES::Epoch>) -> bool;
89
90 fn leader(
98 &self,
99 view: TYPES::View,
100 epoch: Option<TYPES::Epoch>,
101 ) -> Result<TYPES::SignatureKey> {
102 use hotshot_utils::anytrace::*;
103
104 self.lookup_leader(view, epoch).wrap().context(info!(
105 "Failed to get leader for view {view} in epoch {epoch:?}"
106 ))
107 }
108
109 fn lookup_leader(
117 &self,
118 view: TYPES::View,
119 epoch: Option<TYPES::Epoch>,
120 ) -> std::result::Result<TYPES::SignatureKey, Self::Error>;
121
122 fn total_nodes(&self, epoch: Option<TYPES::Epoch>) -> usize;
124
125 fn da_total_nodes(&self, epoch: Option<TYPES::Epoch>) -> usize;
127
128 fn success_threshold(&self, epoch: Option<TYPES::Epoch>) -> U256;
130
131 fn da_success_threshold(&self, epoch: Option<TYPES::Epoch>) -> U256;
133
134 fn failure_threshold(&self, epoch: Option<TYPES::Epoch>) -> U256;
136
137 fn upgrade_threshold(&self, epoch: Option<TYPES::Epoch>) -> U256;
139
140 fn has_stake_table(&self, epoch: TYPES::Epoch) -> bool;
142
143 fn has_randomized_stake_table(&self, epoch: TYPES::Epoch) -> anyhow::Result<bool>;
145
146 fn get_epoch_root(
149 _membership: Arc<RwLock<Self>>,
150 _block_height: u64,
151 _epoch: TYPES::Epoch,
152 ) -> impl std::future::Future<Output = anyhow::Result<Leaf2<TYPES>>> + Send {
153 async move { anyhow::bail!("Not implemented") }
154 }
155
156 fn get_epoch_drb(
158 _membership: Arc<RwLock<Self>>,
159 _block_height: u64,
160 _epoch: TYPES::Epoch,
161 ) -> impl std::future::Future<Output = anyhow::Result<DrbResult>> + Send {
162 async move { anyhow::bail!("Not implemented") }
163 }
164
165 fn add_epoch_root(
167 _membership: Arc<RwLock<Self>>,
168 _epoch: TYPES::Epoch,
169 _block_header: TYPES::BlockHeader,
170 ) -> impl std::future::Future<Output = anyhow::Result<()>> + Send {
171 async { Ok(()) }
172 }
173
174 fn add_drb_result(&mut self, _epoch: TYPES::Epoch, _drb_result: DrbResult);
177
178 fn set_first_epoch(&mut self, _epoch: TYPES::Epoch, _initial_drb_result: DrbResult) {}
183
184 fn first_epoch(&self) -> Option<TYPES::Epoch> {
186 None
187 }
188}
189
190pub fn membership_spawn_add_epoch_root<TYPES: NodeType>(
191 membership: Arc<RwLock<impl Membership<TYPES> + 'static>>,
192 epoch: TYPES::Epoch,
193 block_header: TYPES::BlockHeader,
194) {
195 tokio::spawn(async move {
196 if let Err(e) = Membership::<TYPES>::add_epoch_root(membership, epoch, block_header).await {
197 tracing::error!("Failed to add epoch root for epoch {epoch}: {e}");
198 }
199 });
200}