f7db29dd0f3278dc79cec7364cd53a8b893e9d31
[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 }
83
84 struct FullUpdateValueHistograms {
85         cltv_expiry_delta: HashMap<u16, usize>,
86         htlc_minimum_msat: HashMap<u64, usize>,
87         fee_base_msat: HashMap<u32, usize>,
88         fee_proportional_millionths: HashMap<u32, usize>,
89         htlc_maximum_msat: HashMap<u64, usize>,
90 }
91
92 pub(super) fn serialize_delta_set(delta_set: DeltaSet, last_sync_timestamp: u32) -> SerializationSet {
93         let mut serialization_set = SerializationSet {
94                 announcements: vec![],
95                 updates: vec![],
96                 full_update_defaults: Default::default(),
97                 chain_hash: BlockHash::all_zeros(),
98                 latest_seen: 0,
99         };
100
101         let mut chain_hash_set = false;
102
103         let mut full_update_histograms = FullUpdateValueHistograms {
104                 cltv_expiry_delta: Default::default(),
105                 htlc_minimum_msat: Default::default(),
106                 fee_base_msat: Default::default(),
107                 fee_proportional_millionths: Default::default(),
108                 htlc_maximum_msat: Default::default(),
109         };
110
111         let mut record_full_update_in_histograms = |full_update: &UnsignedChannelUpdate| {
112                 *full_update_histograms.cltv_expiry_delta.entry(full_update.cltv_expiry_delta).or_insert(0) += 1;
113                 *full_update_histograms.htlc_minimum_msat.entry(full_update.htlc_minimum_msat).or_insert(0) += 1;
114                 *full_update_histograms.fee_base_msat.entry(full_update.fee_base_msat).or_insert(0) += 1;
115                 *full_update_histograms.fee_proportional_millionths.entry(full_update.fee_proportional_millionths).or_insert(0) += 1;
116                 *full_update_histograms.htlc_maximum_msat.entry(full_update.htlc_maximum_msat).or_insert(0) += 1;
117         };
118
119         for (_scid, channel_delta) in delta_set.into_iter() {
120
121                 // any announcement chain hash is gonna be the same value. Just set it from the first one.
122                 let channel_announcement_delta = channel_delta.announcement.as_ref().unwrap();
123                 if !chain_hash_set {
124                         chain_hash_set = true;
125                         serialization_set.chain_hash = channel_announcement_delta.announcement.chain_hash.clone();
126                 }
127
128                 let current_announcement_seen = channel_announcement_delta.seen;
129                 let is_new_announcement = current_announcement_seen >= last_sync_timestamp;
130                 let is_newly_updated_announcement = if let Some(first_update_seen) = channel_delta.first_update_seen {
131                         first_update_seen >= last_sync_timestamp
132                 } else {
133                         false
134                 };
135                 let send_announcement = is_new_announcement || is_newly_updated_announcement;
136                 if send_announcement {
137                         serialization_set.latest_seen = max(serialization_set.latest_seen, current_announcement_seen);
138                         serialization_set.announcements.push(channel_delta.announcement.unwrap().announcement);
139                 }
140
141                 let direction_a_updates = channel_delta.updates.0;
142                 let direction_b_updates = channel_delta.updates.1;
143
144                 let mut categorize_directed_update_serialization = |directed_updates: Option<DirectedUpdateDelta>| {
145                         if let Some(updates) = directed_updates {
146                                 if let Some(latest_update_delta) = updates.latest_update_after_seen {
147                                         let latest_update = latest_update_delta.update;
148
149                                         // the returned seen timestamp should be the latest of all the returned
150                                         // announcements and latest updates
151                                         serialization_set.latest_seen = max(serialization_set.latest_seen, latest_update_delta.seen);
152
153                                         if updates.last_update_before_seen.is_some() {
154                                                 let mutated_properties = updates.mutated_properties;
155                                                 if mutated_properties.len() == 5 {
156                                                         // all five values have changed, it makes more sense to just
157                                                         // serialize the update as a full update instead of as a change
158                                                         // this way, the default values can be computed more efficiently
159                                                         record_full_update_in_histograms(&latest_update);
160                                                         serialization_set.updates.push(UpdateSerialization {
161                                                                 update: latest_update,
162                                                                 mechanism: UpdateSerializationMechanism::Full,
163                                                         });
164                                                 } else if mutated_properties.len() > 0 || mutated_properties.flags {
165                                                         // we don't count flags as mutated properties
166                                                         serialization_set.updates.push(UpdateSerialization {
167                                                                 update: latest_update,
168                                                                 mechanism: UpdateSerializationMechanism::Incremental(mutated_properties),
169                                                         });
170                                                 }
171                                         } else {
172                                                 // serialize the full update
173                                                 record_full_update_in_histograms(&latest_update);
174                                                 serialization_set.updates.push(UpdateSerialization {
175                                                         update: latest_update,
176                                                         mechanism: UpdateSerializationMechanism::Full,
177                                                 });
178                                         }
179                                 }
180                         };
181                 };
182
183                 categorize_directed_update_serialization(direction_a_updates);
184                 categorize_directed_update_serialization(direction_b_updates);
185         }
186
187         let default_update_values = DefaultUpdateValues {
188                 cltv_expiry_delta: find_most_common_histogram_entry_with_default(full_update_histograms.cltv_expiry_delta, 0),
189                 htlc_minimum_msat: find_most_common_histogram_entry_with_default(full_update_histograms.htlc_minimum_msat, 0),
190                 fee_base_msat: find_most_common_histogram_entry_with_default(full_update_histograms.fee_base_msat, 0),
191                 fee_proportional_millionths: find_most_common_histogram_entry_with_default(full_update_histograms.fee_proportional_millionths, 0),
192                 htlc_maximum_msat: find_most_common_histogram_entry_with_default(full_update_histograms.htlc_maximum_msat, 0),
193         };
194
195         serialization_set.full_update_defaults = default_update_values;
196         serialization_set
197 }
198
199 pub fn serialize_stripped_channel_announcement(announcement: &UnsignedChannelAnnouncement, node_id_a_index: usize, node_id_b_index: usize, previous_scid: u64) -> Vec<u8> {
200         let mut stripped_announcement = vec![];
201
202         announcement.features.write(&mut stripped_announcement).unwrap();
203
204         if previous_scid > announcement.short_channel_id {
205                 panic!("unsorted scids!");
206         }
207         let scid_delta = BigSize(announcement.short_channel_id - previous_scid);
208         scid_delta.write(&mut stripped_announcement).unwrap();
209
210         // write indices of node ids rather than the node IDs themselves
211         BigSize(node_id_a_index as u64).write(&mut stripped_announcement).unwrap();
212         BigSize(node_id_b_index as u64).write(&mut stripped_announcement).unwrap();
213
214         // println!("serialized CA: {}, \n{:?}\n{:?}\n", announcement.short_channel_id, announcement.node_id_1, announcement.node_id_2);
215         stripped_announcement
216 }
217
218 pub(super) fn serialize_stripped_channel_update(update: &UpdateSerialization, default_values: &DefaultUpdateValues, previous_scid: u64) -> Vec<u8> {
219         let latest_update = &update.update;
220         let mut serialized_flags = latest_update.flags;
221
222         if previous_scid > latest_update.short_channel_id {
223                 panic!("unsorted scids!");
224         }
225
226         let mut delta_serialization = Vec::new();
227         let mut prefixed_serialization = Vec::new();
228
229         match &update.mechanism {
230                 UpdateSerializationMechanism::Full => {
231                         if latest_update.cltv_expiry_delta != default_values.cltv_expiry_delta {
232                                 serialized_flags |= 0b_0100_0000;
233                                 latest_update.cltv_expiry_delta.write(&mut delta_serialization).unwrap();
234                         }
235
236                         if latest_update.htlc_minimum_msat != default_values.htlc_minimum_msat {
237                                 serialized_flags |= 0b_0010_0000;
238                                 latest_update.htlc_minimum_msat.write(&mut delta_serialization).unwrap();
239                         }
240
241                         if latest_update.fee_base_msat != default_values.fee_base_msat {
242                                 serialized_flags |= 0b_0001_0000;
243                                 latest_update.fee_base_msat.write(&mut delta_serialization).unwrap();
244                         }
245
246                         if latest_update.fee_proportional_millionths != default_values.fee_proportional_millionths {
247                                 serialized_flags |= 0b_0000_1000;
248                                 latest_update.fee_proportional_millionths.write(&mut delta_serialization).unwrap();
249                         }
250
251                         if latest_update.htlc_maximum_msat != default_values.htlc_maximum_msat {
252                                 serialized_flags |= 0b_0000_0100;
253                                 latest_update.htlc_maximum_msat.write(&mut delta_serialization).unwrap();
254                         }
255                 }
256
257                 UpdateSerializationMechanism::Incremental(mutated_properties) => {
258                         // indicate that this update is incremental
259                         serialized_flags |= 0b_1000_0000;
260
261                         if mutated_properties.cltv_expiry_delta {
262                                 serialized_flags |= 0b_0100_0000;
263                                 latest_update.cltv_expiry_delta.write(&mut delta_serialization).unwrap();
264                         }
265
266                         if mutated_properties.htlc_minimum_msat {
267                                 serialized_flags |= 0b_0010_0000;
268                                 latest_update.htlc_minimum_msat.write(&mut delta_serialization).unwrap();
269                         }
270
271                         if mutated_properties.fee_base_msat {
272                                 serialized_flags |= 0b_0001_0000;
273                                 latest_update.fee_base_msat.write(&mut delta_serialization).unwrap();
274                         }
275
276                         if mutated_properties.fee_proportional_millionths {
277                                 serialized_flags |= 0b_0000_1000;
278                                 latest_update.fee_proportional_millionths.write(&mut delta_serialization).unwrap();
279                         }
280
281                         if mutated_properties.htlc_maximum_msat {
282                                 serialized_flags |= 0b_0000_0100;
283                                 latest_update.htlc_maximum_msat.write(&mut delta_serialization).unwrap();
284                         }
285                 }
286         }
287         let scid_delta = BigSize(latest_update.short_channel_id - previous_scid);
288         scid_delta.write(&mut prefixed_serialization).unwrap();
289
290         serialized_flags.write(&mut prefixed_serialization).unwrap();
291         prefixed_serialization.append(&mut delta_serialization);
292
293         prefixed_serialization
294 }
295
296 pub(super) fn find_most_common_histogram_entry_with_default<T: Copy>(histogram: HashMap<T, usize>, default: T) -> T {
297         let most_frequent_entry = histogram.iter().max_by(|a, b| a.1.cmp(&b.1));
298         if let Some(entry_details) = most_frequent_entry {
299                 // .0 is the value
300                 // .1 is the frequency
301                 return entry_details.0.to_owned();
302         }
303         // the default should pretty much always be a 0 as T
304         // though for htlc maximum msat it could be a u64::max
305         default
306 }