1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
// This file is part of the HotShot repository.

// You should have received a copy of the MIT License
// along with the HotShot repository. If not, see <https://mit-license.org/>.

//! Events that a `HotShot` instance can emit

use std::sync::Arc;

use serde::{Deserialize, Serialize};

use crate::{
    data::{DaProposal2, Leaf2, QuorumProposal2, UpgradeProposal, VidDisperseShare2},
    error::HotShotError,
    message::Proposal,
    simple_certificate::QuorumCertificate2,
    traits::{node_implementation::NodeType, ValidatedState},
};

/// A status event emitted by a `HotShot` instance
///
/// This includes some metadata, such as the stage and view number that the event was generated in,
/// as well as an inner [`EventType`] describing the event proper.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound(deserialize = "TYPES: NodeType"))]
pub struct Event<TYPES: NodeType> {
    /// The view number that this event originates from
    pub view_number: TYPES::View,
    /// The underlying event
    pub event: EventType<TYPES>,
}

/// Decided leaf with the corresponding state and VID info.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound(deserialize = "TYPES: NodeType"))]
pub struct LeafInfo<TYPES: NodeType> {
    /// Decided leaf.
    pub leaf: Leaf2<TYPES>,
    /// Validated state.
    pub state: Arc<<TYPES as NodeType>::ValidatedState>,
    /// Optional application-specific state delta.
    pub delta: Option<Arc<<<TYPES as NodeType>::ValidatedState as ValidatedState<TYPES>>::Delta>>,
    /// Optional VID share data.
    pub vid_share: Option<VidDisperseShare2<TYPES>>,
}

impl<TYPES: NodeType> LeafInfo<TYPES> {
    /// Constructor.
    pub fn new(
        leaf: Leaf2<TYPES>,
        state: Arc<<TYPES as NodeType>::ValidatedState>,
        delta: Option<Arc<<<TYPES as NodeType>::ValidatedState as ValidatedState<TYPES>>::Delta>>,
        vid_share: Option<VidDisperseShare2<TYPES>>,
    ) -> Self {
        Self {
            leaf,
            state,
            delta,
            vid_share,
        }
    }
}

/// The chain of decided leaves with its corresponding state and VID info.
pub type LeafChain<TYPES> = Vec<LeafInfo<TYPES>>;

/// Utilities for converting between HotShotError and a string.
pub mod error_adaptor {
    use serde::{de::Deserializer, ser::Serializer};

    use super::{Arc, Deserialize, HotShotError, NodeType};

    /// Convert a HotShotError into a string
    ///
    /// # Errors
    /// Returns `Err` if the serializer fails.
    pub fn serialize<S: Serializer, TYPES: NodeType>(
        elem: &Arc<HotShotError<TYPES>>,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&format!("{elem}"))
    }

    /// Convert a string into a HotShotError
    ///
    /// # Errors
    /// Returns `Err` if the string cannot be deserialized.
    pub fn deserialize<'de, D: Deserializer<'de>, TYPES: NodeType>(
        deserializer: D,
    ) -> Result<Arc<HotShotError<TYPES>>, D::Error> {
        let str = String::deserialize(deserializer)?;
        Ok(Arc::new(HotShotError::FailedToDeserialize(str)))
    }
}

/// The type and contents of a status event emitted by a `HotShot` instance
///
/// This enum does not include metadata shared among all variants, such as the stage and view
/// number, and is thus always returned wrapped in an [`Event`].
#[non_exhaustive]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound(deserialize = "TYPES: NodeType"))]
#[allow(clippy::large_enum_variant)]
pub enum EventType<TYPES: NodeType> {
    /// A view encountered an error and was interrupted
    Error {
        /// The underlying error
        #[serde(with = "error_adaptor")]
        error: Arc<HotShotError<TYPES>>,
    },
    /// A new decision event was issued
    Decide {
        /// The chain of Leaves that were committed by this decision
        ///
        /// This list is sorted in reverse view number order, with the newest (highest view number)
        /// block first in the list.
        ///
        /// This list may be incomplete if the node is currently performing catchup.
        /// Vid Info for a decided view may be missing if this node never saw it's share.
        leaf_chain: Arc<LeafChain<TYPES>>,
        /// The QC signing the most recent leaf in `leaf_chain`.
        ///
        /// Note that the QC for each additional leaf in the chain can be obtained from the leaf
        /// before it using
        qc: Arc<QuorumCertificate2<TYPES>>,
        /// Optional information of the number of transactions in the block, for logging purposes.
        block_size: Option<u64>,
    },
    /// A replica task was canceled by a timeout interrupt
    ReplicaViewTimeout {
        /// The view that timed out
        view_number: TYPES::View,
    },
    /// The view has finished.  If values were decided on, a `Decide` event will also be emitted.
    ViewFinished {
        /// The view number that has just finished
        view_number: TYPES::View,
    },
    /// The view timed out
    ViewTimeout {
        /// The view that timed out
        view_number: TYPES::View,
    },
    /// New transactions were received from the network
    /// or submitted to the network by us
    Transactions {
        /// The list of transactions
        transactions: Vec<TYPES::Transaction>,
    },
    /// DA proposal was received from the network
    /// or submitted to the network by us
    DaProposal {
        /// Contents of the proposal
        proposal: Proposal<TYPES, DaProposal2<TYPES>>,
        /// Public key of the leader submitting the proposal
        sender: TYPES::SignatureKey,
    },
    /// Quorum proposal was received from the network
    /// or submitted to the network by us
    QuorumProposal {
        /// Contents of the proposal
        proposal: Proposal<TYPES, QuorumProposal2<TYPES>>,
        /// Public key of the leader submitting the proposal
        sender: TYPES::SignatureKey,
    },
    /// Upgrade proposal was received from the network
    /// or submitted to the network by us
    UpgradeProposal {
        /// Contents of the proposal
        proposal: Proposal<TYPES, UpgradeProposal<TYPES>>,
        /// Public key of the leader submitting the proposal
        sender: TYPES::SignatureKey,
    },

    /// A message destined for external listeners was received
    ExternalMessageReceived {
        /// Public Key of the message sender
        sender: TYPES::SignatureKey,
        /// Serialized data of the message
        data: Vec<u8>,
    },
}
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
/// A list of actions that we track for nodes
pub enum HotShotAction {
    /// A quorum vote was sent
    Vote,
    /// View Sync Vote
    ViewSyncVote,
    /// A quorum proposal was sent
    Propose,
    /// DA proposal was sent
    DaPropose,
    /// DA vote was sent
    DaVote,
    /// DA certificate was sent
    DaCert,
    /// VID shares were sent
    VidDisperse,
    /// An upgrade vote was sent
    UpgradeVote,
    /// An upgrade proposal was sent
    UpgradePropose,
}