titan_types/
block.rs

1use {
2    bitcoin::{
3        block::{Header, Version},
4        hashes::Hash,
5        BlockHash, CompactTarget, TxMerkleNode,
6    },
7    borsh::{BorshDeserialize, BorshSerialize},
8    ordinals::RuneId,
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<String>,
18    pub etched_runes: Vec<RuneId>,
19}
20
21impl BorshSerialize for Block {
22    fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
23        // 1) Serialize `height`
24        BorshSerialize::serialize(&self.height, writer)?;
25
26        // 2) Serialize `header` manually
27        BorshSerialize::serialize(&self.header.version.to_consensus(), writer)?;
28
29        // `as_raw_hash()` returns a &sha256d::Hash, which we can then convert
30        // into a 32-byte array. That array is what Borsh will see.
31        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        // 3) Serialize `tx_ids` as a Vec<String>
45        //    (Vec<String> already implements BorshSerialize)
46        BorshSerialize::serialize(&self.tx_ids, writer)?;
47
48        // 3) Serialize `etched_runes` manually:
49        //    Borsh doesn't know about `RuneId`, so we store it ourselves:
50        //
51        //    - First, write the length of the vector
52        //    - Then for each `RuneId`, write out (block, tx)
53
54        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        // 1) Deserialize `height`
69        let height = u64::deserialize_reader(reader)?;
70
71        // 2) Deserialize `header` manually
72        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        // 3) Deserialize `tx_ids` (Vec<String>)
101        let tx_ids = Vec::<String>::deserialize_reader(reader)?;
102
103        // 3) Deserialize `etched_runes` manually:
104        //    - Read the length
105        //    - For each entry, read `block` (u64) then `tx` (u32)
106
107        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 { 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}