hotshot_types/traits/
election.rs1use std::fmt::Debug;
17
18use alloy::primitives::U256;
19use committable::{Commitment, Committable};
20use hotshot_utils::anytrace;
21
22use super::node_implementation::NodeType;
23use crate::{
24 PeerConfig,
25 data::{EpochNumber, Leaf2, ViewNumber},
26 drb::DrbResult,
27 stake_table::supermajority_threshold,
28 traits::signature_key::StakeTableEntryType,
29};
30
31pub struct NoStakeTableHash;
32
33impl Committable for NoStakeTableHash {
34 fn commit(&self) -> Commitment<Self> {
35 Commitment::from_raw([0u8; 32])
36 }
37}
38
39pub trait MembershipSnapshot<T: NodeType>: Clone + Send + Sync {
41 type Error: std::error::Error + Send + Sync + 'static;
42 type StakeTableHash: Committable;
43
44 fn epoch(&self) -> EpochNumber;
46
47 fn first_epoch(&self) -> Option<EpochNumber>;
49
50 fn has_drb(&self) -> bool;
53
54 fn stake_table(&self) -> impl ExactSizeIterator<Item = &PeerConfig<T>> + Send;
61
62 fn da_stake_table(&self) -> impl ExactSizeIterator<Item = &PeerConfig<T>> + Send;
64
65 fn committee_members(
67 &self,
68 view: ViewNumber,
69 ) -> impl ExactSizeIterator<Item = &T::SignatureKey> + Send;
70
71 fn da_committee_members(
73 &self,
74 view: ViewNumber,
75 ) -> impl ExactSizeIterator<Item = &T::SignatureKey> + Send;
76
77 fn stake(&self, key: &T::SignatureKey) -> Option<PeerConfig<T>>;
80
81 fn da_stake(&self, key: &T::SignatureKey) -> Option<PeerConfig<T>>;
83
84 fn has_stake(&self, key: &T::SignatureKey) -> bool;
86
87 fn has_da_stake(&self, key: &T::SignatureKey) -> bool;
89
90 fn lookup_leader(&self, view: ViewNumber) -> Result<T::SignatureKey, Self::Error>;
96
97 fn stake_table_hash(&self) -> Option<Commitment<Self::StakeTableHash>> {
99 None
100 }
101
102 fn total_nodes(&self) -> usize {
104 self.stake_table().len()
105 }
106
107 fn da_total_nodes(&self) -> usize {
109 self.da_stake_table().len()
110 }
111
112 fn total_stake(&self) -> U256 {
114 self.stake_table()
115 .fold(U256::ZERO, |acc, e| acc + e.stake_table_entry.stake())
116 }
117
118 fn total_da_stake(&self) -> U256 {
120 self.da_stake_table()
121 .fold(U256::ZERO, |acc, e| acc + e.stake_table_entry.stake())
122 }
123
124 fn success_threshold(&self) -> U256 {
126 supermajority_threshold(self.total_stake())
127 }
128
129 fn da_success_threshold(&self) -> U256 {
131 let total = self.total_da_stake();
132 let one = U256::ONE;
133 let two = U256::from(2);
134 let three = U256::from(3);
135 if total < U256::MAX / two {
136 ((total * two) / three) + one
137 } else {
138 ((total / three) * two) + two
139 }
140 }
141
142 fn failure_threshold(&self) -> U256 {
144 let total = self.total_stake();
145 (total / U256::from(3)) + U256::ONE
146 }
147
148 fn upgrade_threshold(&self) -> U256 {
150 let total = self.total_stake();
151 let nine = U256::from(9);
152 let ten = U256::from(10);
153 let normal = self.success_threshold();
154 let higher = if total < U256::MAX / nine {
155 (total * nine) / ten
156 } else {
157 (total / ten) * nine
158 };
159 std::cmp::max(higher, normal)
160 }
161
162 fn leader(&self, view: ViewNumber) -> anytrace::Result<T::SignatureKey> {
165 use hotshot_utils::anytrace::*;
166 let epoch = self.epoch();
167 self.lookup_leader(view).wrap().context(info!(
168 "Failed to get leader for view {view} in epoch {epoch}"
169 ))
170 }
171}
172
173pub trait NonEpochMembershipSnapshot<T: NodeType>: Clone + Send + Sync {
178 type Error: std::error::Error + Send + Sync + 'static;
179
180 fn stake_table(&self) -> impl ExactSizeIterator<Item = &PeerConfig<T>> + Send + '_;
181 fn da_stake_table(&self) -> impl ExactSizeIterator<Item = &PeerConfig<T>> + Send + '_;
182 fn committee_members(
183 &self,
184 view: ViewNumber,
185 ) -> impl ExactSizeIterator<Item = &T::SignatureKey> + Send + '_;
186 fn da_committee_members(
187 &self,
188 view: ViewNumber,
189 ) -> impl ExactSizeIterator<Item = &T::SignatureKey> + Send + '_;
190 fn stake(&self, key: &T::SignatureKey) -> Option<PeerConfig<T>>;
191 fn da_stake(&self, key: &T::SignatureKey) -> Option<PeerConfig<T>>;
192 fn has_stake(&self, key: &T::SignatureKey) -> bool;
193 fn has_da_stake(&self, key: &T::SignatureKey) -> bool;
194 fn lookup_leader(&self, view: ViewNumber) -> Result<T::SignatureKey, Self::Error>;
195
196 fn total_nodes(&self) -> usize {
197 self.stake_table().len()
198 }
199
200 fn da_total_nodes(&self) -> usize {
201 self.da_stake_table().len()
202 }
203
204 fn total_stake(&self) -> U256 {
205 self.stake_table()
206 .fold(U256::ZERO, |acc, e| acc + e.stake_table_entry.stake())
207 }
208
209 fn total_da_stake(&self) -> U256 {
210 self.da_stake_table()
211 .fold(U256::ZERO, |acc, e| acc + e.stake_table_entry.stake())
212 }
213
214 fn success_threshold(&self) -> U256 {
215 supermajority_threshold(self.total_stake())
216 }
217
218 fn da_success_threshold(&self) -> U256 {
219 let total = self.total_da_stake();
220 let one = U256::ONE;
221 let two = U256::from(2);
222 let three = U256::from(3);
223 if total < U256::MAX / two {
224 ((total * two) / three) + one
225 } else {
226 ((total / three) * two) + two
227 }
228 }
229
230 fn failure_threshold(&self) -> U256 {
231 let total = self.total_stake();
232 (total / U256::from(3)) + U256::ONE
233 }
234
235 fn upgrade_threshold(&self) -> U256 {
236 let total = self.total_stake();
237 let nine = U256::from(9);
238 let ten = U256::from(10);
239 let normal = self.success_threshold();
240 let higher = if total < U256::MAX / nine {
241 (total * nine) / ten
242 } else {
243 (total / ten) * nine
244 };
245 std::cmp::max(higher, normal)
246 }
247
248 fn leader(&self, view: ViewNumber) -> anytrace::Result<T::SignatureKey> {
249 use hotshot_utils::anytrace::*;
250 self.lookup_leader(view)
251 .wrap()
252 .context(info!("Failed to get leader for view {view} (non-epoch)"))
253 }
254}
255
256pub trait Membership<T: NodeType>: Debug + Send + Sync {
265 type Error: std::error::Error + Send + Sync + 'static;
266
267 type Snapshot: MembershipSnapshot<T, Error = Self::Error>;
269
270 type NonEpochSnapshot: NonEpochMembershipSnapshot<T, Error = Self::Error>;
272
273 fn snapshot(&self, epoch: EpochNumber) -> Option<Self::Snapshot>;
277
278 fn non_epoch_snapshot(&self) -> Self::NonEpochSnapshot;
280
281 fn first_epoch(&self) -> Option<EpochNumber>;
283
284 fn highest_known_epoch(&self) -> Option<EpochNumber> {
288 None
289 }
290
291 fn get_epoch_root(
294 &self,
295 e: EpochNumber,
296 ) -> impl Future<Output = Result<Leaf2<T>, Self::Error>> + Send;
297
298 fn get_epoch_drb(
300 &self,
301 e: EpochNumber,
302 ) -> impl Future<Output = Result<DrbResult, Self::Error>> + Send;
303
304 fn add_epoch_root(
306 &self,
307 h: T::BlockHeader,
308 ) -> impl Future<Output = Result<(), Self::Error>> + Send;
309
310 fn add_drb_result(&self, e: EpochNumber, d: DrbResult);
312
313 fn set_first_epoch(&self, e: EpochNumber, r: DrbResult);
318
319 fn add_da_committee(&self, first_epoch: EpochNumber, da_committee: Vec<PeerConfig<T>>);
321}