hotshot/tasks/
task_state.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7use std::{
8    collections::{BTreeMap, HashMap},
9    sync::{atomic::AtomicBool, Arc},
10    time::Instant,
11};
12
13use async_trait::async_trait;
14use chrono::Utc;
15use hotshot_task_impls::{
16    builder::BuilderClient, consensus::ConsensusTaskState, da::DaTaskState,
17    quorum_proposal::QuorumProposalTaskState, quorum_proposal_recv::QuorumProposalRecvTaskState,
18    quorum_vote::QuorumVoteTaskState, request::NetworkRequestState, rewind::RewindTaskState,
19    transactions::TransactionTaskState, upgrade::UpgradeTaskState, vid::VidTaskState,
20    view_sync::ViewSyncTaskState,
21};
22use hotshot_types::{
23    consensus::OuterConsensus,
24    traits::{
25        consensus_api::ConsensusApi,
26        node_implementation::{ConsensusTime, NodeImplementation, NodeType},
27    },
28};
29use tokio::spawn;
30
31use crate::{types::SystemContextHandle, Versions};
32
33/// Trait for creating task states.
34#[async_trait]
35pub trait CreateTaskState<TYPES, I, V>
36where
37    TYPES: NodeType,
38    I: NodeImplementation<TYPES>,
39    V: Versions,
40{
41    /// Function to create the task state from a given `SystemContextHandle`.
42    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self;
43}
44
45#[async_trait]
46impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
47    for NetworkRequestState<TYPES, I>
48{
49    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
50        Self {
51            network: Arc::clone(&handle.hotshot.network),
52            consensus: OuterConsensus::new(handle.hotshot.consensus()),
53            view: handle.cur_view().await,
54            delay: handle.hotshot.config.data_request_delay,
55            membership_coordinator: handle.hotshot.membership_coordinator.clone(),
56            public_key: handle.public_key().clone(),
57            private_key: handle.private_key().clone(),
58            id: handle.hotshot.id,
59            shutdown_flag: Arc::new(AtomicBool::new(false)),
60            spawned_tasks: BTreeMap::new(),
61            epoch_height: handle.epoch_height,
62        }
63    }
64}
65
66#[async_trait]
67impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
68    for UpgradeTaskState<TYPES, V>
69{
70    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
71        #[cfg(not(feature = "example-upgrade"))]
72        return Self {
73            output_event_stream: handle.hotshot.external_event_stream.0.clone(),
74            cur_view: handle.cur_view().await,
75            cur_epoch: handle.cur_epoch().await,
76            membership_coordinator: handle.hotshot.membership_coordinator.clone(),
77            vote_collectors: BTreeMap::default(),
78            public_key: handle.public_key().clone(),
79            private_key: handle.private_key().clone(),
80            id: handle.hotshot.id,
81            start_proposing_view: handle.hotshot.config.start_proposing_view,
82            stop_proposing_view: handle.hotshot.config.stop_proposing_view,
83            start_voting_view: handle.hotshot.config.start_voting_view,
84            stop_voting_view: handle.hotshot.config.stop_voting_view,
85            start_proposing_time: handle.hotshot.config.start_proposing_time,
86            stop_proposing_time: handle.hotshot.config.stop_proposing_time,
87            start_voting_time: handle.hotshot.config.start_voting_time,
88            stop_voting_time: handle.hotshot.config.stop_voting_time,
89            epoch_start_block: handle.hotshot.config.epoch_start_block,
90            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
91            epoch_height: handle.epoch_height,
92            consensus: OuterConsensus::new(handle.hotshot.consensus()),
93        };
94
95        #[cfg(feature = "example-upgrade")]
96        return Self {
97            output_event_stream: handle.hotshot.external_event_stream.0.clone(),
98            cur_view: handle.cur_view().await,
99            cur_epoch: handle.cur_epoch().await,
100            membership: Arc::clone(&handle.hotshot.memberships),
101            network: Arc::clone(&handle.hotshot.network),
102            vote_collector: None.into(),
103            public_key: handle.public_key().clone(),
104            private_key: handle.private_key().clone(),
105            id: handle.hotshot.id,
106            start_proposing_view: 5,
107            stop_proposing_view: 10,
108            start_voting_view: 0,
109            stop_voting_view: 20,
110            start_proposing_time: 0,
111            stop_proposing_time: u64::MAX,
112            start_voting_time: 0,
113            stop_voting_time: u64::MAX,
114            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
115        };
116    }
117}
118
119#[async_trait]
120impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
121    for VidTaskState<TYPES, I, V>
122{
123    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
124        Self {
125            consensus: OuterConsensus::new(handle.hotshot.consensus()),
126            cur_view: handle.cur_view().await,
127            cur_epoch: handle.cur_epoch().await,
128            network: Arc::clone(&handle.hotshot.network),
129            membership_coordinator: handle.hotshot.membership_coordinator.clone(),
130            public_key: handle.public_key().clone(),
131            private_key: handle.private_key().clone(),
132            id: handle.hotshot.id,
133            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
134            epoch_height: handle.epoch_height,
135        }
136    }
137}
138
139#[async_trait]
140impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
141    for DaTaskState<TYPES, I, V>
142{
143    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
144        Self {
145            consensus: OuterConsensus::new(handle.hotshot.consensus()),
146            output_event_stream: handle.hotshot.external_event_stream.0.clone(),
147            membership_coordinator: handle.hotshot.membership_coordinator.clone(),
148            network: Arc::clone(&handle.hotshot.network),
149            cur_view: handle.cur_view().await,
150            cur_epoch: handle.cur_epoch().await,
151            vote_collectors: BTreeMap::default(),
152            public_key: handle.public_key().clone(),
153            private_key: handle.private_key().clone(),
154            id: handle.hotshot.id,
155            storage: handle.storage.clone(),
156            storage_metrics: handle.storage_metrics(),
157            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
158        }
159    }
160}
161
162#[async_trait]
163impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
164    for ViewSyncTaskState<TYPES, V>
165{
166    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
167        let cur_view = handle.cur_view().await;
168
169        Self {
170            cur_view,
171            next_view: cur_view,
172            cur_epoch: handle.cur_epoch().await,
173            membership_coordinator: handle.hotshot.membership_coordinator.clone(),
174            public_key: handle.public_key().clone(),
175            private_key: handle.private_key().clone(),
176            num_timeouts_tracked: 0,
177            replica_task_map: HashMap::default().into(),
178            pre_commit_relay_map: HashMap::default().into(),
179            commit_relay_map: HashMap::default().into(),
180            finalize_relay_map: HashMap::default().into(),
181            view_sync_timeout: handle.hotshot.config.view_sync_timeout,
182            id: handle.hotshot.id,
183            last_garbage_collected_view: TYPES::View::new(0),
184            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
185            first_epoch: None,
186        }
187    }
188}
189
190#[async_trait]
191impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
192    for TransactionTaskState<TYPES, V>
193{
194    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
195        Self {
196            builder_timeout: handle.builder_timeout(),
197            output_event_stream: handle.hotshot.external_event_stream.0.clone(),
198            consensus: OuterConsensus::new(handle.hotshot.consensus()),
199            cur_view: handle.cur_view().await,
200            cur_epoch: handle.cur_epoch().await,
201            membership_coordinator: handle.hotshot.membership_coordinator.clone(),
202            public_key: handle.public_key().clone(),
203            private_key: handle.private_key().clone(),
204            instance_state: handle.hotshot.instance_state(),
205            id: handle.hotshot.id,
206            builder_clients: handle
207                .hotshot
208                .config
209                .builder_urls
210                .iter()
211                .cloned()
212                .map(BuilderClient::new)
213                .collect(),
214            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
215            epoch_height: handle.epoch_height,
216        }
217    }
218}
219
220#[async_trait]
221impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
222    for QuorumVoteTaskState<TYPES, I, V>
223{
224    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
225        let consensus = handle.hotshot.consensus();
226
227        // Clone the consensus metrics
228        let consensus_metrics = Arc::clone(&consensus.read().await.metrics);
229
230        Self {
231            public_key: handle.public_key().clone(),
232            private_key: handle.private_key().clone(),
233            state_private_key: handle.state_private_key().clone(),
234            consensus: OuterConsensus::new(consensus),
235            instance_state: handle.hotshot.instance_state(),
236            latest_voted_view: handle.cur_view().await,
237            vote_dependencies: BTreeMap::new(),
238            network: Arc::clone(&handle.hotshot.network),
239            membership: handle.hotshot.membership_coordinator.clone(),
240            output_event_stream: handle.hotshot.external_event_stream.0.clone(),
241            id: handle.hotshot.id,
242            storage: handle.storage.clone(),
243            storage_metrics: handle.storage_metrics(),
244            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
245            epoch_height: handle.hotshot.config.epoch_height,
246            consensus_metrics,
247            first_epoch: None,
248            stake_table_capacity: handle.hotshot.config.stake_table_capacity,
249        }
250    }
251}
252
253#[async_trait]
254impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
255    for QuorumProposalTaskState<TYPES, I, V>
256{
257    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
258        let consensus = handle.hotshot.consensus();
259
260        Self {
261            latest_proposed_view: handle.cur_view().await,
262            cur_epoch: handle.cur_epoch().await,
263            proposal_dependencies: BTreeMap::new(),
264            formed_state_cert: BTreeMap::new(),
265            formed_quorum_certificates: BTreeMap::new(),
266            formed_next_epoch_quorum_certificates: BTreeMap::new(),
267            consensus: OuterConsensus::new(consensus),
268            instance_state: handle.hotshot.instance_state(),
269            membership_coordinator: handle.hotshot.membership_coordinator.clone(),
270            public_key: handle.public_key().clone(),
271            private_key: handle.private_key().clone(),
272            storage: handle.storage.clone(),
273            timeout: handle.hotshot.config.next_view_timeout,
274            id: handle.hotshot.id,
275            formed_upgrade_certificate: None,
276            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
277            epoch_height: handle.hotshot.config.epoch_height,
278            first_epoch: None,
279        }
280    }
281}
282
283#[async_trait]
284impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
285    for QuorumProposalRecvTaskState<TYPES, I, V>
286{
287    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
288        let consensus = handle.hotshot.consensus();
289
290        Self {
291            public_key: handle.public_key().clone(),
292            private_key: handle.private_key().clone(),
293            consensus: OuterConsensus::new(consensus),
294            cur_view: handle.cur_view().await,
295            cur_epoch: handle.cur_epoch().await,
296            membership: handle.hotshot.membership_coordinator.clone(),
297            timeout: handle.hotshot.config.next_view_timeout,
298            output_event_stream: handle.hotshot.external_event_stream.0.clone(),
299            storage: handle.storage.clone(),
300            spawned_tasks: BTreeMap::new(),
301            id: handle.hotshot.id,
302            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
303            epoch_height: handle.hotshot.config.epoch_height,
304            first_epoch: None,
305        }
306    }
307}
308
309#[async_trait]
310impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
311    for ConsensusTaskState<TYPES, I, V>
312{
313    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
314        let consensus = handle.hotshot.consensus();
315
316        Self {
317            public_key: handle.public_key().clone(),
318            private_key: handle.private_key().clone(),
319            instance_state: handle.hotshot.instance_state(),
320            network: Arc::clone(&handle.hotshot.network),
321            membership_coordinator: handle.hotshot.membership_coordinator.clone(),
322            vote_collectors: BTreeMap::default(),
323            epoch_root_vote_collectors: BTreeMap::default(),
324            next_epoch_vote_collectors: BTreeMap::default(),
325            timeout_vote_collectors: BTreeMap::default(),
326            cur_view: handle.cur_view().await,
327            cur_view_time: Utc::now().timestamp(),
328            cur_epoch: handle.cur_epoch().await,
329            output_event_stream: handle.hotshot.external_event_stream.0.clone(),
330            timeout_task: spawn(async {}),
331            timeout: handle.hotshot.config.next_view_timeout,
332            consensus: OuterConsensus::new(consensus),
333            storage: handle.storage.clone(),
334            id: handle.hotshot.id,
335            upgrade_lock: handle.hotshot.upgrade_lock.clone(),
336            epoch_height: handle.hotshot.config.epoch_height,
337            view_start_time: Instant::now(),
338            first_epoch: None,
339        }
340    }
341}
342
343#[async_trait]
344impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> CreateTaskState<TYPES, I, V>
345    for RewindTaskState<TYPES>
346{
347    async fn create_from(handle: &SystemContextHandle<TYPES, I, V>) -> Self {
348        Self {
349            events: Vec::new(),
350            id: handle.hotshot.id,
351        }
352    }
353}