1use crate::block_id::{BlockId, BlockIdDeserializer, BlockIdSerializer};
2use crate::denunciation::{Denunciation, DenunciationDeserializer, DenunciationSerializer};
3use crate::endorsement::{
4 Endorsement, EndorsementDeserializerLW, EndorsementId, EndorsementSerializer,
5 EndorsementSerializerLW, SecureShareEndorsement,
6};
7use crate::secure_share::{
8 SecureShare, SecureShareContent, SecureShareDeserializer, SecureShareSerializer,
9};
10use crate::slot::{Slot, SlotDeserializer, SlotSerializer};
11use massa_hash::{Hash, HashDeserializer};
12use massa_serialization::{
13 Deserializer, OptionDeserializer, OptionSerializer, SerializeError, Serializer,
14 U32VarIntDeserializer, U32VarIntSerializer,
15};
16use massa_signature::PublicKey;
17use nom::branch::alt;
18use nom::bytes::complete::tag;
19use nom::error::{context, ContextError, ParseError};
20use nom::multi::{count, length_count};
21use nom::sequence::{preceded, tuple};
22use nom::{IResult, Parser};
23use serde::{Deserialize, Serialize};
24use std::collections::Bound::{Excluded, Included};
25use std::collections::HashSet;
26use std::fmt::Formatter;
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct BlockHeader {
31 pub current_version: u32,
33 pub announced_version: Option<u32>,
35 pub slot: Slot,
37 pub parents: Vec<BlockId>,
39 pub operation_merkle_root: Hash,
41 pub endorsements: Vec<SecureShareEndorsement>,
43 pub denunciations: Vec<Denunciation>,
45}
46
47#[cfg(any(test, feature = "test-exports"))]
49impl BlockHeader {
50 fn assert_invariants(
54 &self,
55 thread_count: u8,
56 endorsement_count: u32,
57 ) -> Result<(), Box<dyn std::error::Error>> {
58 if self.slot.period == 0 {
59 if !self.parents.is_empty() {
60 return Err("Invariant broken: genesis block with parent(s)".into());
61 }
62 if !self.endorsements.is_empty() {
63 return Err("Invariant broken: genesis block with endorsement(s)".into());
64 }
65 } else {
66 if self.parents.len() != thread_count as usize {
67 return Err(
68 "Invariant broken: non-genesis block with incorrect number of parents".into(),
69 );
70 }
71 if self.endorsements.len() > endorsement_count as usize {
72 return Err("Invariant broken: endorsement count too high".into());
73 }
74
75 let parent_id = self.parents[self.slot.thread as usize];
76 for endo in self.endorsements.iter() {
77 if endo.content.endorsed_block != parent_id {
78 return Err("Invariant broken: endorsement doesn't match parent".into());
79 }
80 }
81 }
82
83 let mut set = HashSet::new();
85 for endo in self.endorsements.iter() {
86 if !set.insert(endo.content.index) {
87 return Err("Endorsement duplicate index found".into());
88 }
89 }
90
91 for de in self.denunciations.iter() {
92 de.check_invariants()?;
93 }
94
95 Ok(())
96 }
97}
98
99pub type SecuredHeader = SecureShare<BlockHeader, BlockId>;
101
102impl SecureShareContent for BlockHeader {
103 fn compute_signed_hash(&self, public_key: &PublicKey, content_hash: &Hash) -> Hash {
105 let mut signed_data: Vec<u8> = Vec::new();
106 signed_data.extend(public_key.to_bytes());
107 signed_data.extend(BlockHeaderDenunciationData::new(self.slot).to_bytes());
108 signed_data.extend(content_hash.to_bytes());
109 Hash::compute_from(&signed_data)
110 }
111}
112
113impl SecuredHeader {
114 pub fn get_fitness(&self) -> u64 {
116 (self.content.endorsements.len() as u64) + 1
117 }
118 #[allow(dead_code)]
120 #[cfg(any(test, feature = "test-exports"))]
121 pub(crate) fn assert_invariants(
122 &self,
123 thread_count: u8,
124 endorsement_count: u32,
125 ) -> Result<(), Box<dyn std::error::Error>> {
126 self.content
127 .assert_invariants(thread_count, endorsement_count)?;
128 self.verify_signature()
129 .map_err(|er| format!("{}", er).into())
130 }
131}
132
133pub struct BlockHeaderSerializer {
135 slot_serializer: SlotSerializer,
136 endorsement_serializer: SecureShareSerializer,
137 endorsement_content_serializer: EndorsementSerializerLW,
138 denunciation_serializer: DenunciationSerializer,
139 u32_serializer: U32VarIntSerializer,
140 opt_serializer: OptionSerializer<u32, U32VarIntSerializer>,
141 block_id_serializer: BlockIdSerializer,
142}
143
144impl BlockHeaderSerializer {
145 pub fn new() -> Self {
147 Self {
148 slot_serializer: SlotSerializer::new(),
149 endorsement_serializer: SecureShareSerializer::new(),
150 u32_serializer: U32VarIntSerializer::new(),
151 opt_serializer: OptionSerializer::new(U32VarIntSerializer),
152 endorsement_content_serializer: EndorsementSerializerLW::new(),
153 denunciation_serializer: DenunciationSerializer::new(),
154 block_id_serializer: BlockIdSerializer::new(),
155 }
156 }
157}
158
159impl Default for BlockHeaderSerializer {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165impl Serializer<BlockHeader> for BlockHeaderSerializer {
166 fn serialize(&self, value: &BlockHeader, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
217 self.u32_serializer
219 .serialize(&value.current_version, buffer)?;
220 self.opt_serializer
221 .serialize(&value.announced_version, buffer)?;
222
223 self.slot_serializer.serialize(&value.slot, buffer)?;
225
226 if value.parents.is_empty() {
228 buffer.push(0);
229 } else {
230 buffer.push(1);
231 }
232 for parent_h in value.parents.iter() {
233 self.block_id_serializer.serialize(parent_h, buffer)?;
234 }
235
236 buffer.extend(value.operation_merkle_root.to_bytes());
238
239 self.u32_serializer.serialize(
240 &value.endorsements.len().try_into().map_err(|err| {
241 SerializeError::GeneralError(format!("too many endorsements: {}", err))
242 })?,
243 buffer,
244 )?;
245
246 for endorsement in value.endorsements.iter() {
247 self.endorsement_serializer.serialize_with(
248 &self.endorsement_content_serializer,
249 endorsement,
250 buffer,
251 )?;
252 }
253 self.u32_serializer.serialize(
254 &value.denunciations.len().try_into().map_err(|err| {
255 SerializeError::GeneralError(format!("too many denunciations: {}", err))
256 })?,
257 buffer,
258 )?;
259 for denunciation in value.denunciations.iter() {
260 self.denunciation_serializer
261 .serialize(denunciation, buffer)?;
262 }
263
264 Ok(())
265 }
266}
267
268pub struct BlockHeaderDeserializer {
270 slot_deserializer: SlotDeserializer,
271 endorsement_serializer: EndorsementSerializer,
272 endorsement_len_deserializer: U32VarIntDeserializer,
273 hash_deserializer: HashDeserializer,
274 thread_count: u8,
275 endorsement_count: u32,
276 last_start_period: Option<u64>,
277 denunciation_len_deserializer: U32VarIntDeserializer,
278 denunciation_deserializer: DenunciationDeserializer,
279 network_versions_deserializer: U32VarIntDeserializer,
280 opt_deserializer: OptionDeserializer<u32, U32VarIntDeserializer>,
281 block_id_deserializer: BlockIdDeserializer,
282 chain_id: u64,
283}
284
285impl BlockHeaderDeserializer {
286 pub fn new(
289 thread_count: u8,
290 endorsement_count: u32,
291 max_denunciations_in_block_header: u32,
292 last_start_period: Option<u64>,
293 chain_id: u64,
294 ) -> Self {
295 Self {
296 slot_deserializer: SlotDeserializer::new(
297 (Included(0), Included(u64::MAX)),
298 (Included(0), Excluded(thread_count)),
299 ),
300 endorsement_serializer: EndorsementSerializer::new(),
301 endorsement_len_deserializer: U32VarIntDeserializer::new(
302 Included(0),
303 Included(endorsement_count),
304 ),
305 hash_deserializer: HashDeserializer::new(),
306 denunciation_len_deserializer: U32VarIntDeserializer::new(
307 Included(0),
308 Included(max_denunciations_in_block_header),
309 ),
310 network_versions_deserializer: U32VarIntDeserializer::new(
311 Included(0),
312 Included(u32::MAX),
313 ),
314 opt_deserializer: OptionDeserializer::new(U32VarIntDeserializer::new(
315 Included(0),
316 Included(u32::MAX),
317 )),
318 denunciation_deserializer: DenunciationDeserializer::new(
319 thread_count,
320 endorsement_count,
321 ),
322 block_id_deserializer: BlockIdDeserializer::new(),
323 thread_count,
324 endorsement_count,
325 last_start_period,
326 chain_id,
327 }
328 }
329}
330
331impl Deserializer<BlockHeader> for BlockHeaderDeserializer {
332 #[allow(clippy::type_complexity)]
388 fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
389 &self,
390 buffer: &'a [u8],
391 ) -> IResult<&'a [u8], BlockHeader, E> {
392 let (rest, (current_version, announced_version, slot, parents, operation_merkle_root)): (
393 &[u8],
394 (u32, Option<u32>, Slot, Vec<BlockId>, Hash),
395 ) = context("Failed BlockHeader deserialization", |input| {
396 let (rest, (current_version, announced_version, slot, parents)) = tuple((
397 context("Failed current_version deserialization", |input| {
398 self.network_versions_deserializer.deserialize(input)
399 }),
400 context("Failed announced_version deserialization", |input| {
401 self.opt_deserializer.deserialize(input)
402 }),
403 context("Failed slot deserialization", |input| {
404 self.slot_deserializer.deserialize(input)
405 }),
406 context(
407 "Failed parents deserialization",
408 alt((
409 preceded(tag(&[0]), |input| Ok((input, Vec::new()))),
410 preceded(
411 tag(&[1]),
412 count(
413 context("Failed block_id deserialization", |input| {
414 self.block_id_deserializer.deserialize(input)
415 }),
416 self.thread_count as usize,
417 ),
418 ),
419 )),
420 ),
421 ))
422 .parse(input)?;
423
424 if let Some(last_start_period) = self.last_start_period {
426 if slot.period == last_start_period && !parents.is_empty() {
427 return Err(nom::Err::Failure(ContextError::add_context(
428 rest,
429 "Genesis block cannot contain parents",
430 ParseError::from_error_kind(rest, nom::error::ErrorKind::Fail),
431 )));
432 } else if slot.period != last_start_period
433 && parents.len() != self.thread_count as usize
434 {
435 return Err(nom::Err::Failure(ContextError::add_context(
436 rest,
437 "Non-genesis block must have same numbers of parents as threads count",
438 ParseError::from_error_kind(rest, nom::error::ErrorKind::Fail),
439 )));
440 }
441 }
442
443 let (rest, merkle) = context("Failed operation_merkle_root", |input| {
444 self.hash_deserializer.deserialize(input)
445 })
446 .parse(rest)?;
447 Ok((
448 rest,
449 (current_version, announced_version, slot, parents, merkle),
450 ))
451 })
452 .parse(buffer)?;
453
454 if parents.is_empty() {
455 let res = BlockHeader {
456 current_version,
457 announced_version,
458 slot,
459 parents,
460 operation_merkle_root,
461 endorsements: Vec::new(),
462 denunciations: Vec::new(),
463 };
464
465 #[cfg(any(test, feature = "test-exports"))]
467 res.assert_invariants(self.thread_count, self.endorsement_count)
468 .unwrap();
469
470 let (rest2, _) = tag(&[0, 0])(rest)?;
473 return Ok((rest2, res));
474 }
475
476 let endorsement_deserializer = SecureShareDeserializer::new(
478 EndorsementDeserializerLW::new(
479 self.endorsement_count,
480 slot,
481 parents[slot.thread as usize],
482 ),
483 self.chain_id,
484 );
485
486 let parent_id = parents[slot.thread as usize];
487 let (rest, endorsements): (&[u8], Vec<SecureShare<Endorsement, EndorsementId>>) = context(
488 "Failed endorsements deserialization",
489 length_count::<&[u8], SecureShare<Endorsement, EndorsementId>, u32, E, _, _>(
490 context("Failed length deserialization", |input| {
491 self.endorsement_len_deserializer.deserialize(input)
492 }),
493 context("Failed endorsement deserialization", |input| {
494 let (rest, endo) = endorsement_deserializer
495 .deserialize_with(&self.endorsement_serializer, input)?;
496
497 if endo.content.endorsed_block != parent_id {
498 return Err(nom::Err::Failure(ContextError::add_context(
499 rest,
500 "Endorsement does not match block parents",
501 ParseError::from_error_kind(rest, nom::error::ErrorKind::Fail),
502 )));
503 }
504
505 Ok((rest, endo))
506 }),
507 ),
508 )
509 .parse(rest)?;
510
511 let mut set = HashSet::new();
512 for end in endorsements.iter() {
513 if !set.insert(end.content.index) {
514 return Err(nom::Err::Failure(ContextError::add_context(
515 rest,
516 "Duplicate endorsement index found",
517 ParseError::from_error_kind(rest, nom::error::ErrorKind::Fail),
518 )));
519 }
520 }
521
522 let (rest, denunciations): (&[u8], Vec<Denunciation>) = context(
523 "Failed denunciations deserialization",
524 length_count::<&[u8], Denunciation, u32, E, _, _>(
525 context("Failed length deserialization", |input| {
526 let (res, count) = self.denunciation_len_deserializer.deserialize(input)?;
527 IResult::Ok((res, count))
528 }),
529 context("Failed denunciation deserialization", |input| {
530 self.denunciation_deserializer.deserialize(input)
531 }),
532 ),
533 )
534 .parse(rest)?;
535
536 let header = BlockHeader {
537 current_version,
538 announced_version,
539 slot,
540 parents,
541 operation_merkle_root,
542 endorsements,
543 denunciations,
544 };
545
546 #[cfg(any(test, feature = "test-exports"))]
548 header
549 .assert_invariants(self.thread_count, self.endorsement_count)
550 .unwrap();
551
552 Ok((rest, header))
553 }
554}
555
556impl std::fmt::Display for BlockHeader {
557 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
558 writeln!(
559 f,
560 "\t(period: {}, thread: {})",
561 self.slot.period, self.slot.thread,
562 )?;
563 writeln!(f, "\tMerkle root: {}", self.operation_merkle_root,)?;
564 writeln!(f, "\tParents: ")?;
565 for id in self.parents.iter() {
566 let str_id = id.to_string();
567 writeln!(f, "\t\t{}", str_id)?;
568 }
569 if self.parents.is_empty() {
570 writeln!(f, "No parents found: This is a genesis header")?;
571 }
572 writeln!(f, "\tEndorsements:")?;
573 for ed in self.endorsements.iter() {
574 writeln!(f, "\t\t-----")?;
575 writeln!(f, "\t\tId: {}", ed.id)?;
576 writeln!(f, "\t\tIndex: {}", ed.content.index)?;
577 writeln!(f, "\t\tEndorsed slot: {}", ed.content.slot)?;
578 writeln!(
579 f,
580 "\t\tEndorser's public key: {}",
581 ed.content_creator_pub_key
582 )?;
583 writeln!(f, "\t\tEndorsed block: {}", ed.content.endorsed_block)?;
584 writeln!(f, "\t\tSignature: {}", ed.signature)?;
585 }
586 if self.endorsements.is_empty() {
587 writeln!(f, "\tNo endorsements found")?;
588 }
589 Ok(())
590 }
591}
592
593#[derive(Debug)]
595pub struct BlockHeaderDenunciationData {
596 slot: Slot,
597}
598
599impl BlockHeaderDenunciationData {
600 pub fn new(slot: Slot) -> Self {
602 Self { slot }
603 }
604
605 pub fn to_bytes(&self) -> Vec<u8> {
607 let mut buf = Vec::new();
608 buf.extend(self.slot.to_bytes_key());
609 buf
610 }
611}
612
613#[cfg(test)]
614mod test {
615 use super::*;
616 use massa_serialization::DeserializeError;
617 use serde_json::Value;
618
619 use crate::config::{
620 CHAINID, ENDORSEMENT_COUNT, MAX_DENUNCIATIONS_PER_BLOCK_HEADER, THREAD_COUNT,
621 };
622
623 use crate::test_exports::{
624 gen_block_headers_for_denunciation, gen_endorsements_for_denunciation,
625 };
626 use massa_signature::{verify_signature_batch, KeyPair};
627
628 impl PartialEq for BlockHeader {
630 fn eq(&self, other: &Self) -> bool {
631 self.slot == other.slot
632 && self.parents == other.parents
633 && self.operation_merkle_root == other.operation_merkle_root
634 && self.endorsements == other.endorsements
635 && self.denunciations == other.denunciations
636 }
637 }
638
639 #[test]
640 fn test_block_header_ser_der() {
641 let keypair = KeyPair::generate(0).unwrap();
642
643 let slot = Slot::new(7, 1);
644 let parents_1: Vec<BlockId> = (0..THREAD_COUNT)
645 .map(|i| BlockId::generate_from_hash(Hash::compute_from(&[i])))
646 .collect();
647
648 let endorsement_1 = Endorsement {
649 slot,
650 index: 1,
651 endorsed_block: parents_1[1],
652 };
653
654 assert_eq!(parents_1[1], endorsement_1.endorsed_block);
655
656 let s_endorsement_1: SecureShareEndorsement = Endorsement::new_verifiable(
657 endorsement_1,
658 EndorsementSerializer::new(),
659 &keypair,
660 *CHAINID,
661 )
662 .unwrap();
663
664 let (slot_a, _, s_header_1, s_header_2, _) = gen_block_headers_for_denunciation(None, None);
665 assert!(slot_a < slot);
666 let de_a = Denunciation::try_from((&s_header_1, &s_header_2)).unwrap();
667 let (slot_b, _, s_endo_1, s_endo_2, _) = gen_endorsements_for_denunciation(None, None);
668 assert!(slot_b < slot);
669 let de_b = Denunciation::try_from((&s_endo_1, &s_endo_2)).unwrap();
670
671 let block_header_1 = BlockHeader {
672 current_version: 0,
673 announced_version: None,
674 slot,
675 parents: parents_1,
676 operation_merkle_root: Hash::compute_from("mno".as_bytes()),
677 endorsements: vec![s_endorsement_1],
678 denunciations: vec![de_a, de_b],
679 };
680
681 let mut buffer = Vec::new();
682 let ser = BlockHeaderSerializer::new();
683 ser.serialize(&block_header_1, &mut buffer).unwrap();
684 let der = BlockHeaderDeserializer::new(
685 THREAD_COUNT,
686 ENDORSEMENT_COUNT,
687 MAX_DENUNCIATIONS_PER_BLOCK_HEADER,
688 None,
689 *CHAINID,
690 );
691
692 let (rem, block_header_der) = der.deserialize::<DeserializeError>(&buffer).unwrap();
693
694 assert!(rem.is_empty());
695 assert_eq!(block_header_1, block_header_der);
696 }
697
698 #[test]
699 fn test_block_header_no_parents_ser_der() {
700 let slot = Slot::new(0, 1);
701 let block_header_1 = BlockHeader {
702 current_version: 0,
703 announced_version: None,
704 slot,
705 parents: vec![],
706 operation_merkle_root: Hash::compute_from("mno".as_bytes()),
707 endorsements: vec![],
708 denunciations: vec![],
709 };
710
711 let mut buffer = Vec::new();
712 let ser = BlockHeaderSerializer::new();
713 ser.serialize(&block_header_1, &mut buffer).unwrap();
714 let der = BlockHeaderDeserializer::new(
715 THREAD_COUNT,
716 ENDORSEMENT_COUNT,
717 MAX_DENUNCIATIONS_PER_BLOCK_HEADER,
718 None,
719 *CHAINID,
720 );
721
722 let (rem, block_header_der) = der.deserialize::<DeserializeError>(&buffer).unwrap();
723
724 assert!(rem.is_empty());
725 assert_eq!(block_header_1, block_header_der);
726 }
727
728 #[test]
729 fn test_verify_sig_batch() {
730 let (_slot, _keypair, secured_header_1, secured_header_2, secured_header_3) =
731 gen_block_headers_for_denunciation(None, None);
732
733 let batch_1 = [(
735 secured_header_1.compute_signed_hash(),
736 secured_header_1.signature,
737 secured_header_1.content_creator_pub_key,
738 )];
739 verify_signature_batch(&batch_1).unwrap();
740
741 let batch_2 = [
743 (
744 secured_header_1.compute_signed_hash(),
745 secured_header_1.signature,
746 secured_header_1.content_creator_pub_key,
747 ),
748 (
749 secured_header_2.compute_signed_hash(),
750 secured_header_2.signature,
751 secured_header_2.content_creator_pub_key,
752 ),
753 (
754 secured_header_3.compute_signed_hash(),
755 secured_header_3.signature,
756 secured_header_3.content_creator_pub_key,
757 ),
758 ];
759 verify_signature_batch(&batch_2).unwrap();
760 }
761
762 #[test]
763 fn test_block_header_serde() {
764 let keypair = KeyPair::generate(0).unwrap();
765
766 let slot = Slot::new(7, 1);
767 let parents_1: Vec<BlockId> = (0..THREAD_COUNT)
768 .map(|i| BlockId::generate_from_hash(Hash::compute_from(&[i])))
769 .collect();
770
771 let endorsement_1 = Endorsement {
772 slot,
773 index: 1,
774 endorsed_block: parents_1[1],
775 };
776
777 assert_eq!(parents_1[1], endorsement_1.endorsed_block);
778
779 let s_endorsement_1: SecureShareEndorsement = Endorsement::new_verifiable(
780 endorsement_1,
781 EndorsementSerializer::new(),
782 &keypair,
783 *CHAINID,
784 )
785 .unwrap();
786
787 let (slot_a, _, s_header_1, s_header_2, _) = gen_block_headers_for_denunciation(None, None);
788 assert!(slot_a < slot);
789 let de_a = Denunciation::try_from((&s_header_1, &s_header_2)).unwrap();
790 let (slot_b, _, s_endo_1, s_endo_2, _) = gen_endorsements_for_denunciation(None, None);
791 assert!(slot_b < slot);
792 let de_b = Denunciation::try_from((&s_endo_1, &s_endo_2)).unwrap();
793
794 let block_header_1 = BlockHeader {
795 current_version: 0,
796 announced_version: None,
797 slot,
798 parents: parents_1,
799 operation_merkle_root: Hash::compute_from("mno".as_bytes()),
800 endorsements: vec![s_endorsement_1],
801 denunciations: vec![de_a, de_b],
802 };
803
804 let serialized_block_header = serde_json::to_string(&block_header_1).unwrap();
805 let res_block_header: Value = serde_json::from_str(&serialized_block_header).unwrap();
806 assert_eq!(
808 block_header_1.current_version,
809 res_block_header["current_version"]
810 );
811 assert_eq!(
812 block_header_1.slot.period,
813 res_block_header["slot"]["period"]
814 );
815 assert_eq!(
816 block_header_1.slot.thread,
817 res_block_header["slot"]["thread"]
818 );
819 }
820}