hotshot_types/traits/
election.rs1use std::{collections::BTreeSet, fmt::Debug, sync::Arc};
9
10use alloy::primitives::U256;
11use async_broadcast::Receiver;
12use async_lock::RwLock;
13use committable::{Commitment, Committable};
14use hotshot_utils::anytrace::Result;
15
16use super::node_implementation::NodeType;
17use crate::{
18 data::Leaf2,
19 drb::DrbResult,
20 event::Event,
21 stake_table::{supermajority_threshold, HSStakeTable},
22 traits::{node_implementation::NodeImplementation, signature_key::StakeTableEntryType},
23 PeerConfig,
24};
25
26pub struct NoStakeTableHash;
27
28impl Committable for NoStakeTableHash {
29 fn commit(&self) -> Commitment<Self> {
30 Commitment::from_raw([0u8; 32])
31 }
32}
33
34pub trait Membership<TYPES: NodeType>: Debug + Send + Sync {
36 type Error: std::fmt::Display;
38
39 type Storage;
41
42 type StakeTableHash: Committable;
43
44 fn new<I: NodeImplementation<TYPES>>(
46 stake_committee_members: Vec<PeerConfig<TYPES>>,
49 da_committee_members: Vec<PeerConfig<TYPES>>,
50 storage: Self::Storage,
51 network: Arc<<I as NodeImplementation<TYPES>>::Network>,
52 public_key: TYPES::SignatureKey,
53 epoch_height: u64,
54 ) -> Self;
55
56 fn set_external_channel(
57 &mut self,
58 _external_channel: Receiver<Event<TYPES>>,
59 ) -> impl std::future::Future<Output = ()> + Send {
60 async {}
61 }
62
63 fn total_stake(&self, epoch: Option<TYPES::Epoch>) -> U256 {
64 self.stake_table(epoch)
65 .iter()
66 .fold(U256::ZERO, |acc, entry| {
67 acc + entry.stake_table_entry.stake()
68 })
69 }
70
71 fn total_da_stake(&self, epoch: Option<TYPES::Epoch>) -> U256 {
72 self.da_stake_table(epoch)
73 .iter()
74 .fold(U256::ZERO, |acc, entry| {
75 acc + entry.stake_table_entry.stake()
76 })
77 }
78
79 fn stake_table(&self, epoch: Option<TYPES::Epoch>) -> HSStakeTable<TYPES>;
81
82 fn da_stake_table(&self, epoch: Option<TYPES::Epoch>) -> HSStakeTable<TYPES>;
84
85 fn committee_members(
87 &self,
88 view_number: TYPES::View,
89 epoch: Option<TYPES::Epoch>,
90 ) -> BTreeSet<TYPES::SignatureKey>;
91
92 fn da_committee_members(
94 &self,
95 view_number: TYPES::View,
96 epoch: Option<TYPES::Epoch>,
97 ) -> BTreeSet<TYPES::SignatureKey>;
98
99 fn stake(
102 &self,
103 pub_key: &TYPES::SignatureKey,
104 epoch: Option<TYPES::Epoch>,
105 ) -> Option<PeerConfig<TYPES>>;
106
107 fn da_stake(
110 &self,
111 pub_key: &TYPES::SignatureKey,
112 epoch: Option<TYPES::Epoch>,
113 ) -> Option<PeerConfig<TYPES>>;
114
115 fn has_stake(&self, pub_key: &TYPES::SignatureKey, epoch: Option<TYPES::Epoch>) -> bool;
117
118 fn has_da_stake(&self, pub_key: &TYPES::SignatureKey, epoch: Option<TYPES::Epoch>) -> bool;
120
121 fn leader(
129 &self,
130 view: TYPES::View,
131 epoch: Option<TYPES::Epoch>,
132 ) -> Result<TYPES::SignatureKey> {
133 use hotshot_utils::anytrace::*;
134
135 self.lookup_leader(view, epoch).wrap().context(info!(
136 "Failed to get leader for view {view} in epoch {epoch:?}"
137 ))
138 }
139
140 fn lookup_leader(
148 &self,
149 view: TYPES::View,
150 epoch: Option<TYPES::Epoch>,
151 ) -> std::result::Result<TYPES::SignatureKey, Self::Error>;
152
153 fn total_nodes(&self, epoch: Option<TYPES::Epoch>) -> usize;
155
156 fn da_total_nodes(&self, epoch: Option<TYPES::Epoch>) -> usize;
158
159 fn success_threshold(&self, epoch: Option<<TYPES as NodeType>::Epoch>) -> U256 {
161 let total_stake = self.total_stake(epoch);
162 supermajority_threshold(total_stake)
163 }
164
165 fn da_success_threshold(&self, epoch: Option<<TYPES as NodeType>::Epoch>) -> U256 {
167 let total_stake = self.total_da_stake(epoch);
168 let one = U256::ONE;
169 let two = U256::from(2);
170 let three = U256::from(3);
171
172 if total_stake < U256::MAX / two {
173 ((total_stake * two) / three) + one
174 } else {
175 ((total_stake / three) * two) + two
176 }
177 }
178
179 fn failure_threshold(&self, epoch: Option<<TYPES as NodeType>::Epoch>) -> U256 {
181 let total_stake = self.total_stake(epoch);
182 let one = U256::ONE;
183 let three = U256::from(3);
184
185 (total_stake / three) + one
186 }
187
188 fn upgrade_threshold(&self, epoch: Option<<TYPES as NodeType>::Epoch>) -> U256 {
190 let total_stake = self.total_stake(epoch);
191 let nine = U256::from(9);
192 let ten = U256::from(10);
193
194 let normal_threshold = self.success_threshold(epoch);
195 let higher_threshold = if total_stake < U256::MAX / nine {
196 (total_stake * nine) / ten
197 } else {
198 (total_stake / ten) * nine
199 };
200
201 std::cmp::max(higher_threshold, normal_threshold)
202 }
203
204 fn has_stake_table(&self, epoch: TYPES::Epoch) -> bool;
206
207 fn has_randomized_stake_table(&self, epoch: TYPES::Epoch) -> anyhow::Result<bool>;
209
210 fn get_epoch_root(
213 _membership: Arc<RwLock<Self>>,
214 _epoch: TYPES::Epoch,
215 ) -> impl std::future::Future<Output = anyhow::Result<Leaf2<TYPES>>> + Send;
216
217 fn get_epoch_drb(
219 _membership: Arc<RwLock<Self>>,
220 _epoch: TYPES::Epoch,
221 ) -> impl std::future::Future<Output = anyhow::Result<DrbResult>> + Send;
222
223 fn add_epoch_root(
225 _membership: Arc<RwLock<Self>>,
226 _block_header: TYPES::BlockHeader,
227 ) -> impl std::future::Future<Output = anyhow::Result<()>> + Send;
228
229 fn add_drb_result(&mut self, _epoch: TYPES::Epoch, _drb_result: DrbResult);
232
233 fn set_first_epoch(&mut self, _epoch: TYPES::Epoch, _initial_drb_result: DrbResult);
238
239 fn first_epoch(&self) -> Option<TYPES::Epoch>;
241
242 fn stake_table_hash(&self, _epoch: TYPES::Epoch) -> Option<Commitment<Self::StakeTableHash>> {
245 None
246 }
247
248 fn add_da_committee(&mut self, _first_epoch: u64, _da_committee: Vec<PeerConfig<TYPES>>);
249}