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) sv: StepVotes,
729 }
730
731 impl ValidationResult {
732 pub fn new(sv: StepVotes, vote: Vote, quorum: QuorumType) -> Self {
733 Self { sv, vote, quorum }
734 }
735
736 pub fn quorum(&self) -> QuorumType {
737 self.quorum
738 }
739
740 pub fn sv(&self) -> &StepVotes {
741 &self.sv
742 }
743
744 pub fn vote(&self) -> &Vote {
745 &self.vote
746 }
747 }
748
749 #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize)]
750 #[serde(untagged)]
751 #[cfg_attr(any(feature = "faker", test), derive(fake::Dummy))]
752 pub enum RatificationResult {
753 Fail(Vote),
754 Success(Vote),
755 }
756
757 impl Default for RatificationResult {
758 fn default() -> Self {
759 Self::Fail(Vote::NoQuorum)
760 }
761 }
762
763 impl From<Vote> for RatificationResult {
764 fn from(vote: Vote) -> Self {
765 match vote {
766 Vote::Valid(hash) => {
767 RatificationResult::Success(Vote::Valid(hash))
768 }
769 fail => RatificationResult::Fail(fail),
770 }
771 }
772 }
773
774 impl RatificationResult {
775 pub fn vote(&self) -> &Vote {
776 match self {
777 Self::Success(v) => v,
778 Self::Fail(v) => v,
779 }
780 }
781
782 pub fn failed(&self) -> bool {
783 match self {
784 Self::Success(_) => false,
785 Self::Fail(_) => true,
786 }
787 }
788 }
789
790 #[derive(Debug, Clone, Eq, PartialEq)]
791 pub struct Quorum {
792 pub header: ConsensusHeader,
793 pub att: Attestation,
794 }
795
796 impl Serializable for Quorum {
797 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
798 self.header.write(w)?;
799 self.att.write(w)?;
800
801 Ok(())
802 }
803
804 fn read<R: Read>(r: &mut R) -> io::Result<Self>
805 where
806 Self: Sized,
807 {
808 let header = ConsensusHeader::read(r)?;
809 let att = Attestation::read(r)?;
810
811 Ok(Quorum { header, att })
812 }
813 }
814
815 impl Quorum {
816 pub fn vote(&self) -> &Vote {
817 self.att.result.vote()
818 }
819 }
820
821 #[derive(Debug, Clone, Default)]
822 pub struct GetCandidate {
823 pub hash: [u8; 32],
824 }
825
826 impl Serializable for GetCandidate {
827 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
828 w.write_all(&self.hash[..])?;
829
830 Ok(())
831 }
832
833 fn read<R: Read>(r: &mut R) -> io::Result<Self>
834 where
835 Self: Sized,
836 {
837 let hash = Self::read_bytes(r)?;
838
839 Ok(GetCandidate { hash })
840 }
841 }
842
843 #[derive(Debug, Clone, Default)]
844 pub struct GetCandidateResp {
845 pub candidate: Block,
846 }
847
848 impl Serializable for GetCandidateResp {
849 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
850 self.candidate.write(w)
851 }
852
853 fn read<R: Read>(r: &mut R) -> io::Result<Self>
854 where
855 Self: Sized,
856 {
857 Ok(GetCandidateResp {
858 candidate: Block::read(r)?,
859 })
860 }
861 }
862 #[derive(Debug, Clone, Default)]
863 pub struct Nonce([u8; 8]);
864
865 impl Serializable for Nonce {
866 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
867 w.write_all(&self.0)
868 }
869
870 fn read<R: Read>(r: &mut R) -> io::Result<Self>
871 where
872 Self: Sized,
873 {
874 let nonce = Self::read_bytes(r)?;
875 Ok(Self(nonce))
876 }
877 }
878
879 impl From<Nonce> for u64 {
880 fn from(value: Nonce) -> Self {
881 u64::from_le_bytes(value.0)
882 }
883 }
884
885 impl From<u64> for Nonce {
886 fn from(value: u64) -> Self {
887 Self(value.to_le_bytes())
888 }
889 }
890
891 impl From<IpAddr> for Nonce {
892 fn from(value: IpAddr) -> Self {
893 match value {
894 IpAddr::V4(v4) => v4.into(),
895 IpAddr::V6(v6) => v6.into(),
896 }
897 }
898 }
899
900 impl From<Ipv4Addr> for Nonce {
901 fn from(value: Ipv4Addr) -> Self {
902 let num = u32::from_le_bytes(value.octets());
903 (num as u64).into()
904 }
905 }
906
907 impl From<Ipv6Addr> for Nonce {
908 fn from(value: Ipv6Addr) -> Self {
909 let mut ret = [0u8; 8];
910 let value = value.octets();
911 let (a, b) = value.split_at(8);
912 a.iter()
913 .zip(b)
914 .map(|(a, b)| a.wrapping_add(*b))
915 .enumerate()
916 .for_each(|(idx, v)| ret[idx] = v);
917
918 Self(ret)
919 }
920 }
921
922 #[derive(Debug, Clone, Default)]
923 pub struct GetMempool {
924 pub(crate) nonce: Nonce,
925 }
926
927 impl GetMempool {
928 pub fn set_nonce<N: Into<Nonce>>(&mut self, nonce: N) {
929 self.nonce = nonce.into()
930 }
931 }
932
933 impl Serializable for GetMempool {
934 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
935 self.nonce.write(w)?;
936 Ok(())
937 }
938
939 fn read<R: Read>(r: &mut R) -> io::Result<Self>
940 where
941 Self: Sized,
942 {
943 let nonce = Nonce::read(r)?;
944 Ok(GetMempool { nonce })
945 }
946 }
947
948 #[derive(Clone, Default, Debug, Copy)]
949 pub enum InvType {
950 MempoolTx,
952 #[default]
953 BlockFromHash,
955 BlockFromHeight,
957 CandidateFromHash,
959 CandidateFromIteration,
961 ValidationResult,
963 }
964
965 #[derive(Clone, Copy)]
966 pub enum InvParam {
967 Hash([u8; 32]),
968 Height(u64),
969 Iteration(ConsensusHeader),
970 }
971
972 impl Default for InvParam {
973 fn default() -> Self {
974 Self::Height(0)
975 }
976 }
977
978 impl fmt::Debug for InvParam {
979 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
980 match self {
981 InvParam::Hash(hash) => write!(f, "Hash: {}", to_str(hash)),
982 InvParam::Height(height) => write!(f, "Height: {}", height),
983 InvParam::Iteration(ch) => {
984 write!(
985 f,
986 "PrevBlock: {}, Round: {}, Iteration: {}",
987 to_str(&ch.prev_block_hash),
988 ch.round,
989 ch.iteration
990 )
991 }
992 }
993 }
994 }
995
996 #[derive(Default, Debug, Clone, Copy)]
997 pub struct InvVect {
998 pub inv_type: InvType,
999 pub param: InvParam,
1000 }
1001
1002 #[derive(Default, Debug, Clone)]
1003 pub struct Inv {
1004 pub inv_list: Vec<InvVect>,
1005 pub max_entries: u16,
1006 }
1007
1008 impl Inv {
1009 pub fn new(max_entries: u16) -> Self {
1010 Self {
1011 inv_list: Default::default(),
1012 max_entries,
1013 }
1014 }
1015
1016 pub fn add_tx_id(&mut self, id: [u8; 32]) {
1017 self.inv_list.push(InvVect {
1018 inv_type: InvType::MempoolTx,
1019 param: InvParam::Hash(id),
1020 });
1021 }
1022
1023 pub fn add_block_from_hash(&mut self, hash: [u8; 32]) {
1024 self.inv_list.push(InvVect {
1025 inv_type: InvType::BlockFromHash,
1026 param: InvParam::Hash(hash),
1027 });
1028 }
1029
1030 pub fn add_block_from_height(&mut self, height: u64) {
1031 self.inv_list.push(InvVect {
1032 inv_type: InvType::BlockFromHeight,
1033 param: InvParam::Height(height),
1034 });
1035 }
1036
1037 pub fn add_candidate_from_hash(&mut self, hash: [u8; 32]) {
1038 self.inv_list.push(InvVect {
1039 inv_type: InvType::CandidateFromHash,
1040 param: InvParam::Hash(hash),
1041 });
1042 }
1043
1044 pub fn add_candidate_from_iteration(
1045 &mut self,
1046 consensus_header: ConsensusHeader,
1047 ) {
1048 self.inv_list.push(InvVect {
1049 inv_type: InvType::CandidateFromIteration,
1050 param: InvParam::Iteration(consensus_header),
1051 });
1052 }
1053
1054 pub fn add_validation_result(
1055 &mut self,
1056 consensus_header: ConsensusHeader,
1057 ) {
1058 self.inv_list.push(InvVect {
1059 inv_type: InvType::ValidationResult,
1060 param: InvParam::Iteration(consensus_header),
1061 });
1062 }
1063 }
1064
1065 impl Serializable for Inv {
1066 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1067 let items_len = self.inv_list.len() as u32;
1068 w.write_all(&items_len.to_le_bytes())?;
1069
1070 for item in &self.inv_list {
1071 w.write_all(&[item.inv_type as u8])?;
1072
1073 match &item.param {
1074 InvParam::Hash(hash) => w.write_all(&hash[..])?,
1075 InvParam::Height(height) => {
1076 w.write_all(&height.to_le_bytes())?
1077 }
1078 InvParam::Iteration(ch) => {
1079 ch.write(w)?;
1080 }
1081 };
1082 }
1083
1084 w.write_all(&self.max_entries.to_le_bytes())?;
1085 Ok(())
1086 }
1087
1088 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1089 where
1090 Self: Sized,
1091 {
1092 let items_len = Self::read_u32_le(r)?;
1093
1094 let mut inv = Inv::default();
1095 for _ in 0..items_len {
1096 let inv_type = Self::read_u8(r)?;
1097
1098 let inv_type = match inv_type {
1099 0 => InvType::MempoolTx,
1100 1 => InvType::BlockFromHash,
1101 2 => InvType::BlockFromHeight,
1102 3 => InvType::CandidateFromHash,
1103 4 => InvType::CandidateFromIteration,
1104 5 => InvType::ValidationResult,
1105 _ => {
1106 return Err(io::Error::from(io::ErrorKind::InvalidData))
1107 }
1108 };
1109
1110 match inv_type {
1111 InvType::MempoolTx => {
1112 let hash = Self::read_bytes(r)?;
1113 inv.add_tx_id(hash);
1114 }
1115 InvType::BlockFromHash => {
1116 let hash = Self::read_bytes(r)?;
1117 inv.add_block_from_hash(hash);
1118 }
1119 InvType::BlockFromHeight => {
1120 inv.add_block_from_height(Self::read_u64_le(r)?);
1121 }
1122 InvType::CandidateFromHash => {
1123 inv.add_candidate_from_hash(Self::read_bytes(r)?);
1124 }
1125 InvType::CandidateFromIteration => {
1126 let ch = ConsensusHeader::read(r)?;
1127 inv.add_candidate_from_iteration(ch);
1128 }
1129 InvType::ValidationResult => {
1130 let ch = ConsensusHeader::read(r)?;
1131 inv.add_validation_result(ch);
1132 }
1133 }
1134 }
1135
1136 inv.max_entries = Self::read_u16_le(r)?;
1137 Ok(inv)
1138 }
1139 }
1140
1141 #[derive(Clone)]
1142 pub struct GetBlocks {
1143 pub locator: [u8; 32],
1144 pub(crate) nonce: Nonce,
1145 }
1146
1147 impl GetBlocks {
1148 pub fn new(locator: [u8; 32]) -> Self {
1149 Self {
1150 locator,
1151 nonce: Nonce::default(),
1152 }
1153 }
1154 pub fn set_nonce<N: Into<Nonce>>(&mut self, nonce: N) {
1155 self.nonce = nonce.into()
1156 }
1157 }
1158
1159 impl fmt::Debug for GetBlocks {
1160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1161 write!(f, "GetBlocks, locator: {}", to_str(&self.locator))
1162 }
1163 }
1164
1165 impl Serializable for GetBlocks {
1166 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1167 w.write_all(&self.locator[..])?;
1168 self.nonce.write(w)?;
1169 Ok(())
1170 }
1171
1172 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1173 where
1174 Self: Sized,
1175 {
1176 let locator = Self::read_bytes(r)?;
1177 let nonce = Nonce::read(r)?;
1178 Ok(Self { locator, nonce })
1179 }
1180 }
1181
1182 #[derive(Debug, Clone)]
1183 pub struct GetResource {
1184 inventory: Inv,
1186
1187 requester_addr: Option<SocketAddr>,
1189
1190 ttl_as_sec: u64,
1192
1193 hops_limit: u16,
1195 }
1196
1197 impl GetResource {
1198 pub fn new(
1199 inventory: Inv,
1200 requester_addr: Option<SocketAddr>,
1201 ttl_as_sec: u64,
1202 hops_limit: u16,
1203 ) -> Self {
1204 Self {
1205 inventory,
1206 requester_addr,
1207 ttl_as_sec,
1208 hops_limit,
1209 }
1210 }
1211
1212 pub fn clone_with_hop_decrement(&self) -> Option<Self> {
1213 if self.hops_limit <= 1 {
1214 return None;
1215 }
1216 let mut req = self.clone();
1217 req.hops_limit -= 1;
1218 Some(req)
1219 }
1220
1221 pub fn get_addr(&self) -> Option<SocketAddr> {
1222 self.requester_addr
1223 }
1224
1225 pub fn get_inv(&self) -> &Inv {
1226 &self.inventory
1227 }
1228
1229 pub fn is_expired(&self) -> bool {
1230 get_current_timestamp() > self.ttl_as_sec
1231 }
1232 }
1233
1234 impl Serializable for GetResource {
1235 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1236 self.inventory.write(w)?;
1237
1238 let requester_addr = self.requester_addr.ok_or(io::Error::new(
1239 io::ErrorKind::InvalidData,
1240 "Requester address is missing",
1241 ))?;
1242
1243 requester_addr.write(w)?;
1244 w.write_all(&self.ttl_as_sec.to_le_bytes()[..])?;
1245 w.write_all(&self.hops_limit.to_le_bytes()[..])
1246 }
1247
1248 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1249 where
1250 Self: Sized,
1251 {
1252 let inner = Inv::read(r)?;
1253 let requester_addr = SocketAddr::read(r)?;
1254
1255 let mut buf = [0u8; 8];
1256 r.read_exact(&mut buf)?;
1257 let ttl_as_sec = u64::from_le_bytes(buf);
1258
1259 let mut buf = [0u8; 2];
1260 r.read_exact(&mut buf)?;
1261 let hops_limit = u16::from_le_bytes(buf);
1262
1263 Ok(GetResource {
1264 inventory: inner,
1265 requester_addr: Some(requester_addr),
1266 ttl_as_sec,
1267 hops_limit,
1268 })
1269 }
1270 }
1271
1272 impl Serializable for SocketAddr {
1273 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1274 match self {
1275 SocketAddr::V4(addr_v4) => {
1276 w.write_all(&[4])?;
1277 w.write_all(&addr_v4.ip().octets())?;
1278 w.write_all(&addr_v4.port().to_le_bytes())?;
1279 }
1280 SocketAddr::V6(addr_v6) => {
1281 w.write_all(&[6])?;
1282 w.write_all(&addr_v6.ip().octets())?;
1283 w.write_all(&addr_v6.port().to_le_bytes())?;
1284 }
1285 }
1286 Ok(())
1287 }
1288
1289 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1290 where
1291 Self: Sized,
1292 {
1293 let mut ip_type = [0u8; 1];
1294 r.read_exact(&mut ip_type)?;
1295
1296 let ip = match ip_type[0] {
1297 4 => {
1298 let mut octets = [0u8; 4];
1299 r.read_exact(&mut octets)?;
1300
1301 let mut port_bytes = [0u8; 2];
1302 r.read_exact(&mut port_bytes)?;
1303
1304 SocketAddr::V4(SocketAddrV4::new(
1305 Ipv4Addr::from(octets),
1306 u16::from_le_bytes(port_bytes),
1307 ))
1308 }
1309 6 => {
1310 let mut octets = [0u8; 16];
1311 r.read_exact(&mut octets)?;
1312
1313 let mut port_bytes = [0u8; 2];
1314 r.read_exact(&mut port_bytes)?;
1315
1316 SocketAddr::V6(SocketAddrV6::new(
1317 Ipv6Addr::from(octets),
1318 u16::from_le_bytes(port_bytes),
1319 0,
1320 0,
1321 ))
1322 }
1323 _ => {
1324 return Err(io::Error::new(
1325 io::ErrorKind::InvalidData,
1326 "Invalid IP type",
1327 ))
1328 }
1329 };
1330 Ok(ip)
1331 }
1332 }
1333}
1334
1335macro_rules! map_topic {
1336 ($v:expr, $enum_v:expr) => {
1337 if $v == $enum_v as u8 {
1338 return $enum_v;
1339 }
1340 };
1341}
1342
1343#[derive(Debug, Clone, PartialEq, Eq, Copy, Default)]
1344#[cfg_attr(any(feature = "faker", test), derive(fake::Dummy))]
1345pub enum Topics {
1346 GetResource = 8,
1348 GetBlocks = 9,
1349 GetMempool = 13, Inv = 14,
1351
1352 Tx = 10,
1354 Block = 11,
1355
1356 Candidate = 16,
1358 Validation = 17,
1359 Ratification = 18,
1360 Quorum = 19,
1361 ValidationQuorum = 20,
1362
1363 #[default]
1364 Unknown = 255,
1365}
1366
1367impl Topics {
1368 pub fn is_consensus_msg(&self) -> bool {
1369 matches!(
1370 &self,
1371 Topics::Candidate
1372 | Topics::Validation
1373 | Topics::Ratification
1374 | Topics::Quorum
1375 | Topics::ValidationQuorum
1376 )
1377 }
1378}
1379
1380impl From<u8> for Topics {
1381 fn from(v: u8) -> Self {
1382 map_topic!(v, Topics::GetResource);
1383 map_topic!(v, Topics::GetBlocks);
1384 map_topic!(v, Topics::Tx);
1385 map_topic!(v, Topics::Block);
1386 map_topic!(v, Topics::GetMempool);
1387 map_topic!(v, Topics::Inv);
1388 map_topic!(v, Topics::Candidate);
1389 map_topic!(v, Topics::Validation);
1390 map_topic!(v, Topics::Ratification);
1391 map_topic!(v, Topics::Quorum);
1392 map_topic!(v, Topics::ValidationQuorum);
1393
1394 Topics::Unknown
1395 }
1396}
1397
1398impl From<Topics> for u8 {
1399 fn from(t: Topics) -> Self {
1400 t as u8
1401 }
1402}
1403
1404#[derive(Clone)]
1406pub struct AsyncQueue<M: Clone> {
1407 receiver: async_channel::Receiver<M>,
1408 sender: async_channel::Sender<M>,
1409
1410 cap: usize,
1411 label: &'static str,
1412}
1413
1414impl<M: Clone> AsyncQueue<M> {
1415 pub fn bounded(cap: usize, label: &'static str) -> Self {
1421 let (sender, receiver) = async_channel::bounded(cap);
1422 Self {
1423 receiver,
1424 sender,
1425 cap,
1426 label,
1427 }
1428 }
1429}
1430
1431impl<M: Clone> AsyncQueue<M> {
1432 pub fn try_send(&self, msg: M) {
1433 let label = self.label;
1434 let _ = self.sender.try_send(msg).map_err(|err| match err {
1435 TrySendError::Full(_) => {
1436 error!("queue ({label}) is full, cap: {}", self.cap);
1437 }
1438 TrySendError::Closed(_) => {
1439 error!("queue ({label}) is closed");
1440 }
1441 });
1442 }
1443
1444 pub fn recv(&self) -> async_channel::Recv<'_, M> {
1445 self.receiver.recv()
1446 }
1447}
1448
1449pub trait StepMessage {
1450 const STEP_NAME: StepName;
1451 fn header(&self) -> ConsensusHeader;
1452
1453 fn get_step(&self) -> u8 {
1454 Self::STEP_NAME.to_step(self.header().iteration)
1455 }
1456}
1457
1458pub trait SignedStepMessage: StepMessage {
1459 const SIGN_SEED: &'static [u8];
1460 fn signable(&self) -> Vec<u8>;
1461 fn sign_info(&self) -> SignInfo;
1462 fn sign_info_mut(&mut self) -> &mut SignInfo;
1463
1464 fn verify_signature(&self) -> Result<(), BlsSigError> {
1465 let signature = self.sign_info().signature;
1466 let sig = BlsMultisigSignature::from_bytes(signature.inner())?;
1467 let pk = BlsMultisigPublicKey::aggregate(&[*self
1468 .sign_info()
1469 .signer
1470 .inner()])?;
1471 let msg = self.signable();
1472 pk.verify(&sig, &msg)
1473 }
1474
1475 fn sign(&mut self, sk: &BlsSecretKey, pk: &BlsPublicKey) {
1476 let msg = self.signable();
1477 let sign_info = self.sign_info_mut();
1478 let signature = sk.sign_multisig(pk, &msg).to_bytes();
1479 sign_info.signature = signature.into();
1480 sign_info.signer = PublicKey::new(*pk)
1481 }
1482}
1483
1484impl StepMessage for Validation {
1485 const STEP_NAME: StepName = StepName::Validation;
1486
1487 fn header(&self) -> ConsensusHeader {
1488 self.header
1489 }
1490}
1491
1492impl SignedStepMessage for Validation {
1493 const SIGN_SEED: &'static [u8] = &[1u8];
1494
1495 fn sign_info(&self) -> SignInfo {
1496 self.sign_info.clone()
1497 }
1498 fn sign_info_mut(&mut self) -> &mut SignInfo {
1499 &mut self.sign_info
1500 }
1501 fn signable(&self) -> Vec<u8> {
1502 let mut signable = self.header.signable();
1503 signable.extend_from_slice(Self::SIGN_SEED);
1504 self.vote
1505 .write(&mut signable)
1506 .expect("Writing to vec should succeed");
1507 signable
1508 }
1509}
1510
1511impl StepMessage for Ratification {
1512 const STEP_NAME: StepName = StepName::Ratification;
1513
1514 fn header(&self) -> ConsensusHeader {
1515 self.header
1516 }
1517}
1518
1519impl SignedStepMessage for Ratification {
1520 const SIGN_SEED: &'static [u8] = &[2u8];
1521 fn sign_info(&self) -> SignInfo {
1522 self.sign_info.clone()
1523 }
1524 fn sign_info_mut(&mut self) -> &mut SignInfo {
1525 &mut self.sign_info
1526 }
1527 fn signable(&self) -> Vec<u8> {
1528 let mut signable = self.header.signable();
1529 signable.extend_from_slice(Self::SIGN_SEED);
1530 self.vote
1531 .write(&mut signable)
1532 .expect("Writing to vec should succeed");
1533 signable
1534 }
1535}
1536
1537impl StepMessage for Candidate {
1538 const STEP_NAME: StepName = StepName::Proposal;
1539
1540 fn header(&self) -> ConsensusHeader {
1541 ConsensusHeader {
1542 iteration: self.candidate.header().iteration,
1543 prev_block_hash: self.candidate.header().prev_block_hash,
1544 round: self.candidate.header().height,
1545 }
1546 }
1547}
1548
1549impl SignedStepMessage for Candidate {
1550 const SIGN_SEED: &'static [u8] = &[];
1551 fn sign_info(&self) -> SignInfo {
1552 let header = self.candidate.header();
1553 SignInfo {
1554 signer: PublicKey::try_from(header.generator_bls_pubkey.0)
1555 .unwrap_or_default(),
1556 signature: header.signature,
1557 }
1558 }
1559 fn sign_info_mut(&mut self) -> &mut SignInfo {
1560 panic!("sign_info_mut called on Candidate, this is a bug")
1561 }
1562 fn signable(&self) -> Vec<u8> {
1563 self.candidate.header().hash.to_vec()
1564 }
1565
1566 fn sign(&mut self, sk: &BlsSecretKey, pk: &BlsPublicKey) {
1567 let msg = self.signable();
1568 let signature = sk.sign_multisig(pk, &msg).to_bytes();
1569 self.candidate.set_signature(signature.into());
1570 }
1571}
1572
1573impl StepMessage for ValidationQuorum {
1574 const STEP_NAME: StepName = StepName::Validation;
1575
1576 fn header(&self) -> ConsensusHeader {
1577 self.header
1578 }
1579}
1580
1581#[derive(Clone, Default)]
1582#[cfg_attr(any(feature = "faker", test), derive(fake::Dummy, Eq, PartialEq))]
1583pub struct SignInfo {
1584 pub signer: bls::PublicKey,
1585 pub signature: Signature,
1586}
1587
1588impl Serializable for SignInfo {
1589 fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
1590 w.write_all(self.signer.bytes().inner())?;
1591 w.write_all(self.signature.inner())?;
1592
1593 Ok(())
1594 }
1595
1596 fn read<R: Read>(r: &mut R) -> io::Result<Self>
1597 where
1598 Self: Sized,
1599 {
1600 let signer = Self::read_bytes(r)?;
1602 let signer = signer
1603 .try_into()
1604 .map_err(|_| io::Error::from(io::ErrorKind::InvalidData))?;
1605
1606 let signature = Self::read_bytes(r)?.into();
1607
1608 Ok(Self { signer, signature })
1609 }
1610}
1611
1612impl std::fmt::Debug for SignInfo {
1613 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1614 f.debug_struct("SignInfo")
1615 .field("signer", &to_str(self.signature.inner()))
1616 .field("signature", &self.signature)
1617 .finish()
1618 }
1619}
1620
1621#[cfg(test)]
1622#[allow(unused)]
1623mod tests {
1624 use self::payload::ValidationResult;
1625 use super::*;
1626 use crate::ledger::*;
1627 use crate::{ledger, Serializable};
1628
1629 #[test]
1630 fn test_serialize() {
1631 let consensus_header = ConsensusHeader {
1632 iteration: 1,
1633 prev_block_hash: [2; 32],
1634 round: 4,
1635 };
1636 assert_serialize(consensus_header.clone());
1637
1638 let header = ledger::Header {
1639 version: 3,
1640 height: 1888881,
1641 timestamp: 123456789,
1642 gas_limit: 111111111,
1643 prev_block_hash: [1; 32],
1644 seed: ledger::Seed::from([2; 48]),
1645 generator_bls_pubkey: bls::PublicKeyBytes([5; 96]),
1646 state_hash: [4; 32],
1647 event_bloom: [5; 256],
1648 hash: [6; 32],
1649 txroot: [7; 32],
1650 faultroot: [8; 32],
1651 att: Attestation {
1652 validation: ledger::StepVotes::new([6; 48], 22222222),
1653 ratification: ledger::StepVotes::new([7; 48], 3333333),
1654 ..Default::default()
1655 },
1656 iteration: 1,
1657 prev_block_cert: Attestation {
1658 validation: ledger::StepVotes::new([6; 48], 444444444),
1659 ratification: ledger::StepVotes::new([7; 48], 55555555),
1660 ..Default::default()
1661 },
1662 failed_iterations: Default::default(),
1663 signature: Signature::from([9; 48]),
1664 };
1665
1666 let sample_block = ledger::Block::new(header, vec![], vec![])
1667 .expect("should be valid block");
1668
1669 let sign_info = SignInfo {
1670 signer: bls::PublicKey::from_sk_seed_u64(3),
1671 signature: [5; 48].into(),
1672 };
1673
1674 assert_serialize(payload::Candidate {
1675 candidate: sample_block,
1676 });
1677
1678 assert_serialize(ledger::StepVotes::new([4; 48], 12345));
1679
1680 assert_serialize(payload::Validation {
1681 header: consensus_header.clone(),
1682 vote: payload::Vote::Valid([4; 32]),
1683 sign_info: sign_info.clone(),
1684 });
1685
1686 let validation_result = ValidationResult::new(
1687 ledger::StepVotes::new([1; 48], 12345),
1688 payload::Vote::Valid([5; 32]),
1689 payload::QuorumType::Valid,
1690 );
1691
1692 assert_serialize(payload::Ratification {
1693 header: consensus_header.clone(),
1694 vote: payload::Vote::Valid([4; 32]),
1695 sign_info: sign_info.clone(),
1696 validation_result,
1697 timestamp: 1_000_000,
1698 });
1699
1700 assert_serialize(payload::Quorum {
1701 header: consensus_header.clone(),
1702 att: Attestation {
1703 result: payload::Vote::Valid([4; 32]).into(),
1704 validation: ledger::StepVotes::new([1; 48], 12345),
1705 ratification: ledger::StepVotes::new([2; 48], 98765),
1706 },
1707 });
1708 }
1709
1710 fn assert_serialize<S: Serializable + PartialEq + core::fmt::Debug>(v: S) {
1711 let mut buf = vec![];
1712 assert!(v.write(&mut buf).is_ok());
1713 let dup = S::read(&mut &buf[..]).expect("deserialize is ok");
1714 assert_eq!(
1715 v,
1716 dup,
1717 "failed to (de)serialize {}",
1718 std::any::type_name::<S>()
1719 );
1720 }
1721}