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 PeerConfig,
19 data::{EpochNumber, Leaf2, ViewNumber},
20 drb::DrbResult,
21 event::Event,
22 stake_table::{HSStakeTable, supermajority_threshold},
23 traits::{node_implementation::NodeImplementation, signature_key::StakeTableEntryType},
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<EpochNumber>) -> 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<EpochNumber>) -> 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<EpochNumber>) -> HSStakeTable<TYPES>;
81
82 fn da_stake_table(&self, epoch: Option<EpochNumber>) -> HSStakeTable<TYPES>;
84
85 fn committee_members(
87 &self,
88 view_number: ViewNumber,
89 epoch: Option<EpochNumber>,
90 ) -> BTreeSet<TYPES::SignatureKey>;
91
92 fn da_committee_members(
94 &self,
95 view_number: ViewNumber,
96 epoch: Option<EpochNumber>,
97 ) -> BTreeSet<TYPES::SignatureKey>;
98
99 fn stake(
102 &self,
103 pub_key: &TYPES::SignatureKey,
104 epoch: Option<EpochNumber>,
105 ) -> Option<PeerConfig<TYPES>>;
106
107 fn da_stake(
110 &self,
111 pub_key: &TYPES::SignatureKey,
112 epoch: Option<EpochNumber>,
113 ) -> Option<PeerConfig<TYPES>>;
114
115 fn has_stake(&self, pub_key: &TYPES::SignatureKey, epoch: Option<EpochNumber>) -> bool;
117
118 fn has_da_stake(&self, pub_key: &TYPES::SignatureKey, epoch: Option<EpochNumber>) -> bool;
120
121 fn leader(&self, view: ViewNumber, epoch: Option<EpochNumber>) -> Result<TYPES::SignatureKey> {
129 use hotshot_utils::anytrace::*;
130
131 self.lookup_leader(view, epoch).wrap().context(info!(
132 "Failed to get leader for view {view} in epoch {epoch:?}"
133 ))
134 }
135
136 fn lookup_leader(
144 &self,
145 view: ViewNumber,
146 epoch: Option<EpochNumber>,
147 ) -> std::result::Result<TYPES::SignatureKey, Self::Error>;
148
149 fn total_nodes(&self, epoch: Option<EpochNumber>) -> usize;
151
152 fn da_total_nodes(&self, epoch: Option<EpochNumber>) -> usize;
154
155 fn success_threshold(&self, epoch: Option<EpochNumber>) -> U256 {
157 let total_stake = self.total_stake(epoch);
158 supermajority_threshold(total_stake)
159 }
160
161 fn da_success_threshold(&self, epoch: Option<EpochNumber>) -> U256 {
163 let total_stake = self.total_da_stake(epoch);
164 let one = U256::ONE;
165 let two = U256::from(2);
166 let three = U256::from(3);
167
168 if total_stake < U256::MAX / two {
169 ((total_stake * two) / three) + one
170 } else {
171 ((total_stake / three) * two) + two
172 }
173 }
174
175 fn failure_threshold(&self, epoch: Option<EpochNumber>) -> U256 {
177 let total_stake = self.total_stake(epoch);
178 let one = U256::ONE;
179 let three = U256::from(3);
180
181 (total_stake / three) + one
182 }
183
184 fn upgrade_threshold(&self, epoch: Option<EpochNumber>) -> U256 {
186 let total_stake = self.total_stake(epoch);
187 let nine = U256::from(9);
188 let ten = U256::from(10);
189
190 let normal_threshold = self.success_threshold(epoch);
191 let higher_threshold = if total_stake < U256::MAX / nine {
192 (total_stake * nine) / ten
193 } else {
194 (total_stake / ten) * nine
195 };
196
197 std::cmp::max(higher_threshold, normal_threshold)
198 }
199
200 fn has_stake_table(&self, epoch: EpochNumber) -> bool;
202
203 fn has_randomized_stake_table(&self, epoch: EpochNumber) -> anyhow::Result<bool>;
205
206 fn get_epoch_root(
209 _membership: Arc<RwLock<Self>>,
210 _epoch: EpochNumber,
211 ) -> impl std::future::Future<Output = anyhow::Result<Leaf2<TYPES>>> + Send;
212
213 fn get_epoch_drb(
215 _membership: Arc<RwLock<Self>>,
216 _epoch: EpochNumber,
217 ) -> impl std::future::Future<Output = anyhow::Result<DrbResult>> + Send;
218
219 fn add_epoch_root(
221 _membership: Arc<RwLock<Self>>,
222 _block_header: TYPES::BlockHeader,
223 ) -> impl std::future::Future<Output = anyhow::Result<()>> + Send;
224
225 fn add_drb_result(&mut self, _epoch: EpochNumber, _drb_result: DrbResult);
228
229 fn set_first_epoch(&mut self, _epoch: EpochNumber, _initial_drb_result: DrbResult);
234
235 fn first_epoch(&self) -> Option<EpochNumber>;
237
238 fn stake_table_hash(&self, _epoch: EpochNumber) -> Option<Commitment<Self::StakeTableHash>> {
241 None
242 }
243
244 fn add_da_committee(&mut self, _first_epoch: u64, _da_committee: Vec<PeerConfig<TYPES>>);
245}