hotshot_task_impls/
rewind.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::{fs::OpenOptions, io::Write, sync::Arc};
8
9use async_broadcast::{Receiver, Sender};
10use async_trait::async_trait;
11use hotshot_task::task::TaskState;
12use hotshot_types::traits::node_implementation::NodeType;
13use hotshot_utils::anytrace::Result;
14
15use crate::events::HotShotEvent;
16
17/// The task state for the `Rewind` task is used to capture all events received
18/// by a particular node, in the order they've been received.
19pub struct RewindTaskState<TYPES: NodeType> {
20    /// All events received by this node since the beginning of time.
21    pub events: Vec<Arc<HotShotEvent<TYPES>>>,
22
23    /// The id of this node
24    pub id: u64,
25}
26
27impl<TYPES: NodeType> RewindTaskState<TYPES> {
28    /// Handles all events, storing them to the private state
29    pub fn handle(&mut self, event: &Arc<HotShotEvent<TYPES>>) {
30        self.events.push(Arc::clone(event));
31    }
32}
33
34#[async_trait]
35impl<TYPES: NodeType> TaskState for RewindTaskState<TYPES> {
36    type Event = HotShotEvent<TYPES>;
37
38    async fn handle_event(
39        &mut self,
40        event: Arc<Self::Event>,
41        _sender: &Sender<Arc<Self::Event>>,
42        _receiver: &Receiver<Arc<Self::Event>>,
43    ) -> Result<()> {
44        self.handle(&event);
45        Ok(())
46    }
47
48    fn cancel_subtasks(&mut self) {
49        tracing::info!("Node ID {} Recording {} events", self.id, self.events.len());
50        let filename = format!("rewind_{}.log", self.id);
51        let mut file = match OpenOptions::new()
52            .write(true)
53            .create(true)
54            .truncate(true)
55            .open(&filename)
56        {
57            Ok(file) => file,
58            Err(e) => {
59                tracing::error!("Failed to write file {filename}; error = {e}");
60                return;
61            },
62        };
63
64        for (event_number, event) in self.events.iter().enumerate() {
65            // We do not want to die here, so we log and move on capturing as many events as we can.
66            if let Err(e) = writeln!(file, "{event_number}: {event}") {
67                tracing::error!(
68                    "Failed to write event number {event_number} and event {event}; error = {e}"
69                );
70            }
71        }
72    }
73}