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 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
28pub const TOPIC_FIELD_POS: usize = 1 + 2 + 2;
30pub const PROTOCOL_VERSION: Version = Version(1, 0, 0);
31
32pub const BLOCK_HEADER_VERSION: u8 = 1;
34
35pub const MESSAGE_MAX_FAILED_ITERATIONS: u8 = 8;
37
38#[derive(Debug, Clone)]
39pub 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#[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 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#[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(()), }
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 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 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 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
436impl 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
463impl 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
495impl 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 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 Valid = 0,
691 Invalid = 1,
693 NoCandidate = 2,
695 #[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 MempoolTx,
961 #[default]
962 BlockFromHash,
964 BlockFromHeight,
966 CandidateFromHash,
968 CandidateFromIteration,
970 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: Inv,
1205
1206 requester_addr: Option<SocketAddr>,
1208
1209 ttl_as_sec: u64,
1211
1212 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 GetResource = 8,
1367 GetBlocks = 9,
1368 GetMempool = 13, Inv = 14,
1370
1371 Tx = 10,
1373 Block = 11,
1374
1375 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#[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 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 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}