Skip to main content

near_primitives/
block_header.rs

1use crate::challenge::SlashedValidator;
2use crate::hash::{CryptoHash, hash};
3use crate::merkle::combine_hash;
4use crate::network::PeerId;
5use crate::stateless_validation::chunk_endorsements_bitmap::ChunkEndorsementsBitmap;
6use crate::types::validator_stake::{ValidatorStake, ValidatorStakeIter, ValidatorStakeV1};
7use crate::types::{
8    AccountId, Balance, BlockHeight, EpochId, MerkleHash, NumBlocks, ShardId,
9    SpiceChunkEndorsementStats,
10};
11use crate::validator_signer::ValidatorSigner;
12use crate::version::ProtocolVersion;
13use borsh::{BorshDeserialize, BorshSerialize};
14use near_crypto::{KeyType, PublicKey, Signature};
15use near_primitives_core::version::ProtocolFeature;
16use near_schema_checker_lib::ProtocolSchema;
17use near_time::Utc;
18
19#[derive(
20    BorshSerialize,
21    BorshDeserialize,
22    serde::Serialize,
23    Debug,
24    Clone,
25    Eq,
26    PartialEq,
27    Default,
28    ProtocolSchema,
29)]
30pub struct BlockHeaderInnerLite {
31    /// Height of this block.
32    pub height: BlockHeight,
33    /// Epoch start hash of this block's epoch.
34    /// Used for retrieving validator information
35    pub epoch_id: EpochId,
36    pub next_epoch_id: EpochId,
37    /// Root hash of the state at the previous block.
38    pub prev_state_root: MerkleHash,
39    /// Root of the outcomes of transactions and receipts from the previous chunks.
40    pub prev_outcome_root: MerkleHash,
41    /// Timestamp at which the block was built (number of non-leap-nanoseconds since January 1, 1970 0:00:00 UTC).
42    pub timestamp: u64,
43    /// Hash of the next epoch block producers set
44    pub next_bp_hash: CryptoHash,
45    /// Merkle root of block hashes up to the current block.
46    pub block_merkle_root: CryptoHash,
47}
48
49#[derive(
50    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
51)]
52pub struct BlockHeaderInnerRest {
53    /// Root hash of the previous chunks' outgoing receipts in the given block.
54    pub prev_chunk_outgoing_receipts_root: MerkleHash,
55    /// Root hash of the chunk headers in the given block.
56    pub chunk_headers_root: MerkleHash,
57    /// Root hash of the chunk transactions in the given block.
58    pub chunk_tx_root: MerkleHash,
59    /// Number of chunks included into the block.
60    pub chunks_included: u64,
61    /// Root hash of the challenges in the given block.
62    #[deprecated]
63    pub challenges_root: MerkleHash,
64    /// The output of the randomness beacon
65    pub random_value: CryptoHash,
66    /// Validator proposals from the previous chunks.
67    pub prev_validator_proposals: Vec<ValidatorStakeV1>,
68    /// Mask for new chunks included in the block
69    pub chunk_mask: Vec<bool>,
70    /// Gas price for chunks in the next block.
71    pub next_gas_price: Balance,
72    /// Total supply of tokens in the system
73    pub total_supply: Balance,
74    /// List of challenges result from previous block.
75    #[deprecated]
76    pub challenges_result: Vec<SlashedValidator>,
77
78    /// Last block that has full BFT finality
79    pub last_final_block: CryptoHash,
80    /// Last block that has doomslug finality
81    pub last_ds_final_block: CryptoHash,
82
83    /// All the approvals included in this block
84    pub approvals: Vec<Option<Box<Signature>>>,
85
86    /// Latest protocol version that this block producer has.
87    pub latest_protocol_version: ProtocolVersion,
88}
89
90/// Remove `chunks_included` from V1
91#[derive(
92    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
93)]
94pub struct BlockHeaderInnerRestV2 {
95    /// Root hash of the previous chunks' outgoing receipts in the given block.
96    pub prev_chunk_outgoing_receipts_root: MerkleHash,
97    /// Root hash of the chunk headers in the given block.
98    pub chunk_headers_root: MerkleHash,
99    /// Root hash of the chunk transactions in the given block.
100    pub chunk_tx_root: MerkleHash,
101    /// Root hash of the challenges in the given block.
102    #[deprecated]
103    pub challenges_root: MerkleHash,
104    /// The output of the randomness beacon
105    pub random_value: CryptoHash,
106    /// Validator proposals from the previous chunks.
107    pub prev_validator_proposals: Vec<ValidatorStakeV1>,
108    /// Mask for new chunks included in the block
109    pub chunk_mask: Vec<bool>,
110    /// Gas price for chunks in the next block.
111    pub next_gas_price: Balance,
112    /// Total supply of tokens in the system
113    pub total_supply: Balance,
114    /// List of challenges result from previous block.
115    #[deprecated]
116    pub challenges_result: Vec<SlashedValidator>,
117
118    /// Last block that has full BFT finality
119    pub last_final_block: CryptoHash,
120    /// Last block that has doomslug finality
121    pub last_ds_final_block: CryptoHash,
122
123    /// All the approvals included in this block
124    pub approvals: Vec<Option<Box<Signature>>>,
125
126    /// Latest protocol version that this block producer has.
127    pub latest_protocol_version: ProtocolVersion,
128}
129
130/// Add `prev_height`
131/// Add `block_ordinal`
132/// Add `epoch_sync_data_hash`
133/// Use new `ValidatorStake` struct
134#[derive(
135    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
136)]
137pub struct BlockHeaderInnerRestV3 {
138    /// Root hash of the previous chunks' outgoing receipts in the given block.
139    pub prev_chunk_outgoing_receipts_root: MerkleHash,
140    /// Root hash of the chunk headers in the given block.
141    pub chunk_headers_root: MerkleHash,
142    /// Root hash of the chunk transactions in the given block.
143    pub chunk_tx_root: MerkleHash,
144    /// Root hash of the challenges in the given block.
145    #[deprecated]
146    pub challenges_root: MerkleHash,
147    /// The output of the randomness beacon
148    pub random_value: CryptoHash,
149    /// Validator proposals from the previous chunks.
150    pub prev_validator_proposals: Vec<ValidatorStake>,
151    /// Mask for new chunks included in the block
152    pub chunk_mask: Vec<bool>,
153    /// Gas price for chunks in the next block.
154    pub next_gas_price: Balance,
155    /// Total supply of tokens in the system
156    pub total_supply: Balance,
157    /// List of challenges result from previous block.
158    #[deprecated]
159    pub challenges_result: Vec<SlashedValidator>,
160
161    /// Last block that has full BFT finality
162    pub last_final_block: CryptoHash,
163    /// Last block that has doomslug finality
164    pub last_ds_final_block: CryptoHash,
165
166    /// The ordinal of the Block on the Canonical Chain
167    pub block_ordinal: NumBlocks,
168
169    pub prev_height: BlockHeight,
170
171    pub epoch_sync_data_hash: Option<CryptoHash>,
172
173    /// All the approvals included in this block
174    pub approvals: Vec<Option<Box<Signature>>>,
175
176    /// Latest protocol version that this block producer has.
177    pub latest_protocol_version: ProtocolVersion,
178}
179
180/// Add `block_body_hash`
181#[derive(
182    BorshSerialize,
183    BorshDeserialize,
184    serde::Serialize,
185    Debug,
186    Clone,
187    Eq,
188    PartialEq,
189    Default,
190    ProtocolSchema,
191)]
192pub struct BlockHeaderInnerRestV4 {
193    /// Hash of block body
194    pub block_body_hash: CryptoHash,
195    /// Root hash of the previous chunks' outgoing receipts in the given block.
196    pub prev_chunk_outgoing_receipts_root: MerkleHash,
197    /// Root hash of the chunk headers in the given block.
198    pub chunk_headers_root: MerkleHash,
199    /// Root hash of the chunk transactions in the given block.
200    pub chunk_tx_root: MerkleHash,
201    /// Root hash of the challenges in the given block.
202    #[deprecated]
203    pub challenges_root: MerkleHash,
204    /// The output of the randomness beacon
205    pub random_value: CryptoHash,
206    /// Validator proposals from the previous chunks.
207    pub prev_validator_proposals: Vec<ValidatorStake>,
208    /// Mask for new chunks included in the block
209    pub chunk_mask: Vec<bool>,
210    /// Gas price for chunks in the next block.
211    pub next_gas_price: Balance,
212    /// Total supply of tokens in the system
213    pub total_supply: Balance,
214    /// List of challenges result from previous block.
215    #[deprecated]
216    pub challenges_result: Vec<SlashedValidator>,
217
218    /// Last block that has full BFT finality
219    pub last_final_block: CryptoHash,
220    /// Last block that has doomslug finality
221    pub last_ds_final_block: CryptoHash,
222
223    /// The ordinal of the Block on the Canonical Chain
224    pub block_ordinal: NumBlocks,
225
226    pub prev_height: BlockHeight,
227
228    pub epoch_sync_data_hash: Option<CryptoHash>,
229
230    /// All the approvals included in this block
231    pub approvals: Vec<Option<Box<Signature>>>,
232
233    /// Latest protocol version that this block producer has.
234    pub latest_protocol_version: ProtocolVersion,
235}
236
237/// Add `chunk_endorsements`
238#[derive(
239    BorshSerialize,
240    BorshDeserialize,
241    serde::Serialize,
242    Debug,
243    Clone,
244    Eq,
245    PartialEq,
246    Default,
247    ProtocolSchema,
248)]
249pub struct BlockHeaderInnerRestV5 {
250    /// Hash of block body
251    pub block_body_hash: CryptoHash,
252    /// Root hash of the previous chunks' outgoing receipts in the given block.
253    pub prev_chunk_outgoing_receipts_root: MerkleHash,
254    /// Root hash of the chunk headers in the given block.
255    pub chunk_headers_root: MerkleHash,
256    /// Root hash of the chunk transactions in the given block.
257    pub chunk_tx_root: MerkleHash,
258    /// Root hash of the challenges in the given block.
259    #[deprecated]
260    pub challenges_root: MerkleHash,
261    /// The output of the randomness beacon
262    pub random_value: CryptoHash,
263    /// Validator proposals from the previous chunks.
264    pub prev_validator_proposals: Vec<ValidatorStake>,
265    /// Mask for new chunks included in the block
266    pub chunk_mask: Vec<bool>,
267    /// Gas price for chunks in the next block.
268    pub next_gas_price: Balance,
269    /// Total supply of tokens in the system
270    pub total_supply: Balance,
271    /// List of challenges result from previous block.
272    #[deprecated]
273    pub challenges_result: Vec<SlashedValidator>,
274
275    /// Last block that has full BFT finality
276    pub last_final_block: CryptoHash,
277    /// Last block that has doomslug finality
278    pub last_ds_final_block: CryptoHash,
279
280    /// The ordinal of the Block on the Canonical Chain
281    pub block_ordinal: NumBlocks,
282
283    pub prev_height: BlockHeight,
284
285    pub epoch_sync_data_hash: Option<CryptoHash>,
286
287    /// All the approvals included in this block
288    pub approvals: Vec<Option<Box<Signature>>>,
289
290    /// Latest protocol version that this block producer has.
291    pub latest_protocol_version: ProtocolVersion,
292
293    pub chunk_endorsements: ChunkEndorsementsBitmap,
294}
295
296/// Add `shard_split`, remove challenges
297#[derive(
298    BorshSerialize,
299    BorshDeserialize,
300    serde::Serialize,
301    Debug,
302    Clone,
303    Eq,
304    PartialEq,
305    Default,
306    ProtocolSchema,
307)]
308pub struct BlockHeaderInnerRestV6 {
309    /// Hash of block body
310    pub block_body_hash: CryptoHash,
311    /// Root hash of the previous chunks' outgoing receipts in the given block.
312    pub prev_chunk_outgoing_receipts_root: MerkleHash,
313    /// Root hash of the chunk headers in the given block.
314    pub chunk_headers_root: MerkleHash,
315    /// Root hash of the chunk transactions in the given block.
316    pub chunk_tx_root: MerkleHash,
317    /// The output of the randomness beacon
318    pub random_value: CryptoHash,
319    /// Validator proposals from the previous chunks.
320    pub prev_validator_proposals: Vec<ValidatorStake>,
321    /// Mask for new chunks included in the block
322    pub chunk_mask: Vec<bool>,
323    /// Gas price for chunks in the next block.
324    pub next_gas_price: Balance,
325    /// Total supply of tokens in the system
326    pub total_supply: Balance,
327
328    /// Last block that has full BFT finality
329    pub last_final_block: CryptoHash,
330    /// Last block that has doomslug finality
331    pub last_ds_final_block: CryptoHash,
332
333    /// The ordinal of the Block on the Canonical Chain
334    pub block_ordinal: NumBlocks,
335
336    pub prev_height: BlockHeight,
337
338    pub epoch_sync_data_hash: Option<CryptoHash>,
339
340    /// All the approvals included in this block
341    pub approvals: Vec<Option<Box<Signature>>>,
342
343    /// Latest protocol version that this block producer has.
344    pub latest_protocol_version: ProtocolVersion,
345
346    pub chunk_endorsements: ChunkEndorsementsBitmap,
347
348    /// Shard ID and boundary account for the upcoming resharding.
349    /// This field may be set only for the last block of an epoch.
350    /// Split proposed at the end of epoch N will be executed in epoch N+2.
351    pub shard_split: Option<(ShardId, AccountId)>,
352}
353
354/// Add spice fields
355#[derive(
356    BorshSerialize,
357    BorshDeserialize,
358    serde::Serialize,
359    Debug,
360    Clone,
361    Eq,
362    PartialEq,
363    Default,
364    ProtocolSchema,
365)]
366pub struct BlockHeaderInnerRestV7 {
367    /// Hash of block body
368    pub block_body_hash: CryptoHash,
369    /// Root hash of the previous chunks' outgoing receipts in the given block.
370    pub prev_chunk_outgoing_receipts_root: MerkleHash,
371    /// Root hash of the chunk headers in the given block.
372    pub chunk_headers_root: MerkleHash,
373    /// Root hash of the chunk transactions in the given block.
374    pub chunk_tx_root: MerkleHash,
375    /// The output of the randomness beacon
376    pub random_value: CryptoHash,
377    /// Validator proposals from the previous chunks.
378    pub prev_validator_proposals: Vec<ValidatorStake>,
379    /// Mask for new chunks included in the block
380    pub chunk_mask: Vec<bool>,
381    /// Gas price for chunks in the next block.
382    pub next_gas_price: Balance,
383    /// Total supply of tokens in the system
384    pub total_supply: Balance,
385
386    /// Last block that has full BFT finality
387    pub last_final_block: CryptoHash,
388    /// Last block that has doomslug finality
389    pub last_ds_final_block: CryptoHash,
390
391    /// The ordinal of the Block on the Canonical Chain
392    pub block_ordinal: NumBlocks,
393
394    pub prev_height: BlockHeight,
395
396    pub epoch_sync_data_hash: Option<CryptoHash>,
397
398    /// All the approvals included in this block
399    pub approvals: Vec<Option<Box<Signature>>>,
400
401    /// Latest protocol version that this block producer has.
402    pub latest_protocol_version: ProtocolVersion,
403
404    pub chunk_endorsements: ChunkEndorsementsBitmap,
405
406    /// Shard ID and boundary account for the upcoming resharding.
407    /// This field may be set only for the last block of an epoch.
408    /// Split proposed at the end of epoch N will be executed in epoch N+2.
409    pub shard_split: Option<(ShardId, AccountId)>,
410
411    /// Epoch ID of the last block whose spice execution results are certified.
412    pub prev_last_certified_block_epoch_id: EpochId,
413
414    /// Per-validator chunk endorsement stats accumulated over the epoch,
415    /// indexed by the current epoch's validator id. Set only on the last block
416    /// of an epoch (empty otherwise); consumed by reward and kickout.
417    pub spice_chunk_endorsement_stats: Vec<SpiceChunkEndorsementStats>,
418}
419
420/// The part of the block approval that is different for endorsements and skips
421#[derive(
422    BorshSerialize,
423    BorshDeserialize,
424    serde::Serialize,
425    Debug,
426    Clone,
427    PartialEq,
428    Eq,
429    Hash,
430    ProtocolSchema,
431)]
432#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
433pub enum ApprovalInner {
434    Endorsement(CryptoHash),
435    Skip(BlockHeight),
436}
437
438/// Block approval by other block producers with a signature
439#[derive(
440    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, ProtocolSchema,
441)]
442pub struct Approval {
443    pub inner: ApprovalInner,
444    pub target_height: BlockHeight,
445    pub signature: Signature,
446    pub account_id: AccountId,
447}
448
449/// The type of approvals. It is either approval from self or from a peer
450#[derive(PartialEq, Eq, Debug)]
451pub enum ApprovalType {
452    SelfApproval,
453    PeerApproval(PeerId),
454}
455
456/// Block approval by other block producers.
457#[derive(
458    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, ProtocolSchema,
459)]
460pub struct ApprovalMessage {
461    pub approval: Approval,
462    pub target: AccountId,
463}
464
465impl ApprovalInner {
466    pub fn new(
467        parent_hash: &CryptoHash,
468        parent_height: BlockHeight,
469        target_height: BlockHeight,
470    ) -> Self {
471        if target_height == parent_height + 1 {
472            ApprovalInner::Endorsement(*parent_hash)
473        } else {
474            ApprovalInner::Skip(parent_height)
475        }
476    }
477}
478
479impl Approval {
480    pub fn new(
481        parent_hash: CryptoHash,
482        parent_height: BlockHeight,
483        target_height: BlockHeight,
484        signer: &ValidatorSigner,
485    ) -> Self {
486        let inner = ApprovalInner::new(&parent_hash, parent_height, target_height);
487
488        let signature = signer.sign_bytes(&Approval::get_data_for_sig(&inner, target_height));
489        Approval { inner, target_height, signature, account_id: signer.validator_id().clone() }
490    }
491
492    pub fn get_data_for_sig(inner: &ApprovalInner, target_height: BlockHeight) -> Vec<u8> {
493        [borsh::to_vec(&inner).unwrap().as_ref(), target_height.to_le_bytes().as_ref()].concat()
494    }
495}
496
497impl ApprovalMessage {
498    pub fn new(approval: Approval, target: AccountId) -> Self {
499        ApprovalMessage { approval, target }
500    }
501}
502
503#[derive(
504    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
505)]
506#[borsh(init=init)]
507pub struct BlockHeaderV1 {
508    pub prev_hash: CryptoHash,
509
510    /// Inner part of the block header that gets hashed, split into two parts, one that is sent
511    ///    to light clients, and the rest
512    pub inner_lite: BlockHeaderInnerLite,
513    pub inner_rest: BlockHeaderInnerRest,
514
515    /// Signature of the block producer.
516    pub signature: Signature,
517
518    /// Cached value of hash for this block.
519    #[borsh(skip)]
520    pub hash: CryptoHash,
521}
522
523impl BlockHeaderV1 {
524    pub fn init(&mut self) {
525        self.hash = BlockHeader::compute_hash(
526            self.prev_hash,
527            &borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
528            &borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
529        );
530    }
531}
532
533/// V1 -> V2: Remove `chunks_included` from `inner_reset`
534#[derive(
535    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
536)]
537#[borsh(init=init)]
538pub struct BlockHeaderV2 {
539    pub prev_hash: CryptoHash,
540
541    /// Inner part of the block header that gets hashed, split into two parts, one that is sent
542    ///    to light clients, and the rest
543    pub inner_lite: BlockHeaderInnerLite,
544    pub inner_rest: BlockHeaderInnerRestV2,
545
546    /// Signature of the block producer.
547    pub signature: Signature,
548
549    /// Cached value of hash for this block.
550    #[borsh(skip)]
551    pub hash: CryptoHash,
552}
553
554/// V2 -> V3: Add `prev_height` to `inner_rest` and use new `ValidatorStake`
555// Add `block_ordinal` to `inner_rest`
556#[derive(
557    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
558)]
559#[borsh(init=init)]
560pub struct BlockHeaderV3 {
561    pub prev_hash: CryptoHash,
562
563    /// Inner part of the block header that gets hashed, split into two parts, one that is sent
564    ///    to light clients, and the rest
565    pub inner_lite: BlockHeaderInnerLite,
566    pub inner_rest: BlockHeaderInnerRestV3,
567
568    /// Signature of the block producer.
569    pub signature: Signature,
570
571    /// Cached value of hash for this block.
572    #[borsh(skip)]
573    pub hash: CryptoHash,
574}
575
576/// V3 -> V4: Add hash of block body to inner_rest
577#[derive(
578    BorshSerialize,
579    BorshDeserialize,
580    serde::Serialize,
581    Debug,
582    Clone,
583    Eq,
584    PartialEq,
585    Default,
586    ProtocolSchema,
587)]
588#[borsh(init=init)]
589pub struct BlockHeaderV4 {
590    pub prev_hash: CryptoHash,
591
592    /// Inner part of the block header that gets hashed, split into two parts, one that is sent
593    ///    to light clients, and the rest
594    pub inner_lite: BlockHeaderInnerLite,
595    pub inner_rest: BlockHeaderInnerRestV4,
596
597    /// Signature of the block producer.
598    pub signature: Signature,
599
600    /// Cached value of hash for this block.
601    #[borsh(skip)]
602    pub hash: CryptoHash,
603}
604
605/// V4 -> V5: Add chunk_endorsements to inner_rest
606#[derive(
607    BorshSerialize,
608    BorshDeserialize,
609    serde::Serialize,
610    Debug,
611    Clone,
612    Eq,
613    PartialEq,
614    Default,
615    ProtocolSchema,
616)]
617#[borsh(init=init)]
618pub struct BlockHeaderV5 {
619    pub prev_hash: CryptoHash,
620
621    /// Inner part of the block header that gets hashed, split into two parts, one that is sent
622    ///    to light clients, and the rest
623    pub inner_lite: BlockHeaderInnerLite,
624    pub inner_rest: BlockHeaderInnerRestV5,
625
626    /// Signature of the block producer.
627    pub signature: Signature,
628
629    /// Cached value of hash for this block.
630    #[borsh(skip)]
631    pub hash: CryptoHash,
632}
633
634/// V5 -> V6: Add shard_split, remove challenges
635#[derive(
636    BorshSerialize,
637    BorshDeserialize,
638    serde::Serialize,
639    Debug,
640    Clone,
641    Eq,
642    PartialEq,
643    Default,
644    ProtocolSchema,
645)]
646#[borsh(init=init)]
647pub struct BlockHeaderV6 {
648    pub prev_hash: CryptoHash,
649
650    /// Inner part of the block header that gets hashed.
651    /// It's split into two parts: one that is sent to light clients,
652    /// and the other which contains the rest of information.
653    pub inner_lite: BlockHeaderInnerLite,
654    pub inner_rest: BlockHeaderInnerRestV6,
655
656    /// Signature of the block producer.
657    pub signature: Signature,
658
659    /// Cached value of hash for this block.
660    #[borsh(skip)]
661    pub hash: CryptoHash,
662}
663
664/// V6 -> V7: Add spice fields
665#[derive(
666    BorshSerialize,
667    BorshDeserialize,
668    serde::Serialize,
669    Debug,
670    Clone,
671    Eq,
672    PartialEq,
673    Default,
674    ProtocolSchema,
675)]
676#[borsh(init=init)]
677pub struct BlockHeaderV7 {
678    pub prev_hash: CryptoHash,
679
680    /// Inner part of the block header that gets hashed.
681    /// It's split into two parts: one that is sent to light clients,
682    /// and the other which contains the rest of information.
683    pub inner_lite: BlockHeaderInnerLite,
684    pub inner_rest: BlockHeaderInnerRestV7,
685
686    /// Signature of the block producer.
687    pub signature: Signature,
688
689    /// Cached value of hash for this block.
690    #[borsh(skip)]
691    pub hash: CryptoHash,
692}
693
694impl BlockHeaderV2 {
695    pub fn init(&mut self) {
696        self.hash = BlockHeader::compute_hash(
697            self.prev_hash,
698            &borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
699            &borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
700        );
701    }
702}
703
704impl BlockHeaderV3 {
705    pub fn init(&mut self) {
706        self.hash = BlockHeader::compute_hash(
707            self.prev_hash,
708            &borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
709            &borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
710        );
711    }
712}
713
714impl BlockHeaderV4 {
715    pub fn init(&mut self) {
716        self.hash = BlockHeader::compute_hash(
717            self.prev_hash,
718            &borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
719            &borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
720        );
721    }
722}
723
724impl BlockHeaderV5 {
725    pub fn init(&mut self) {
726        self.hash = BlockHeader::compute_hash(
727            self.prev_hash,
728            &borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
729            &borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
730        );
731    }
732}
733
734impl BlockHeaderV6 {
735    pub fn init(&mut self) {
736        self.hash = BlockHeader::compute_hash(
737            self.prev_hash,
738            &borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
739            &borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
740        );
741    }
742}
743
744impl BlockHeaderV7 {
745    pub fn init(&mut self) {
746        self.hash = BlockHeader::compute_hash(
747            self.prev_hash,
748            &borsh::to_vec(&self.inner_lite).expect("Failed to serialize"),
749            &borsh::to_vec(&self.inner_rest).expect("Failed to serialize"),
750        );
751    }
752}
753
754/// Used in the BlockHeader::new_impl to specify the source of the block header signature.
755enum SignatureSource<'a> {
756    /// Use the given signer to sign a new block header.
757    /// This variant is used only when some features are enabled. There is a warning
758    /// because it's unused in the default configuration, where the features are disabled.
759    #[allow(dead_code)]
760    Signer(&'a ValidatorSigner),
761    /// Use a previously-computed signature (for reconstructing an already-produced block header).
762    Signature(Signature),
763}
764
765/// Versioned BlockHeader data structure.
766/// For each next version, document what are the changes between versions.
767#[derive(
768    BorshSerialize, BorshDeserialize, serde::Serialize, Debug, Clone, Eq, PartialEq, ProtocolSchema,
769)]
770pub enum BlockHeader {
771    BlockHeaderV1(BlockHeaderV1),
772    BlockHeaderV2(BlockHeaderV2),
773    BlockHeaderV3(BlockHeaderV3),
774    BlockHeaderV4(BlockHeaderV4),
775    BlockHeaderV5(BlockHeaderV5),
776    BlockHeaderV6(BlockHeaderV6),
777    BlockHeaderV7(BlockHeaderV7),
778}
779
780impl BlockHeader {
781    pub fn compute_inner_hash(inner_lite: &[u8], inner_rest: &[u8]) -> CryptoHash {
782        let hash_lite = hash(inner_lite);
783        let hash_rest = hash(inner_rest);
784        combine_hash(&hash_lite, &hash_rest)
785    }
786
787    pub fn compute_hash(prev_hash: CryptoHash, inner_lite: &[u8], inner_rest: &[u8]) -> CryptoHash {
788        let hash_inner = BlockHeader::compute_inner_hash(inner_lite, inner_rest);
789
790        combine_hash(&hash_inner, &prev_hash)
791    }
792
793    /// Creates BlockHeader for a newly produced block.
794    pub fn new(
795        current_protocol_version: ProtocolVersion,
796        latest_protocol_version: ProtocolVersion,
797        height: BlockHeight,
798        prev_hash: CryptoHash,
799        block_body_hash: CryptoHash,
800        prev_state_root: MerkleHash,
801        prev_chunk_outgoing_receipts_root: MerkleHash,
802        chunk_headers_root: MerkleHash,
803        chunk_tx_root: MerkleHash,
804        outcome_root: MerkleHash,
805        timestamp: u64,
806        random_value: CryptoHash,
807        prev_validator_proposals: Vec<ValidatorStake>,
808        chunk_mask: Vec<bool>,
809        block_ordinal: NumBlocks,
810        epoch_id: EpochId,
811        next_epoch_id: EpochId,
812        next_gas_price: Balance,
813        total_supply: Balance,
814        signer: &ValidatorSigner,
815        last_final_block: CryptoHash,
816        last_ds_final_block: CryptoHash,
817        epoch_sync_data_hash: Option<CryptoHash>,
818        approvals: Vec<Option<Box<Signature>>>,
819        next_bp_hash: CryptoHash,
820        block_merkle_root: CryptoHash,
821        prev_height: BlockHeight,
822        chunk_endorsements: Option<ChunkEndorsementsBitmap>,
823        shard_split: Option<(ShardId, AccountId)>,
824        prev_last_certified_block_epoch_id: Option<EpochId>,
825        spice_chunk_endorsement_stats: Option<Vec<SpiceChunkEndorsementStats>>,
826    ) -> Self {
827        Self::new_impl(
828            current_protocol_version,
829            latest_protocol_version,
830            height,
831            prev_hash,
832            block_body_hash,
833            prev_state_root,
834            prev_chunk_outgoing_receipts_root,
835            chunk_headers_root,
836            chunk_tx_root,
837            outcome_root,
838            timestamp,
839            random_value,
840            prev_validator_proposals,
841            chunk_mask,
842            block_ordinal,
843            epoch_id,
844            next_epoch_id,
845            next_gas_price,
846            total_supply,
847            SignatureSource::Signer(signer),
848            last_final_block,
849            last_ds_final_block,
850            epoch_sync_data_hash,
851            approvals,
852            next_bp_hash,
853            block_merkle_root,
854            prev_height,
855            chunk_endorsements,
856            shard_split,
857            prev_last_certified_block_epoch_id,
858            spice_chunk_endorsement_stats,
859        )
860    }
861
862    /// Creates a new BlockHeader from information in the view of an existing block.
863    pub fn from_view(
864        expected_hash: &CryptoHash,
865        epoch_protocol_version: ProtocolVersion,
866        height: BlockHeight,
867        prev_hash: CryptoHash,
868        block_body_hash: CryptoHash,
869        prev_state_root: MerkleHash,
870        prev_chunk_outgoing_receipts_root: MerkleHash,
871        chunk_headers_root: MerkleHash,
872        chunk_tx_root: MerkleHash,
873        outcome_root: MerkleHash,
874        timestamp: u64,
875        random_value: CryptoHash,
876        prev_validator_proposals: Vec<ValidatorStake>,
877        chunk_mask: Vec<bool>,
878        block_ordinal: NumBlocks,
879        epoch_id: EpochId,
880        next_epoch_id: EpochId,
881        next_gas_price: Balance,
882        total_supply: Balance,
883        signature: Signature,
884        last_final_block: CryptoHash,
885        last_ds_final_block: CryptoHash,
886        epoch_sync_data_hash: Option<CryptoHash>,
887        approvals: Vec<Option<Box<Signature>>>,
888        next_bp_hash: CryptoHash,
889        block_merkle_root: CryptoHash,
890        prev_height: BlockHeight,
891        chunk_endorsements: Option<ChunkEndorsementsBitmap>,
892        shard_split: Option<(ShardId, AccountId)>,
893        prev_last_certified_block_epoch_id: Option<EpochId>,
894        spice_chunk_endorsement_stats: Option<Vec<SpiceChunkEndorsementStats>>,
895    ) -> Self {
896        let header = Self::new_impl(
897            epoch_protocol_version,
898            epoch_protocol_version,
899            height,
900            prev_hash,
901            block_body_hash,
902            prev_state_root,
903            prev_chunk_outgoing_receipts_root,
904            chunk_headers_root,
905            chunk_tx_root,
906            outcome_root,
907            timestamp,
908            random_value,
909            prev_validator_proposals,
910            chunk_mask,
911            block_ordinal,
912            epoch_id,
913            next_epoch_id,
914            next_gas_price,
915            total_supply,
916            SignatureSource::Signature(signature),
917            last_final_block,
918            last_ds_final_block,
919            epoch_sync_data_hash,
920            approvals,
921            next_bp_hash,
922            block_merkle_root,
923            prev_height,
924            chunk_endorsements,
925            shard_split,
926            prev_last_certified_block_epoch_id,
927            spice_chunk_endorsement_stats,
928        );
929        // Note: We do not panic but only log if the hash of the created header does not match the expected hash (From the view)
930        // because there are tests that check if we can downgrade a BlockHeader's view a previous version, in which case the hash
931        // of the header changes.
932        if header.hash() != expected_hash {
933            tracing::debug!(height, header_hash=?header.hash(), ?expected_hash, "hash of the created header does not match expected hash");
934        }
935        header
936    }
937
938    /// Common logic for generating BlockHeader for different purposes, including new blocks, from views, and for genesis block
939    fn new_impl(
940        current_protocol_version: ProtocolVersion,
941        latest_protocol_version: ProtocolVersion,
942        height: BlockHeight,
943        prev_hash: CryptoHash,
944        block_body_hash: CryptoHash,
945        prev_state_root: MerkleHash,
946        prev_chunk_outgoing_receipts_root: MerkleHash,
947        chunk_headers_root: MerkleHash,
948        chunk_tx_root: MerkleHash,
949        outcome_root: MerkleHash,
950        timestamp: u64,
951        random_value: CryptoHash,
952        prev_validator_proposals: Vec<ValidatorStake>,
953        chunk_mask: Vec<bool>,
954        block_ordinal: NumBlocks,
955        epoch_id: EpochId,
956        next_epoch_id: EpochId,
957        next_gas_price: Balance,
958        total_supply: Balance,
959        signature_source: SignatureSource,
960        last_final_block: CryptoHash,
961        last_ds_final_block: CryptoHash,
962        epoch_sync_data_hash: Option<CryptoHash>,
963        approvals: Vec<Option<Box<Signature>>>,
964        next_bp_hash: CryptoHash,
965        block_merkle_root: CryptoHash,
966        prev_height: BlockHeight,
967        chunk_endorsements: Option<ChunkEndorsementsBitmap>,
968        shard_split: Option<(ShardId, AccountId)>,
969        prev_last_certified_block_epoch_id: Option<EpochId>,
970        spice_chunk_endorsement_stats: Option<Vec<SpiceChunkEndorsementStats>>,
971    ) -> Self {
972        let inner_lite = BlockHeaderInnerLite {
973            height,
974            epoch_id,
975            next_epoch_id,
976            prev_state_root,
977            prev_outcome_root: outcome_root,
978            timestamp,
979            next_bp_hash,
980            block_merkle_root,
981        };
982
983        let chunk_endorsements = chunk_endorsements.unwrap_or_else(|| {
984            panic!(
985                "BlockHeaderV5 (or newer) is enabled but chunk endorsement bitmap is not provided"
986            )
987        });
988
989        if ProtocolFeature::Spice.enabled(current_protocol_version) {
990            let prev_last_certified_block_epoch_id = prev_last_certified_block_epoch_id.expect(
991                "BlockHeaderV7 requires prev_last_certified_block_epoch_id when Spice is enabled",
992            );
993            let spice_chunk_endorsement_stats = spice_chunk_endorsement_stats.expect(
994                "BlockHeaderV7 requires spice_chunk_endorsement_stats when Spice is enabled",
995            );
996            let inner_rest = BlockHeaderInnerRestV7 {
997                block_body_hash,
998                prev_chunk_outgoing_receipts_root,
999                chunk_headers_root,
1000                chunk_tx_root,
1001                random_value,
1002                prev_validator_proposals,
1003                chunk_mask,
1004                next_gas_price,
1005                total_supply,
1006                last_final_block,
1007                last_ds_final_block,
1008                block_ordinal,
1009                prev_height,
1010                epoch_sync_data_hash,
1011                approvals,
1012                latest_protocol_version,
1013                chunk_endorsements,
1014                shard_split,
1015                prev_last_certified_block_epoch_id,
1016                spice_chunk_endorsement_stats,
1017            };
1018            let (hash, signature) =
1019                Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest);
1020            Self::BlockHeaderV7(BlockHeaderV7 {
1021                prev_hash,
1022                inner_lite,
1023                inner_rest,
1024                signature,
1025                hash,
1026            })
1027        } else if ProtocolFeature::DynamicResharding.enabled(current_protocol_version) {
1028            let inner_rest = BlockHeaderInnerRestV6 {
1029                block_body_hash,
1030                prev_chunk_outgoing_receipts_root,
1031                chunk_headers_root,
1032                chunk_tx_root,
1033                random_value,
1034                prev_validator_proposals,
1035                chunk_mask,
1036                next_gas_price,
1037                block_ordinal,
1038                total_supply,
1039                last_final_block,
1040                last_ds_final_block,
1041                prev_height,
1042                epoch_sync_data_hash,
1043                approvals,
1044                latest_protocol_version,
1045                chunk_endorsements,
1046                shard_split,
1047            };
1048            let (hash, signature) =
1049                Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest);
1050            Self::BlockHeaderV6(BlockHeaderV6 {
1051                prev_hash,
1052                inner_lite,
1053                inner_rest,
1054                signature,
1055                hash,
1056            })
1057        } else {
1058            #[allow(deprecated)]
1059            let inner_rest = BlockHeaderInnerRestV5 {
1060                block_body_hash,
1061                prev_chunk_outgoing_receipts_root,
1062                chunk_headers_root,
1063                chunk_tx_root,
1064                challenges_root: Default::default(),
1065                random_value,
1066                prev_validator_proposals,
1067                chunk_mask,
1068                next_gas_price,
1069                total_supply,
1070                challenges_result: vec![],
1071                last_final_block,
1072                last_ds_final_block,
1073                block_ordinal,
1074                prev_height,
1075                epoch_sync_data_hash,
1076                approvals,
1077                latest_protocol_version,
1078                chunk_endorsements,
1079            };
1080            let (hash, signature) =
1081                Self::compute_hash_and_sign(signature_source, prev_hash, &inner_lite, &inner_rest);
1082            Self::BlockHeaderV5(BlockHeaderV5 {
1083                prev_hash,
1084                inner_lite,
1085                inner_rest,
1086                signature,
1087                hash,
1088            })
1089        }
1090    }
1091
1092    /// Helper function for `new_impl` and `old_impl` to compute the hash and signature of the hash from the block header parts.
1093    /// Exactly one of the `signer` and `signature` must be provided.
1094    /// If `signer` is given signs the header with given `prev_hash`, `inner_lite`, and `inner_rest` and returns the hash and signature of the header.
1095    /// If `signature` is given, uses the signature as is and only computes the hash.
1096    fn compute_hash_and_sign<T>(
1097        signature_source: SignatureSource,
1098        prev_hash: CryptoHash,
1099        inner_lite: &BlockHeaderInnerLite,
1100        inner_rest: &T,
1101    ) -> (CryptoHash, Signature)
1102    where
1103        T: BorshSerialize + ?Sized,
1104    {
1105        let hash = BlockHeader::compute_hash(
1106            prev_hash,
1107            &borsh::to_vec(&inner_lite).expect("Failed to serialize"),
1108            &borsh::to_vec(&inner_rest).expect("Failed to serialize"),
1109        );
1110        match signature_source {
1111            SignatureSource::Signer(signer) => (hash, signer.sign_bytes(hash.as_ref())),
1112            SignatureSource::Signature(signature) => (hash, signature),
1113        }
1114    }
1115
1116    pub fn genesis(
1117        genesis_protocol_version: ProtocolVersion,
1118        height: BlockHeight,
1119        state_root: MerkleHash,
1120        block_body_hash: CryptoHash,
1121        prev_chunk_outgoing_receipts_root: MerkleHash,
1122        chunk_headers_root: MerkleHash,
1123        chunk_tx_root: MerkleHash,
1124        num_shards: u64,
1125        timestamp: Utc,
1126        initial_gas_price: Balance,
1127        initial_total_supply: Balance,
1128        next_bp_hash: CryptoHash,
1129    ) -> Self {
1130        let chunks_included = if height == 0 { num_shards } else { 0 };
1131        let genesis_prev_last_certified_block_epoch_id =
1132            if ProtocolFeature::Spice.enabled(genesis_protocol_version) {
1133                Some(EpochId::default())
1134            } else {
1135                None
1136            };
1137        let genesis_spice_chunk_endorsement_stats =
1138            if ProtocolFeature::Spice.enabled(genesis_protocol_version) {
1139                Some(Vec::new())
1140            } else {
1141                None
1142            };
1143        Self::new_impl(
1144            genesis_protocol_version,
1145            genesis_protocol_version,
1146            height,
1147            CryptoHash::default(), // prev_hash
1148            block_body_hash,
1149            state_root,
1150            prev_chunk_outgoing_receipts_root,
1151            chunk_headers_root,
1152            chunk_tx_root,
1153            CryptoHash::default(), // prev_outcome_root
1154            timestamp.unix_timestamp_nanos() as u64,
1155            CryptoHash::default(),                // random_value
1156            vec![],                               // prev_validator_proposals
1157            vec![true; chunks_included as usize], // chunk_mask
1158            1, // block_ordinal. It is guaranteed that Chain has the only Block which is Genesis
1159            EpochId::default(), // epoch_id
1160            EpochId::default(), // next_epoch_id
1161            initial_gas_price,
1162            initial_total_supply,
1163            SignatureSource::Signature(Signature::empty(KeyType::ED25519)),
1164            CryptoHash::default(), // last_final_block
1165            CryptoHash::default(), // last_ds_final_block
1166            None,   // epoch_sync_data_hash. Epoch Sync cannot be executed up to Genesis
1167            vec![], // approvals
1168            next_bp_hash,
1169            CryptoHash::default(), // block_merkle_root,
1170            0,                     // prev_height
1171            Some(ChunkEndorsementsBitmap::genesis()),
1172            None, // shard_split
1173            genesis_prev_last_certified_block_epoch_id,
1174            genesis_spice_chunk_endorsement_stats,
1175        )
1176    }
1177
1178    #[inline]
1179    pub fn is_genesis(&self) -> bool {
1180        self.prev_hash() == &CryptoHash::default()
1181    }
1182
1183    #[inline]
1184    pub fn hash(&self) -> &CryptoHash {
1185        match self {
1186            BlockHeader::BlockHeaderV1(header) => &header.hash,
1187            BlockHeader::BlockHeaderV2(header) => &header.hash,
1188            BlockHeader::BlockHeaderV3(header) => &header.hash,
1189            BlockHeader::BlockHeaderV4(header) => &header.hash,
1190            BlockHeader::BlockHeaderV5(header) => &header.hash,
1191            BlockHeader::BlockHeaderV6(header) => &header.hash,
1192            BlockHeader::BlockHeaderV7(header) => &header.hash,
1193        }
1194    }
1195
1196    #[inline]
1197    pub fn prev_hash(&self) -> &CryptoHash {
1198        match self {
1199            BlockHeader::BlockHeaderV1(header) => &header.prev_hash,
1200            BlockHeader::BlockHeaderV2(header) => &header.prev_hash,
1201            BlockHeader::BlockHeaderV3(header) => &header.prev_hash,
1202            BlockHeader::BlockHeaderV4(header) => &header.prev_hash,
1203            BlockHeader::BlockHeaderV5(header) => &header.prev_hash,
1204            BlockHeader::BlockHeaderV6(header) => &header.prev_hash,
1205            BlockHeader::BlockHeaderV7(header) => &header.prev_hash,
1206        }
1207    }
1208
1209    #[inline]
1210    pub fn signature(&self) -> &Signature {
1211        match self {
1212            BlockHeader::BlockHeaderV1(header) => &header.signature,
1213            BlockHeader::BlockHeaderV2(header) => &header.signature,
1214            BlockHeader::BlockHeaderV3(header) => &header.signature,
1215            BlockHeader::BlockHeaderV4(header) => &header.signature,
1216            BlockHeader::BlockHeaderV5(header) => &header.signature,
1217            BlockHeader::BlockHeaderV6(header) => &header.signature,
1218            BlockHeader::BlockHeaderV7(header) => &header.signature,
1219        }
1220    }
1221
1222    #[inline]
1223    pub fn height(&self) -> BlockHeight {
1224        match self {
1225            BlockHeader::BlockHeaderV1(header) => header.inner_lite.height,
1226            BlockHeader::BlockHeaderV2(header) => header.inner_lite.height,
1227            BlockHeader::BlockHeaderV3(header) => header.inner_lite.height,
1228            BlockHeader::BlockHeaderV4(header) => header.inner_lite.height,
1229            BlockHeader::BlockHeaderV5(header) => header.inner_lite.height,
1230            BlockHeader::BlockHeaderV6(header) => header.inner_lite.height,
1231            BlockHeader::BlockHeaderV7(header) => header.inner_lite.height,
1232        }
1233    }
1234
1235    #[inline]
1236    pub fn prev_height(&self) -> Option<BlockHeight> {
1237        match self {
1238            BlockHeader::BlockHeaderV1(_) => None,
1239            BlockHeader::BlockHeaderV2(_) => None,
1240            BlockHeader::BlockHeaderV3(header) => Some(header.inner_rest.prev_height),
1241            BlockHeader::BlockHeaderV4(header) => Some(header.inner_rest.prev_height),
1242            BlockHeader::BlockHeaderV5(header) => Some(header.inner_rest.prev_height),
1243            BlockHeader::BlockHeaderV6(header) => Some(header.inner_rest.prev_height),
1244            BlockHeader::BlockHeaderV7(header) => Some(header.inner_rest.prev_height),
1245        }
1246    }
1247
1248    #[inline]
1249    pub fn epoch_id(&self) -> &EpochId {
1250        match self {
1251            BlockHeader::BlockHeaderV1(header) => &header.inner_lite.epoch_id,
1252            BlockHeader::BlockHeaderV2(header) => &header.inner_lite.epoch_id,
1253            BlockHeader::BlockHeaderV3(header) => &header.inner_lite.epoch_id,
1254            BlockHeader::BlockHeaderV4(header) => &header.inner_lite.epoch_id,
1255            BlockHeader::BlockHeaderV5(header) => &header.inner_lite.epoch_id,
1256            BlockHeader::BlockHeaderV6(header) => &header.inner_lite.epoch_id,
1257            BlockHeader::BlockHeaderV7(header) => &header.inner_lite.epoch_id,
1258        }
1259    }
1260
1261    #[inline]
1262    pub fn next_epoch_id(&self) -> &EpochId {
1263        match self {
1264            BlockHeader::BlockHeaderV1(header) => &header.inner_lite.next_epoch_id,
1265            BlockHeader::BlockHeaderV2(header) => &header.inner_lite.next_epoch_id,
1266            BlockHeader::BlockHeaderV3(header) => &header.inner_lite.next_epoch_id,
1267            BlockHeader::BlockHeaderV4(header) => &header.inner_lite.next_epoch_id,
1268            BlockHeader::BlockHeaderV5(header) => &header.inner_lite.next_epoch_id,
1269            BlockHeader::BlockHeaderV6(header) => &header.inner_lite.next_epoch_id,
1270            BlockHeader::BlockHeaderV7(header) => &header.inner_lite.next_epoch_id,
1271        }
1272    }
1273
1274    #[inline]
1275    pub fn prev_state_root(&self) -> &MerkleHash {
1276        match self {
1277            BlockHeader::BlockHeaderV1(header) => &header.inner_lite.prev_state_root,
1278            BlockHeader::BlockHeaderV2(header) => &header.inner_lite.prev_state_root,
1279            BlockHeader::BlockHeaderV3(header) => &header.inner_lite.prev_state_root,
1280            BlockHeader::BlockHeaderV4(header) => &header.inner_lite.prev_state_root,
1281            BlockHeader::BlockHeaderV5(header) => &header.inner_lite.prev_state_root,
1282            BlockHeader::BlockHeaderV6(header) => &header.inner_lite.prev_state_root,
1283            BlockHeader::BlockHeaderV7(header) => &header.inner_lite.prev_state_root,
1284        }
1285    }
1286
1287    #[inline]
1288    pub fn prev_chunk_outgoing_receipts_root(&self) -> &MerkleHash {
1289        match self {
1290            BlockHeader::BlockHeaderV1(header) => {
1291                &header.inner_rest.prev_chunk_outgoing_receipts_root
1292            }
1293            BlockHeader::BlockHeaderV2(header) => {
1294                &header.inner_rest.prev_chunk_outgoing_receipts_root
1295            }
1296            BlockHeader::BlockHeaderV3(header) => {
1297                &header.inner_rest.prev_chunk_outgoing_receipts_root
1298            }
1299            BlockHeader::BlockHeaderV4(header) => {
1300                &header.inner_rest.prev_chunk_outgoing_receipts_root
1301            }
1302            BlockHeader::BlockHeaderV5(header) => {
1303                &header.inner_rest.prev_chunk_outgoing_receipts_root
1304            }
1305            BlockHeader::BlockHeaderV6(header) => {
1306                &header.inner_rest.prev_chunk_outgoing_receipts_root
1307            }
1308            BlockHeader::BlockHeaderV7(header) => {
1309                &header.inner_rest.prev_chunk_outgoing_receipts_root
1310            }
1311        }
1312    }
1313
1314    #[inline]
1315    pub fn chunk_headers_root(&self) -> &MerkleHash {
1316        match self {
1317            BlockHeader::BlockHeaderV1(header) => &header.inner_rest.chunk_headers_root,
1318            BlockHeader::BlockHeaderV2(header) => &header.inner_rest.chunk_headers_root,
1319            BlockHeader::BlockHeaderV3(header) => &header.inner_rest.chunk_headers_root,
1320            BlockHeader::BlockHeaderV4(header) => &header.inner_rest.chunk_headers_root,
1321            BlockHeader::BlockHeaderV5(header) => &header.inner_rest.chunk_headers_root,
1322            BlockHeader::BlockHeaderV6(header) => &header.inner_rest.chunk_headers_root,
1323            BlockHeader::BlockHeaderV7(header) => &header.inner_rest.chunk_headers_root,
1324        }
1325    }
1326
1327    #[inline]
1328    pub fn chunk_tx_root(&self) -> &MerkleHash {
1329        match self {
1330            BlockHeader::BlockHeaderV1(header) => &header.inner_rest.chunk_tx_root,
1331            BlockHeader::BlockHeaderV2(header) => &header.inner_rest.chunk_tx_root,
1332            BlockHeader::BlockHeaderV3(header) => &header.inner_rest.chunk_tx_root,
1333            BlockHeader::BlockHeaderV4(header) => &header.inner_rest.chunk_tx_root,
1334            BlockHeader::BlockHeaderV5(header) => &header.inner_rest.chunk_tx_root,
1335            BlockHeader::BlockHeaderV6(header) => &header.inner_rest.chunk_tx_root,
1336            BlockHeader::BlockHeaderV7(header) => &header.inner_rest.chunk_tx_root,
1337        }
1338    }
1339
1340    pub fn chunks_included(&self) -> u64 {
1341        let mask = match self {
1342            BlockHeader::BlockHeaderV1(header) => return header.inner_rest.chunks_included,
1343            BlockHeader::BlockHeaderV2(header) => &header.inner_rest.chunk_mask,
1344            BlockHeader::BlockHeaderV3(header) => &header.inner_rest.chunk_mask,
1345            BlockHeader::BlockHeaderV4(header) => &header.inner_rest.chunk_mask,
1346            BlockHeader::BlockHeaderV5(header) => &header.inner_rest.chunk_mask,
1347            BlockHeader::BlockHeaderV6(header) => &header.inner_rest.chunk_mask,
1348            BlockHeader::BlockHeaderV7(header) => &header.inner_rest.chunk_mask,
1349        };
1350        mask.iter().map(|&x| u64::from(x)).sum::<u64>()
1351    }
1352
1353    #[inline]
1354    pub fn outcome_root(&self) -> &MerkleHash {
1355        match self {
1356            BlockHeader::BlockHeaderV1(header) => &header.inner_lite.prev_outcome_root,
1357            BlockHeader::BlockHeaderV2(header) => &header.inner_lite.prev_outcome_root,
1358            BlockHeader::BlockHeaderV3(header) => &header.inner_lite.prev_outcome_root,
1359            BlockHeader::BlockHeaderV4(header) => &header.inner_lite.prev_outcome_root,
1360            BlockHeader::BlockHeaderV5(header) => &header.inner_lite.prev_outcome_root,
1361            BlockHeader::BlockHeaderV6(header) => &header.inner_lite.prev_outcome_root,
1362            BlockHeader::BlockHeaderV7(header) => &header.inner_lite.prev_outcome_root,
1363        }
1364    }
1365
1366    #[inline]
1367    pub fn block_body_hash(&self) -> Option<CryptoHash> {
1368        match self {
1369            BlockHeader::BlockHeaderV1(_) => None,
1370            BlockHeader::BlockHeaderV2(_) => None,
1371            BlockHeader::BlockHeaderV3(_) => None,
1372            BlockHeader::BlockHeaderV4(header) => Some(header.inner_rest.block_body_hash),
1373            BlockHeader::BlockHeaderV5(header) => Some(header.inner_rest.block_body_hash),
1374            BlockHeader::BlockHeaderV6(header) => Some(header.inner_rest.block_body_hash),
1375            BlockHeader::BlockHeaderV7(header) => Some(header.inner_rest.block_body_hash),
1376        }
1377    }
1378
1379    #[inline]
1380    pub fn raw_timestamp(&self) -> u64 {
1381        match self {
1382            BlockHeader::BlockHeaderV1(header) => header.inner_lite.timestamp,
1383            BlockHeader::BlockHeaderV2(header) => header.inner_lite.timestamp,
1384            BlockHeader::BlockHeaderV3(header) => header.inner_lite.timestamp,
1385            BlockHeader::BlockHeaderV4(header) => header.inner_lite.timestamp,
1386            BlockHeader::BlockHeaderV5(header) => header.inner_lite.timestamp,
1387            BlockHeader::BlockHeaderV6(header) => header.inner_lite.timestamp,
1388            BlockHeader::BlockHeaderV7(header) => header.inner_lite.timestamp,
1389        }
1390    }
1391
1392    #[inline]
1393    pub fn prev_validator_proposals(&self) -> ValidatorStakeIter<'_> {
1394        match self {
1395            BlockHeader::BlockHeaderV1(header) => {
1396                ValidatorStakeIter::v1(&header.inner_rest.prev_validator_proposals)
1397            }
1398            BlockHeader::BlockHeaderV2(header) => {
1399                ValidatorStakeIter::v1(&header.inner_rest.prev_validator_proposals)
1400            }
1401            BlockHeader::BlockHeaderV3(header) => {
1402                ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
1403            }
1404            BlockHeader::BlockHeaderV4(header) => {
1405                ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
1406            }
1407            BlockHeader::BlockHeaderV5(header) => {
1408                ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
1409            }
1410            BlockHeader::BlockHeaderV6(header) => {
1411                ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
1412            }
1413            BlockHeader::BlockHeaderV7(header) => {
1414                ValidatorStakeIter::new(&header.inner_rest.prev_validator_proposals)
1415            }
1416        }
1417    }
1418
1419    #[inline]
1420    pub fn chunk_mask(&self) -> &[bool] {
1421        match self {
1422            BlockHeader::BlockHeaderV1(header) => &header.inner_rest.chunk_mask,
1423            BlockHeader::BlockHeaderV2(header) => &header.inner_rest.chunk_mask,
1424            BlockHeader::BlockHeaderV3(header) => &header.inner_rest.chunk_mask,
1425            BlockHeader::BlockHeaderV4(header) => &header.inner_rest.chunk_mask,
1426            BlockHeader::BlockHeaderV5(header) => &header.inner_rest.chunk_mask,
1427            BlockHeader::BlockHeaderV6(header) => &header.inner_rest.chunk_mask,
1428            BlockHeader::BlockHeaderV7(header) => &header.inner_rest.chunk_mask,
1429        }
1430    }
1431
1432    #[inline]
1433    pub fn block_ordinal(&self) -> NumBlocks {
1434        match self {
1435            BlockHeader::BlockHeaderV1(_) => 0, // not applicable
1436            BlockHeader::BlockHeaderV2(_) => 0, // not applicable
1437            BlockHeader::BlockHeaderV3(header) => header.inner_rest.block_ordinal,
1438            BlockHeader::BlockHeaderV4(header) => header.inner_rest.block_ordinal,
1439            BlockHeader::BlockHeaderV5(header) => header.inner_rest.block_ordinal,
1440            BlockHeader::BlockHeaderV6(header) => header.inner_rest.block_ordinal,
1441            BlockHeader::BlockHeaderV7(header) => header.inner_rest.block_ordinal,
1442        }
1443    }
1444
1445    #[inline]
1446    pub fn next_gas_price(&self) -> Balance {
1447        match self {
1448            BlockHeader::BlockHeaderV1(header) => header.inner_rest.next_gas_price,
1449            BlockHeader::BlockHeaderV2(header) => header.inner_rest.next_gas_price,
1450            BlockHeader::BlockHeaderV3(header) => header.inner_rest.next_gas_price,
1451            BlockHeader::BlockHeaderV4(header) => header.inner_rest.next_gas_price,
1452            BlockHeader::BlockHeaderV5(header) => header.inner_rest.next_gas_price,
1453            BlockHeader::BlockHeaderV6(header) => header.inner_rest.next_gas_price,
1454            BlockHeader::BlockHeaderV7(header) => header.inner_rest.next_gas_price,
1455        }
1456    }
1457
1458    #[inline]
1459    pub fn total_supply(&self) -> Balance {
1460        match self {
1461            BlockHeader::BlockHeaderV1(header) => header.inner_rest.total_supply,
1462            BlockHeader::BlockHeaderV2(header) => header.inner_rest.total_supply,
1463            BlockHeader::BlockHeaderV3(header) => header.inner_rest.total_supply,
1464            BlockHeader::BlockHeaderV4(header) => header.inner_rest.total_supply,
1465            BlockHeader::BlockHeaderV5(header) => header.inner_rest.total_supply,
1466            BlockHeader::BlockHeaderV6(header) => header.inner_rest.total_supply,
1467            BlockHeader::BlockHeaderV7(header) => header.inner_rest.total_supply,
1468        }
1469    }
1470
1471    #[inline]
1472    pub fn random_value(&self) -> &CryptoHash {
1473        match self {
1474            BlockHeader::BlockHeaderV1(header) => &header.inner_rest.random_value,
1475            BlockHeader::BlockHeaderV2(header) => &header.inner_rest.random_value,
1476            BlockHeader::BlockHeaderV3(header) => &header.inner_rest.random_value,
1477            BlockHeader::BlockHeaderV4(header) => &header.inner_rest.random_value,
1478            BlockHeader::BlockHeaderV5(header) => &header.inner_rest.random_value,
1479            BlockHeader::BlockHeaderV6(header) => &header.inner_rest.random_value,
1480            BlockHeader::BlockHeaderV7(header) => &header.inner_rest.random_value,
1481        }
1482    }
1483
1484    #[inline]
1485    pub fn last_final_block(&self) -> &CryptoHash {
1486        match self {
1487            BlockHeader::BlockHeaderV1(header) => &header.inner_rest.last_final_block,
1488            BlockHeader::BlockHeaderV2(header) => &header.inner_rest.last_final_block,
1489            BlockHeader::BlockHeaderV3(header) => &header.inner_rest.last_final_block,
1490            BlockHeader::BlockHeaderV4(header) => &header.inner_rest.last_final_block,
1491            BlockHeader::BlockHeaderV5(header) => &header.inner_rest.last_final_block,
1492            BlockHeader::BlockHeaderV6(header) => &header.inner_rest.last_final_block,
1493            BlockHeader::BlockHeaderV7(header) => &header.inner_rest.last_final_block,
1494        }
1495    }
1496
1497    #[inline]
1498    /// Get the hash of what will be considered the last final block after a new block with
1499    /// `target_height` is produced on top of this (`self`) block.
1500    pub fn last_final_block_for_height(&self, target_height: BlockHeight) -> &CryptoHash {
1501        if target_height == self.height() + 1 && self.last_ds_final_block() == self.prev_hash() {
1502            self.prev_hash()
1503        } else {
1504            self.last_final_block()
1505        }
1506    }
1507
1508    #[inline]
1509    pub fn last_ds_final_block(&self) -> &CryptoHash {
1510        match self {
1511            BlockHeader::BlockHeaderV1(header) => &header.inner_rest.last_ds_final_block,
1512            BlockHeader::BlockHeaderV2(header) => &header.inner_rest.last_ds_final_block,
1513            BlockHeader::BlockHeaderV3(header) => &header.inner_rest.last_ds_final_block,
1514            BlockHeader::BlockHeaderV4(header) => &header.inner_rest.last_ds_final_block,
1515            BlockHeader::BlockHeaderV5(header) => &header.inner_rest.last_ds_final_block,
1516            BlockHeader::BlockHeaderV6(header) => &header.inner_rest.last_ds_final_block,
1517            BlockHeader::BlockHeaderV7(header) => &header.inner_rest.last_ds_final_block,
1518        }
1519    }
1520
1521    #[inline]
1522    pub fn next_bp_hash(&self) -> &CryptoHash {
1523        match self {
1524            BlockHeader::BlockHeaderV1(header) => &header.inner_lite.next_bp_hash,
1525            BlockHeader::BlockHeaderV2(header) => &header.inner_lite.next_bp_hash,
1526            BlockHeader::BlockHeaderV3(header) => &header.inner_lite.next_bp_hash,
1527            BlockHeader::BlockHeaderV4(header) => &header.inner_lite.next_bp_hash,
1528            BlockHeader::BlockHeaderV5(header) => &header.inner_lite.next_bp_hash,
1529            BlockHeader::BlockHeaderV6(header) => &header.inner_lite.next_bp_hash,
1530            BlockHeader::BlockHeaderV7(header) => &header.inner_lite.next_bp_hash,
1531        }
1532    }
1533
1534    #[inline]
1535    pub fn block_merkle_root(&self) -> &CryptoHash {
1536        match self {
1537            BlockHeader::BlockHeaderV1(header) => &header.inner_lite.block_merkle_root,
1538            BlockHeader::BlockHeaderV2(header) => &header.inner_lite.block_merkle_root,
1539            BlockHeader::BlockHeaderV3(header) => &header.inner_lite.block_merkle_root,
1540            BlockHeader::BlockHeaderV4(header) => &header.inner_lite.block_merkle_root,
1541            BlockHeader::BlockHeaderV5(header) => &header.inner_lite.block_merkle_root,
1542            BlockHeader::BlockHeaderV6(header) => &header.inner_lite.block_merkle_root,
1543            BlockHeader::BlockHeaderV7(header) => &header.inner_lite.block_merkle_root,
1544        }
1545    }
1546
1547    #[inline]
1548    pub fn epoch_sync_data_hash(&self) -> Option<CryptoHash> {
1549        match self {
1550            BlockHeader::BlockHeaderV1(_) => None,
1551            BlockHeader::BlockHeaderV2(_) => None,
1552            BlockHeader::BlockHeaderV3(header) => header.inner_rest.epoch_sync_data_hash,
1553            BlockHeader::BlockHeaderV4(header) => header.inner_rest.epoch_sync_data_hash,
1554            BlockHeader::BlockHeaderV5(header) => header.inner_rest.epoch_sync_data_hash,
1555            BlockHeader::BlockHeaderV6(header) => header.inner_rest.epoch_sync_data_hash,
1556            BlockHeader::BlockHeaderV7(header) => header.inner_rest.epoch_sync_data_hash,
1557        }
1558    }
1559
1560    #[inline]
1561    pub fn approvals(&self) -> &[Option<Box<Signature>>] {
1562        match self {
1563            BlockHeader::BlockHeaderV1(header) => &header.inner_rest.approvals,
1564            BlockHeader::BlockHeaderV2(header) => &header.inner_rest.approvals,
1565            BlockHeader::BlockHeaderV3(header) => &header.inner_rest.approvals,
1566            BlockHeader::BlockHeaderV4(header) => &header.inner_rest.approvals,
1567            BlockHeader::BlockHeaderV5(header) => &header.inner_rest.approvals,
1568            BlockHeader::BlockHeaderV6(header) => &header.inner_rest.approvals,
1569            BlockHeader::BlockHeaderV7(header) => &header.inner_rest.approvals,
1570        }
1571    }
1572
1573    /// Verifies that given public key produced the block.
1574    pub fn verify_block_producer(&self, public_key: &PublicKey) -> bool {
1575        self.signature().verify(self.hash().as_ref(), public_key)
1576    }
1577
1578    pub fn timestamp(&self) -> Utc {
1579        Utc::from_unix_timestamp_nanos(self.raw_timestamp() as i128).unwrap()
1580    }
1581
1582    pub fn num_approvals(&self) -> u64 {
1583        self.approvals().iter().filter(|x| x.is_some()).count() as u64
1584    }
1585
1586    pub fn verify_chunks_included(&self) -> bool {
1587        match self {
1588            BlockHeader::BlockHeaderV1(header) => {
1589                header.inner_rest.chunk_mask.iter().map(|&x| u64::from(x)).sum::<u64>()
1590                    == header.inner_rest.chunks_included
1591            }
1592            BlockHeader::BlockHeaderV2(_header) => true,
1593            BlockHeader::BlockHeaderV3(_header) => true,
1594            BlockHeader::BlockHeaderV4(_header) => true,
1595            BlockHeader::BlockHeaderV5(_header) => true,
1596            BlockHeader::BlockHeaderV6(_header) => true,
1597            BlockHeader::BlockHeaderV7(_header) => true,
1598        }
1599    }
1600
1601    #[inline]
1602    pub fn latest_protocol_version(&self) -> u32 {
1603        match self {
1604            BlockHeader::BlockHeaderV1(header) => header.inner_rest.latest_protocol_version,
1605            BlockHeader::BlockHeaderV2(header) => header.inner_rest.latest_protocol_version,
1606            BlockHeader::BlockHeaderV3(header) => header.inner_rest.latest_protocol_version,
1607            BlockHeader::BlockHeaderV4(header) => header.inner_rest.latest_protocol_version,
1608            BlockHeader::BlockHeaderV5(header) => header.inner_rest.latest_protocol_version,
1609            BlockHeader::BlockHeaderV6(header) => header.inner_rest.latest_protocol_version,
1610            BlockHeader::BlockHeaderV7(header) => header.inner_rest.latest_protocol_version,
1611        }
1612    }
1613
1614    pub fn inner_lite_bytes(&self) -> Vec<u8> {
1615        match self {
1616            BlockHeader::BlockHeaderV1(header) => {
1617                borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
1618            }
1619            BlockHeader::BlockHeaderV2(header) => {
1620                borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
1621            }
1622            BlockHeader::BlockHeaderV3(header) => {
1623                borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
1624            }
1625            BlockHeader::BlockHeaderV4(header) => {
1626                borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
1627            }
1628            BlockHeader::BlockHeaderV5(header) => {
1629                borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
1630            }
1631            BlockHeader::BlockHeaderV6(header) => {
1632                borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
1633            }
1634            BlockHeader::BlockHeaderV7(header) => {
1635                borsh::to_vec(&header.inner_lite).expect("Failed to serialize")
1636            }
1637        }
1638    }
1639
1640    pub fn inner_rest_bytes(&self) -> Vec<u8> {
1641        match self {
1642            BlockHeader::BlockHeaderV1(header) => {
1643                borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
1644            }
1645            BlockHeader::BlockHeaderV2(header) => {
1646                borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
1647            }
1648            BlockHeader::BlockHeaderV3(header) => {
1649                borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
1650            }
1651            BlockHeader::BlockHeaderV4(header) => {
1652                borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
1653            }
1654            BlockHeader::BlockHeaderV5(header) => {
1655                borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
1656            }
1657            BlockHeader::BlockHeaderV6(header) => {
1658                borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
1659            }
1660            BlockHeader::BlockHeaderV7(header) => {
1661                borsh::to_vec(&header.inner_rest).expect("Failed to serialize")
1662            }
1663        }
1664    }
1665
1666    #[inline]
1667    pub fn chunk_endorsements(&self) -> Option<&ChunkEndorsementsBitmap> {
1668        match self {
1669            BlockHeader::BlockHeaderV1(_) => None,
1670            BlockHeader::BlockHeaderV2(_) => None,
1671            BlockHeader::BlockHeaderV3(_) => None,
1672            BlockHeader::BlockHeaderV4(_) => None,
1673            BlockHeader::BlockHeaderV5(header) => Some(&header.inner_rest.chunk_endorsements),
1674            BlockHeader::BlockHeaderV6(header) => Some(&header.inner_rest.chunk_endorsements),
1675            BlockHeader::BlockHeaderV7(header) => Some(&header.inner_rest.chunk_endorsements),
1676        }
1677    }
1678
1679    #[inline]
1680    pub fn inner_lite(&self) -> &BlockHeaderInnerLite {
1681        match self {
1682            BlockHeader::BlockHeaderV1(header) => &header.inner_lite,
1683            BlockHeader::BlockHeaderV2(header) => &header.inner_lite,
1684            BlockHeader::BlockHeaderV3(header) => &header.inner_lite,
1685            BlockHeader::BlockHeaderV4(header) => &header.inner_lite,
1686            BlockHeader::BlockHeaderV5(header) => &header.inner_lite,
1687            BlockHeader::BlockHeaderV6(header) => &header.inner_lite,
1688            BlockHeader::BlockHeaderV7(header) => &header.inner_lite,
1689        }
1690    }
1691
1692    /// As challenges are now deprecated and not supported, a valid block should
1693    /// not have challenges.
1694    pub fn challenges_present(&self) -> bool {
1695        #[allow(deprecated)]
1696        let (challenges_root, challenges_result) = match self {
1697            Self::BlockHeaderV1(header) => {
1698                (&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
1699            }
1700            Self::BlockHeaderV2(header) => {
1701                (&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
1702            }
1703            Self::BlockHeaderV3(header) => {
1704                (&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
1705            }
1706            Self::BlockHeaderV4(header) => {
1707                (&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
1708            }
1709            Self::BlockHeaderV5(header) => {
1710                (&header.inner_rest.challenges_root, &header.inner_rest.challenges_result)
1711            }
1712            Self::BlockHeaderV6(_) => return false,
1713            Self::BlockHeaderV7(_) => return false,
1714        };
1715
1716        !challenges_result.is_empty() || challenges_root != &MerkleHash::default()
1717    }
1718
1719    /// Shard ID and boundary account for the upcoming resharding.
1720    /// This field may be set only for the last block of an epoch.
1721    /// Split proposed at the end of epoch N will be effective since the beginning of epoch N+2.
1722    #[inline]
1723    pub fn shard_split(&self) -> Option<&(ShardId, AccountId)> {
1724        match self {
1725            BlockHeader::BlockHeaderV1(_) => None,
1726            BlockHeader::BlockHeaderV2(_) => None,
1727            BlockHeader::BlockHeaderV3(_) => None,
1728            BlockHeader::BlockHeaderV4(_) => None,
1729            BlockHeader::BlockHeaderV5(_) => None,
1730            BlockHeader::BlockHeaderV6(header) => header.inner_rest.shard_split.as_ref(),
1731            BlockHeader::BlockHeaderV7(header) => header.inner_rest.shard_split.as_ref(),
1732        }
1733    }
1734
1735    /// Epoch ID of the last block whose spice execution results are certified.
1736    /// Returns `None` for header versions prior to V7.
1737    #[inline]
1738    pub fn prev_last_certified_block_epoch_id(&self) -> Option<&EpochId> {
1739        match self {
1740            BlockHeader::BlockHeaderV1(_)
1741            | BlockHeader::BlockHeaderV2(_)
1742            | BlockHeader::BlockHeaderV3(_)
1743            | BlockHeader::BlockHeaderV4(_)
1744            | BlockHeader::BlockHeaderV5(_)
1745            | BlockHeader::BlockHeaderV6(_) => None,
1746            BlockHeader::BlockHeaderV7(header) => {
1747                Some(&header.inner_rest.prev_last_certified_block_epoch_id)
1748            }
1749        }
1750    }
1751
1752    /// Set only on the last block of an epoch; `None` before header V7.
1753    /// See `SpiceChunkEndorsementStats`.
1754    #[inline]
1755    pub fn spice_chunk_endorsement_stats(&self) -> Option<&[SpiceChunkEndorsementStats]> {
1756        match self {
1757            BlockHeader::BlockHeaderV1(_)
1758            | BlockHeader::BlockHeaderV2(_)
1759            | BlockHeader::BlockHeaderV3(_)
1760            | BlockHeader::BlockHeaderV4(_)
1761            | BlockHeader::BlockHeaderV5(_)
1762            | BlockHeader::BlockHeaderV6(_) => None,
1763            BlockHeader::BlockHeaderV7(header) => {
1764                Some(&header.inner_rest.spice_chunk_endorsement_stats)
1765            }
1766        }
1767    }
1768
1769    /// Returns true if the header is a spice-protocol header (V7 or later).
1770    #[inline]
1771    pub fn is_spice(&self) -> bool {
1772        match self {
1773            BlockHeader::BlockHeaderV1(_)
1774            | BlockHeader::BlockHeaderV2(_)
1775            | BlockHeader::BlockHeaderV3(_)
1776            | BlockHeader::BlockHeaderV4(_)
1777            | BlockHeader::BlockHeaderV5(_)
1778            | BlockHeader::BlockHeaderV6(_) => false,
1779            BlockHeader::BlockHeaderV7(_) => true,
1780        }
1781    }
1782}
1783
1784pub fn compute_bp_hash_from_validator_stakes(
1785    validator_stakes: &Vec<ValidatorStake>,
1786    use_versioned_bp_hash_format: bool,
1787) -> CryptoHash {
1788    if use_versioned_bp_hash_format {
1789        CryptoHash::hash_borsh_iter(validator_stakes)
1790    } else {
1791        let stakes = validator_stakes.into_iter().map(|stake| stake.clone().into_v1());
1792        CryptoHash::hash_borsh_iter(stakes)
1793    }
1794}