Skip to main content

celestia_types/
test_utils.rs

1//! Utilities for writing tests.
2use 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/// [`ExtendedHeader`] generator for testing purposes.
26///
27/// **WARNING: ALL METHODS PANIC! DO NOT USE IT IN PRODUCTION!**
28#[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    /// Creates new `ExtendedHeaderGenerator`.
38    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    /// Creates new `ExtendedHeaderGenerator` starting from specified height.
51    ///
52    /// ```
53    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
54    ///
55    /// let mut generator = ExtendedHeaderGenerator::new_from_height(5);
56    /// let header5 = generator.next();
57    /// ```
58    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    /// Generates the next header for a random non-empty data square.
78    ///
79    /// ```
80    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
81    ///
82    /// let mut generator = ExtendedHeaderGenerator::new();
83    /// let header1 = generator.next();
84    /// ```
85    #[allow(clippy::should_implement_trait)]
86    pub fn next(&mut self) -> ExtendedHeader {
87        self.next_impl(Some(generate_dah(8)))
88    }
89
90    /// Generates the next header for an empty data square.
91    ///
92    /// ```
93    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
94    ///
95    /// let mut generator = ExtendedHeaderGenerator::new();
96    /// let header1 = generator.next_empty();
97    /// ```
98    pub fn next_empty(&mut self) -> ExtendedHeader {
99        self.next_impl(None)
100    }
101
102    /// Generates the next header with the given [`DataAvailabilityHeader`]
103    ///
104    /// ```no_run
105    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
106    /// # fn generate_dah() -> celestia_types::DataAvailabilityHeader {
107    /// #    unimplemented!();
108    /// # }
109    ///
110    /// let mut generator = ExtendedHeaderGenerator::new();
111    /// let header1 = generator.next_with_dah(generate_dah());
112    /// ```
113    #[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    /// Generate the `amount` of subsequent non-empty headers.
130    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    /// Generate the `amount` of subsequent empty headers.
141    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    /// Generates the next header of the provided header.
150    ///
151    /// This can be used to create two headers of same height but different hash.
152    ///
153    /// ```
154    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
155    ///
156    /// let mut generator = ExtendedHeaderGenerator::new();
157    /// let header1 = generator.next();
158    /// let header2 = generator.next();
159    /// let another_header2 = generator.next_of(&header1);
160    /// ```
161    ///
162    /// # Note
163    ///
164    /// This method does not change the state of `ExtendedHeaderGenerator`.
165    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    /// Generates the next header of the provided header with the given [`DataAvailabilityHeader`].
174    ///
175    /// This can be used to create two headers of same height but different hash.
176    ///
177    /// ```no_run
178    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
179    /// # fn generate_dah() -> celestia_types::DataAvailabilityHeader {
180    /// #    unimplemented!();
181    /// # }
182    ///
183    /// let mut generator = ExtendedHeaderGenerator::new();
184    /// let header1 = generator.next();
185    /// let header2 = generator.next();
186    /// let another_header2 = generator.next_of_with_dah(&header1, generate_dah());
187    /// ```
188    ///
189    /// # Note
190    ///
191    /// This method does not change the state of `ExtendedHeaderGenerator`.
192    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    /// Generates the next amount of headers of the provided header.
205    ///
206    /// This can be used to create two chains of headers of same
207    /// heights but different hashes.
208    ///
209    /// ```
210    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
211    ///
212    /// let mut generator = ExtendedHeaderGenerator::new();
213    /// let header1 = generator.next();
214    /// let headers_2_to_12 = generator.next_many(10);
215    /// let another_headers_2_to_12 = generator.next_many_of(&header1, 10);
216    /// ```
217    ///
218    /// # Note
219    ///
220    /// This method does not change the state of `ExtendedHeaderGenerator`.
221    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    /// Generates the another header of the same height but different hash.
234    ///
235    /// ```
236    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
237    ///
238    /// let mut generator = ExtendedHeaderGenerator::new();
239    /// let header1 = generator.next();
240    /// let header2 = generator.next();
241    /// let another_header2 = generator.another_of(&header2);
242    /// ```
243    ///
244    /// # Note
245    ///
246    /// This method does not change the state of `ExtendedHeaderGenerator`.
247    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    /// Skips an amount of headers.
261    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    /// Create a "forked" generator for "forking" the chain.
277    ///
278    /// ```
279    /// use celestia_types::test_utils::ExtendedHeaderGenerator;
280    ///
281    /// let mut gen_chain1 = ExtendedHeaderGenerator::new();
282    ///
283    /// let header1 = gen_chain1.next();
284    /// let header2 = gen_chain1.next();
285    ///
286    /// let mut gen_chain2 = gen_chain1.fork();
287    ///
288    /// let header3_chain1 = gen_chain1.next();
289    /// let header3_chain2 = gen_chain2.next();
290    /// ```
291    ///
292    /// # Note
293    ///
294    /// This is the same as clone, but the name describes the intention.
295    pub fn fork(&self) -> ExtendedHeaderGenerator {
296        self.clone()
297    }
298
299    /// Change header generator time. Headers generated from now on will have `time` as creation
300    /// time.
301    pub fn set_time(&mut self, time: Time, block_time: Duration) {
302        self.spoofed_block_time = Some((time, block_time));
303    }
304
305    /// Reset header generator time, so that it produces headers with current timestamp
306    pub fn reset_time(&mut self) {
307        self.spoofed_block_time = None;
308    }
309
310    // private function which gets and increments generator time, since we cannot have multiple headers on the
311    // exact same timestamp
312    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
333/// Invalidate the provided header.
334///
335/// This can be combined with [`unverify`]
336pub fn invalidate(header: &mut ExtendedHeader) {
337    // One way of invalidate `ExtendedHeader` but still passes the
338    // verification check, is to clear `dah` but keep `data_hash` unchanged.
339    header.dah = DataAvailabilityHeader::new_unchecked(Vec::new(), Vec::new());
340
341    header.validate().unwrap_err();
342}
343
344/// Unverify the provided header.
345///
346/// This can be combined with [`invalidate`].
347pub fn unverify(header: &mut ExtendedHeader) {
348    let was_invalidated = header.validate().is_err();
349
350    // One way to unverify `ExtendedHeader` but still passes the
351    // validation check, is to sign it with a new key.
352    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
385/// Generate a dummy DAH, with semi-real namespace structure
386///
387/// Computes fake roots of an EDS where:
388/// - first share is PFB
389/// - second is primary padding
390/// - last is tail padding
391/// - each share between is a blob within unique namespace
392fn generate_dah(square_width: usize) -> DataAvailabilityHeader {
393    // allow minimum ODS to be 2x2, to not handle case with single
394    // share in ODS
395    assert!(square_width >= 4);
396
397    let ods_width = square_width / 2;
398
399    // toss random namespaces for our blobs. we do it for the whole ODS even tho
400    // 3 of those will be unused, but it makes operating on indexes simpler
401    let blob_namespaces: Vec<_> = (0..ods_width * ods_width)
402        .map(|n| {
403            let ns = [
404                // ensure ordering
405                (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    // within ODS, create hashes with proper min and max namespaces
424    // based on blobs namespaces we created earlier. Outside ODS
425    // everything is parity
426    let row_roots: Vec<_> = (0..ods_width)
427        .map(|n| {
428            let min_ns = match n {
429                0 => Namespace::PAY_FOR_BLOB,
430                _ => {
431                    // take blobs from first column
432                    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                // take blobs from last column
440                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                // take blobs from first row
458                _ => blob_namespaces[n],
459            };
460            let max_ns = if n == ods_width - 1 {
461                Namespace::TAIL_PADDING
462            } else {
463                // take blobs from last row
464                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
479/// Generate a properly encoded [`ExtendedDataSquare`] with random data.
480pub 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
498/// Generate a properly encoded [`ExtendedDataSquare`] with random data.
499///
500/// The generated EDS will try to mimic structure of the real blocks,
501/// having some shares from primary reserved namespace and padding shares.
502///
503/// The generated square will have PFB shares and primary reserved namespace padding
504/// in first ODS row. Then it will have a blob that spans 2 rows with padding.
505/// 4th row will have a blob with padding in the same namespace as the previous blob.
506/// Each next row have a blob in random namespace followed by padding, and last one
507/// is padded with tail padding namespace.
508///
509/// Minimum supported square_width is 8.
510pub 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    // pay for blob shares, only in first row
517    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; // first has sequence_start
520        [
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    // primary namespace padding
528    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    // fill rest of rows with user blobs
537    let mut namespaces: Vec<_> = (3..ods_width)
538        .map(|_| Namespace::const_v0(rand::random()))
539        .collect();
540    namespaces.sort();
541
542    // first blob is bigger so that it spans over 2 rows
543    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    // namespace padding
549    shares.extend(
550        (blob_shares - ods_width..ods_width)
551            .map(|_| [namespaces[0].as_bytes(), &[0; SHARE_SIZE - NS_SIZE][..]].concat()),
552    );
553
554    // rest of the blobs, starting with one in the same namespace as the big one before
555    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        // `next_of` and `next_many_of` does not change the state of the
919        // generator, so `next` must return height 6 header.
920        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        // Check that can be called multiple times
957        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        // Check that can be called multiple times
979        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        // check different order too
1009        unverify(&mut header6);
1010        invalidate(&mut header6);
1011
1012        header6.validate().unwrap_err();
1013        header5.verify(&header6).unwrap_err();
1014    }
1015}