kaspa_consensus_core/
header.rs

1use crate::{hashing, BlueWorkType};
2use borsh::{BorshDeserialize, BorshSerialize};
3use kaspa_hashes::Hash;
4use kaspa_utils::mem_size::MemSizeEstimator;
5use serde::{Deserialize, Serialize};
6
7/// @category Consensus
8#[derive(Clone, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
9#[serde(rename_all = "camelCase")]
10pub struct Header {
11    /// Cached hash
12    pub hash: Hash,
13    pub version: u16,
14    pub parents_by_level: Vec<Vec<Hash>>,
15    pub hash_merkle_root: Hash,
16    pub accepted_id_merkle_root: Hash,
17    pub utxo_commitment: Hash,
18    /// Timestamp is in milliseconds
19    pub timestamp: u64,
20    pub bits: u32,
21    pub nonce: u64,
22    pub daa_score: u64,
23    pub blue_work: BlueWorkType,
24    pub blue_score: u64,
25    pub pruning_point: Hash,
26}
27
28impl Header {
29    #[allow(clippy::too_many_arguments)]
30    pub fn new_finalized(
31        version: u16,
32        parents_by_level: Vec<Vec<Hash>>,
33        hash_merkle_root: Hash,
34        accepted_id_merkle_root: Hash,
35        utxo_commitment: Hash,
36        timestamp: u64,
37        bits: u32,
38        nonce: u64,
39        daa_score: u64,
40        blue_work: BlueWorkType,
41        blue_score: u64,
42        pruning_point: Hash,
43    ) -> Self {
44        let mut header = Self {
45            hash: Default::default(), // Temp init before the finalize below
46            version,
47            parents_by_level,
48            hash_merkle_root,
49            accepted_id_merkle_root,
50            utxo_commitment,
51            nonce,
52            timestamp,
53            daa_score,
54            bits,
55            blue_work,
56            blue_score,
57            pruning_point,
58        };
59        header.finalize();
60        header
61    }
62
63    /// Finalizes the header and recomputes the header hash
64    pub fn finalize(&mut self) {
65        self.hash = hashing::header::hash(self);
66    }
67
68    pub fn direct_parents(&self) -> &[Hash] {
69        if self.parents_by_level.is_empty() {
70            &[]
71        } else {
72            &self.parents_by_level[0]
73        }
74    }
75
76    /// WARNING: To be used for test purposes only
77    pub fn from_precomputed_hash(hash: Hash, parents: Vec<Hash>) -> Header {
78        Header {
79            version: crate::constants::BLOCK_VERSION,
80            hash,
81            parents_by_level: vec![parents],
82            hash_merkle_root: Default::default(),
83            accepted_id_merkle_root: Default::default(),
84            utxo_commitment: Default::default(),
85            nonce: 0,
86            timestamp: 0,
87            daa_score: 0,
88            bits: 0,
89            blue_work: 0.into(),
90            blue_score: 0,
91            pruning_point: Default::default(),
92        }
93    }
94}
95
96impl AsRef<Header> for Header {
97    fn as_ref(&self) -> &Header {
98        self
99    }
100}
101
102impl MemSizeEstimator for Header {
103    fn estimate_mem_bytes(&self) -> usize {
104        size_of::<Self>() + self.parents_by_level.iter().map(|l| l.len()).sum::<usize>() * size_of::<Hash>()
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111    use kaspa_math::Uint192;
112    use serde_json::Value;
113
114    #[test]
115    fn test_header_ser() {
116        let header = Header::new_finalized(
117            1,
118            vec![vec![1.into()]],
119            Default::default(),
120            Default::default(),
121            Default::default(),
122            234,
123            23,
124            567,
125            0,
126            Uint192([0x1234567890abcfed, 0xc0dec0ffeec0ffee, 0x1234567890abcdef]),
127            u64::MAX,
128            Default::default(),
129        );
130        let json = serde_json::to_string(&header).unwrap();
131        println!("{}", json);
132
133        let v = serde_json::from_str::<Value>(&json).unwrap();
134        let blue_work = v.get("blueWork").expect("missing `blueWork` property");
135        let blue_work = blue_work.as_str().expect("`blueWork` is not a string");
136        assert_eq!(blue_work, "1234567890abcdefc0dec0ffeec0ffee1234567890abcfed");
137        let blue_score = v.get("blueScore").expect("missing `blueScore` property");
138        let blue_score: u64 = blue_score.as_u64().expect("blueScore is not a u64 compatible value");
139        assert_eq!(blue_score, u64::MAX);
140
141        let h = serde_json::from_str::<Header>(&json).unwrap();
142        assert!(h.blue_score == header.blue_score && h.blue_work == header.blue_work);
143    }
144}