Skip to main content

hotmint_types/
block.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4use crate::validator::ValidatorId;
5use crate::view::ViewNumber;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
8pub struct BlockHash(pub [u8; 32]);
9
10impl BlockHash {
11    pub const GENESIS: Self = Self([0u8; 32]);
12
13    pub fn is_genesis(&self) -> bool {
14        self.0 == [0u8; 32]
15    }
16}
17
18impl fmt::Display for BlockHash {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        write!(f, "{}", hex::encode(&self.0[..4]))
21    }
22}
23
24#[derive(
25    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default,
26)]
27pub struct Height(pub u64);
28
29impl Height {
30    pub const GENESIS: Self = Self(0);
31
32    pub fn next(self) -> Self {
33        Self(self.0 + 1)
34    }
35
36    pub fn as_u64(self) -> u64 {
37        self.0
38    }
39}
40
41impl fmt::Display for Height {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        write!(f, "h{}", self.0)
44    }
45}
46
47impl From<u64> for Height {
48    fn from(v: u64) -> Self {
49        Self(v)
50    }
51}
52
53/// Block B_k := (b_k, h_{k-1})
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct Block {
56    pub height: Height,
57    pub parent_hash: BlockHash,
58    pub view: ViewNumber,
59    pub proposer: ValidatorId,
60    pub payload: Vec<u8>,
61    pub hash: BlockHash,
62}
63
64impl Block {
65    pub fn genesis() -> Self {
66        Self {
67            height: Height::GENESIS,
68            parent_hash: BlockHash::GENESIS,
69            view: ViewNumber::GENESIS,
70            proposer: ValidatorId::default(),
71            payload: Vec::new(),
72            hash: BlockHash::GENESIS,
73        }
74    }
75}
76
77mod hex {
78    pub fn encode(bytes: &[u8]) -> String {
79        bytes.iter().map(|b| format!("{:02x}", b)).collect()
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_block_hash_genesis() {
89        assert!(BlockHash::GENESIS.is_genesis());
90        assert!(!BlockHash([1u8; 32]).is_genesis());
91    }
92
93    #[test]
94    fn test_block_hash_display() {
95        let h = BlockHash([
96            0xab, 0xcd, 0xef, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97            0, 0, 0, 0, 0, 0, 0,
98        ]);
99        assert_eq!(format!("{h}"), "abcdef12");
100    }
101
102    #[test]
103    fn test_height_next() {
104        assert_eq!(Height(0).next(), Height(1));
105        assert_eq!(Height(99).next(), Height(100));
106    }
107
108    #[test]
109    fn test_height_ordering() {
110        assert!(Height(1) < Height(2));
111        assert!(Height(5) > Height(3));
112        assert!(Height(0) <= Height::GENESIS);
113    }
114
115    #[test]
116    fn test_genesis_block() {
117        let g = Block::genesis();
118        assert_eq!(g.height, Height::GENESIS);
119        assert!(g.parent_hash.is_genesis());
120        assert!(g.hash.is_genesis());
121        assert!(g.payload.is_empty());
122    }
123}