Skip to main content

dusk_node_data/
message.rs

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