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#[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}