Skip to main content

csv_adapter_bitcoin/
types.rs

1//! Bitcoin-specific type definitions
2
3use serde::{Deserialize, Serialize};
4
5/// Bitcoin seal reference (UTXO OutPoint)
6#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub struct BitcoinSealRef {
8    /// Transaction ID (32 bytes)
9    pub txid: [u8; 32],
10    /// Output index
11    pub vout: u32,
12    /// Optional nonce for replay resistance
13    pub nonce: Option<u64>,
14}
15
16impl BitcoinSealRef {
17    /// Create a new Bitcoin seal reference
18    pub fn new(txid: [u8; 32], vout: u32, nonce: Option<u64>) -> Self {
19        Self { txid, vout, nonce }
20    }
21
22    /// Serialize to bytes
23    pub fn to_vec(&self) -> Vec<u8> {
24        let mut out = Vec::with_capacity(32 + 4 + 8);
25        out.extend_from_slice(&self.txid);
26        out.extend_from_slice(&self.vout.to_le_bytes());
27        if let Some(nonce) = self.nonce {
28            out.extend_from_slice(&nonce.to_le_bytes());
29        } else {
30            out.extend_from_slice(&[0u8; 8]);
31        }
32        out
33    }
34
35    /// Get txid as hex string
36    pub fn txid_hex(&self) -> String {
37        hex::encode(self.txid)
38    }
39}
40
41/// Bitcoin anchor reference (Transaction containing commitment)
42#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
43pub struct BitcoinAnchorRef {
44    /// Transaction ID
45    pub txid: [u8; 32],
46    /// Output index (for OP_RETURN or Taproot leaf)
47    pub output_index: u32,
48    /// Block height where transaction was included
49    pub block_height: u64,
50}
51
52impl BitcoinAnchorRef {
53    /// Create a new Bitcoin anchor reference
54    pub fn new(txid: [u8; 32], output_index: u32, block_height: u64) -> Self {
55        Self {
56            txid,
57            output_index,
58            block_height,
59        }
60    }
61}
62
63/// Bitcoin inclusion proof (Merkle proof + block header)
64#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
65pub struct BitcoinInclusionProof {
66    /// Merkle branch hashes
67    pub merkle_branch: Vec<[u8; 32]>,
68    /// Block header hash
69    pub block_hash: [u8; 32],
70    /// Transaction index in block
71    pub tx_index: u32,
72    /// Block height
73    pub block_height: u64,
74}
75
76impl BitcoinInclusionProof {
77    /// Create a new Bitcoin inclusion proof
78    pub fn new(
79        merkle_branch: Vec<[u8; 32]>,
80        block_hash: [u8; 32],
81        tx_index: u32,
82        block_height: u64,
83    ) -> Self {
84        Self {
85            merkle_branch,
86            block_hash,
87            tx_index,
88            block_height,
89        }
90    }
91
92    /// Check if confirmed with required depth
93    pub fn is_confirmed(&self, current_height: u64, required_depth: u32) -> bool {
94        self.block_height + required_depth as u64 <= current_height
95    }
96}
97
98/// Bitcoin finality proof (confirmation depth)
99#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
100pub struct BitcoinFinalityProof {
101    /// Number of confirmations
102    pub confirmations: u64,
103    /// Whether the required depth is met
104    pub meets_required_depth: bool,
105    /// Required confirmation depth
106    pub required_depth: u32,
107}
108
109impl BitcoinFinalityProof {
110    /// Create a new Bitcoin finality proof
111    pub fn new(confirmations: u64, required_depth: u32) -> Self {
112        Self {
113            confirmations,
114            meets_required_depth: confirmations >= required_depth as u64,
115            required_depth,
116        }
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_seal_ref_creation() {
126        let seal = BitcoinSealRef::new([1u8; 32], 0, Some(42));
127        assert_eq!(seal.vout, 0);
128        assert_eq!(seal.nonce, Some(42));
129    }
130
131    #[test]
132    fn test_anchor_ref_creation() {
133        let anchor = BitcoinAnchorRef::new([2u8; 32], 1, 100);
134        assert_eq!(anchor.output_index, 1);
135        assert_eq!(anchor.block_height, 100);
136    }
137
138    #[test]
139    fn test_inclusion_proof_confirmed() {
140        let proof = BitcoinInclusionProof::new(vec![], [3u8; 32], 0, 100);
141        assert!(proof.is_confirmed(106, 6));
142        assert!(!proof.is_confirmed(105, 6));
143    }
144
145    #[test]
146    fn test_finality_proof() {
147        let proof = BitcoinFinalityProof::new(6, 6);
148        assert!(proof.meets_required_depth);
149
150        let proof = BitcoinFinalityProof::new(5, 6);
151        assert!(!proof.meets_required_depth);
152    }
153}