1use std::{collections::BTreeMap, sync::Arc};
11
12use versions::Upgrade;
13
14use crate::{
15 data::{EpochNumber, Leaf2, QuorumProposalWrapper, ViewNumber},
16 drb::DrbResult,
17 epoch_membership::EpochMembershipCoordinator,
18 error::HotShotError,
19 message::Proposal,
20 simple_certificate::{
21 LightClientStateUpdateCertificateV2, QuorumCertificate2, UpgradeCertificate,
22 },
23 traits::{election::Membership, node_implementation::NodeType, states::ValidatedState},
24};
25
26#[derive(Clone, Debug, PartialEq)]
27pub struct InitializerEpochInfo<TYPES: NodeType> {
28 pub epoch: EpochNumber,
29 pub drb_result: DrbResult,
30 pub block_header: Option<TYPES::BlockHeader>,
32}
33
34pub type InitializerAnchor<TYPES> = (
37 Leaf2<TYPES>,
38 Option<Arc<<TYPES as NodeType>::ValidatedState>>,
39);
40
41#[derive(Clone, Debug)]
43pub struct HotShotInitializer<TYPES: NodeType> {
44 instance_state: TYPES::InstanceState,
46
47 epoch_height: u64,
49
50 anchor_leaf: Leaf2<TYPES>,
52
53 anchor_state: Arc<TYPES::ValidatedState>,
55
56 start_view: ViewNumber,
58
59 last_actioned_view: ViewNumber,
62
63 high_qc: QuorumCertificate2<TYPES>,
67
68 saved_proposals: BTreeMap<ViewNumber, Proposal<TYPES, QuorumProposalWrapper<TYPES>>>,
70
71 decided_upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
73
74 state_cert: Option<LightClientStateUpdateCertificateV2<TYPES>>,
76
77 start_epoch_info: Vec<InitializerEpochInfo<TYPES>>,
79}
80
81impl<TYPES: NodeType> HotShotInitializer<TYPES> {
82 pub async fn from_genesis(
86 instance_state: TYPES::InstanceState,
87 epoch_height: u64,
88 start_epoch_info: Vec<InitializerEpochInfo<TYPES>>,
89 upgrade: Upgrade,
90 ) -> Result<Self, HotShotError<TYPES>> {
91 let (validated_state, _state_delta) = TYPES::ValidatedState::genesis(&instance_state);
92 let high_qc = QuorumCertificate2::genesis(&validated_state, &instance_state, upgrade).await;
93
94 Ok(Self {
95 anchor_leaf: Leaf2::genesis(&validated_state, &instance_state, upgrade.base).await,
96 anchor_state: Arc::new(validated_state),
97 start_view: ViewNumber::new(0),
98 last_actioned_view: ViewNumber::new(0),
99 saved_proposals: BTreeMap::new(),
100 high_qc,
101 decided_upgrade_certificate: None,
102 instance_state,
103 epoch_height,
104 state_cert: None,
105 start_epoch_info,
106 })
107 }
108
109 #[allow(clippy::too_many_arguments)]
114 pub fn load(
115 instance_state: TYPES::InstanceState,
116 epoch_height: u64,
117 start_epoch_info: Vec<InitializerEpochInfo<TYPES>>,
118 (anchor_leaf, anchor_state): InitializerAnchor<TYPES>,
119 start_view: ViewNumber,
120 high_qc: QuorumCertificate2<TYPES>,
121 last_actioned_view: ViewNumber,
122 saved_proposals: BTreeMap<ViewNumber, Proposal<TYPES, QuorumProposalWrapper<TYPES>>>,
123 decided_upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
124 state_cert: Option<LightClientStateUpdateCertificateV2<TYPES>>,
125 ) -> Self {
126 let anchor_state = anchor_state.unwrap_or_else(|| {
127 Arc::new(TYPES::ValidatedState::from_header(
128 anchor_leaf.block_header(),
129 ))
130 });
131
132 Self {
133 instance_state,
134 epoch_height,
135 anchor_leaf,
136 anchor_state,
137 high_qc,
138 start_view,
139 last_actioned_view,
140 saved_proposals,
141 decided_upgrade_certificate,
142 state_cert,
143 start_epoch_info,
144 }
145 }
146
147 pub fn instance_state(&self) -> &TYPES::InstanceState {
149 &self.instance_state
150 }
151
152 pub fn epoch_height(&self) -> u64 {
154 self.epoch_height
155 }
156
157 pub fn anchor_leaf(&self) -> &Leaf2<TYPES> {
159 &self.anchor_leaf
160 }
161
162 pub fn anchor_state(&self) -> &Arc<TYPES::ValidatedState> {
164 &self.anchor_state
165 }
166
167 pub fn start_view(&self) -> ViewNumber {
169 self.start_view
170 }
171
172 pub fn last_actioned_view(&self) -> ViewNumber {
174 self.last_actioned_view
175 }
176
177 pub fn high_qc(&self) -> &QuorumCertificate2<TYPES> {
179 &self.high_qc
180 }
181
182 pub fn saved_proposals(
184 &self,
185 ) -> &BTreeMap<ViewNumber, Proposal<TYPES, QuorumProposalWrapper<TYPES>>> {
186 &self.saved_proposals
187 }
188
189 pub fn decided_upgrade_certificate(&self) -> Option<&UpgradeCertificate<TYPES>> {
191 self.decided_upgrade_certificate.as_ref()
192 }
193
194 pub fn state_cert(&self) -> Option<&LightClientStateUpdateCertificateV2<TYPES>> {
196 self.state_cert.as_ref()
197 }
198
199 pub fn start_epoch_info(&self) -> &[InitializerEpochInfo<TYPES>] {
201 &self.start_epoch_info
202 }
203}
204
205pub async fn load_start_epoch_info<TYPES: NodeType>(
207 coordinator: &EpochMembershipCoordinator<TYPES>,
208 start_epoch_info: &[InitializerEpochInfo<TYPES>],
209) {
210 let membership = coordinator.membership();
211 let mut sorted_epoch_info = start_epoch_info.to_vec();
212 sorted_epoch_info.sort_by_key(|info| info.epoch);
213 for epoch_info in sorted_epoch_info {
214 if let Some(block_header) = &epoch_info.block_header {
215 tracing::warn!("Calling add_epoch_root for epoch {}", epoch_info.epoch);
216
217 coordinator
218 .add_epoch_root(block_header.clone())
219 .await
220 .unwrap_or_else(|err| {
221 tracing::error!(
223 "Failed to add epoch root for epoch {}: {err}",
224 epoch_info.epoch
225 );
226 });
227 }
228 }
229
230 for epoch_info in start_epoch_info {
231 tracing::warn!("Calling add_drb_result for epoch {}", epoch_info.epoch);
232 membership.add_drb_result(epoch_info.epoch, epoch_info.drb_result);
233 }
234}