1use crate::block::{Block, BlockId, FinalizedBlock};
9use crate::transaction::{SerializablePublicKey, SerializableSignature, Transaction};
10use bytes::Bytes;
11use serde::{Deserialize, Serialize};
12
13pub const CONSENSUS_CHANNEL: u64 = 0;
15
16pub const TRANSACTION_CHANNEL: u64 = 2;
18
19pub const SYNC_CHANNEL: u64 = 3;
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub enum ConsensusMessage {
25 Propose(ProposeMessage),
27
28 Notarize(NotarizeMessage),
30
31 Nullify(NullifyMessage),
33
34 Finalize(FinalizeMessage),
36
37 Transaction(TransactionMessage),
39
40 SyncRequest(SyncRequestMessage),
42
43 SyncResponse(SyncResponseMessage),
45}
46
47impl ConsensusMessage {
48 pub fn encode(&self) -> Bytes {
50 let json = serde_json::to_vec(self).expect("message serialization should not fail");
51 Bytes::from(json)
52 }
53
54 pub fn decode(data: &[u8]) -> Result<Self, serde_json::Error> {
56 serde_json::from_slice(data)
57 }
58
59 pub fn kind(&self) -> &'static str {
61 match self {
62 ConsensusMessage::Propose(_) => "propose",
63 ConsensusMessage::Notarize(_) => "notarize",
64 ConsensusMessage::Nullify(_) => "nullify",
65 ConsensusMessage::Finalize(_) => "finalize",
66 ConsensusMessage::Transaction(_) => "transaction",
67 ConsensusMessage::SyncRequest(_) => "sync_request",
68 ConsensusMessage::SyncResponse(_) => "sync_response",
69 }
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct ProposeMessage {
76 pub view: u64,
78
79 pub block: Block,
81
82 pub producer: SerializablePublicKey,
84
85 pub signature: SerializableSignature,
87}
88
89impl ProposeMessage {
90 pub fn new(
92 view: u64,
93 block: Block,
94 producer: SerializablePublicKey,
95 signature: SerializableSignature,
96 ) -> Self {
97 Self {
98 view,
99 block,
100 producer,
101 signature,
102 }
103 }
104
105 pub fn block_id(&self) -> BlockId {
107 self.block.id()
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct NotarizeMessage {
114 pub view: u64,
116
117 pub block_id: BlockId,
119
120 pub voter: SerializablePublicKey,
122
123 pub signature: SerializableSignature,
125}
126
127impl NotarizeMessage {
128 pub fn new(
130 view: u64,
131 block_id: BlockId,
132 voter: SerializablePublicKey,
133 signature: SerializableSignature,
134 ) -> Self {
135 Self {
136 view,
137 block_id,
138 voter,
139 signature,
140 }
141 }
142
143 pub fn signing_data(&self) -> Vec<u8> {
145 let mut data = Vec::new();
146 data.extend_from_slice(b"NOTARIZE:");
147 data.extend_from_slice(&self.view.to_le_bytes());
148 data.extend_from_slice(self.block_id.as_bytes());
149 data
150 }
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct NullifyMessage {
156 pub view: u64,
158
159 pub voter: SerializablePublicKey,
161
162 pub signature: SerializableSignature,
164}
165
166impl NullifyMessage {
167 pub fn new(view: u64, voter: SerializablePublicKey, signature: SerializableSignature) -> Self {
169 Self {
170 view,
171 voter,
172 signature,
173 }
174 }
175
176 pub fn signing_data(&self) -> Vec<u8> {
178 let mut data = Vec::new();
179 data.extend_from_slice(b"NULLIFY:");
180 data.extend_from_slice(&self.view.to_le_bytes());
181 data
182 }
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct FinalizeMessage {
188 pub view: u64,
190
191 pub block_id: BlockId,
193
194 pub voter: SerializablePublicKey,
196
197 pub signature: SerializableSignature,
199}
200
201impl FinalizeMessage {
202 pub fn new(
204 view: u64,
205 block_id: BlockId,
206 voter: SerializablePublicKey,
207 signature: SerializableSignature,
208 ) -> Self {
209 Self {
210 view,
211 block_id,
212 voter,
213 signature,
214 }
215 }
216
217 pub fn signing_data(&self) -> Vec<u8> {
219 let mut data = Vec::new();
220 data.extend_from_slice(b"FINALIZE:");
221 data.extend_from_slice(&self.view.to_le_bytes());
222 data.extend_from_slice(self.block_id.as_bytes());
223 data
224 }
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct TransactionMessage {
230 pub transaction: Transaction,
232}
233
234impl TransactionMessage {
235 pub fn new(transaction: Transaction) -> Self {
237 Self { transaction }
238 }
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct SyncRequestMessage {
244 pub from_height: u64,
246
247 pub to_height: u64,
249
250 pub requestor: SerializablePublicKey,
252}
253
254impl SyncRequestMessage {
255 pub fn new(from_height: u64, to_height: u64, requestor: SerializablePublicKey) -> Self {
257 Self {
258 from_height,
259 to_height,
260 requestor,
261 }
262 }
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct SyncResponseMessage {
268 pub blocks: Vec<FinalizedBlock>,
270
271 pub responder: SerializablePublicKey,
273}
274
275impl SyncResponseMessage {
276 pub fn new(blocks: Vec<FinalizedBlock>, responder: SerializablePublicKey) -> Self {
278 Self { blocks, responder }
279 }
280}
281
282#[derive(Debug, Clone, Default)]
284pub struct VoteCollector {
285 notarize_votes: std::collections::HashMap<BlockId, Vec<NotarizeMessage>>,
287
288 finalize_votes: std::collections::HashMap<BlockId, Vec<FinalizeMessage>>,
290
291 nullify_votes: std::collections::HashMap<u64, Vec<NullifyMessage>>,
293}
294
295impl VoteCollector {
296 pub fn new() -> Self {
298 Self::default()
299 }
300
301 pub fn add_notarize(&mut self, vote: NotarizeMessage) {
303 self.notarize_votes
304 .entry(vote.block_id)
305 .or_default()
306 .push(vote);
307 }
308
309 pub fn add_finalize(&mut self, vote: FinalizeMessage) {
311 self.finalize_votes
312 .entry(vote.block_id)
313 .or_default()
314 .push(vote);
315 }
316
317 pub fn add_nullify(&mut self, vote: NullifyMessage) {
319 self.nullify_votes.entry(vote.view).or_default().push(vote);
320 }
321
322 pub fn get_notarize_votes(&self, block_id: &BlockId) -> &[NotarizeMessage] {
324 self.notarize_votes
325 .get(block_id)
326 .map(|v| v.as_slice())
327 .unwrap_or(&[])
328 }
329
330 pub fn get_finalize_votes(&self, block_id: &BlockId) -> &[FinalizeMessage] {
332 self.finalize_votes
333 .get(block_id)
334 .map(|v| v.as_slice())
335 .unwrap_or(&[])
336 }
337
338 pub fn get_nullify_votes(&self, view: u64) -> &[NullifyMessage] {
340 self.nullify_votes
341 .get(&view)
342 .map(|v| v.as_slice())
343 .unwrap_or(&[])
344 }
345
346 pub fn notarize_count(&self, block_id: &BlockId) -> usize {
348 self.notarize_votes
349 .get(block_id)
350 .map(|v| v.len())
351 .unwrap_or(0)
352 }
353
354 pub fn finalize_count(&self, block_id: &BlockId) -> usize {
356 self.finalize_votes
357 .get(block_id)
358 .map(|v| v.len())
359 .unwrap_or(0)
360 }
361
362 pub fn nullify_count(&self, view: u64) -> usize {
364 self.nullify_votes.get(&view).map(|v| v.len()).unwrap_or(0)
365 }
366
367 pub fn clear_view(&mut self, view: u64) {
369 self.nullify_votes.remove(&view);
370 }
372
373 pub fn clear_all(&mut self) {
375 self.notarize_votes.clear();
376 self.finalize_votes.clear();
377 self.nullify_votes.clear();
378 }
379}
380
381#[cfg(test)]
382mod tests {
383 use super::*;
384 use commonware_cryptography::{ed25519, PrivateKeyExt, Signer};
385
386 fn test_keypair() -> (SerializablePublicKey, SerializableSignature) {
387 let key = ed25519::PrivateKey::from_seed(42);
388 let sig = key.sign(Some(b"_GUTS"), b"test");
389 (
390 SerializablePublicKey::from_pubkey(&key.public_key()),
391 SerializableSignature::from_signature(&sig),
392 )
393 }
394
395 #[test]
396 fn test_consensus_message_roundtrip() {
397 let (pk, sig) = test_keypair();
398 let block_id = BlockId::from_bytes([1u8; 32]);
399
400 let msg = ConsensusMessage::Notarize(NotarizeMessage {
401 view: 10,
402 block_id,
403 voter: pk,
404 signature: sig,
405 });
406
407 let encoded = msg.encode();
408 let decoded = ConsensusMessage::decode(&encoded).unwrap();
409
410 assert_eq!(decoded.kind(), "notarize");
411 if let ConsensusMessage::Notarize(n) = decoded {
412 assert_eq!(n.view, 10);
413 assert_eq!(n.block_id, block_id);
414 } else {
415 panic!("unexpected message type");
416 }
417 }
418
419 #[test]
420 fn test_vote_collector() {
421 let (pk, sig) = test_keypair();
422 let block_id = BlockId::from_bytes([1u8; 32]);
423
424 let mut collector = VoteCollector::new();
425
426 let vote = NotarizeMessage {
427 view: 1,
428 block_id,
429 voter: pk.clone(),
430 signature: sig.clone(),
431 };
432
433 collector.add_notarize(vote);
434 assert_eq!(collector.notarize_count(&block_id), 1);
435
436 let finalize_vote = FinalizeMessage {
437 view: 1,
438 block_id,
439 voter: pk,
440 signature: sig,
441 };
442
443 collector.add_finalize(finalize_vote);
444 assert_eq!(collector.finalize_count(&block_id), 1);
445 }
446
447 #[test]
448 fn test_signing_data() {
449 let (pk, sig) = test_keypair();
450 let block_id = BlockId::from_bytes([1u8; 32]);
451
452 let notarize = NotarizeMessage::new(5, block_id, pk.clone(), sig.clone());
453 let data = notarize.signing_data();
454 assert!(data.starts_with(b"NOTARIZE:"));
455
456 let nullify = NullifyMessage::new(5, pk.clone(), sig.clone());
457 let data = nullify.signing_data();
458 assert!(data.starts_with(b"NULLIFY:"));
459
460 let finalize = FinalizeMessage::new(5, block_id, pk, sig);
461 let data = finalize.signing_data();
462 assert!(data.starts_with(b"FINALIZE:"));
463 }
464}