1use core::fmt;
8use std::cmp::Ordering;
9use std::io::{self, Read, Write};
10use std::net::SocketAddr;
11
12use async_channel::TrySendError;
13use dusk_bytes::Serializable as DuskSerializable;
14use dusk_core::signatures::bls::{
15 Error as BlsSigError, MultisigPublicKey as BlsMultisigPublicKey,
16 MultisigSignature as BlsMultisigSignature, PublicKey as BlsPublicKey,
17 SecretKey as BlsSecretKey,
18};
19use payload::{Nonce, ValidationQuorum};
20use tracing::{error, warn};
21
22use self::payload::{Candidate, Ratification, Validation};
23use crate::bls::PublicKey;
24use crate::ledger::{to_str, Hash, Signature};
25use crate::{bls, ledger, Serializable, StepName};
26
27pub const TOPIC_FIELD_POS: usize = 1 + 2 + 2;
29pub const PROTOCOL_VERSION: Version = Version(1, 0, 0);
30
31pub const BLOCK_HEADER_VERSION: u8 = 1;
33
34pub const MESSAGE_MAX_FAILED_ITERATIONS: u8 = 8;
36
37#[derive(Debug, Clone)]
38pub struct Version(pub u8, pub u16, pub u16);
40
41impl Default for Version {
42 fn default() -> Self {
43 PROTOCOL_VERSION
44 }
45}
46
47impl fmt::Display for Version {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 let Version(maj, min, patch) = self;
50 write!(f, "{maj}.{min}.{patch}")
51 }
52}
53
54impl crate::Serializable for Version {
55 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
56 let Version(maj, min, patch) = self;
57 w.write_all(&[*maj])?;
58 w.write_all(&min.to_le_bytes())?;
59 w.write_all(&patch.to_le_bytes())?;
60
61 Ok(())
62 }
63
64 fn read<R: Read>(r: &mut R) -> io::Result<Self>
65 where
66 Self: Sized,
67 {
68 let maj = Self::read_u8(r)?;
69 let min = Self::read_u16_le(r)?;
70 let patch = Self::read_u16_le(r)?;
71 Ok(Self(maj, min, patch))
72 }
73}
74
75#[derive(Debug, Clone)]
76pub enum Status {
77 Past,
78 Present,
79 Future,
80}
81
82impl From<Ordering> for Status {
83 fn from(value: Ordering) -> Self {
84 match value {
85 Ordering::Less => Self::Past,
86 Ordering::Equal => Self::Present,
87 Ordering::Greater => Self::Future,
88 }
89 }
90}
91
92#[derive(Debug, Default, Clone)]
94pub struct Message {
95 pub version: Version,
96 topic: Topics,
97 pub header: ConsensusHeader,
98 pub payload: Payload,
99
100 pub metadata: Option<Metadata>,
101}
102
103pub trait WireMessage: Into<Payload> {
104 const TOPIC: Topics;
105 fn consensus_header(&self) -> ConsensusHeader {
106 ConsensusHeader::default()
107 }
108 fn payload(self) -> Payload {
109 self.into()
110 }
111}
112
113impl Message {
114 pub fn compare(&self, round: u64, iteration: u8, step: StepName) -> Status {
115 self.header
116 .round
117 .cmp(&round)
118 .then_with(|| self.get_step().cmp(&step.to_step(iteration)))
119 .into()
120 }
121 pub fn get_signer(&self) -> Option<bls::PublicKey> {
122 let signer = match &self.payload {
123 Payload::Candidate(c) => c.sign_info().signer,
124 Payload::Validation(v) => v.sign_info().signer,
125 Payload::Ratification(r) => r.sign_info().signer,
126 msg => {
127 warn!("Calling get_signer for {msg:?}");
128 return None;
129 }
130 };
131 Some(signer)
132 }
133 pub fn get_step(&self) -> u8 {
134 match &self.payload {
135 Payload::Candidate(c) => c.get_step(),
136 Payload::Validation(v) => v.get_step(),
137 Payload::Ratification(r) => r.get_step(),
138 Payload::Quorum(_) => {
139 StepName::Ratification.to_step(self.header.iteration)
141 }
142 _ => StepName::Proposal.to_step(self.header.iteration),
143 }
144 }
145
146 pub fn get_iteration(&self) -> u8 {
147 match &self.payload {
148 Payload::Block(b) => b.header().iteration,
149 _ => self.header.iteration,
150 }
151 }
152
153 pub fn get_height(&self) -> u64 {
154 match &self.payload {
155 Payload::Block(b) => b.header().height,
156 _ => self.header.round,
157 }
158 }
159
160 pub fn version(&self) -> &Version {
161 &self.version
162 }
163
164 pub fn ray_id(&self) -> &str {
165 self.metadata
166 .as_ref()
167 .map(|m| m.ray_id.as_str())
168 .unwrap_or_default()
169 }
170
171 pub fn with_version(mut self, v: Version) -> Self {
172 self.version = v;
173 self
174 }
175
176 pub fn is_local(&self) -> bool {
177 self.metadata.is_none()
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq)]
184pub struct Metadata {
185 pub height: u8,
186 pub src_addr: SocketAddr,
187 pub ray_id: String,
188}
189
190impl Serializable for Message {
191 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
192 self.version.write(w)?;
193 w.write_all(&[self.topic as u8])?;
194
195 match &self.payload {
196 Payload::Candidate(p) => p.write(w),
197 Payload::Validation(p) => p.write(w),
198 Payload::Ratification(p) => p.write(w),
199 Payload::Quorum(p) => p.write(w),
200 Payload::ValidationQuorum(p) => p.write(w),
201
202 Payload::Block(p) => p.write(w),
203 Payload::Transaction(p) => p.write(w),
204 Payload::GetMempool(p) => p.write(w),
205 Payload::Inv(p) => p.write(w),
206 Payload::GetBlocks(p) => p.write(w),
207 Payload::GetResource(p) => p.write(w),
208
209 Payload::Empty | Payload::ValidationResult(_) => Ok(()), }
211 }
212
213 fn read<R: Read>(r: &mut R) -> io::Result<Self>
214 where
215 Self: Sized,
216 {
217 let version = Version::read(r)?;
218
219 let topic = Topics::from(Self::read_u8(r)?);
221 let message: Message = match topic {
222 Topics::Candidate => payload::Candidate::read(r)?.into(),
223 Topics::Validation => payload::Validation::read(r)?.into(),
224 Topics::Ratification => payload::Ratification::read(r)?.into(),
225 Topics::Quorum => payload::Quorum::read(r)?.into(),
226 Topics::ValidationQuorum => {
227 payload::ValidationQuorum::read(r)?.into()
228 }
229
230 Topics::Block => ledger::Block::read(r)?.into(),
231 Topics::Tx => ledger::Transaction::read(r)?.into(),
232 Topics::GetResource => payload::GetResource::read(r)?.into(),
233 Topics::GetBlocks => payload::GetBlocks::read(r)?.into(),
234 Topics::GetMempool => payload::GetMempool::read(r)?.into(),
235 Topics::Inv => payload::Inv::read(r)?.into(),
236
237 Topics::Unknown => {
238 return Err(io::Error::new(
239 io::ErrorKind::InvalidData,
240 "Unknown topic",
241 ));
242 }
243 };
244
245 Ok(message.with_version(version))
246 }
247}
248
249impl<W: WireMessage> From<W> for Message {
250 fn from(wire_msg: W) -> Self {
251 Self {
252 header: wire_msg.consensus_header(),
253 topic: W::TOPIC,
254 payload: wire_msg.payload(),
255 ..Default::default()
256 }
257 }
258}
259
260impl WireMessage for Candidate {
261 const TOPIC: Topics = Topics::Candidate;
262 fn consensus_header(&self) -> ConsensusHeader {
263 self.header()
264 }
265}
266
267impl WireMessage for Validation {
268 const TOPIC: Topics = Topics::Validation;
269 fn consensus_header(&self) -> ConsensusHeader {
270 self.header
271 }
272}
273
274impl WireMessage for Ratification {
275 const TOPIC: Topics = Topics::Ratification;
276 fn consensus_header(&self) -> ConsensusHeader {
277 self.header
278 }
279}
280
281impl WireMessage for payload::Quorum {
282 const TOPIC: Topics = Topics::Quorum;
283 fn consensus_header(&self) -> ConsensusHeader {
284 self.header
285 }
286}
287
288impl WireMessage for payload::ValidationQuorum {
289 const TOPIC: Topics = Topics::ValidationQuorum;
290 fn consensus_header(&self) -> ConsensusHeader {
291 self.header
292 }
293}
294
295impl WireMessage for payload::GetMempool {
296 const TOPIC: Topics = Topics::GetMempool;
297}
298
299impl WireMessage for payload::Inv {
300 const TOPIC: Topics = Topics::Inv;
301}
302
303impl WireMessage for payload::GetBlocks {
304 const TOPIC: Topics = Topics::GetBlocks;
305}
306
307impl WireMessage for payload::GetResource {
308 const TOPIC: Topics = Topics::GetResource;
309}
310
311impl WireMessage for ledger::Block {
312 const TOPIC: Topics = Topics::Block;
313}
314
315impl WireMessage for ledger::Transaction {
316 const TOPIC: Topics = Topics::Tx;
317}
318
319impl WireMessage for payload::ValidationResult {
320 const TOPIC: Topics = Topics::Unknown;
321}
322
323impl Message {
324 pub fn empty() -> Message {
326 Self {
327 topic: Topics::default(),
328 payload: Payload::Empty,
329 ..Default::default()
330 }
331 }
332
333 pub fn topic(&self) -> Topics {
334 self.topic
335 }
336}
337
338#[derive(Default, Clone, PartialEq, Eq, Copy)]
339#[cfg_attr(any(feature = "faker", test), derive(fake::Dummy))]
340pub struct ConsensusHeader {
341 pub prev_block_hash: Hash,
342 pub round: u64,
343 #[cfg_attr(any(feature = "faker", test), dummy(faker = "0..50"))]
344 pub iteration: u8,
345}
346
347impl std::fmt::Debug for ConsensusHeader {
348 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
349 f.debug_struct("ConsensusHeader")
350 .field("prev_block_hash", &to_str(&self.prev_block_hash))
351 .field("round", &self.round)
352 .field("iteration", &self.iteration)
353 .finish()
354 }
355}
356
357impl Serializable for ConsensusHeader {
358 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
359 w.write_all(&self.prev_block_hash)?;
360 w.write_all(&self.round.to_le_bytes())?;
361 w.write_all(&[self.iteration])?;
362
363 Ok(())
364 }
365
366 fn read<R: Read>(r: &mut R) -> io::Result<Self>
367 where
368 Self: Sized,
369 {
370 let prev_block_hash = Self::read_bytes(r)?;
371 let round = Self::read_u64_le(r)?;
372 let iteration = Self::read_u8(r)?;
373
374 Ok(ConsensusHeader {
375 prev_block_hash,
376 round,
377 iteration,
378 })
379 }
380}
381
382impl ConsensusHeader {
383 pub fn compare_round(&self, round: u64) -> Status {
384 if self.round == round {
385 return Status::Present;
386 }
387
388 if self.round > round {
389 return Status::Future;
390 }
391
392 Status::Past
393 }
394
395 pub fn signable(&self) -> Vec<u8> {
396 let mut buf = vec![];
397 self.write(&mut buf).expect("Writing to vec should succeed");
398 buf
399 }
400}
401
402#[derive(Default, Debug, Clone)]
403pub enum Payload {
404 Ratification(payload::Ratification),
405 Validation(payload::Validation),
406 Candidate(Box<payload::Candidate>),
407 Quorum(payload::Quorum),
408 ValidationQuorum(Box<payload::ValidationQuorum>),
409
410 Block(Box<ledger::Block>),
411 Transaction(Box<ledger::Transaction>),
412 GetMempool(payload::GetMempool),
413 Inv(payload::Inv),
414 GetBlocks(payload::GetBlocks),
415 GetResource(payload::GetResource),
416
417 ValidationResult(Box<payload::ValidationResult>),
420
421 #[default]
422 Empty,
423}
424
425impl Payload {
426 pub fn set_nonce<N: Into<Nonce>>(&mut self, nonce: N) {
427 match self {
428 Payload::GetMempool(p) => p.set_nonce(nonce),
429 Payload::GetBlocks(p) => p.set_nonce(nonce),
430 _ => {}
431 }
432 }
433}
434
435impl From<payload::Candidate> for Payload {
437 fn from(value: payload::Candidate) -> Self {
438 Self::Candidate(Box::new(value))
439 }
440}
441impl From<payload::Validation> for Payload {
442 fn from(value: payload::Validation) -> Self {
443 Self::Validation(value)
444 }
445}
446impl From<payload::Ratification> for Payload {
447 fn from(value: payload::Ratification) -> Self {
448 Self::Ratification(value)
449 }
450}
451impl From<payload::Quorum> for Payload {
452 fn from(value: payload::Quorum) -> Self {
453 Self::Quorum(value)
454 }
455}
456impl From<payload::ValidationQuorum> for Payload {
457 fn from(value: payload::ValidationQuorum) -> Self {
458 Self::ValidationQuorum(Box::new(value))
459 }
460}
461
462impl From<ledger::Block> for Payload {
464 fn from(value: ledger::Block) -> Self {
465 Self::Block(Box::new(value))
466 }
467}
468impl From<ledger::Transaction> for Payload {
469 fn from(value: ledger::Transaction) -> Self {
470 Self::Transaction(Box::new(value))
471 }
472}
473impl From<payload::GetMempool> for Payload {
474 fn from(value: payload::GetMempool) -> Self {
475 Self::GetMempool(value)
476 }
477}
478impl From<payload::Inv> for Payload {
479 fn from(value: payload::Inv) -> Self {
480 Self::Inv(value)
481 }
482}
483impl From<payload::GetBlocks> for Payload {
484 fn from(value: payload::GetBlocks) -> Self {
485 Self::GetBlocks(value)
486 }
487}
488impl From<payload::GetResource> for Payload {
489 fn from(value: payload::GetResource) -> Self {
490 Self::GetResource(value)
491 }
492}
493
494impl From<payload::ValidationResult> for Payload {
496 fn from(value: payload::ValidationResult) -> Self {
497 Self::ValidationResult(Box::new(value))
498 }
499}
500
501pub mod payload {
502 use std::fmt;
503 use std::io::{self, Read, Write};
504 use std::net::{
505 IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6,
506 };
507
508 use serde::Serialize;
509
510 use super::{ConsensusHeader, SignInfo};
511 use crate::ledger::{self, to_str, Attestation, Block, Hash, StepVotes};
512 use crate::{get_current_timestamp, Serializable};
513
514 #[derive(Debug, Clone)]
515 #[cfg_attr(
516 any(feature = "faker", test),
517 derive(fake::Dummy, Eq, PartialEq)
518 )]
519 pub struct Ratification {
520 pub header: ConsensusHeader,
521 pub vote: Vote,
522 pub timestamp: u64,
523 pub validation_result: ValidationResult,
524 pub sign_info: SignInfo,
525 }
526
527 #[derive(Debug, Clone)]
528 #[cfg_attr(
529 any(feature = "faker", test),
530 derive(fake::Dummy, Eq, PartialEq)
531 )]
532 pub struct Validation {
533 pub header: ConsensusHeader,
534 pub vote: Vote,
535 pub sign_info: SignInfo,
536 }
537
538 #[derive(
539 Clone, Copy, Hash, Eq, PartialEq, Default, PartialOrd, Ord, Serialize,
540 )]
541 #[cfg_attr(any(feature = "faker", test), derive(fake::Dummy))]
542 #[repr(u8)]
543 pub enum Vote {
544 NoCandidate = 0,
545 Valid(#[serde(serialize_with = "crate::serialize_hex")] Hash) = 1,
546 Invalid(#[serde(serialize_with = "crate::serialize_hex")] Hash) = 2,
547
548 #[default]
549 NoQuorum = 3,
550 }
551
552 impl Vote {
553 pub fn is_valid(&self) -> bool {
554 matches!(self, Vote::Valid(_))
555 }
556 pub fn size(&self) -> usize {
557 const ENUM_BYTE: usize = 1;
558
559 let data_size: usize = match &self {
560 Vote::NoCandidate => 0,
561 Vote::Valid(_) => 32,
562 Vote::Invalid(_) => 32,
563 Vote::NoQuorum => 0,
564 };
565 ENUM_BYTE + data_size
566 }
567 }
568
569 impl fmt::Debug for Vote {
570 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571 let (desc, hash) = match &self {
572 Self::NoCandidate => ("NoCandidate", "".into()),
573 Self::Valid(hash) => ("Valid", to_str(hash)),
574 Self::Invalid(hash) => ("Invalid", to_str(hash)),
575 Self::NoQuorum => ("NoQuorum", "".into()),
576 };
577 write!(f, "Vote: {desc}({hash})")
578 }
579 }
580
581 impl Serializable for Vote {
582 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
583 match &self {
584 Self::NoCandidate => w.write_all(&[0])?,
585
586 Self::Valid(hash) => {
587 w.write_all(&[1])?;
588 w.write_all(hash)?;
589 }
590 Self::Invalid(hash) => {
591 w.write_all(&[2])?;
592 w.write_all(hash)?;
593 }
594 Self::NoQuorum => w.write_all(&[3])?,
595 };
596 Ok(())
597 }
598
599 fn read<R: Read>(r: &mut R) -> io::Result<Self>
600 where
601 Self: Sized,
602 {
603 Ok(match Self::read_u8(r)? {
604 0 => Self::NoCandidate,
605 1 => Self::Valid(Self::read_bytes(r)?),
606 2 => Self::Invalid(Self::read_bytes(r)?),
607 3 => Self::NoQuorum,
608 _ => Err(io::Error::new(
609 io::ErrorKind::InvalidData,
610 "Invalid vote",
611 ))?,
612 })
613 }
614 }
615
616 impl Serializable for Validation {
617 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
618 self.header.write(w)?;
619 self.vote.write(w)?;
620 self.sign_info.write(w)?;
622 Ok(())
623 }
624
625 fn read<R: Read>(r: &mut R) -> io::Result<Self>
626 where
627 Self: Sized,
628 {
629 let header = ConsensusHeader::read(r)?;
630 let vote = Vote::read(r)?;
631 let sign_info = SignInfo::read(r)?;
632
633 Ok(Validation {
634 header,
635 vote,
636 sign_info,
637 })
638 }
639 }
640
641 #[derive(Clone)]
642 #[cfg_attr(any(feature = "faker", test), derive(fake::Dummy))]
643 pub struct Candidate {
644 pub candidate: Block,
645 }
646
647 impl std::fmt::Debug for Candidate {
648 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
649 f.debug_struct("Candidate")
650 .field(
651 "signature",
652 &ledger::to_str(self.candidate.header().signature.inner()),
653 )
654 .field("block", &self.candidate)
655 .finish()
656 }
657 }
658
659 impl PartialEq<Self> for Candidate {
660 fn eq(&self, other: &Self) -> bool {
661 self.candidate
662 .header()
663 .hash
664 .eq(&other.candidate.header().hash)
665 }
666 }
667
668 impl Eq for Candidate {}
669
670 impl Serializable for Candidate {
671 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
672 self.candidate.write(w)?;
673 Ok(())
674 }
675
676 fn read<R: Read>(r: &mut R) -> io::Result<Self>
677 where
678 Self: Sized,
679 {
680 let candidate = Block::read(r)?;
681
682 Ok(Candidate { candidate })
683 }
684 }
685 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
686 #[cfg_attr(any(feature = "faker", test), derive(fake::Dummy))]
687 pub enum QuorumType {
688 Valid = 0,
690 Invalid = 1,
692 NoCandidate = 2,
694 #[default]
696 NoQuorum = 255,
697 }
698
699 impl From<u8> for QuorumType {
700 fn from(v: u8) -> QuorumType {
701 match v {
702 0 => QuorumType::Valid,
703 1 => QuorumType::Invalid,
704 2 => QuorumType::NoCandidate,
705 _ => QuorumType::NoQuorum,
706 }
707 }
708 }
709
710 #[derive(Debug, Clone, Default)]
711 #[cfg_attr(
712 any(feature = "faker", test),
713 derive(fake::Dummy, Eq, PartialEq)
714 )]
715 pub struct ValidationQuorum {
716 pub header: ConsensusHeader,
717 pub result: ValidationResult,
718 }
719
720 #[derive(Debug, Clone, Default)]
721 #[cfg_attr(
722 any(feature = "faker", test),
723 derive(fake::Dummy, Eq, PartialEq)
724 )]
725 pub struct ValidationResult {
726 pub(crate) quorum: QuorumType,
727 pub(crate) vote: Vote,
728 pub(crate) step_votes: StepVotes,
729 }
730
731 impl ValidationResult {
732 pub fn new(
733 step_votes: StepVotes,
734 vote: Vote,
735 quorum: QuorumType,
736 ) -> Self {
737 Self {
738 step_votes,
739 vote,
740 quorum,
741 }
742 }
743
744 pub fn quorum(&self) -> QuorumType {
745 self.quorum
746 }
747
748 pub fn step_votes(&self) -> &StepVotes {
749 &self.step_votes
750 }
751
752 pub fn vote(&self) -> &Vote {
753 &self.vote
754 }
755 }
756
757 #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize)]
758 #[serde(untagged)]
759 #[cfg_attr(any(feature = "faker", test), derive(fake::Dummy))]
760 pub enum RatificationResult {
761 Fail(Vote),
762 Success(Vote),
763 }
764
765 impl Default for RatificationResult {
766 fn default() -> Self {
767 Self::Fail(Vote::NoQuorum)
768 }
769 }
770
771 impl From<Vote> for RatificationResult {
772 fn from(vote: Vote) -> Self {
773 match vote {
774 Vote::Valid(hash) => {
775 RatificationResult::Success(Vote::Valid(hash))
776 }
777 fail => RatificationResult::Fail(fail),
778 }
779 }
780 }
781
782 impl RatificationResult {
783 pub fn vote(&self) -> &Vote {
784 match self {
785 Self::Success(v) => v,
786 Self::Fail(v) => v,
787 }
788 }
789
790 pub fn failed(&self) -> bool {
791 match self {
792 Self::Success(_) => false,
793 Self::Fail(_) => true,
794 }
795 }
796 }
797
798 #[derive(Debug, Clone, Eq, PartialEq)]
799 pub struct Quorum {
800 pub header: ConsensusHeader,
801 pub att: Attestation,
802 }
803
804 impl Serializable for Quorum {
805 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
806 self.header.write(w)?;
807 self.att.write(w)?;
808
809 Ok(())
810 }
811
812 fn read<R: Read>(r: &mut R) -> io::Result<Self>
813 where
814 Self: Sized,
815 {
816 let header = ConsensusHeader::read(r)?;
817 let att = Attestation::read(r)?;
818
819 Ok(Quorum { header, att })
820 }
821 }
822
823 impl Quorum {
824 pub fn vote(&self) -> &Vote {
825 self.att.result.vote()
826 }
827 }
828
829 #[derive(Debug, Clone, Default)]
830 pub struct GetCandidate {
831 pub hash: [u8; 32],
832 }
833
834 impl Serializable for GetCandidate {
835 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
836 w.write_all(&self.hash[..])?;
837
838 Ok(())
839 }
840
841 fn read<R: Read>(r: &mut R) -> io::Result<Self>
842 where
843 Self: Sized,
844 {
845 let hash = Self::read_bytes(r)?;
846
847 Ok(GetCandidate { hash })
848 }
849 }
850
851 #[derive(Debug, Clone, Default)]
852 pub struct GetCandidateResp {
853 pub candidate: Block,
854 }
855
856 impl Serializable for GetCandidateResp {
857 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
858 self.candidate.write(w)
859 }
860
861 fn read<R: Read>(r: &mut R) -> io::Result<Self>
862 where
863 Self: Sized,
864 {
865 Ok(GetCandidateResp {
866 candidate: Block::read(r)?,
867 })
868 }
869 }
870 #[derive(Debug, Clone, Default)]
871 pub struct Nonce([u8; 8]);
872
873 impl Serializable for Nonce {
874 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
875 w.write_all(&self.0)
876 }
877
878 fn read<R: Read>(r: &mut R) -> io::Result<Self>
879 where
880 Self: Sized,
881 {
882 let nonce = Self::read_bytes(r)?;
883 Ok(Self(nonce))
884 }
885 }
886
887 impl From<Nonce> for u64 {
888 fn from(value: Nonce) -> Self {
889 u64::from_le_bytes(value.0)
890 }
891 }
892
893 impl From<u64> for Nonce {
894 fn from(value: u64) -> Self {
895 Self(value.to_le_bytes())
896 }
897 }
898
899 impl From<IpAddr> for Nonce {
900 fn from(value: IpAddr) -> Self {
901 match value {
902 IpAddr::V4(v4) => v4.into(),
903 IpAddr::V6(v6) => v6.into(),
904 }
905 }
906 }
907
908 impl From<Ipv4Addr> for Nonce {
909 fn from(value: Ipv4Addr) -> Self {
910 let num = u32::from_le_bytes(value.octets());
911 (num as u64).into()
912 }
913 }
914
915 impl From<Ipv6Addr> for Nonce {
916 fn from(value: Ipv6Addr) -> Self {
917 let mut ret = [0u8; 8];
918 let value = value.octets();
919 let (a, b) = value.split_at(8);
920 a.iter()
921 .zip(b)
922 .map(|(a, b)| a.wrapping_add(*b))
923 .enumerate()
924 .for_each(|(idx, v)| ret[idx] = v);
925
926 Self(ret)
927 }
928 }
929
930 #[derive(Debug, Clone, Default)]
931 pub struct GetMempool {
932 pub(crate) nonce: Nonce,
933 }
934
935 impl GetMempool {
936 pub fn set_nonce<N: Into<Nonce>>(&mut self, nonce: N) {
937 self.nonce = nonce.into()
938 }
939 }
940
941 impl Serializable for GetMempool {
942 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
943 self.nonce.write(w)?;
944 Ok(())
945 }
946
947 fn read<R: Read>(r: &mut R) -> io::Result<Self>
948 where
949 Self: Sized,
950 {
951 let nonce = Nonce::read(r)?;
952 Ok(GetMempool { nonce })
953 }
954 }
955
956 #[derive(Clone, Default, Debug, Copy)]
957 pub enum InvType {
958 MempoolTx,
960 #[default]
961 BlockFromHash,
963 BlockFromHeight,
965 CandidateFromHash,
967 CandidateFromIteration,
969 ValidationResult,
971 }
972
973 #[derive(Clone, Copy)]
974 pub enum InvParam {
975 Hash([u8; 32]),
976 Height(u64),
977 Iteration(ConsensusHeader),
978 }
979
980 impl Default for InvParam {
981 fn default() -> Self {
982 Self::Height(0)
983 }
984 }
985
986 impl fmt::Debug for InvParam {
987 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
988 match self {
989 InvParam::Hash(hash) => write!(f, "Hash: {}", to_str(hash)),
990 InvParam::Height(height) => write!(f, "Height: {}", height),
991 InvParam::Iteration(ch) => {
992 write!(
993 f,
994 "PrevBlock: {}, Round: {}, Iteration: {}",
995 to_str(&ch.prev_block_hash),
996 ch.round,
997 ch.iteration
998 )
999 }
1000 }
1001 }
1002 }
1003
1004 #[derive(Default, Debug, Clone, Copy)]
1005 pub struct InvVect {
1006 pub inv_type: InvType,
1007 pub param: InvParam,
1008 }
1009
1010 #[derive(Default, Debug, Clone)]
1011 pub struct Inv {
1012 pub inv_list: Vec<InvVect>,
1013 pub max_entries: u16,
1014 }
1015
1016 impl Inv {
1017 pub fn new(max_entries: u16) -> Self {
1018 Self {
1019 inv_list: Default::default(),
1020 max_entries,
1021 }
1022 }
1023
1024 pub fn add_tx_id(&mut self, id: [u8; 32]) {
1025 self.inv_list.push(InvVect {
1026 inv_type: InvType::MempoolTx,
1027 param: InvParam::Hash(id),
1028 });
1029 }
1030
1031 pub fn add_block_from_hash(&mut self, hash: [u8; 32]) {
1032 self.inv_list.push(InvVect {
1033 inv_type: InvType::BlockFromHash,
1034 param: InvParam::Hash(hash),
1035 });
1036 }
1037
1038 pub fn add_block_from_height(&mut self, height: u64) {
1039 self.inv_list.push(InvVect {
1040 inv_type: InvType::BlockFromHeight,
1041 param: InvParam::Height(height),
1042 });
1043 }
1044
1045 pub fn add_candidate_from_hash(&mut self, hash: [u8; 32]) {
1046 self.inv_list.push(InvVect {
1047 inv_type: InvType::CandidateFromHash,
1048 param: InvParam::Hash(hash),
1049 });
1050 }
1051
1052 pub fn add_candidate_from_iteration(
1053 &mut self,
1054 consensus_header: ConsensusHeader,
1055 ) {
1056 self.inv_list.push(InvVect {
1057 inv_type: InvType::CandidateFromIteration,
1058 param: InvParam::Iteration(consensus_header),
1059 });
1060 }
1061
1062 pub fn add_validation_result(
1063 &mut self,
1064 consensus_header: ConsensusHeader,
1065 ) {
1066 self.inv_list.push(InvVect {
1067 inv_type: InvType::ValidationResult,
1068 param: InvParam::Iteration(consensus_header),
1069 });
1070 }
1071 }
1072
1073 impl Serializable for Inv {
1074 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1075 let items_len = self.inv_list.len() as u32;
1076 w.write_all(&items_len.to_le_bytes())?;
1077
1078 for item in &self.inv_list {
1079 w.write_all(&[item.inv_type as u8])?;
1080
1081 match &item.param {
1082 InvParam::Hash(hash) => w.write_all(&hash[..])?,
1083 InvParam::Height(height) => {
1084 w.write_all(&height.to_le_bytes())?
1085 }
1086 InvParam::Iteration(ch) => {
1087 ch.write(w)?;
1088 }
1089 };
1090 }
1091
1092 w.write_all(&self.max_entries.to_le_bytes())?;
1093 Ok(())
1094 }
1095
1096 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1097 where
1098 Self: Sized,
1099 {
1100 let items_len = Self::read_u32_le(r)?;
1101
1102 let mut inv = Inv::default();
1103 for _ in 0..items_len {
1104 let inv_type = Self::read_u8(r)?;
1105
1106 let inv_type = match inv_type {
1107 0 => InvType::MempoolTx,
1108 1 => InvType::BlockFromHash,
1109 2 => InvType::BlockFromHeight,
1110 3 => InvType::CandidateFromHash,
1111 4 => InvType::CandidateFromIteration,
1112 5 => InvType::ValidationResult,
1113 _ => {
1114 return Err(io::Error::from(io::ErrorKind::InvalidData))
1115 }
1116 };
1117
1118 match inv_type {
1119 InvType::MempoolTx => {
1120 let hash = Self::read_bytes(r)?;
1121 inv.add_tx_id(hash);
1122 }
1123 InvType::BlockFromHash => {
1124 let hash = Self::read_bytes(r)?;
1125 inv.add_block_from_hash(hash);
1126 }
1127 InvType::BlockFromHeight => {
1128 inv.add_block_from_height(Self::read_u64_le(r)?);
1129 }
1130 InvType::CandidateFromHash => {
1131 inv.add_candidate_from_hash(Self::read_bytes(r)?);
1132 }
1133 InvType::CandidateFromIteration => {
1134 let ch = ConsensusHeader::read(r)?;
1135 inv.add_candidate_from_iteration(ch);
1136 }
1137 InvType::ValidationResult => {
1138 let ch = ConsensusHeader::read(r)?;
1139 inv.add_validation_result(ch);
1140 }
1141 }
1142 }
1143
1144 inv.max_entries = Self::read_u16_le(r)?;
1145 Ok(inv)
1146 }
1147 }
1148
1149 #[derive(Clone)]
1150 pub struct GetBlocks {
1151 pub locator: [u8; 32],
1152 pub(crate) nonce: Nonce,
1153 }
1154
1155 impl GetBlocks {
1156 pub fn new(locator: [u8; 32]) -> Self {
1157 Self {
1158 locator,
1159 nonce: Nonce::default(),
1160 }
1161 }
1162 pub fn set_nonce<N: Into<Nonce>>(&mut self, nonce: N) {
1163 self.nonce = nonce.into()
1164 }
1165 }
1166
1167 impl fmt::Debug for GetBlocks {
1168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1169 write!(f, "GetBlocks, locator: {}", to_str(&self.locator))
1170 }
1171 }
1172
1173 impl Serializable for GetBlocks {
1174 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1175 w.write_all(&self.locator[..])?;
1176 self.nonce.write(w)?;
1177 Ok(())
1178 }
1179
1180 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1181 where
1182 Self: Sized,
1183 {
1184 let locator = Self::read_bytes(r)?;
1185 let nonce = Nonce::read(r)?;
1186 Ok(Self { locator, nonce })
1187 }
1188 }
1189
1190 #[derive(Debug, Clone)]
1191 pub struct GetResource {
1192 inventory: Inv,
1194
1195 requester_addr: Option<SocketAddr>,
1197
1198 ttl_as_sec: u64,
1200
1201 hops_limit: u16,
1203 }
1204
1205 impl GetResource {
1206 pub fn new(
1207 inventory: Inv,
1208 requester_addr: Option<SocketAddr>,
1209 ttl_as_sec: u64,
1210 hops_limit: u16,
1211 ) -> Self {
1212 Self {
1213 inventory,
1214 requester_addr,
1215 ttl_as_sec,
1216 hops_limit,
1217 }
1218 }
1219
1220 pub fn clone_with_hop_decrement(&self) -> Option<Self> {
1221 if self.hops_limit <= 1 {
1222 return None;
1223 }
1224 let mut req = self.clone();
1225 req.hops_limit -= 1;
1226 Some(req)
1227 }
1228
1229 pub fn get_addr(&self) -> Option<SocketAddr> {
1230 self.requester_addr
1231 }
1232
1233 pub fn get_inv(&self) -> &Inv {
1234 &self.inventory
1235 }
1236
1237 pub fn is_expired(&self) -> bool {
1238 get_current_timestamp() > self.ttl_as_sec
1239 }
1240 }
1241
1242 impl Serializable for GetResource {
1243 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1244 self.inventory.write(w)?;
1245
1246 let requester_addr = self.requester_addr.ok_or(io::Error::new(
1247 io::ErrorKind::InvalidData,
1248 "Requester address is missing",
1249 ))?;
1250
1251 requester_addr.write(w)?;
1252 w.write_all(&self.ttl_as_sec.to_le_bytes()[..])?;
1253 w.write_all(&self.hops_limit.to_le_bytes()[..])
1254 }
1255
1256 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1257 where
1258 Self: Sized,
1259 {
1260 let inner = Inv::read(r)?;
1261 let requester_addr = SocketAddr::read(r)?;
1262
1263 let mut buf = [0u8; 8];
1264 r.read_exact(&mut buf)?;
1265 let ttl_as_sec = u64::from_le_bytes(buf);
1266
1267 let mut buf = [0u8; 2];
1268 r.read_exact(&mut buf)?;
1269 let hops_limit = u16::from_le_bytes(buf);
1270
1271 Ok(GetResource {
1272 inventory: inner,
1273 requester_addr: Some(requester_addr),
1274 ttl_as_sec,
1275 hops_limit,
1276 })
1277 }
1278 }
1279
1280 impl Serializable for SocketAddr {
1281 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1282 match self {
1283 SocketAddr::V4(addr_v4) => {
1284 w.write_all(&[4])?;
1285 w.write_all(&addr_v4.ip().octets())?;
1286 w.write_all(&addr_v4.port().to_le_bytes())?;
1287 }
1288 SocketAddr::V6(addr_v6) => {
1289 w.write_all(&[6])?;
1290 w.write_all(&addr_v6.ip().octets())?;
1291 w.write_all(&addr_v6.port().to_le_bytes())?;
1292 }
1293 }
1294 Ok(())
1295 }
1296
1297 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1298 where
1299 Self: Sized,
1300 {
1301 let mut ip_type = [0u8; 1];
1302 r.read_exact(&mut ip_type)?;
1303
1304 let ip = match ip_type[0] {
1305 4 => {
1306 let mut octets = [0u8; 4];
1307 r.read_exact(&mut octets)?;
1308
1309 let mut port_bytes = [0u8; 2];
1310 r.read_exact(&mut port_bytes)?;
1311
1312 SocketAddr::V4(SocketAddrV4::new(
1313 Ipv4Addr::from(octets),
1314 u16::from_le_bytes(port_bytes),
1315 ))
1316 }
1317 6 => {
1318 let mut octets = [0u8; 16];
1319 r.read_exact(&mut octets)?;
1320
1321 let mut port_bytes = [0u8; 2];
1322 r.read_exact(&mut port_bytes)?;
1323
1324 SocketAddr::V6(SocketAddrV6::new(
1325 Ipv6Addr::from(octets),
1326 u16::from_le_bytes(port_bytes),
1327 0,
1328 0,
1329 ))
1330 }
1331 _ => {
1332 return Err(io::Error::new(
1333 io::ErrorKind::InvalidData,
1334 "Invalid IP type",
1335 ))
1336 }
1337 };
1338 Ok(ip)
1339 }
1340 }
1341}
1342
1343macro_rules! map_topic {
1344 ($v:expr, $enum_v:expr) => {
1345 if $v == $enum_v as u8 {
1346 return $enum_v;
1347 }
1348 };
1349}
1350
1351#[derive(Debug, Clone, PartialEq, Eq, Copy, Default)]
1352#[cfg_attr(any(feature = "faker", test), derive(fake::Dummy))]
1353pub enum Topics {
1354 GetResource = 8,
1356 GetBlocks = 9,
1357 GetMempool = 13, Inv = 14,
1359
1360 Tx = 10,
1362 Block = 11,
1363
1364 Candidate = 16,
1366 Validation = 17,
1367 Ratification = 18,
1368 Quorum = 19,
1369 ValidationQuorum = 20,
1370
1371 #[default]
1372 Unknown = 255,
1373}
1374
1375impl Topics {
1376 pub fn is_consensus_msg(&self) -> bool {
1377 matches!(
1378 &self,
1379 Topics::Candidate
1380 | Topics::Validation
1381 | Topics::Ratification
1382 | Topics::Quorum
1383 | Topics::ValidationQuorum
1384 )
1385 }
1386}
1387
1388impl From<u8> for Topics {
1389 fn from(v: u8) -> Self {
1390 map_topic!(v, Topics::GetResource);
1391 map_topic!(v, Topics::GetBlocks);
1392 map_topic!(v, Topics::Tx);
1393 map_topic!(v, Topics::Block);
1394 map_topic!(v, Topics::GetMempool);
1395 map_topic!(v, Topics::Inv);
1396 map_topic!(v, Topics::Candidate);
1397 map_topic!(v, Topics::Validation);
1398 map_topic!(v, Topics::Ratification);
1399 map_topic!(v, Topics::Quorum);
1400 map_topic!(v, Topics::ValidationQuorum);
1401
1402 Topics::Unknown
1403 }
1404}
1405
1406impl From<Topics> for u8 {
1407 fn from(t: Topics) -> Self {
1408 t as u8
1409 }
1410}
1411
1412#[derive(Clone)]
1414pub struct AsyncQueue<M: Clone> {
1415 receiver: async_channel::Receiver<M>,
1416 sender: async_channel::Sender<M>,
1417
1418 cap: usize,
1419 label: &'static str,
1420}
1421
1422impl<M: Clone> AsyncQueue<M> {
1423 pub fn bounded(cap: usize, label: &'static str) -> Self {
1429 let (sender, receiver) = async_channel::bounded(cap);
1430 Self {
1431 receiver,
1432 sender,
1433 cap,
1434 label,
1435 }
1436 }
1437}
1438
1439impl<M: Clone> AsyncQueue<M> {
1440 pub fn try_send(&self, msg: M) {
1441 let label = self.label;
1442 let _ = self.sender.try_send(msg).map_err(|err| match err {
1443 TrySendError::Full(_) => {
1444 error!("queue ({label}) is full, cap: {}", self.cap);
1445 }
1446 TrySendError::Closed(_) => {
1447 error!("queue ({label}) is closed");
1448 }
1449 });
1450 }
1451
1452 pub fn recv(&self) -> async_channel::Recv<'_, M> {
1453 self.receiver.recv()
1454 }
1455}
1456
1457pub trait StepMessage {
1458 const STEP_NAME: StepName;
1459 fn header(&self) -> ConsensusHeader;
1460
1461 fn get_step(&self) -> u8 {
1462 Self::STEP_NAME.to_step(self.header().iteration)
1463 }
1464}
1465
1466pub trait SignedStepMessage: StepMessage {
1467 const SIGN_SEED: &'static [u8];
1468 fn signable(&self) -> Vec<u8>;
1469 fn sign_info(&self) -> SignInfo;
1470 fn sign_info_mut(&mut self) -> &mut SignInfo;
1471
1472 fn verify_signature(&self) -> Result<(), BlsSigError> {
1473 let signature = self.sign_info().signature;
1474 let sig = BlsMultisigSignature::from_bytes(signature.inner())?;
1475 let pk = BlsMultisigPublicKey::aggregate(&[*self
1476 .sign_info()
1477 .signer
1478 .inner()])?;
1479 let msg = self.signable();
1480 pk.verify(&sig, &msg)
1481 }
1482
1483 fn sign(&mut self, sk: &BlsSecretKey, pk: &BlsPublicKey) {
1484 let msg = self.signable();
1485 let sign_info = self.sign_info_mut();
1486 let signature = sk.sign_multisig(pk, &msg).to_bytes();
1487 sign_info.signature = signature.into();
1488 sign_info.signer = PublicKey::new(*pk)
1489 }
1490}
1491
1492impl StepMessage for Validation {
1493 const STEP_NAME: StepName = StepName::Validation;
1494
1495 fn header(&self) -> ConsensusHeader {
1496 self.header
1497 }
1498}
1499
1500impl SignedStepMessage for Validation {
1501 const SIGN_SEED: &'static [u8] = &[1u8];
1502
1503 fn sign_info(&self) -> SignInfo {
1504 self.sign_info.clone()
1505 }
1506 fn sign_info_mut(&mut self) -> &mut SignInfo {
1507 &mut self.sign_info
1508 }
1509 fn signable(&self) -> Vec<u8> {
1510 let mut signable = self.header.signable();
1511 signable.extend_from_slice(Self::SIGN_SEED);
1512 self.vote
1513 .write(&mut signable)
1514 .expect("Writing to vec should succeed");
1515 signable
1516 }
1517}
1518
1519impl StepMessage for Ratification {
1520 const STEP_NAME: StepName = StepName::Ratification;
1521
1522 fn header(&self) -> ConsensusHeader {
1523 self.header
1524 }
1525}
1526
1527impl SignedStepMessage for Ratification {
1528 const SIGN_SEED: &'static [u8] = &[2u8];
1529 fn sign_info(&self) -> SignInfo {
1530 self.sign_info.clone()
1531 }
1532 fn sign_info_mut(&mut self) -> &mut SignInfo {
1533 &mut self.sign_info
1534 }
1535 fn signable(&self) -> Vec<u8> {
1536 let mut signable = self.header.signable();
1537 signable.extend_from_slice(Self::SIGN_SEED);
1538 self.vote
1539 .write(&mut signable)
1540 .expect("Writing to vec should succeed");
1541 signable
1542 }
1543}
1544
1545impl StepMessage for Candidate {
1546 const STEP_NAME: StepName = StepName::Proposal;
1547
1548 fn header(&self) -> ConsensusHeader {
1549 ConsensusHeader {
1550 iteration: self.candidate.header().iteration,
1551 prev_block_hash: self.candidate.header().prev_block_hash,
1552 round: self.candidate.header().height,
1553 }
1554 }
1555}
1556
1557impl SignedStepMessage for Candidate {
1558 const SIGN_SEED: &'static [u8] = &[];
1559 fn sign_info(&self) -> SignInfo {
1560 let header = self.candidate.header();
1561 SignInfo {
1562 signer: PublicKey::try_from(header.generator_bls_pubkey.0)
1563 .unwrap_or_default(),
1564 signature: header.signature,
1565 }
1566 }
1567 fn sign_info_mut(&mut self) -> &mut SignInfo {
1568 panic!("sign_info_mut called on Candidate, this is a bug")
1569 }
1570 fn signable(&self) -> Vec<u8> {
1571 self.candidate.header().hash.to_vec()
1572 }
1573
1574 fn sign(&mut self, sk: &BlsSecretKey, pk: &BlsPublicKey) {
1575 let msg = self.signable();
1576 let signature = sk.sign_multisig(pk, &msg).to_bytes();
1577 self.candidate.set_signature(signature.into());
1578 }
1579}
1580
1581impl StepMessage for ValidationQuorum {
1582 const STEP_NAME: StepName = StepName::Validation;
1583
1584 fn header(&self) -> ConsensusHeader {
1585 self.header
1586 }
1587}
1588
1589#[derive(Clone, Default)]
1590#[cfg_attr(any(feature = "faker", test), derive(fake::Dummy, Eq, PartialEq))]
1591pub struct SignInfo {
1592 pub signer: bls::PublicKey,
1593 pub signature: Signature,
1594}
1595
1596impl Serializable for SignInfo {
1597 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1598 w.write_all(self.signer.bytes().inner())?;
1599 w.write_all(self.signature.inner())?;
1600
1601 Ok(())
1602 }
1603
1604 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1605 where
1606 Self: Sized,
1607 {
1608 let signer = Self::read_bytes(r)?;
1610 let signer = signer
1611 .try_into()
1612 .map_err(|_| io::Error::from(io::ErrorKind::InvalidData))?;
1613
1614 let signature = Self::read_bytes(r)?.into();
1615
1616 Ok(Self { signer, signature })
1617 }
1618}
1619
1620impl std::fmt::Debug for SignInfo {
1621 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1622 f.debug_struct("SignInfo")
1623 .field("signer", &to_str(self.signature.inner()))
1624 .field("signature", &self.signature)
1625 .finish()
1626 }
1627}
1628
1629#[cfg(test)]
1630#[allow(unused)]
1631mod tests {
1632 use self::payload::ValidationResult;
1633 use super::*;
1634 use crate::ledger::*;
1635 use crate::{ledger, Serializable};
1636
1637 #[test]
1638 fn test_serialize() {
1639 let consensus_header = ConsensusHeader {
1640 iteration: 1,
1641 prev_block_hash: [2; 32],
1642 round: 4,
1643 };
1644 assert_serialize(consensus_header.clone());
1645
1646 let header = ledger::Header {
1647 version: 3,
1648 height: 1888881,
1649 timestamp: 123456789,
1650 gas_limit: 111111111,
1651 prev_block_hash: [1; 32],
1652 seed: ledger::Seed::from([2; 48]),
1653 generator_bls_pubkey: bls::PublicKeyBytes([5; 96]),
1654 state_hash: [4; 32],
1655 event_bloom: [5; 256],
1656 hash: [6; 32],
1657 txroot: [7; 32],
1658 faultroot: [8; 32],
1659 att: Attestation {
1660 validation: ledger::StepVotes::new([6; 48], 22222222),
1661 ratification: ledger::StepVotes::new([7; 48], 3333333),
1662 ..Default::default()
1663 },
1664 iteration: 1,
1665 prev_block_cert: Attestation {
1666 validation: ledger::StepVotes::new([6; 48], 444444444),
1667 ratification: ledger::StepVotes::new([7; 48], 55555555),
1668 ..Default::default()
1669 },
1670 failed_iterations: Default::default(),
1671 signature: Signature::from([9; 48]),
1672 };
1673
1674 let sample_block = ledger::Block::new(header, vec![], vec![])
1675 .expect("should be valid block");
1676
1677 let sign_info = SignInfo {
1678 signer: bls::PublicKey::from_sk_seed_u64(3),
1679 signature: [5; 48].into(),
1680 };
1681
1682 assert_serialize(payload::Candidate {
1683 candidate: sample_block,
1684 });
1685
1686 assert_serialize(ledger::StepVotes::new([4; 48], 12345));
1687
1688 assert_serialize(payload::Validation {
1689 header: consensus_header.clone(),
1690 vote: payload::Vote::Valid([4; 32]),
1691 sign_info: sign_info.clone(),
1692 });
1693
1694 let validation_result = ValidationResult::new(
1695 ledger::StepVotes::new([1; 48], 12345),
1696 payload::Vote::Valid([5; 32]),
1697 payload::QuorumType::Valid,
1698 );
1699
1700 assert_serialize(payload::Ratification {
1701 header: consensus_header.clone(),
1702 vote: payload::Vote::Valid([4; 32]),
1703 sign_info: sign_info.clone(),
1704 validation_result,
1705 timestamp: 1_000_000,
1706 });
1707
1708 assert_serialize(payload::Quorum {
1709 header: consensus_header.clone(),
1710 att: Attestation {
1711 result: payload::Vote::Valid([4; 32]).into(),
1712 validation: ledger::StepVotes::new([1; 48], 12345),
1713 ratification: ledger::StepVotes::new([2; 48], 98765),
1714 },
1715 });
1716 }
1717
1718 fn assert_serialize<S: Serializable + PartialEq + core::fmt::Debug>(v: S) {
1719 let mut buf = vec![];
1720 assert!(v.write(&mut buf).is_ok());
1721 let dup = S::read(&mut &buf[..]).expect("deserialize is ok");
1722 assert_eq!(
1723 v,
1724 dup,
1725 "failed to (de)serialize {}",
1726 std::any::type_name::<S>()
1727 );
1728 }
1729}