titan_types/
mempool_entry.rs

1use {
2    crate::SerializedTxid,
3    bitcoincore_rpc::json::GetMempoolEntryResult,
4    borsh::{BorshDeserialize, BorshSerialize},
5    serde::{Deserialize, Serialize},
6    std::io::{Read, Result, Write},
7};
8
9#[derive(
10    Debug, Clone, PartialEq, Eq, Hash, BorshSerialize, BorshDeserialize, Serialize, Deserialize,
11)]
12pub struct MempoolEntryFee {
13    pub base: u64,
14    pub descendant: u64,
15    pub ancestor: u64,
16}
17
18#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
19pub struct MempoolEntry {
20    pub vsize: u64,
21    pub weight: Option<u64>,
22    pub descendant_count: u64,
23    pub descendant_size: u64,
24    pub ancestor_count: u64,
25    pub ancestor_size: u64,
26    pub fees: MempoolEntryFee,
27    pub depends: Vec<SerializedTxid>,
28    #[serde(rename = "spentby")]
29    pub spent_by: Vec<SerializedTxid>,
30}
31
32impl From<&GetMempoolEntryResult> for MempoolEntry {
33    fn from(value: &GetMempoolEntryResult) -> Self {
34        Self {
35            vsize: value.vsize,
36            weight: value.weight,
37            descendant_count: value.descendant_count,
38            descendant_size: value.descendant_size,
39            ancestor_count: value.ancestor_count,
40            ancestor_size: value.ancestor_size,
41            fees: MempoolEntryFee {
42                base: value.fees.base.to_sat(),
43                descendant: value.fees.descendant.to_sat(),
44                ancestor: value.fees.ancestor.to_sat(),
45            },
46            depends: value.depends.iter().map(|txid| txid.into()).collect(),
47            spent_by: value.spent_by.iter().map(|txid| txid.into()).collect(),
48        }
49    }
50}
51
52impl BorshSerialize for MempoolEntry {
53    fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
54        BorshSerialize::serialize(&self.vsize, writer)?;
55
56        if let Some(weight) = self.weight {
57            BorshSerialize::serialize(&true, writer)?;
58            BorshSerialize::serialize(&weight, writer)?;
59        } else {
60            BorshSerialize::serialize(&false, writer)?;
61        }
62
63        BorshSerialize::serialize(&self.descendant_count, writer)?;
64        BorshSerialize::serialize(&self.descendant_size, writer)?;
65        BorshSerialize::serialize(&self.ancestor_count, writer)?;
66        BorshSerialize::serialize(&self.ancestor_size, writer)?;
67        BorshSerialize::serialize(&self.fees, writer)?;
68
69        BorshSerialize::serialize(&(self.depends.len() as u64), writer)?;
70        for txid in &self.depends {
71            BorshSerialize::serialize(&txid, writer)?;
72        }
73
74        BorshSerialize::serialize(&(self.spent_by.len() as u64), writer)?;
75        for txid in &self.spent_by {
76            BorshSerialize::serialize(&txid, writer)?;
77        }
78        Ok(())
79    }
80}
81
82impl BorshDeserialize for MempoolEntry {
83    fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
84        let vsize = u64::deserialize_reader(reader)?;
85
86        let weight_exists = bool::deserialize_reader(reader)?;
87        let weight = if weight_exists {
88            Some(u64::deserialize_reader(reader)?)
89        } else {
90            None
91        };
92
93        let descendant_count = u64::deserialize_reader(reader)?;
94        let descendant_size = u64::deserialize_reader(reader)?;
95        let ancestor_count = u64::deserialize_reader(reader)?;
96        let ancestor_size = u64::deserialize_reader(reader)?;
97        let fees = MempoolEntryFee::deserialize_reader(reader)?;
98
99        let depends_len = u64::deserialize_reader(reader)?;
100        let mut depends = Vec::new();
101        for _ in 0..depends_len {
102            let txid = SerializedTxid::deserialize_reader(reader)?;
103            depends.push(txid);
104        }
105
106        let spent_by_len = u64::deserialize_reader(reader)?;
107        let mut spent_by = Vec::new();
108        for _ in 0..spent_by_len {
109            let txid = SerializedTxid::deserialize_reader(reader)?;
110            spent_by.push(txid);
111        }
112
113        Ok(Self {
114            vsize,
115            weight,
116            descendant_count,
117            descendant_size,
118            ancestor_count,
119            ancestor_size,
120            fees,
121            depends,
122            spent_by,
123        })
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130    use borsh::{BorshDeserialize, BorshSerialize};
131
132    fn create_test_mempool_entry() -> MempoolEntry {
133        MempoolEntry {
134            vsize: 250,
135            weight: Some(1000),
136            descendant_count: 5,
137            descendant_size: 1500,
138            ancestor_count: 3,
139            ancestor_size: 800,
140            fees: MempoolEntryFee {
141                base: 5000,
142                descendant: 7500,
143                ancestor: 4200,
144            },
145            depends: vec![
146                SerializedTxid::from([1u8; 32]),
147                SerializedTxid::from([2u8; 32]),
148            ],
149            spent_by: vec![SerializedTxid::from([3u8; 32])],
150        }
151    }
152
153    fn create_minimal_mempool_entry() -> MempoolEntry {
154        MempoolEntry {
155            vsize: 100,
156            weight: None,
157            descendant_count: 0,
158            descendant_size: 0,
159            ancestor_count: 0,
160            ancestor_size: 0,
161            fees: MempoolEntryFee {
162                base: 1000,
163                descendant: 1000,
164                ancestor: 1000,
165            },
166            depends: vec![],
167            spent_by: vec![],
168        }
169    }
170
171    fn serialize_entry(entry: &MempoolEntry) -> std::io::Result<Vec<u8>> {
172        let mut buffer = Vec::new();
173        BorshSerialize::serialize(entry, &mut buffer)?;
174        Ok(buffer)
175    }
176
177    fn deserialize_entry(data: &[u8]) -> std::io::Result<MempoolEntry> {
178        MempoolEntry::deserialize_reader(&mut data.as_ref())
179    }
180
181    fn serialize_fee(fee: &MempoolEntryFee) -> std::io::Result<Vec<u8>> {
182        let mut buffer = Vec::new();
183        BorshSerialize::serialize(fee, &mut buffer)?;
184        Ok(buffer)
185    }
186
187    fn deserialize_fee(data: &[u8]) -> std::io::Result<MempoolEntryFee> {
188        MempoolEntryFee::deserialize_reader(&mut data.as_ref())
189    }
190
191    #[test]
192    fn test_mempool_entry_serialization_deserialization_round_trip() {
193        let original = create_test_mempool_entry();
194
195        // Serialize
196        let serialized = serialize_entry(&original).expect("Serialization should succeed");
197
198        // Deserialize
199        let deserialized = deserialize_entry(&serialized).expect("Deserialization should succeed");
200
201        // Assert equality
202        assert_eq!(original, deserialized);
203    }
204
205    #[test]
206    fn test_mempool_entry_minimal_serialization_deserialization() {
207        let original = create_minimal_mempool_entry();
208
209        // Serialize
210        let serialized = serialize_entry(&original).expect("Serialization should succeed");
211
212        // Deserialize
213        let deserialized = deserialize_entry(&serialized).expect("Deserialization should succeed");
214
215        // Assert equality
216        assert_eq!(original, deserialized);
217    }
218
219    #[test]
220    fn test_mempool_entry_with_none_weight() {
221        let mut entry = create_test_mempool_entry();
222        entry.weight = None;
223
224        let serialized = serialize_entry(&entry).expect("Serialization should succeed");
225        let deserialized = deserialize_entry(&serialized).expect("Deserialization should succeed");
226
227        assert_eq!(entry, deserialized);
228        assert_eq!(deserialized.weight, None);
229    }
230
231    #[test]
232    fn test_mempool_entry_with_some_weight() {
233        let mut entry = create_test_mempool_entry();
234        entry.weight = Some(42000);
235
236        let serialized = serialize_entry(&entry).expect("Serialization should succeed");
237        let deserialized = deserialize_entry(&serialized).expect("Deserialization should succeed");
238
239        assert_eq!(entry, deserialized);
240        assert_eq!(deserialized.weight, Some(42000));
241    }
242
243    #[test]
244    fn test_mempool_entry_empty_vectors() {
245        let mut entry = create_test_mempool_entry();
246        entry.depends = vec![];
247        entry.spent_by = vec![];
248
249        let serialized = serialize_entry(&entry).expect("Serialization should succeed");
250        let deserialized = deserialize_entry(&serialized).expect("Deserialization should succeed");
251
252        assert_eq!(entry, deserialized);
253        assert!(deserialized.depends.is_empty());
254        assert!(deserialized.spent_by.is_empty());
255    }
256
257    #[test]
258    fn test_mempool_entry_large_vectors() {
259        let mut entry = create_test_mempool_entry();
260
261        // Create larger vectors
262        entry.depends = (0..10)
263            .map(|i| SerializedTxid::from([i as u8; 32]))
264            .collect();
265        entry.spent_by = (10..15)
266            .map(|i| SerializedTxid::from([i as u8; 32]))
267            .collect();
268
269        let serialized = serialize_entry(&entry).expect("Serialization should succeed");
270        let deserialized = deserialize_entry(&serialized).expect("Deserialization should succeed");
271
272        assert_eq!(entry, deserialized);
273        assert_eq!(deserialized.depends.len(), 10);
274        assert_eq!(deserialized.spent_by.len(), 5);
275    }
276
277    #[test]
278    fn test_mempool_entry_fee_serialization() {
279        let fee = MempoolEntryFee {
280            base: u64::MAX,
281            descendant: 0,
282            ancestor: 12345,
283        };
284
285        let serialized = serialize_fee(&fee).expect("Fee serialization should succeed");
286        let deserialized =
287            deserialize_fee(&serialized).expect("Fee deserialization should succeed");
288
289        assert_eq!(fee, deserialized);
290    }
291
292    #[test]
293    fn test_mempool_entry_extreme_values() {
294        let entry = MempoolEntry {
295            vsize: u64::MAX,
296            weight: Some(u64::MAX),
297            descendant_count: u64::MAX,
298            descendant_size: u64::MAX,
299            ancestor_count: u64::MAX,
300            ancestor_size: u64::MAX,
301            fees: MempoolEntryFee {
302                base: u64::MAX,
303                descendant: u64::MAX,
304                ancestor: u64::MAX,
305            },
306            depends: vec![SerializedTxid::all_zeros()],
307            spent_by: vec![SerializedTxid::from([255u8; 32])],
308        };
309
310        let serialized = serialize_entry(&entry).expect("Serialization should succeed");
311        let deserialized = deserialize_entry(&serialized).expect("Deserialization should succeed");
312
313        assert_eq!(entry, deserialized);
314    }
315
316    #[test]
317    fn test_mempool_entry_zero_values() {
318        let entry = MempoolEntry {
319            vsize: 0,
320            weight: Some(0),
321            descendant_count: 0,
322            descendant_size: 0,
323            ancestor_count: 0,
324            ancestor_size: 0,
325            fees: MempoolEntryFee {
326                base: 0,
327                descendant: 0,
328                ancestor: 0,
329            },
330            depends: vec![],
331            spent_by: vec![],
332        };
333
334        let serialized = serialize_entry(&entry).expect("Serialization should succeed");
335        let deserialized = deserialize_entry(&serialized).expect("Deserialization should succeed");
336
337        assert_eq!(entry, deserialized);
338    }
339
340    #[test]
341    fn test_serialized_data_consistency() {
342        let entry1 = create_test_mempool_entry();
343        let entry2 = create_test_mempool_entry();
344
345        let serialized1 = serialize_entry(&entry1).expect("Serialization should succeed");
346        let serialized2 = serialize_entry(&entry2).expect("Serialization should succeed");
347
348        // Same data should produce same serialized bytes
349        assert_eq!(serialized1, serialized2);
350    }
351
352    #[test]
353    fn test_serialization_size_efficiency() {
354        let minimal = create_minimal_mempool_entry();
355        let full = create_test_mempool_entry();
356
357        let minimal_size = serialize_entry(&minimal).unwrap().len();
358        let full_size = serialize_entry(&full).unwrap().len();
359
360        // Full entry should be larger than minimal (basic sanity check)
361        assert!(full_size > minimal_size);
362
363        // Print sizes for debugging (will only show when test runs with --nocapture)
364        println!("Minimal entry serialized size: {} bytes", minimal_size);
365        println!("Full entry serialized size: {} bytes", full_size);
366    }
367
368    #[test]
369    fn test_invalid_deserialization_handling() {
370        // Test with incomplete data
371        let incomplete_data = vec![1, 2, 3]; // Too short to be valid
372        let result = deserialize_entry(&incomplete_data);
373        assert!(
374            result.is_err(),
375            "Should fail to deserialize incomplete data"
376        );
377    }
378}