titan_types/
lib.rs

1pub use {
2    address::{AddressData, AddressTxOut},
3    block::Block,
4    event::{Event, EventType, Location},
5    inscription_id::InscriptionId,
6    mempool_entry::{MempoolEntry, MempoolEntryFee},
7    outpoint::SerializedOutPoint,
8    pagination::{Pagination, PaginationResponse},
9    rune::{MintResponse, RuneAmount, RuneResponse},
10    stats::{BlockTip, Status},
11    subscription::{Subscription, TcpSubscriptionRequest},
12    transaction::{Transaction, TransactionStatus},
13    tx_in::TxIn,
14    tx_out::{SpenderReference, SpentStatus, TxOut},
15    txid::SerializedTxid,
16};
17
18mod address;
19mod block;
20mod event;
21mod inscription_id;
22mod mempool_entry;
23mod outpoint;
24mod pagination;
25pub mod query;
26mod rune;
27mod rune_id;
28mod rune_type;
29mod serde_str;
30mod spaced_rune;
31mod stats;
32mod subscription;
33mod transaction;
34mod tx_in;
35mod tx_out;
36mod txid;
37
38// Re-export from ordinals crate
39pub use ordinals::{Artifact, Cenotaph, Edict, Etching, Runestone};
40
41pub use crate::rune_id::RuneId;
42pub use crate::rune_type::Rune;
43pub use crate::spaced_rune::SpacedRune;
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use bitcoin::{hashes::Hash, BlockHash, ScriptBuf};
49    use borsh::{BorshDeserialize, BorshSerialize};
50    use serde_json;
51    use std::str::FromStr;
52
53    /// Helper function to test borsh serialization roundtrip
54    fn test_borsh_roundtrip<T>(original: &T) -> T
55    where
56        T: BorshSerialize + BorshDeserialize + std::fmt::Debug + PartialEq,
57    {
58        let serialized = borsh::to_vec(original).expect("Failed to serialize");
59        let deserialized = borsh::from_slice(&serialized).expect("Failed to deserialize");
60        assert_eq!(original, &deserialized, "Borsh roundtrip failed");
61        deserialized
62    }
63
64    /// Helper function to test serde serialization roundtrip
65    fn test_serde_roundtrip<T>(original: &T) -> T
66    where
67        T: serde::Serialize + for<'de> serde::Deserialize<'de> + std::fmt::Debug + PartialEq,
68    {
69        let serialized = serde_json::to_string(original).expect("Failed to serialize");
70        let deserialized = serde_json::from_str(&serialized).expect("Failed to deserialize");
71        assert_eq!(original, &deserialized, "Serde roundtrip failed");
72        deserialized
73    }
74
75    #[test]
76    fn test_serialized_txid() {
77        let txid_bytes = [1u8; 32];
78        let original = SerializedTxid::from(txid_bytes);
79
80        // Test Borsh
81        test_borsh_roundtrip(&original);
82
83        // Test Serde
84        test_serde_roundtrip(&original);
85
86        // Test string conversion
87        let hex_str = original.to_string();
88        let from_str = SerializedTxid::from_str(&hex_str).expect("Failed to parse from string");
89        assert_eq!(original, from_str);
90    }
91
92    #[test]
93    fn test_rune_amount() {
94        let rune_id = RuneId::new(840000, 1);
95        let original = RuneAmount {
96            rune_id,
97            amount: 1000000000000000000u128,
98        };
99
100        // Test Borsh
101        test_borsh_roundtrip(&original);
102
103        // Test Serde
104        test_serde_roundtrip(&original);
105    }
106
107    #[test]
108    fn test_spender_reference() {
109        let txid = SerializedTxid::from([42u8; 32]);
110        let original = SpenderReference { txid, vin: 3 };
111
112        // Test Borsh
113        test_borsh_roundtrip(&original);
114
115        // Test Serde
116        test_serde_roundtrip(&original);
117    }
118
119    #[test]
120    fn test_spent_status() {
121        // Test Unspent variant
122        let unspent = SpentStatus::Unspent;
123        test_borsh_roundtrip(&unspent);
124        test_serde_roundtrip(&unspent);
125
126        // Test Spent variant
127        let txid = SerializedTxid::from([99u8; 32]);
128        let spender_ref = SpenderReference { txid, vin: 2 };
129        let spent = SpentStatus::Spent(spender_ref);
130        test_borsh_roundtrip(&spent);
131        test_serde_roundtrip(&spent);
132    }
133
134    #[test]
135    fn test_tx_out_entry() {
136        let rune_id = RuneId::new(840000, 1);
137        let rune_amount = RuneAmount {
138            rune_id,
139            amount: 500000000000000000u128,
140        };
141
142        let original = TxOut {
143            runes: vec![rune_amount.clone()],
144            risky_runes: vec![rune_amount],
145            value: 50000,
146            spent: SpentStatus::Unspent,
147            script_pubkey: ScriptBuf::new(),
148        };
149
150        // Test Borsh
151        test_borsh_roundtrip(&original);
152
153        // Test Serde
154        test_serde_roundtrip(&original);
155    }
156
157    #[test]
158    fn test_transaction_tx_out() {
159        let script = ScriptBuf::from_bytes(vec![0x76, 0xa9, 0x14]); // OP_DUP OP_HASH160 PUSH(20)
160        let rune_id = RuneId::new(840000, 1);
161        let rune_amount = RuneAmount {
162            rune_id,
163            amount: 100000000000000000u128,
164        };
165
166        let original = TxOut {
167            value: 100000,
168            script_pubkey: script,
169            runes: vec![rune_amount.clone()],
170            risky_runes: vec![rune_amount],
171            spent: SpentStatus::Unspent,
172        };
173
174        // Test Borsh
175        test_borsh_roundtrip(&original);
176
177        // Test Serde
178        test_serde_roundtrip(&original);
179    }
180
181    #[test]
182    fn test_transaction_status() {
183        // Test unconfirmed
184        let unconfirmed = TransactionStatus::unconfirmed();
185        test_serde_roundtrip(&unconfirmed);
186
187        // Test confirmed
188        let block_hash = BlockHash::from_raw_hash(Hash::from_slice(&[1u8; 32]).unwrap());
189        let confirmed = TransactionStatus::confirmed(840000, block_hash);
190        test_serde_roundtrip(&confirmed);
191    }
192
193    #[test]
194    fn test_serialized_outpoint() {
195        let txid_bytes = [5u8; 32];
196        let original = SerializedOutPoint::new(&txid_bytes, 1);
197
198        // Test Borsh
199        test_borsh_roundtrip(&original);
200
201        // Test Serde
202        test_serde_roundtrip(&original);
203
204        // Test component extraction
205        assert_eq!(original.txid(), &txid_bytes);
206        assert_eq!(original.vout(), 1);
207    }
208
209    #[test]
210    fn test_mempool_entry_fee() {
211        let original = MempoolEntryFee {
212            base: 1000,
213            descendant: 2000,
214            ancestor: 3000,
215        };
216
217        // Test Borsh
218        test_borsh_roundtrip(&original);
219
220        // Test Serde
221        test_serde_roundtrip(&original);
222    }
223
224    #[test]
225    fn test_mempool_entry() {
226        let txid = SerializedTxid::from([7u8; 32]);
227        let fees = MempoolEntryFee {
228            base: 1000,
229            descendant: 2000,
230            ancestor: 3000,
231        };
232
233        let original = MempoolEntry {
234            vsize: 250,
235            weight: Some(1000),
236            descendant_count: 1,
237            descendant_size: 250,
238            ancestor_count: 1,
239            ancestor_size: 250,
240            fees,
241            depends: vec![txid.clone()],
242            spent_by: vec![txid],
243        };
244
245        // Test Borsh
246        test_borsh_roundtrip(&original);
247
248        // Test Serde
249        test_serde_roundtrip(&original);
250    }
251
252    #[test]
253    fn test_edge_cases() {
254        // Test empty vectors
255        let empty_tx_out = TxOut {
256            runes: vec![],
257            risky_runes: vec![],
258            value: 0,
259            spent: SpentStatus::Unspent,
260            script_pubkey: ScriptBuf::new(),
261        };
262        test_borsh_roundtrip(&empty_tx_out);
263        test_serde_roundtrip(&empty_tx_out);
264
265        // Test mempool entry with no weight
266        let mempool_no_weight = MempoolEntry {
267            vsize: 250,
268            weight: None,
269            descendant_count: 1,
270            descendant_size: 250,
271            ancestor_count: 1,
272            ancestor_size: 250,
273            fees: MempoolEntryFee {
274                base: 1000,
275                descendant: 2000,
276                ancestor: 3000,
277            },
278            depends: vec![],
279            spent_by: vec![],
280        };
281        test_borsh_roundtrip(&mempool_no_weight);
282        test_serde_roundtrip(&mempool_no_weight);
283
284        // Test max values
285        let max_rune_amount = RuneAmount {
286            rune_id: RuneId::new(u64::MAX, u32::MAX),
287            amount: u128::MAX,
288        };
289        test_borsh_roundtrip(&max_rune_amount);
290        test_serde_roundtrip(&max_rune_amount);
291    }
292
293    #[test]
294    fn test_complex_nested_structures() {
295        // Create a complex TxOut with multiple runes
296        let rune_id1 = RuneId::new(840000, 1);
297        let rune_id2 = RuneId::new(840001, 2);
298
299        let rune_amounts = vec![
300            RuneAmount {
301                rune_id: rune_id1,
302                amount: 1000000000000000000u128,
303            },
304            RuneAmount {
305                rune_id: rune_id2,
306                amount: 2000000000000000000u128,
307            },
308        ];
309
310        let spender_ref = SpenderReference {
311            txid: SerializedTxid::from([255u8; 32]),
312            vin: 0,
313        };
314
315        let complex_tx_out = TxOut {
316            value: 5000000,
317            script_pubkey: ScriptBuf::from_bytes(vec![0x00, 0x14]), // P2WPKH
318            runes: rune_amounts.clone(),
319            risky_runes: rune_amounts,
320            spent: SpentStatus::Spent(spender_ref),
321        };
322
323        test_borsh_roundtrip(&complex_tx_out);
324        test_serde_roundtrip(&complex_tx_out);
325    }
326
327    #[test]
328    fn test_serialization_consistency() {
329        // Ensure that the same data serialized with Borsh and Serde produces
330        // the same result when deserialized
331        let rune_id = RuneId::new(840000, 1);
332        let original = RuneAmount {
333            rune_id,
334            amount: 1000000000000000000u128,
335        };
336
337        let borsh_serialized = borsh::to_vec(&original).unwrap();
338        let borsh_deserialized: RuneAmount = borsh::from_slice(&borsh_serialized).unwrap();
339
340        let serde_serialized = serde_json::to_string(&original).unwrap();
341        let serde_deserialized: RuneAmount = serde_json::from_str(&serde_serialized).unwrap();
342
343        // Both should deserialize to the same value
344        assert_eq!(borsh_deserialized, serde_deserialized);
345        assert_eq!(original, borsh_deserialized);
346        assert_eq!(original, serde_deserialized);
347    }
348}