1use std::iter;
3use std::time::Duration;
4
5use ed25519_consensus::SigningKey;
6use rand::RngCore;
7use tendermint::block::header::{Header, Version};
8use tendermint::block::{Commit, CommitSig, parts};
9use tendermint::public_key::PublicKey;
10use tendermint::{Signature, Time, chain};
11
12use crate::block::{CommitExt, GENESIS_HEIGHT};
13pub use crate::byzantine::test_utils::corrupt_eds;
14use crate::consts::appconsts::{
15 AppVersion, CONTINUATION_SPARSE_SHARE_CONTENT_SIZE, FIRST_SPARSE_SHARE_CONTENT_SIZE,
16 SHARE_INFO_BYTES, SHARE_SIZE,
17};
18use crate::consts::version;
19use crate::hash::{Hash, HashExt};
20use crate::nmt::{NS_SIZE, Namespace, NamespacedHash, NamespacedHashExt};
21use crate::{
22 Blob, DataAvailabilityHeader, ExtendedDataSquare, ExtendedHeader, Share, ValidatorSet,
23};
24
25#[derive(Debug, Clone)]
29pub struct ExtendedHeaderGenerator {
30 chain_id: chain::Id,
31 key: SigningKey,
32 current_header: Option<ExtendedHeader>,
33 spoofed_block_time: Option<(Time, Duration)>,
34}
35
36impl ExtendedHeaderGenerator {
37 pub fn new() -> ExtendedHeaderGenerator {
39 let chain_id: chain::Id = "private".try_into().unwrap();
40 let key = SigningKey::new(rand::thread_rng());
41
42 ExtendedHeaderGenerator {
43 chain_id,
44 key,
45 current_header: None,
46 spoofed_block_time: None,
47 }
48 }
49
50 pub fn new_from_height(height: u64) -> ExtendedHeaderGenerator {
59 let prev_height = height.saturating_sub(1);
60 let mut generator = ExtendedHeaderGenerator::new();
61
62 generator.current_header = if prev_height == 0 {
63 None
64 } else {
65 Some(generate_new(
66 prev_height,
67 &generator.chain_id,
68 Time::now(),
69 &generator.key,
70 None,
71 ))
72 };
73
74 generator
75 }
76
77 #[allow(clippy::should_implement_trait)]
86 pub fn next(&mut self) -> ExtendedHeader {
87 self.next_impl(Some(generate_dah(8)))
88 }
89
90 pub fn next_empty(&mut self) -> ExtendedHeader {
99 self.next_impl(None)
100 }
101
102 #[allow(clippy::should_implement_trait)]
114 pub fn next_with_dah(&mut self, dah: DataAvailabilityHeader) -> ExtendedHeader {
115 self.next_impl(Some(dah))
116 }
117
118 fn next_impl(&mut self, maybe_dah: Option<DataAvailabilityHeader>) -> ExtendedHeader {
119 let time = self.get_and_increment_time(1);
120 let header = match self.current_header {
121 Some(ref header) => generate_next(1, header, time, &self.key, maybe_dah),
122 None => generate_new(GENESIS_HEIGHT, &self.chain_id, time, &self.key, maybe_dah),
123 };
124
125 self.current_header = Some(header.clone());
126 header
127 }
128
129 pub fn next_many(&mut self, amount: u64) -> Vec<ExtendedHeader> {
131 let mut headers = Vec::with_capacity(amount as usize);
132
133 for _ in 0..amount {
134 headers.push(self.next());
135 }
136
137 headers
138 }
139
140 pub fn next_many_empty(&mut self, amount: u64) -> Vec<ExtendedHeader> {
142 let mut headers = Vec::with_capacity(amount as usize);
143 for _ in 0..amount {
144 headers.push(self.next_empty());
145 }
146 headers
147 }
148
149 pub fn next_of(&self, header: &ExtendedHeader) -> ExtendedHeader {
166 let time = self
167 .spoofed_block_time
168 .map(|t| t.0)
169 .unwrap_or_else(Time::now);
170 generate_next(1, header, time, &self.key, None)
171 }
172
173 pub fn next_of_with_dah(
193 &self,
194 header: &ExtendedHeader,
195 dah: DataAvailabilityHeader,
196 ) -> ExtendedHeader {
197 let time = self
198 .spoofed_block_time
199 .map(|t| t.0)
200 .unwrap_or_else(Time::now);
201 generate_next(1, header, time, &self.key, Some(dah))
202 }
203
204 pub fn next_many_of(&self, header: &ExtendedHeader, amount: u64) -> Vec<ExtendedHeader> {
222 let mut headers = Vec::with_capacity(amount as usize);
223
224 for _ in 0..amount {
225 let current_header = headers.last().unwrap_or(header);
226 let header = self.next_of(current_header);
227 headers.push(header);
228 }
229
230 headers
231 }
232
233 pub fn another_of(&self, header: &ExtendedHeader) -> ExtendedHeader {
248 let mut header = header.to_owned();
249
250 header.header.consensus_hash = Hash::Sha256(rand::random());
251 header.commit.block_id.part_set_header =
252 parts::Header::new(1, Hash::Sha256(rand::random())).expect("invalid PartSetHeader");
253
254 hash_and_sign(&mut header, &self.key);
255 header.validate().expect("invalid header generated");
256
257 header
258 }
259
260 pub fn skip(&mut self, amount: u64) {
262 if amount == 0 {
263 return;
264 }
265
266 let time = self.get_and_increment_time(amount);
267
268 let header = match self.current_header {
269 Some(ref header) => generate_next(amount, header, time, &self.key, None),
270 None => generate_new(amount, &self.chain_id, time, &self.key, None),
271 };
272
273 self.current_header = Some(header.clone());
274 }
275
276 pub fn fork(&self) -> ExtendedHeaderGenerator {
296 self.clone()
297 }
298
299 pub fn set_time(&mut self, time: Time, block_time: Duration) {
302 self.spoofed_block_time = Some((time, block_time));
303 }
304
305 pub fn reset_time(&mut self) {
307 self.spoofed_block_time = None;
308 }
309
310 fn get_and_increment_time(&mut self, amount: u64) -> Time {
313 let Some((spoofed_time, block_time)) = self.spoofed_block_time.take() else {
314 return Time::now();
315 };
316
317 let block_time_ms: u64 = block_time.as_millis().try_into().expect("u64 overflow");
318
319 let timestamp = (spoofed_time + Duration::from_millis(block_time_ms * amount))
320 .expect("not to overflow");
321 self.spoofed_block_time = Some((timestamp, block_time));
322
323 timestamp
324 }
325}
326
327impl Default for ExtendedHeaderGenerator {
328 fn default() -> Self {
329 ExtendedHeaderGenerator::new()
330 }
331}
332
333pub fn invalidate(header: &mut ExtendedHeader) {
337 header.dah = DataAvailabilityHeader::new_unchecked(Vec::new(), Vec::new());
340
341 header.validate().unwrap_err();
342}
343
344pub fn unverify(header: &mut ExtendedHeader) {
348 let was_invalidated = header.validate().is_err();
349
350 let key = SigningKey::new(rand::thread_rng());
353 let pub_key_bytes = key.verification_key().to_bytes();
354 let pub_key = PublicKey::from_raw_ed25519(&pub_key_bytes).unwrap();
355 let validator_address = tendermint::account::Id::from(pub_key);
356
357 header.header.proposer_address = validator_address;
358
359 header.validator_set = ValidatorSet::new(
360 vec![tendermint::validator::Info {
361 address: validator_address,
362 pub_key,
363 power: 5000_u32.into(),
364 name: None,
365 proposer_priority: 0_i64.into(),
366 }],
367 Some(tendermint::validator::Info {
368 address: validator_address,
369 pub_key,
370 power: 5000_u32.into(),
371 name: None,
372 proposer_priority: 0_i64.into(),
373 }),
374 );
375
376 hash_and_sign(header, &key);
377
378 if was_invalidated {
379 invalidate(header);
380 } else {
381 header.validate().expect("invalid header generated");
382 }
383}
384
385fn generate_dah(square_width: usize) -> DataAvailabilityHeader {
393 assert!(square_width >= 4);
396
397 let ods_width = square_width / 2;
398
399 let blob_namespaces: Vec<_> = (0..ods_width * ods_width)
402 .map(|n| {
403 let ns = [
404 (n as u32).to_be_bytes().as_slice(),
406 random_bytes(6).as_slice(),
407 ]
408 .concat();
409 Namespace::new_v0(&ns).unwrap()
410 })
411 .collect();
412
413 let random_namespaced_hash = |(min_ns, max_ns): (Namespace, Namespace)| {
414 let hash = [
415 min_ns.as_bytes(),
416 max_ns.as_bytes(),
417 random_bytes(32).as_slice(),
418 ]
419 .concat();
420 NamespacedHash::from_raw(&hash).unwrap()
421 };
422
423 let row_roots: Vec<_> = (0..ods_width)
427 .map(|n| {
428 let min_ns = match n {
429 0 => Namespace::PAY_FOR_BLOB,
430 _ => {
431 let first_blob_in_row = ods_width * n;
433 blob_namespaces[first_blob_in_row]
434 }
435 };
436 let max_ns = if n == ods_width - 1 {
437 Namespace::TAIL_PADDING
438 } else {
439 let last_blob_in_row = ods_width * (n + 1) - 1;
441 blob_namespaces[last_blob_in_row]
442 };
443 (min_ns, max_ns)
444 })
445 .chain(iter::repeat_n(
446 (Namespace::PARITY_SHARE, Namespace::PARITY_SHARE),
447 ods_width,
448 ))
449 .map(random_namespaced_hash)
450 .collect();
451
452 let col_roots: Vec<_> = (0..ods_width)
453 .map(|n| {
454 let min_ns = match n {
455 0 => Namespace::PAY_FOR_BLOB,
456 1 => Namespace::PRIMARY_RESERVED_PADDING,
457 _ => blob_namespaces[n],
459 };
460 let max_ns = if n == ods_width - 1 {
461 Namespace::TAIL_PADDING
462 } else {
463 let last_blob_in_col = ods_width * (ods_width - 1) + n;
465 blob_namespaces[last_blob_in_col]
466 };
467 (min_ns, max_ns)
468 })
469 .chain(iter::repeat_n(
470 (Namespace::PARITY_SHARE, Namespace::PARITY_SHARE),
471 ods_width,
472 ))
473 .map(random_namespaced_hash)
474 .collect();
475
476 DataAvailabilityHeader::new_unchecked(row_roots, col_roots)
477}
478
479pub fn generate_dummy_eds(square_width: usize, app_version: AppVersion) -> ExtendedDataSquare {
481 let ns = Namespace::const_v0(rand::random());
482 let ods_width = square_width / 2;
483
484 let shares: Vec<_> = (0..ods_width * ods_width)
485 .map(|_| {
486 [
487 ns.as_bytes(),
488 &[0; SHARE_INFO_BYTES][..],
489 &random_bytes(SHARE_SIZE - NS_SIZE - SHARE_INFO_BYTES)[..],
490 ]
491 .concat()
492 })
493 .collect();
494
495 ExtendedDataSquare::from_ods(shares, app_version).unwrap()
496}
497
498pub fn generate_eds(square_width: usize, app_version: AppVersion) -> ExtendedDataSquare {
511 assert!(square_width >= 8);
512
513 let ods_width = square_width / 2;
514 let mut shares = Vec::with_capacity(ods_width * ods_width);
515
516 let pfb_shares = (rand::random::<usize>() % (ods_width - 1)) + 1;
518 shares.extend((0..pfb_shares).map(|n| {
519 let info_byte = (n == 0) as u8; [
521 Namespace::PAY_FOR_BLOB.as_bytes(),
522 &[info_byte][..],
523 &random_bytes(SHARE_SIZE - NS_SIZE - SHARE_INFO_BYTES)[..],
524 ]
525 .concat()
526 }));
527 shares.extend((pfb_shares..ods_width).map(|_| {
529 [
530 Namespace::PRIMARY_RESERVED_PADDING.as_bytes(),
531 &[0; SHARE_SIZE - NS_SIZE][..],
532 ]
533 .concat()
534 }));
535
536 let mut namespaces: Vec<_> = (3..ods_width)
538 .map(|_| Namespace::const_v0(rand::random()))
539 .collect();
540 namespaces.sort();
541
542 let blob_shares = (rand::random::<usize>() % (ods_width - 1)) + ods_width + 1;
544 let data = random_bytes(blob_len(blob_shares));
545 let blob = Blob::new(namespaces[0], data, None, app_version).unwrap();
546 shares.extend(blob.to_shares().unwrap().iter().map(Share::to_vec));
547
548 shares.extend(
550 (blob_shares - ods_width..ods_width)
551 .map(|_| [namespaces[0].as_bytes(), &[0; SHARE_SIZE - NS_SIZE][..]].concat()),
552 );
553
554 for ns in &namespaces {
556 let blob_shares = (rand::random::<usize>() % (ods_width - 1)) + 1;
557 let data = random_bytes(blob_len(blob_shares));
558 let blob = Blob::new(*ns, data, None, app_version).unwrap();
559 shares.extend(blob.to_shares().unwrap().iter().map(Share::to_vec));
560
561 let padding_ns = if ns != namespaces.last().unwrap() {
562 *ns
563 } else {
564 Namespace::TAIL_PADDING
565 };
566 shares.extend(
567 (blob_shares..ods_width)
568 .map(|_| [padding_ns.as_bytes(), &[0; SHARE_SIZE - NS_SIZE][..]].concat()),
569 );
570 }
571
572 ExtendedDataSquare::from_ods(shares, app_version).unwrap()
573}
574
575fn blob_len(shares: usize) -> usize {
576 assert_ne!(shares, 0);
577 FIRST_SPARSE_SHARE_CONTENT_SIZE + (shares - 1) * CONTINUATION_SPARSE_SHARE_CONTENT_SIZE
578}
579
580pub(crate) fn random_bytes(len: usize) -> Vec<u8> {
581 let mut buf = vec![0u8; len];
582 rand::thread_rng().fill_bytes(&mut buf);
583 buf
584}
585
586fn generate_new(
587 height: u64,
588 chain_id: &chain::Id,
589 time: Time,
590 signing_key: &SigningKey,
591 dah: Option<DataAvailabilityHeader>,
592) -> ExtendedHeader {
593 assert!(height >= GENESIS_HEIGHT);
594
595 let pub_key_bytes = signing_key.verification_key().to_bytes();
596 let pub_key = PublicKey::from_raw_ed25519(&pub_key_bytes).unwrap();
597 let validator_address = tendermint::account::Id::from(pub_key);
598
599 let last_block_id = if height == GENESIS_HEIGHT {
600 None
601 } else {
602 Some(tendermint::block::Id {
603 hash: Hash::Sha256(rand::random()),
604 part_set_header: parts::Header::new(1, Hash::Sha256(rand::random()))
605 .expect("invalid PartSetHeader"),
606 })
607 };
608
609 let mut header = ExtendedHeader {
610 header: Header {
611 version: Version {
612 block: version::BLOCK_PROTOCOL,
613 app: 1,
614 },
615 chain_id: chain_id.clone(),
616 height: height.try_into().unwrap(),
617 time,
618 last_block_id,
619 last_commit_hash: Some(Hash::default_sha256()),
620 data_hash: Some(Hash::None),
621 validators_hash: Hash::None,
622 next_validators_hash: Hash::None,
623 consensus_hash: Hash::Sha256(rand::random()),
624 app_hash: Hash::default_sha256()
625 .as_bytes()
626 .to_vec()
627 .try_into()
628 .unwrap(),
629 last_results_hash: Some(Hash::default_sha256()),
630 evidence_hash: Some(Hash::default_sha256()),
631 proposer_address: validator_address,
632 },
633 commit: Commit {
634 height: height.try_into().unwrap(),
635 round: 0_u16.into(),
636 block_id: tendermint::block::Id {
637 hash: Hash::None,
638 part_set_header: parts::Header::new(1, Hash::Sha256(rand::random()))
639 .expect("invalid PartSetHeader"),
640 },
641 signatures: vec![CommitSig::BlockIdFlagCommit {
642 validator_address,
643 timestamp: time,
644 signature: None,
645 }],
646 },
647 validator_set: ValidatorSet::new(
648 vec![tendermint::validator::Info {
649 address: validator_address,
650 pub_key,
651 power: 5000_u32.into(),
652 name: None,
653 proposer_priority: 0_i64.into(),
654 }],
655 Some(tendermint::validator::Info {
656 address: validator_address,
657 pub_key,
658 power: 5000_u32.into(),
659 name: None,
660 proposer_priority: 0_i64.into(),
661 }),
662 ),
663 dah: dah.unwrap_or_else(|| DataAvailabilityHeader::from_eds(&ExtendedDataSquare::empty())),
664 };
665
666 hash_and_sign(&mut header, signing_key);
667 header.validate().expect("invalid header generated");
668
669 header
670}
671
672fn generate_next(
673 increment: u64,
674 current: &ExtendedHeader,
675 time: Time,
676 signing_key: &SigningKey,
677 dah: Option<DataAvailabilityHeader>,
678) -> ExtendedHeader {
679 assert!(increment > 0);
680
681 let validator_address = current.validator_set.validators()[0].address;
682
683 let height = (current.header.height.value() + increment)
684 .try_into()
685 .unwrap();
686
687 let last_block_id = if increment == 1 {
688 Some(current.commit.block_id)
689 } else {
690 Some(tendermint::block::Id {
691 hash: Hash::Sha256(rand::random()),
692 part_set_header: parts::Header::new(1, Hash::Sha256(rand::random()))
693 .expect("invalid PartSetHeader"),
694 })
695 };
696
697 let mut header = ExtendedHeader {
698 header: Header {
699 version: current.header.version,
700 chain_id: current.header.chain_id.clone(),
701 height,
702 time,
703 last_block_id,
704 last_commit_hash: Some(Hash::default_sha256()),
705 data_hash: Some(Hash::None),
706 validators_hash: Hash::None,
707 next_validators_hash: Hash::None,
708 consensus_hash: Hash::Sha256(rand::random()),
709 app_hash: Hash::default_sha256()
710 .as_bytes()
711 .to_vec()
712 .try_into()
713 .unwrap(),
714 last_results_hash: Some(Hash::default_sha256()),
715 evidence_hash: Some(Hash::default_sha256()),
716 proposer_address: validator_address,
717 },
718 commit: Commit {
719 height,
720 round: 0_u16.into(),
721 block_id: tendermint::block::Id {
722 hash: Hash::None,
723 part_set_header: parts::Header::new(1, Hash::Sha256(rand::random()))
724 .expect("invalid PartSetHeader"),
725 },
726 signatures: vec![CommitSig::BlockIdFlagCommit {
727 validator_address,
728 timestamp: time,
729 signature: None,
730 }],
731 },
732 validator_set: current.validator_set.clone(),
733 dah: dah.unwrap_or_else(|| DataAvailabilityHeader::from_eds(&ExtendedDataSquare::empty())),
734 };
735
736 hash_and_sign(&mut header, signing_key);
737 header.validate().expect("invalid header generated");
738 current.verify(&header).expect("invalid header generated");
739
740 header
741}
742
743fn hash_and_sign(header: &mut ExtendedHeader, signing_key: &SigningKey) {
744 header.header.validators_hash = header.validator_set.hash();
745 header.header.next_validators_hash = header.validator_set.hash();
746 header.header.data_hash = Some(header.dah.hash());
747 header.commit.block_id.hash = header.header.hash();
748
749 let vote_sign = header
750 .commit
751 .vote_sign_bytes(&header.header.chain_id, 0)
752 .unwrap();
753 let sig = signing_key.sign(&vote_sign).to_bytes();
754
755 match header.commit.signatures[0] {
756 CommitSig::BlockIdFlagAbsent => {}
757 CommitSig::BlockIdFlagNil {
758 ref mut signature, ..
759 }
760 | CommitSig::BlockIdFlagCommit {
761 ref mut signature, ..
762 } => {
763 *signature = Some(Signature::new(sig).unwrap().unwrap());
764 }
765 }
766}
767
768#[cfg(test)]
769mod tests {
770 use super::*;
771
772 #[cfg(target_arch = "wasm32")]
773 use wasm_bindgen_test::wasm_bindgen_test as test;
774
775 #[test]
776 fn generate_blocks() {
777 let mut generator = ExtendedHeaderGenerator::new();
778
779 let genesis = generator.next();
780 assert_eq!(genesis.height(), 1);
781
782 let height2 = generator.next();
783 assert_eq!(height2.height(), 2);
784
785 let another_height2 = generator.next_of(&genesis);
786 assert_eq!(another_height2.height(), 2);
787
788 genesis.verify(&height2).unwrap();
789 genesis.verify(&another_height2).unwrap();
790
791 assert_ne!(height2.hash(), another_height2.hash());
792 }
793
794 #[test]
795 fn generate_and_verify_range() {
796 let mut generator = ExtendedHeaderGenerator::new();
797
798 let genesis = generator.next();
799 assert_eq!(genesis.height(), 1);
800
801 let headers = generator.next_many(256);
802 assert_eq!(headers.last().unwrap().height(), 257);
803
804 genesis.verify_adjacent_range(&headers).unwrap();
805 genesis.verify_range(&headers[10..]).unwrap();
806
807 headers[0].verify_adjacent_range(&headers[1..]).unwrap();
808 headers[0].verify_range(&headers[10..]).unwrap();
809
810 headers[5].verify_adjacent_range(&headers[6..]).unwrap();
811 headers[5].verify_range(&headers[10..]).unwrap();
812 }
813
814 #[test]
815 fn generate_and_skip() {
816 let mut generator = ExtendedHeaderGenerator::new();
817
818 let genesis = generator.next();
819 generator.skip(3);
820 let header5 = generator.next();
821
822 assert_eq!(genesis.height(), 1);
823 assert_eq!(header5.height(), 5);
824 genesis.verify(&header5).unwrap();
825 }
826
827 #[test]
828 fn new_and_skip() {
829 let mut generator = ExtendedHeaderGenerator::new();
830
831 generator.skip(3);
832 let header4 = generator.next();
833 let header5 = generator.next();
834
835 assert_eq!(header4.height(), 4);
836 assert_eq!(header5.height(), 5);
837 header4.verify(&header5).unwrap();
838
839 let mut generator = ExtendedHeaderGenerator::new();
840
841 generator.skip(1);
842 let header2 = generator.next();
843 let header3 = generator.next();
844
845 assert_eq!(header2.height(), 2);
846 assert_eq!(header3.height(), 3);
847 header2.verify(&header3).unwrap();
848
849 let mut generator = ExtendedHeaderGenerator::new();
850
851 generator.skip(0);
852 let genesis = generator.next();
853 let header2 = generator.next();
854
855 assert_eq!(genesis.height(), 1);
856 assert_eq!(header2.height(), 2);
857 genesis.verify(&header2).unwrap();
858 }
859
860 #[test]
861 fn new_from_height() {
862 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
863 let header5 = generator.next();
864 assert_eq!(header5.height(), 5);
865
866 let mut generator = ExtendedHeaderGenerator::new_from_height(1);
867 let header1 = generator.next();
868 assert_eq!(header1.height(), 1);
869
870 let mut generator = ExtendedHeaderGenerator::new_from_height(0);
871 let header1 = generator.next();
872 assert_eq!(header1.height(), 1);
873 }
874
875 #[test]
876 fn generate_next_of() {
877 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
878
879 let header5 = generator.next();
880 let header6 = generator.next();
881 let _header7 = generator.next();
882 let another_header6 = generator.next_of(&header5);
883
884 header5.verify(&header6).unwrap();
885 header5.verify(&another_header6).unwrap();
886
887 assert_eq!(header6.height(), 6);
888 assert_eq!(another_header6.height(), 6);
889 assert_ne!(header6.hash(), another_header6.hash());
890 }
891
892 #[test]
893 fn generate_next_many_of() {
894 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
895
896 let header5 = generator.next();
897 let header6 = generator.next();
898 let _header7 = generator.next();
899 let another_header_6_to_10 = generator.next_many_of(&header5, 5);
900
901 header5.verify(&header6).unwrap();
902 header5
903 .verify_adjacent_range(&another_header_6_to_10)
904 .unwrap();
905
906 assert_eq!(another_header_6_to_10.len(), 5);
907 assert_eq!(header6.height(), 6);
908 assert_eq!(another_header_6_to_10[0].height(), 6);
909 assert_ne!(header6.hash(), another_header_6_to_10[0].hash());
910 }
911
912 #[test]
913 fn gen_next_after_next_many_of() {
914 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
915
916 let header5 = generator.next();
917 let another_header_6_to_10 = generator.next_many_of(&header5, 5);
918 let header6 = generator.next();
921
922 header5.verify(&header6).unwrap();
923 header5
924 .verify_adjacent_range(&another_header_6_to_10)
925 .unwrap();
926
927 assert_eq!(another_header_6_to_10.len(), 5);
928 assert_eq!(header6.height(), 6);
929 assert_eq!(another_header_6_to_10[0].height(), 6);
930 assert_ne!(header6.hash(), another_header_6_to_10[0].hash());
931 }
932
933 #[test]
934 fn generate_another_of() {
935 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
936
937 let header5 = generator.next();
938 let header6 = generator.next();
939
940 let another_header6 = generator.another_of(&header6);
941
942 header5.verify(&header6).unwrap();
943 header5.verify(&another_header6).unwrap();
944 }
945
946 #[test]
947 fn invalidate_header() {
948 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
949
950 let header5 = generator.next();
951 let mut header6 = generator.next();
952 let mut header7 = generator.next();
953
954 invalidate(&mut header6);
955
956 invalidate(&mut header7);
958 invalidate(&mut header7);
959 invalidate(&mut header7);
960
961 header6.validate().unwrap_err();
962 header5.verify(&header6).unwrap();
963
964 header7.validate().unwrap_err();
965 header5.verify(&header7).unwrap();
966 }
967
968 #[test]
969 fn unverify_header() {
970 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
971
972 let header5 = generator.next();
973 let mut header6 = generator.next();
974 let mut header7 = generator.next();
975
976 unverify(&mut header6);
977
978 unverify(&mut header7);
980 unverify(&mut header7);
981 unverify(&mut header7);
982
983 header6.validate().unwrap();
984 header5.verify(&header6).unwrap_err();
985
986 header7.validate().unwrap();
987 header5.verify(&header7).unwrap_err();
988 }
989
990 #[test]
991 fn invalidate_and_unverify_header() {
992 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
993
994 let header5 = generator.next();
995 let mut header6 = generator.next();
996
997 invalidate(&mut header6);
998 unverify(&mut header6);
999
1000 header6.validate().unwrap_err();
1001 header5.verify(&header6).unwrap_err();
1002
1003 let mut generator = ExtendedHeaderGenerator::new_from_height(5);
1004
1005 let header5 = generator.next();
1006 let mut header6 = generator.next();
1007
1008 unverify(&mut header6);
1010 invalidate(&mut header6);
1011
1012 header6.validate().unwrap_err();
1013 header5.verify(&header6).unwrap_err();
1014 }
1015}