1use {
2 crate::{rune_id::RuneId, SerializedTxid},
3 bitcoin::{
4 block::{Header, Version},
5 hashes::Hash,
6 BlockHash, CompactTarget, TxMerkleNode,
7 },
8 borsh::{BorshDeserialize, BorshSerialize},
9 serde::{Deserialize, Serialize},
10 std::io::{Read, Result, Write},
11};
12
13#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
14pub struct Block {
15 pub height: u64,
16 pub header: Header,
17 pub tx_ids: Vec<SerializedTxid>,
18 pub etched_runes: Vec<RuneId>,
19}
20
21impl BorshSerialize for Block {
22 fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
23 BorshSerialize::serialize(&self.height, writer)?;
25
26 BorshSerialize::serialize(&self.header.version.to_consensus(), writer)?;
28
29 BorshSerialize::serialize(
32 &self.header.prev_blockhash.as_raw_hash().as_byte_array(),
33 writer,
34 )?;
35
36 BorshSerialize::serialize(
37 &self.header.merkle_root.as_raw_hash().as_byte_array(),
38 writer,
39 )?;
40 BorshSerialize::serialize(&self.header.time, writer)?;
41 BorshSerialize::serialize(&self.header.bits.to_consensus(), writer)?;
42 BorshSerialize::serialize(&self.header.nonce, writer)?;
43
44 BorshSerialize::serialize(&self.tx_ids, writer)?;
47
48 let etched_len = self.etched_runes.len() as u64;
55 BorshSerialize::serialize(&etched_len, writer)?;
56
57 for rune_id in &self.etched_runes {
58 BorshSerialize::serialize(&rune_id.block, writer)?;
59 BorshSerialize::serialize(&rune_id.tx, writer)?;
60 }
61
62 Ok(())
63 }
64}
65
66impl BorshDeserialize for Block {
67 fn deserialize_reader<R: Read>(reader: &mut R) -> std::io::Result<Self> {
68 let height = u64::deserialize_reader(reader)?;
70
71 let version = Version::from_consensus(i32::deserialize_reader(reader)?);
73
74 let mut prev_hash = [0u8; 32];
75 reader.read_exact(&mut prev_hash)?;
76 let prev_blockhash =
77 BlockHash::from_raw_hash(Hash::from_slice(&prev_hash).map_err(|_| {
78 std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid prev_blockhash")
79 })?);
80
81 let mut merkle = [0u8; 32];
82 reader.read_exact(&mut merkle)?;
83 let merkle_root = TxMerkleNode::from_raw_hash(Hash::from_slice(&merkle).map_err(|_| {
84 std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid merkle_root")
85 })?);
86
87 let time = u32::deserialize_reader(reader)?;
88 let bits = CompactTarget::from_consensus(u32::deserialize_reader(reader)?);
89 let nonce = u32::deserialize_reader(reader)?;
90
91 let header = Header {
92 version,
93 prev_blockhash,
94 merkle_root,
95 time,
96 bits,
97 nonce,
98 };
99
100 let tx_ids = Vec::<SerializedTxid>::deserialize_reader(reader)?;
102
103 let etched_len = u64::deserialize_reader(reader)?;
108 let mut etched_runes = Vec::with_capacity(etched_len as usize);
109
110 for _ in 0..etched_len {
111 let block = u64::deserialize_reader(reader)?;
112 let tx = u32::deserialize_reader(reader)?;
113 etched_runes.push(RuneId::new(block, tx));
114 }
115
116 Ok(Self {
117 height,
118 header,
119 tx_ids,
120 etched_runes,
121 })
122 }
123}
124
125impl Block {
126 pub fn empty_block(height: u64, header: Header) -> Self {
127 Self {
128 height,
129 header,
130 tx_ids: vec![],
131 etched_runes: vec![],
132 }
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use crate::rune_id::RuneId;
140 use bitcoin::{block::Version, hashes::Hash, BlockHash, CompactTarget, TxMerkleNode};
141 use borsh::BorshDeserialize;
142
143 fn create_test_header() -> Header {
145 Header {
146 version: Version::from_consensus(1),
147 prev_blockhash: BlockHash::from_raw_hash(Hash::from_slice(&[1u8; 32]).unwrap()),
148 merkle_root: TxMerkleNode::from_raw_hash(Hash::from_slice(&[2u8; 32]).unwrap()),
149 time: 1640995200, bits: CompactTarget::from_consensus(0x1d00ffff),
151 nonce: 42,
152 }
153 }
154
155 fn create_test_txids() -> Vec<SerializedTxid> {
157 vec![
158 SerializedTxid::from([3u8; 32]),
159 SerializedTxid::from([4u8; 32]),
160 SerializedTxid::from([5u8; 32]),
161 ]
162 }
163
164 fn create_test_rune_ids() -> Vec<RuneId> {
166 vec![
167 RuneId::new(100, 0),
168 RuneId::new(101, 1),
169 RuneId::new(102, 2),
170 ]
171 }
172
173 #[test]
174 fn test_empty_block_serialization_roundtrip() {
175 let header = create_test_header();
176 let block = Block::empty_block(12345, header.clone());
177
178 let serialized = borsh::to_vec(&block).expect("Failed to serialize empty block");
180
181 let deserialized =
183 Block::try_from_slice(&serialized).expect("Failed to deserialize empty block");
184
185 assert_eq!(block.height, deserialized.height);
187 assert_eq!(block.header, deserialized.header);
188 assert_eq!(block.tx_ids, deserialized.tx_ids);
189 assert_eq!(block.etched_runes, deserialized.etched_runes);
190 assert_eq!(block, deserialized);
191 }
192
193 #[test]
194 fn test_full_block_serialization_roundtrip() {
195 let header = create_test_header();
196 let tx_ids = create_test_txids();
197 let etched_runes = create_test_rune_ids();
198
199 let block = Block {
200 height: 67890,
201 header: header.clone(),
202 tx_ids: tx_ids.clone(),
203 etched_runes: etched_runes.clone(),
204 };
205
206 let serialized = borsh::to_vec(&block).expect("Failed to serialize full block");
208
209 let deserialized =
211 Block::try_from_slice(&serialized).expect("Failed to deserialize full block");
212
213 assert_eq!(block.height, deserialized.height);
215 assert_eq!(block.header, deserialized.header);
216 assert_eq!(block.tx_ids, deserialized.tx_ids);
217 assert_eq!(block.etched_runes, deserialized.etched_runes);
218 assert_eq!(block, deserialized);
219 }
220
221 #[test]
222 fn test_block_with_single_tx_serialization() {
223 let header = create_test_header();
224 let tx_ids = vec![SerializedTxid::from([6u8; 32])];
225
226 let block = Block {
227 height: 1,
228 header: header.clone(),
229 tx_ids: tx_ids.clone(),
230 etched_runes: vec![],
231 };
232
233 let serialized = borsh::to_vec(&block).expect("Failed to serialize single tx block");
235
236 let deserialized =
238 Block::try_from_slice(&serialized).expect("Failed to deserialize single tx block");
239
240 assert_eq!(block, deserialized);
241 assert_eq!(deserialized.tx_ids.len(), 1);
242 assert_eq!(deserialized.etched_runes.len(), 0);
243 }
244
245 #[test]
246 fn test_block_with_single_rune_serialization() {
247 let header = create_test_header();
248 let etched_runes = vec![RuneId::new(999, 888)];
249
250 let block = Block {
251 height: 2,
252 header: header.clone(),
253 tx_ids: vec![],
254 etched_runes: etched_runes.clone(),
255 };
256
257 let serialized = borsh::to_vec(&block).expect("Failed to serialize single rune block");
259
260 let deserialized =
262 Block::try_from_slice(&serialized).expect("Failed to deserialize single rune block");
263
264 assert_eq!(block, deserialized);
265 assert_eq!(deserialized.tx_ids.len(), 0);
266 assert_eq!(deserialized.etched_runes.len(), 1);
267 assert_eq!(deserialized.etched_runes[0].block, 999);
268 assert_eq!(deserialized.etched_runes[0].tx, 888);
269 }
270
271 #[test]
272 fn test_block_with_edge_case_values() {
273 let header = Header {
274 version: Version::from_consensus(i32::MAX),
275 prev_blockhash: BlockHash::from_raw_hash(Hash::from_slice(&[0u8; 32]).unwrap()),
276 merkle_root: TxMerkleNode::from_raw_hash(Hash::from_slice(&[255u8; 32]).unwrap()),
277 time: u32::MAX,
278 bits: CompactTarget::from_consensus(u32::MAX),
279 nonce: u32::MAX,
280 };
281
282 let block = Block {
283 height: u64::MAX,
284 header: header.clone(),
285 tx_ids: vec![SerializedTxid::all_zeros()],
286 etched_runes: vec![RuneId::new(u64::MAX, u32::MAX)],
287 };
288
289 let serialized = borsh::to_vec(&block).expect("Failed to serialize edge case block");
291
292 let deserialized =
294 Block::try_from_slice(&serialized).expect("Failed to deserialize edge case block");
295
296 assert_eq!(block, deserialized);
297 assert_eq!(deserialized.height, u64::MAX);
298 assert_eq!(deserialized.header.time, u32::MAX);
299 assert_eq!(deserialized.etched_runes[0].block, u64::MAX);
300 assert_eq!(deserialized.etched_runes[0].tx, u32::MAX);
301 }
302
303 #[test]
304 fn test_large_vectors_serialization() {
305 let header = create_test_header();
306
307 let large_tx_ids: Vec<SerializedTxid> = (0..1000)
309 .map(|i| {
310 let mut bytes = [0u8; 32];
311 bytes[0..4].copy_from_slice(&(i as u32).to_le_bytes());
312 SerializedTxid::from(bytes)
313 })
314 .collect();
315
316 let large_etched_runes: Vec<RuneId> = (0..500)
317 .map(|i| RuneId::new(i as u64, (i * 2) as u32))
318 .collect();
319
320 let block = Block {
321 height: 500000,
322 header: header.clone(),
323 tx_ids: large_tx_ids.clone(),
324 etched_runes: large_etched_runes.clone(),
325 };
326
327 let serialized = borsh::to_vec(&block).expect("Failed to serialize large block");
329
330 let deserialized =
332 Block::try_from_slice(&serialized).expect("Failed to deserialize large block");
333
334 assert_eq!(block, deserialized);
335 assert_eq!(deserialized.tx_ids.len(), 1000);
336 assert_eq!(deserialized.etched_runes.len(), 500);
337
338 assert_eq!(deserialized.tx_ids[0], large_tx_ids[0]);
340 assert_eq!(deserialized.tx_ids[999], large_tx_ids[999]);
341 assert_eq!(deserialized.etched_runes[0], large_etched_runes[0]);
342 assert_eq!(deserialized.etched_runes[499], large_etched_runes[499]);
343 }
344
345 #[test]
346 fn test_serialized_data_integrity() {
347 let header = create_test_header();
348 let block = Block {
349 height: 123456,
350 header: header.clone(),
351 tx_ids: create_test_txids(),
352 etched_runes: create_test_rune_ids(),
353 };
354
355 let serialized1 = borsh::to_vec(&block).expect("Failed first serialization");
357 let serialized2 = borsh::to_vec(&block).expect("Failed second serialization");
358
359 assert_eq!(
360 serialized1, serialized2,
361 "Serialization should be deterministic"
362 );
363
364 assert!(
366 !serialized1.is_empty(),
367 "Serialized data should not be empty"
368 );
369
370 let deserialized = Block::try_from_slice(&serialized1).expect("Failed to deserialize");
372 let re_serialized = borsh::to_vec(&deserialized).expect("Failed to re-serialize");
373
374 assert_eq!(
375 serialized1, re_serialized,
376 "Re-serialization should match original"
377 );
378 }
379
380 #[test]
381 fn test_header_fields_preservation() {
382 let headers = vec![
384 Header {
385 version: Version::from_consensus(1),
386 prev_blockhash: BlockHash::from_raw_hash(Hash::from_slice(&[1u8; 32]).unwrap()),
387 merkle_root: TxMerkleNode::from_raw_hash(Hash::from_slice(&[2u8; 32]).unwrap()),
388 time: 1000000,
389 bits: CompactTarget::from_consensus(0x1d00ffff),
390 nonce: 12345,
391 },
392 Header {
393 version: Version::from_consensus(536870912), prev_blockhash: BlockHash::from_raw_hash(Hash::from_slice(&[255u8; 32]).unwrap()),
395 merkle_root: TxMerkleNode::from_raw_hash(Hash::from_slice(&[0u8; 32]).unwrap()),
396 time: 0,
397 bits: CompactTarget::from_consensus(0x1d00ffff),
398 nonce: 0,
399 },
400 ];
401
402 for (i, header) in headers.iter().enumerate() {
403 let block = Block {
404 height: i as u64,
405 header: *header,
406 tx_ids: vec![],
407 etched_runes: vec![],
408 };
409
410 let serialized =
411 borsh::to_vec(&block).expect(&format!("Failed to serialize header test {}", i));
412 let deserialized = Block::try_from_slice(&serialized)
413 .expect(&format!("Failed to deserialize header test {}", i));
414
415 assert_eq!(block.header.version, deserialized.header.version);
416 assert_eq!(
417 block.header.prev_blockhash,
418 deserialized.header.prev_blockhash
419 );
420 assert_eq!(block.header.merkle_root, deserialized.header.merkle_root);
421 assert_eq!(block.header.time, deserialized.header.time);
422 assert_eq!(block.header.bits, deserialized.header.bits);
423 assert_eq!(block.header.nonce, deserialized.header.nonce);
424 }
425 }
426
427 #[test]
428 fn test_invalid_data_handling() {
429 let incomplete_data = vec![1, 2, 3, 4, 5];
431 assert!(Block::try_from_slice(&incomplete_data).is_err());
432
433 let empty_data = vec![];
435 assert!(Block::try_from_slice(&empty_data).is_err());
436 }
437}