zebra_chain/block/header.rs
1//! The block header.
2
3use std::sync::Arc;
4
5use chrono::{DateTime, Duration, Utc};
6use thiserror::Error;
7
8use crate::{
9 fmt::HexDebug,
10 serialization::{TrustedPreallocate, MAX_PROTOCOL_MESSAGE_LEN},
11 work::{difficulty::CompactDifficulty, equihash::Solution},
12};
13
14use super::{merkle, Hash, Height};
15
16#[cfg(any(test, feature = "proptest-impl"))]
17use proptest_derive::Arbitrary;
18
19/// A block header, containing metadata about a block.
20///
21/// How are blocks chained together? They are chained together via the
22/// backwards reference (previous header hash) present in the block
23/// header. Each block points backwards to its parent, all the way
24/// back to the genesis block (the first block in the blockchain).
25#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
26pub struct Header {
27 /// The block's version field. This is supposed to be `4`:
28 ///
29 /// > The current and only defined block version number for Zcash is 4.
30 ///
31 /// but this was not enforced by the consensus rules, and defective mining
32 /// software created blocks with other versions, so instead it's effectively
33 /// a free field. The only constraint is that it must be at least `4` when
34 /// interpreted as an `i32`.
35 pub version: u32,
36
37 /// The hash of the previous block, used to create a chain of blocks back to
38 /// the genesis block.
39 ///
40 /// This ensures no previous block can be changed without also changing this
41 /// block's header.
42 pub previous_block_hash: Hash,
43
44 /// The root of the Bitcoin-inherited transaction Merkle tree, binding the
45 /// block header to the transactions in the block.
46 ///
47 /// Note that because of a flaw in Bitcoin's design, the `merkle_root` does
48 /// not always precisely bind the contents of the block (CVE-2012-2459). It
49 /// is sometimes possible for an attacker to create multiple distinct sets of
50 /// transactions with the same Merkle root, although only one set will be
51 /// valid.
52 pub merkle_root: merkle::Root,
53
54 /// Zcash blocks contain different kinds of commitments to their contents,
55 /// depending on the network and height.
56 ///
57 /// The interpretation of this field has been changed multiple times,
58 /// without incrementing the block [`version`](Self::version). Therefore,
59 /// this field cannot be parsed without the network and height. Use
60 /// [`Block::commitment`](super::Block::commitment) to get the parsed
61 /// [`Commitment`](super::Commitment).
62 pub commitment_bytes: HexDebug<[u8; 32]>,
63
64 /// The block timestamp is a Unix epoch time (UTC) when the miner
65 /// started hashing the header (according to the miner).
66 pub time: DateTime<Utc>,
67
68 /// An encoded version of the target threshold this block's header
69 /// hash must be less than or equal to, in the same nBits format
70 /// used by Bitcoin.
71 ///
72 /// For a block at block height `height`, bits MUST be equal to
73 /// `ThresholdBits(height)`.
74 ///
75 /// [Bitcoin-nBits](https://bitcoin.org/en/developer-reference#target-nbits)
76 pub difficulty_threshold: CompactDifficulty,
77
78 /// An arbitrary field that miners can change to modify the header
79 /// hash in order to produce a hash less than or equal to the
80 /// target threshold.
81 pub nonce: HexDebug<[u8; 32]>,
82
83 /// The Equihash solution.
84 pub solution: Solution,
85}
86
87/// TODO: Use this error as the source for zebra_consensus::error::BlockError::Time,
88/// and make `BlockError::Time` add additional context.
89/// See <https://github.com/ZcashFoundation/zebra/issues/1021> for more details.
90#[allow(missing_docs)]
91#[derive(Error, Debug)]
92pub enum BlockTimeError {
93 #[error("invalid time {0:?} in block header {1:?} {2:?}: block time is more than 2 hours in the future ({3:?}). Hint: check your machine's date, time, and time zone.")]
94 InvalidBlockTime(
95 DateTime<Utc>,
96 crate::block::Height,
97 crate::block::Hash,
98 DateTime<Utc>,
99 ),
100}
101
102impl Header {
103 /// TODO: Inline this function into zebra_consensus::block::check::time_is_valid_at.
104 /// See <https://github.com/ZcashFoundation/zebra/issues/1021> for more details.
105 #[allow(clippy::unwrap_in_result)]
106 pub fn time_is_valid_at(
107 &self,
108 now: DateTime<Utc>,
109 height: &Height,
110 hash: &Hash,
111 ) -> Result<(), BlockTimeError> {
112 let two_hours_in_the_future = now
113 .checked_add_signed(Duration::hours(2))
114 .expect("calculating 2 hours in the future does not overflow");
115 if self.time <= two_hours_in_the_future {
116 Ok(())
117 } else {
118 Err(BlockTimeError::InvalidBlockTime(
119 self.time,
120 *height,
121 *hash,
122 two_hours_in_the_future,
123 ))?
124 }
125 }
126
127 /// Compute the hash of this header.
128 pub fn hash(&self) -> Hash {
129 Hash::from(self)
130 }
131}
132
133/// A header with a count of the number of transactions in its block.
134/// This structure is used in the Bitcoin network protocol.
135///
136/// The transaction count field is always zero, so we don't store it in the struct.
137#[derive(Clone, Debug, Eq, PartialEq)]
138#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
139pub struct CountedHeader {
140 /// The header for a block
141 pub header: Arc<Header>,
142}
143
144/// The serialized size of a Zcash block header.
145///
146/// Includes the equihash input, 32-byte nonce, 3-byte equihash length field, and equihash solution.
147const BLOCK_HEADER_LENGTH: usize =
148 crate::work::equihash::Solution::INPUT_LENGTH + 32 + 3 + crate::work::equihash::SOLUTION_SIZE;
149
150/// The minimum size for a serialized CountedHeader.
151///
152/// A CountedHeader has BLOCK_HEADER_LENGTH bytes + 1 or more bytes for the transaction count
153pub(crate) const MIN_COUNTED_HEADER_LEN: usize = BLOCK_HEADER_LENGTH + 1;
154
155/// The Zcash accepted block version.
156///
157/// The consensus rules do not force the block version to be this value but just equal or greater than it.
158/// However, it is suggested that submitted block versions to be of this exact value.
159pub const ZCASH_BLOCK_VERSION: u32 = 4;
160
161impl TrustedPreallocate for CountedHeader {
162 fn max_allocation() -> u64 {
163 // Every vector type requires a length field of at least one byte for de/serialization.
164 // Therefore, we can never receive more than (MAX_PROTOCOL_MESSAGE_LEN - 1) / MIN_COUNTED_HEADER_LEN counted headers in a single message
165 ((MAX_PROTOCOL_MESSAGE_LEN - 1) / MIN_COUNTED_HEADER_LEN) as u64
166 }
167}