1use std::marker::PhantomData;
2
3use committable::{Commitment, Committable};
4pub use hotshot_types::new_protocol::Proposal;
5use hotshot_types::{
6 data::{EpochNumber, VidDisperseShare2, ViewNumber},
7 message::Proposal as SignedProposal,
8 request_response::ProposalRequestPayload,
9 simple_certificate::{
10 OneHonestThreshold, SimpleCertificate, SuccessThreshold, TimeoutCertificate2,
11 },
12 simple_vote::{
13 CheckpointData, LightClientStateUpdateVote2, QuorumData2, QuorumVote2, SimpleVote,
14 TimeoutData2, TimeoutVote2, Vote2Data,
15 },
16 traits::{node_implementation::NodeType, signature_key::SignatureKey},
17 vote::HasViewNumber,
18};
19use serde::{Deserialize, Serialize};
20
21pub type Vote2<T> = SimpleVote<T, Vote2Data<T>>;
22pub type CheckpointVote<T> = SimpleVote<T, CheckpointData>;
23pub type CheckpointCertificate<T> = SimpleCertificate<T, CheckpointData, SuccessThreshold>;
24pub type Certificate1<T> = SimpleCertificate<T, QuorumData2<T>, SuccessThreshold>;
25pub type Certificate2<T> = SimpleCertificate<T, Vote2Data<T>, SuccessThreshold>;
26pub type TimeoutCertificate<T> = SimpleCertificate<T, TimeoutData2, SuccessThreshold>;
27pub type TimeoutOneHonest<T> = SimpleCertificate<T, TimeoutData2, OneHonestThreshold>;
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Deserialize)]
30pub enum Unchecked {}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize)]
33pub enum Validated {}
34
35#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
36#[serde(bound(deserialize = "S: Deserialize<'de>"))]
37pub struct ProposalMessage<T: NodeType, S> {
38 pub proposal: SignedProposal<T, Proposal<T>>,
39 #[serde(skip)]
40 _marker: PhantomData<fn() -> S>,
41}
42
43impl<T: NodeType> ProposalMessage<T, Validated> {
44 pub fn validated(p: SignedProposal<T, Proposal<T>>) -> Self {
45 Self {
46 proposal: p,
47 _marker: PhantomData,
48 }
49 }
50}
51
52impl<T: NodeType, S> ProposalMessage<T, S> {
53 #[cfg(test)]
54 pub fn into_unchecked(self) -> ProposalMessage<T, Unchecked> {
55 ProposalMessage {
56 proposal: self.proposal,
57 _marker: PhantomData,
58 }
59 }
60}
61
62impl<T: NodeType, S> HasViewNumber for ProposalMessage<T, S> {
63 fn view_number(&self) -> ViewNumber {
64 self.proposal.data.view_number
65 }
66}
67
68pub type VidShareMessage<T> = SignedProposal<T, VidDisperseShare2<T>>;
70
71#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
72#[serde(bound(deserialize = ""))]
73pub struct Vote1<T: NodeType> {
74 pub vote: QuorumVote2<T>,
75 pub vid_share: VidDisperseShare2<T>,
76 pub state_vote: Option<LightClientStateUpdateVote2<T>>,
78}
79
80impl<T: NodeType> HasViewNumber for Vote1<T> {
81 fn view_number(&self) -> ViewNumber {
82 self.vote.view_number()
83 }
84}
85
86#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
87#[serde(bound(deserialize = ""))]
88pub struct TimeoutVoteMessage<T: NodeType> {
89 pub vote: TimeoutVote2<T>,
90 pub lock: Option<Certificate1<T>>,
91}
92
93impl<T: NodeType> HasViewNumber for TimeoutVoteMessage<T> {
94 fn view_number(&self) -> ViewNumber {
95 self.vote.view_number()
96 }
97}
98
99#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
110#[serde(bound(deserialize = ""))]
111pub struct EpochChangeMessage<T: NodeType> {
112 pub cert1: Certificate1<T>,
113 pub cert2: Certificate2<T>,
114 pub proposal: Proposal<T>,
115}
116
117#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
118#[serde(bound(deserialize = ""))]
119pub struct ProposalFetchRequest<T: NodeType> {
120 pub payload: ProposalRequestPayload<T>,
121 pub signature: <T::SignatureKey as SignatureKey>::PureAssembledSignatureType,
122}
123
124impl<T: NodeType> ProposalFetchRequest<T> {
125 pub fn new(
126 view_number: ViewNumber,
127 key: T::SignatureKey,
128 private_key: &<T::SignatureKey as SignatureKey>::PrivateKey,
129 ) -> Result<Self, <T::SignatureKey as SignatureKey>::SignError> {
130 let payload = ProposalRequestPayload { view_number, key };
131 let signature = T::SignatureKey::sign(private_key, payload.commit().as_ref())?;
132 Ok(Self { payload, signature })
133 }
134
135 pub fn validate_sender(&self, sender: &T::SignatureKey) -> bool {
136 &self.payload.key == sender
137 && self
138 .payload
139 .key
140 .validate(&self.signature, self.payload.commit().as_ref())
141 }
142}
143
144impl<T: NodeType> HasViewNumber for ProposalFetchRequest<T> {
145 fn view_number(&self) -> ViewNumber {
146 self.payload.view_number
147 }
148}
149
150#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
151#[serde(bound(deserialize = "S: Deserialize<'de>"))]
152#[allow(clippy::large_enum_variant)]
153pub enum ConsensusMessage<T: NodeType, S> {
154 Proposal(ProposalMessage<T, S>),
155 Vote1(Vote1<T>),
156 Vote2(Vote2<T>),
157 Certificate1(Certificate1<T>, T::SignatureKey),
158 Certificate2(Certificate2<T>, T::SignatureKey),
159 TimeoutVote(TimeoutVoteMessage<T>),
160 TimeoutCertificate(TimeoutCertificate2<T>),
161 EpochChange(EpochChangeMessage<T>),
162 Checkpoint(CheckpointVote<T>),
163 VidShare(VidShareMessage<T>),
164}
165
166impl<T: NodeType, S> ConsensusMessage<T, S> {
167 #[cfg(test)]
168 pub fn into_unchecked(self) -> ConsensusMessage<T, Unchecked> {
169 match self {
170 Self::Proposal(p) => ConsensusMessage::Proposal(p.into_unchecked()),
171 Self::Vote1(v) => ConsensusMessage::Vote1(v),
172 Self::Vote2(v) => ConsensusMessage::Vote2(v),
173 Self::Certificate1(c, k) => ConsensusMessage::Certificate1(c, k),
174 Self::Certificate2(c, k) => ConsensusMessage::Certificate2(c, k),
175 Self::TimeoutVote(v) => ConsensusMessage::TimeoutVote(v),
176 Self::TimeoutCertificate(c) => ConsensusMessage::TimeoutCertificate(c),
177 Self::Checkpoint(v) => ConsensusMessage::Checkpoint(v),
178 Self::EpochChange(c) => ConsensusMessage::EpochChange(c),
179 Self::VidShare(v) => ConsensusMessage::VidShare(v),
180 }
181 }
182}
183
184impl<T: NodeType, S> HasViewNumber for ConsensusMessage<T, S> {
185 fn view_number(&self) -> ViewNumber {
186 match self {
187 Self::Proposal(proposal) => proposal.view_number(),
188 Self::Vote1(vote) => vote.view_number(),
189 Self::Vote2(vote) => vote.view_number(),
190 Self::Certificate1(certificate, _) => certificate.view_number(),
191 Self::Certificate2(certificate, _) => certificate.view_number(),
192 Self::TimeoutVote(msg) => msg.view_number(),
193 Self::TimeoutCertificate(certificate) => certificate.view_number(),
194 Self::Checkpoint(vote) => vote.view_number(),
195 Self::EpochChange(epoch_change) => epoch_change.cert1.view_number(),
196 Self::VidShare(vid_share) => vid_share.data.view_number(),
197 }
198 }
199}
200
201#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
202#[serde(bound(deserialize = ""))]
203pub enum ProposalFetchMessage<T: NodeType> {
204 Request(ProposalFetchRequest<T>),
205 Response(Box<SignedProposal<T, Proposal<T>>>),
206}
207
208impl<T: NodeType> HasViewNumber for ProposalFetchMessage<T> {
209 fn view_number(&self) -> ViewNumber {
210 match self {
211 Self::Request(request) => request.view_number(),
212 Self::Response(proposal) => proposal.data.view_number(),
213 }
214 }
215}
216
217#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
218#[serde(bound(deserialize = ""))]
219pub struct DedupManifest<T: NodeType> {
220 pub(crate) view: ViewNumber,
221 pub(crate) epoch: EpochNumber,
222 pub(crate) hashes: Vec<Commitment<T::Transaction>>,
223}
224
225#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
226#[serde(bound(deserialize = ""))]
227pub struct TransactionMessage<T: NodeType> {
228 pub(crate) view: ViewNumber,
229 pub(crate) transactions: Vec<T::Transaction>,
230}
231
232#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
233#[serde(bound(deserialize = ""))]
234pub enum BlockMessage<T: NodeType> {
235 Transactions(TransactionMessage<T>),
236 DedupManifest(DedupManifest<T>),
237}
238
239impl<T: NodeType> HasViewNumber for BlockMessage<T> {
240 fn view_number(&self) -> ViewNumber {
241 match self {
242 BlockMessage::Transactions(msg) => msg.view,
243 BlockMessage::DedupManifest(msg) => msg.view,
244 }
245 }
246}
247
248#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
249#[serde(bound(deserialize = "S: Deserialize<'de>"))]
250#[allow(clippy::large_enum_variant)]
251pub enum MessageType<T: NodeType, S> {
252 Consensus(ConsensusMessage<T, S>),
253 Block(BlockMessage<T>),
254 ProposalFetch(ProposalFetchMessage<T>),
255 External(Vec<u8>),
256}
257
258impl<T: NodeType, S> MessageType<T, S> {
259 #[cfg(test)]
260 pub fn into_unchecked(self) -> MessageType<T, Unchecked> {
261 match self {
262 Self::Consensus(c) => MessageType::Consensus(c.into_unchecked()),
263 Self::Block(b) => MessageType::Block(b),
264 Self::ProposalFetch(r) => MessageType::ProposalFetch(r),
265 Self::External(v) => MessageType::External(v),
266 }
267 }
268}
269
270#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Hash, Eq)]
271#[serde(bound(deserialize = "S: Deserialize<'de>"))]
272pub struct Message<T: NodeType, S> {
273 pub sender: T::SignatureKey,
274 pub message_type: MessageType<T, S>,
275}
276
277impl<T: NodeType, S> Message<T, S> {
278 pub fn is_external(&self) -> bool {
279 matches!(self.message_type, MessageType::External(_))
280 }
281
282 #[cfg(test)]
283 pub fn into_unchecked(self) -> Message<T, Unchecked> {
284 Message {
285 sender: self.sender,
286 message_type: self.message_type.into_unchecked(),
287 }
288 }
289}
290
291impl<T: NodeType, S> HasViewNumber for Message<T, S> {
292 fn view_number(&self) -> ViewNumber {
293 match &self.message_type {
294 MessageType::Consensus(consensus_message) => consensus_message.view_number(),
295 MessageType::Block(block_message) => block_message.view_number(),
296 MessageType::ProposalFetch(message) => message.view_number(),
297 MessageType::External(_) => ViewNumber::new(0), }
299 }
300}