Send reminders for stale-ish channels.
[rapid-gossip-sync-server] / src / serialization.rs
1 use std::cmp::max;
2 use std::collections::HashMap;
3
4 use bitcoin::BlockHash;
5 use bitcoin::hashes::Hash;
6 use lightning::ln::msgs::{UnsignedChannelAnnouncement, UnsignedChannelUpdate};
7 use lightning::util::ser::{BigSize, Writeable};
8
9 use crate::lookup::{DeltaSet, DirectedUpdateDelta};
10
11 pub(super) struct SerializationSet {
12         pub(super) announcements: Vec<UnsignedChannelAnnouncement>,
13         pub(super) updates: Vec<UpdateSerialization>,
14         pub(super) full_update_defaults: DefaultUpdateValues,
15         pub(super) latest_seen: u32,
16         pub(super) chain_hash: BlockHash,
17 }
18
19 pub(super) struct DefaultUpdateValues {
20         pub(super) cltv_expiry_delta: u16,
21         pub(super) htlc_minimum_msat: u64,
22         pub(super) fee_base_msat: u32,
23         pub(super) fee_proportional_millionths: u32,
24         pub(super) htlc_maximum_msat: u64,
25 }
26
27 impl Default for DefaultUpdateValues {
28         fn default() -> Self {
29                 Self {
30                         cltv_expiry_delta: 0,
31                         htlc_minimum_msat: 0,
32                         fee_base_msat: 0,
33                         fee_proportional_millionths: 0,
34                         htlc_maximum_msat: 0,
35                 }
36         }
37 }
38
39 pub(super) struct MutatedProperties {
40         pub(super) flags: bool,
41         pub(super) cltv_expiry_delta: bool,
42         pub(super) htlc_minimum_msat: bool,
43         pub(super) fee_base_msat: bool,
44         pub(super) fee_proportional_millionths: bool,
45         pub(super) htlc_maximum_msat: bool,
46 }
47
48 impl Default for MutatedProperties {
49         fn default() -> Self {
50                 Self {
51                         flags: false,
52                         cltv_expiry_delta: false,
53                         htlc_minimum_msat: false,
54                         fee_base_msat: false,
55                         fee_proportional_millionths: false,
56                         htlc_maximum_msat: false,
57                 }
58         }
59 }
60
61 pub(super) struct UpdateSerialization {
62         pub(super) update: UnsignedChannelUpdate,
63         pub(super) mechanism: UpdateSerializationMechanism,
64 }
65
66 impl MutatedProperties {
67         /// Does not include flags because the flag byte is always sent in full
68         fn len(&self) -> u8 {
69                 let mut mutations = 0;
70                 if self.cltv_expiry_delta { mutations += 1; };
71                 if self.htlc_minimum_msat { mutations += 1; };
72                 if self.fee_base_msat { mutations += 1; };
73                 if self.fee_proportional_millionths { mutations += 1; };
74                 if self.htlc_maximum_msat { mutations += 1; };
75                 mutations
76         }
77 }
78
79 pub(super) enum UpdateSerializationMechanism {
80         Full,
81         Incremental(MutatedProperties),
82         Reminder,
83 }
84
85 struct FullUpdateValueHistograms {
86         cltv_expiry_delta: HashMap<u16, usize>,
87         htlc_minimum_msat: HashMap<u64, usize>,
88         fee_base_msat: HashMap<u32, usize>,
89         fee_proportional_millionths: HashMap<u32, usize>,
90         htlc_maximum_msat: HashMap<u64, usize>,
91 }
92
93 pub(super) fn serialize_delta_set(delta_set: DeltaSet, last_sync_timestamp: u32) -> SerializationSet {
94         let mut serialization_set = SerializationSet {
95                 announcements: vec![],
96                 updates: vec![],
97                 full_update_defaults: Default::default(),
98                 chain_hash: BlockHash::all_zeros(),
99                 latest_seen: 0,
100         };
101
102         let mut chain_hash_set = false;
103
104         let mut full_update_histograms = FullUpdateValueHistograms {
105                 cltv_expiry_delta: Default::default(),
106                 htlc_minimum_msat: Default::default(),
107                 fee_base_msat: Default::default(),
108                 fee_proportional_millionths: Default::default(),
109                 htlc_maximum_msat: Default::default(),
110         };
111
112         let mut record_full_update_in_histograms = |full_update: &UnsignedChannelUpdate| {
113                 *full_update_histograms.cltv_expiry_delta.entry(full_update.cltv_expiry_delta).or_insert(0) += 1;
114                 *full_update_histograms.htlc_minimum_msat.entry(full_update.htlc_minimum_msat).or_insert(0) += 1;
115                 *full_update_histograms.fee_base_msat.entry(full_update.fee_base_msat).or_insert(0) += 1;
116                 *full_update_histograms.fee_proportional_millionths.entry(full_update.fee_proportional_millionths).or_insert(0) += 1;
117                 *full_update_histograms.htlc_maximum_msat.entry(full_update.htlc_maximum_msat).or_insert(0) += 1;
118         };
119
120         for (_scid, channel_delta) in delta_set.into_iter() {
121
122                 // any announcement chain hash is gonna be the same value. Just set it from the first one.
123                 let channel_announcement_delta = channel_delta.announcement.as_ref().unwrap();
124                 if !chain_hash_set {
125                         chain_hash_set = true;
126                         serialization_set.chain_hash = channel_announcement_delta.announcement.chain_hash.clone();
127                 }
128
129                 let current_announcement_seen = channel_announcement_delta.seen;
130                 let is_new_announcement = current_announcement_seen >= last_sync_timestamp;
131                 let is_newly_updated_announcement = if let Some(first_update_seen) = channel_delta.first_bidirectional_updates_seen {
132                         first_update_seen >= last_sync_timestamp
133                 } else {
134                         false
135                 };
136                 let send_announcement = is_new_announcement || is_newly_updated_announcement;
137                 if send_announcement {
138                         serialization_set.latest_seen = max(serialization_set.latest_seen, current_announcement_seen);
139                         serialization_set.announcements.push(channel_delta.announcement.unwrap().announcement);
140                 }
141
142                 let direction_a_updates = channel_delta.updates.0;
143                 let direction_b_updates = channel_delta.updates.1;
144
145                 let mut categorize_directed_update_serialization = |directed_updates: Option<DirectedUpdateDelta>| {
146                         if let Some(updates) = directed_updates {
147                                 if let Some(latest_update_delta) = updates.latest_update_after_seen {
148                                         let latest_update = latest_update_delta.update;
149
150                                         // the returned seen timestamp should be the latest of all the returned
151                                         // announcements and latest updates
152                                         serialization_set.latest_seen = max(serialization_set.latest_seen, latest_update_delta.seen);
153
154                                         if updates.last_update_before_seen.is_some() {
155                                                 let mutated_properties = updates.mutated_properties;
156                                                 if mutated_properties.len() == 5 {
157                                                         // all five values have changed, it makes more sense to just
158                                                         // serialize the update as a full update instead of as a change
159                                                         // this way, the default values can be computed more efficiently
160                                                         record_full_update_in_histograms(&latest_update);
161                                                         serialization_set.updates.push(UpdateSerialization {
162                                                                 update: latest_update,
163                                                                 mechanism: UpdateSerializationMechanism::Full,
164                                                         });
165                                                 } else if mutated_properties.len() > 0 || mutated_properties.flags {
166                                                         // we don't count flags as mutated properties
167                                                         serialization_set.updates.push(UpdateSerialization {
168                                                                 update: latest_update,
169                                                                 mechanism: UpdateSerializationMechanism::Incremental(mutated_properties),
170                                                         });
171                                                 }
172                                         } else {
173                                                 // serialize the full update
174                                                 record_full_update_in_histograms(&latest_update);
175                                                 serialization_set.updates.push(UpdateSerialization {
176                                                         update: latest_update,
177                                                         mechanism: UpdateSerializationMechanism::Full,
178                                                 });
179                                         }
180                                 } else if let Some(flags) = updates.serialization_update_flags {
181                                         // we need to insert a fake channel update where the only information
182                                         let fake_update = UnsignedChannelUpdate {
183                                                 flags,
184                                                 chain_hash: BlockHash::all_zeros(),
185                                                 short_channel_id: 0,
186                                                 cltv_expiry_delta: 0,
187                                                 fee_base_msat: 0,
188                                                 fee_proportional_millionths: 0,
189                                                 htlc_maximum_msat: 0,
190                                                 htlc_minimum_msat: 0,
191                                                 timestamp: 0,
192                                                 excess_data: Vec::with_capacity(0),
193                                         };
194                                         serialization_set.updates.push(UpdateSerialization {
195                                                 update: fake_update,
196                                                 mechanism: UpdateSerializationMechanism::Reminder
197                                         })
198                                 }
199                         }
200                 };
201
202                 categorize_directed_update_serialization(direction_a_updates);
203                 categorize_directed_update_serialization(direction_b_updates);
204         }
205
206         let default_update_values = DefaultUpdateValues {
207                 cltv_expiry_delta: find_most_common_histogram_entry_with_default(full_update_histograms.cltv_expiry_delta, 0),
208                 htlc_minimum_msat: find_most_common_histogram_entry_with_default(full_update_histograms.htlc_minimum_msat, 0),
209                 fee_base_msat: find_most_common_histogram_entry_with_default(full_update_histograms.fee_base_msat, 0),
210                 fee_proportional_millionths: find_most_common_histogram_entry_with_default(full_update_histograms.fee_proportional_millionths, 0),
211                 htlc_maximum_msat: find_most_common_histogram_entry_with_default(full_update_histograms.htlc_maximum_msat, 0),
212         };
213
214         serialization_set.full_update_defaults = default_update_values;
215         serialization_set
216 }
217
218 pub fn serialize_stripped_channel_announcement(announcement: &UnsignedChannelAnnouncement, node_id_a_index: usize, node_id_b_index: usize, previous_scid: u64) -> Vec<u8> {
219         let mut stripped_announcement = vec![];
220
221         announcement.features.write(&mut stripped_announcement).unwrap();
222
223         if previous_scid > announcement.short_channel_id {
224                 panic!("unsorted scids!");
225         }
226         let scid_delta = BigSize(announcement.short_channel_id - previous_scid);
227         scid_delta.write(&mut stripped_announcement).unwrap();
228
229         // write indices of node ids rather than the node IDs themselves
230         BigSize(node_id_a_index as u64).write(&mut stripped_announcement).unwrap();
231         BigSize(node_id_b_index as u64).write(&mut stripped_announcement).unwrap();
232
233         // println!("serialized CA: {}, \n{:?}\n{:?}\n", announcement.short_channel_id, announcement.node_id_1, announcement.node_id_2);
234         stripped_announcement
235 }
236
237 pub(super) fn serialize_stripped_channel_update(update: &UpdateSerialization, default_values: &DefaultUpdateValues, previous_scid: u64) -> Vec<u8> {
238         let latest_update = &update.update;
239         let mut serialized_flags = latest_update.flags;
240
241         if previous_scid > latest_update.short_channel_id {
242                 panic!("unsorted scids!");
243         }
244
245         let mut delta_serialization = Vec::new();
246         let mut prefixed_serialization = Vec::new();
247
248         match &update.mechanism {
249                 UpdateSerializationMechanism::Full => {
250                         if latest_update.cltv_expiry_delta != default_values.cltv_expiry_delta {
251                                 serialized_flags |= 0b_0100_0000;
252                                 latest_update.cltv_expiry_delta.write(&mut delta_serialization).unwrap();
253                         }
254
255                         if latest_update.htlc_minimum_msat != default_values.htlc_minimum_msat {
256                                 serialized_flags |= 0b_0010_0000;
257                                 latest_update.htlc_minimum_msat.write(&mut delta_serialization).unwrap();
258                         }
259
260                         if latest_update.fee_base_msat != default_values.fee_base_msat {
261                                 serialized_flags |= 0b_0001_0000;
262                                 latest_update.fee_base_msat.write(&mut delta_serialization).unwrap();
263                         }
264
265                         if latest_update.fee_proportional_millionths != default_values.fee_proportional_millionths {
266                                 serialized_flags |= 0b_0000_1000;
267                                 latest_update.fee_proportional_millionths.write(&mut delta_serialization).unwrap();
268                         }
269
270                         if latest_update.htlc_maximum_msat != default_values.htlc_maximum_msat {
271                                 serialized_flags |= 0b_0000_0100;
272                                 latest_update.htlc_maximum_msat.write(&mut delta_serialization).unwrap();
273                         }
274                 }
275
276                 UpdateSerializationMechanism::Incremental(mutated_properties) => {
277                         // indicate that this update is incremental
278                         serialized_flags |= 0b_1000_0000;
279
280                         if mutated_properties.cltv_expiry_delta {
281                                 serialized_flags |= 0b_0100_0000;
282                                 latest_update.cltv_expiry_delta.write(&mut delta_serialization).unwrap();
283                         }
284
285                         if mutated_properties.htlc_minimum_msat {
286                                 serialized_flags |= 0b_0010_0000;
287                                 latest_update.htlc_minimum_msat.write(&mut delta_serialization).unwrap();
288                         }
289
290                         if mutated_properties.fee_base_msat {
291                                 serialized_flags |= 0b_0001_0000;
292                                 latest_update.fee_base_msat.write(&mut delta_serialization).unwrap();
293                         }
294
295                         if mutated_properties.fee_proportional_millionths {
296                                 serialized_flags |= 0b_0000_1000;
297                                 latest_update.fee_proportional_millionths.write(&mut delta_serialization).unwrap();
298                         }
299
300                         if mutated_properties.htlc_maximum_msat {
301                                 serialized_flags |= 0b_0000_0100;
302                                 latest_update.htlc_maximum_msat.write(&mut delta_serialization).unwrap();
303                         }
304                 },
305
306                 UpdateSerializationMechanism::Reminder => {
307                         // indicate that this update is incremental
308                         serialized_flags |= 0b_1000_0000;
309                 }
310         }
311         let scid_delta = BigSize(latest_update.short_channel_id - previous_scid);
312         scid_delta.write(&mut prefixed_serialization).unwrap();
313
314         serialized_flags.write(&mut prefixed_serialization).unwrap();
315         prefixed_serialization.append(&mut delta_serialization);
316
317         prefixed_serialization
318 }
319
320 pub(super) fn find_most_common_histogram_entry_with_default<T: Copy>(histogram: HashMap<T, usize>, default: T) -> T {
321         let most_frequent_entry = histogram.iter().max_by(|a, b| a.1.cmp(&b.1));
322         if let Some(entry_details) = most_frequent_entry {
323                 // .0 is the value
324                 // .1 is the frequency
325                 return entry_details.0.to_owned();
326         }
327         // the default should pretty much always be a 0 as T
328         // though for htlc maximum msat it could be a u64::max
329         default
330 }