amaru_kernel/cardano/
block_header.rs1use std::{
16 cmp::Ordering,
17 fmt::{self, Debug, Display, Formatter},
18};
19
20use crate::{
21 BlockHeight, Hasher, Header, HeaderBody, HeaderHash, IsHeader, Point, Slot, Tip,
22 cbor::{self},
23 size::HEADER,
24};
25
26#[cfg(any(test, feature = "test-utils"))]
27mod tests;
28
29#[cfg(any(test, feature = "test-utils"))]
30pub use tests::*;
31
32#[derive(PartialEq, Eq, Clone)]
34pub struct BlockHeader {
35 header: Header,
36 hash: HeaderHash,
37}
38
39impl Display for BlockHeader {
40 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
41 f.write_str(&format!(
42 "{}. {}{}",
43 self.slot(),
44 self.hash(),
45 self.parent_hash().map(|p| format!(" ({p})")).unwrap_or_default()
46 ))?;
47 Ok(())
48 }
49}
50
51impl serde::Serialize for BlockHeader {
54 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
55 where
56 S: serde::Serializer,
57 {
58 #[derive(serde::Serialize)]
59 struct BlockHeaderSer<'a> {
60 hash: &'a HeaderHash,
61 #[serde(flatten)]
62 header: &'a Header,
63 }
64
65 let helper = BlockHeaderSer { hash: &self.hash, header: &self.header };
66
67 helper.serialize(serializer)
68 }
69}
70
71impl<'de> serde::Deserialize<'de> for BlockHeader {
72 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
73 where
74 D: serde::Deserializer<'de>,
75 {
76 let header = Header::deserialize(deserializer)?;
77 Ok(BlockHeader::from(header))
78 }
79}
80
81impl Debug for BlockHeader {
82 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
83 f.debug_struct("BlockHeader")
84 .field("hash", &hex::encode(self.hash()))
85 .field("slot", &self.slot().as_u64())
86 .field("parent", &self.parent().map(hex::encode))
87 .finish()
88 }
89}
90
91impl PartialOrd for BlockHeader {
92 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
93 Some(self.cmp(other))
94 }
95}
96
97impl Ord for BlockHeader {
98 fn cmp(&self, other: &Self) -> Ordering {
99 self.point().cmp(&other.point())
100 }
101}
102
103impl core::hash::Hash for BlockHeader {
104 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
105 self.hash.hash(state);
106 }
107}
108
109impl BlockHeader {
110 #[cfg(feature = "test-utils")]
113 pub fn new(header: Header, hash: HeaderHash) -> Self {
114 Self { header, hash }
115 }
116
117 pub fn header(&self) -> &Header {
118 &self.header
119 }
120
121 pub fn header_body(&self) -> &HeaderBody {
122 &self.header.header_body
123 }
124
125 pub fn parent_hash(&self) -> Option<HeaderHash> {
126 self.header.header_body.prev_hash
127 }
128
129 fn recompute_hash(&mut self) {
130 self.hash = Hasher::<{ HEADER * 8 }>::hash_cbor(&self.header);
131 }
132
133 pub fn tip(&self) -> Tip {
134 Tip::new(self.point(), self.block_height())
135 }
136}
137
138impl<C> cbor::Encode<C> for BlockHeader {
139 fn encode<W: cbor::encode::Write>(
140 &self,
141 e: &mut cbor::Encoder<W>,
142 ctx: &mut C,
143 ) -> Result<(), cbor::encode::Error<W::Error>> {
144 self.header.encode(e, ctx)
145 }
146}
147
148impl<'b, C> cbor::Decode<'b, C> for BlockHeader {
149 fn decode(d: &mut cbor::Decoder<'b>, ctx: &mut C) -> Result<Self, cbor::decode::Error> {
150 let header = Header::decode(d, ctx)?;
151 Ok(BlockHeader::from(header))
152 }
153}
154
155impl From<Header> for BlockHeader {
156 fn from(header: Header) -> Self {
157 let hash = Point::Origin.hash();
158 let mut block_header = Self { header, hash };
159 block_header.recompute_hash();
160 block_header
161 }
162}
163
164impl From<&Header> for BlockHeader {
165 fn from(header: &Header) -> Self {
166 let hash = Point::Origin.hash();
167 let mut block_header = Self { header: header.clone(), hash };
168 block_header.recompute_hash();
169 block_header
170 }
171}
172
173impl IsHeader for BlockHeader {
179 fn hash(&self) -> HeaderHash {
180 self.hash
181 }
182
183 fn parent(&self) -> Option<HeaderHash> {
184 self.header.header_body.prev_hash
185 }
186
187 fn block_height(&self) -> BlockHeight {
188 self.header.header_body.block_number.into()
189 }
190
191 fn slot(&self) -> Slot {
192 self.header.header_body.slot.into()
193 }
194
195 fn extended_vrf_nonce_output(&self) -> Vec<u8> {
196 self.header.header_body.nonce_vrf_output()
197 }
198}