2 use std::collections::HashMap;
3 use std::time::{SystemTime, UNIX_EPOCH};
6 use bitcoin::blockdata::constants::ChainHash;
7 use lightning::ln::msgs::{UnsignedChannelAnnouncement, UnsignedChannelUpdate};
8 use lightning::util::ser::{BigSize, Writeable};
11 use crate::lookup::{DeltaSet, DirectedUpdateDelta};
13 pub(super) struct SerializationSet {
14 pub(super) announcements: Vec<UnsignedChannelAnnouncement>,
15 pub(super) updates: Vec<UpdateSerialization>,
16 pub(super) full_update_defaults: DefaultUpdateValues,
17 pub(super) latest_seen: u32,
18 pub(super) chain_hash: ChainHash,
21 pub(super) struct DefaultUpdateValues {
22 pub(super) cltv_expiry_delta: u16,
23 pub(super) htlc_minimum_msat: u64,
24 pub(super) fee_base_msat: u32,
25 pub(super) fee_proportional_millionths: u32,
26 pub(super) htlc_maximum_msat: u64,
29 impl Default for DefaultUpdateValues {
30 fn default() -> Self {
35 fee_proportional_millionths: 0,
41 pub(super) struct MutatedProperties {
42 pub(super) flags: bool,
43 pub(super) cltv_expiry_delta: bool,
44 pub(super) htlc_minimum_msat: bool,
45 pub(super) fee_base_msat: bool,
46 pub(super) fee_proportional_millionths: bool,
47 pub(super) htlc_maximum_msat: bool,
50 impl Default for MutatedProperties {
51 fn default() -> Self {
54 cltv_expiry_delta: false,
55 htlc_minimum_msat: false,
57 fee_proportional_millionths: false,
58 htlc_maximum_msat: false,
63 impl MutatedProperties {
64 /// Does not include flags because the flag byte is always sent in full
66 let mut mutations = 0;
67 if self.cltv_expiry_delta { mutations += 1; };
68 if self.htlc_minimum_msat { mutations += 1; };
69 if self.fee_base_msat { mutations += 1; };
70 if self.fee_proportional_millionths { mutations += 1; };
71 if self.htlc_maximum_msat { mutations += 1; };
76 pub(super) enum UpdateSerialization {
77 Full(UnsignedChannelUpdate),
78 Incremental(UnsignedChannelUpdate, MutatedProperties),
81 impl UpdateSerialization {
82 pub(super) fn scid(&self) -> u64 {
84 UpdateSerialization::Full(latest_update)|
85 UpdateSerialization::Incremental(latest_update, _) => latest_update.short_channel_id,
86 UpdateSerialization::Reminder(scid, _) => *scid,
90 fn flags(&self) -> u8 {
92 UpdateSerialization::Full(latest_update)|
93 UpdateSerialization::Incremental(latest_update, _) => latest_update.flags,
94 UpdateSerialization::Reminder(_, flags) => *flags,
99 struct FullUpdateValueHistograms {
100 cltv_expiry_delta: HashMap<u16, usize>,
101 htlc_minimum_msat: HashMap<u64, usize>,
102 fee_base_msat: HashMap<u32, usize>,
103 fee_proportional_millionths: HashMap<u32, usize>,
104 htlc_maximum_msat: HashMap<u64, usize>,
107 pub(super) fn serialize_delta_set(delta_set: DeltaSet, last_sync_timestamp: u32) -> SerializationSet {
108 let mut serialization_set = SerializationSet {
109 announcements: vec![],
111 full_update_defaults: Default::default(),
112 chain_hash: ChainHash::using_genesis_block(Network::Bitcoin),
116 let mut chain_hash_set = false;
118 let mut full_update_histograms = FullUpdateValueHistograms {
119 cltv_expiry_delta: Default::default(),
120 htlc_minimum_msat: Default::default(),
121 fee_base_msat: Default::default(),
122 fee_proportional_millionths: Default::default(),
123 htlc_maximum_msat: Default::default(),
126 let mut record_full_update_in_histograms = |full_update: &UnsignedChannelUpdate| {
127 *full_update_histograms.cltv_expiry_delta.entry(full_update.cltv_expiry_delta).or_insert(0) += 1;
128 *full_update_histograms.htlc_minimum_msat.entry(full_update.htlc_minimum_msat).or_insert(0) += 1;
129 *full_update_histograms.fee_base_msat.entry(full_update.fee_base_msat).or_insert(0) += 1;
130 *full_update_histograms.fee_proportional_millionths.entry(full_update.fee_proportional_millionths).or_insert(0) += 1;
131 *full_update_histograms.htlc_maximum_msat.entry(full_update.htlc_maximum_msat).or_insert(0) += 1;
134 // if the previous seen update happened more than 6 days ago, the client may have pruned it, and an incremental update wouldn't work
135 let non_incremental_previous_update_threshold_timestamp = SystemTime::now().checked_sub(config::CHANNEL_REMINDER_AGE).unwrap().duration_since(UNIX_EPOCH).unwrap().as_secs() as u32;
137 for (scid, channel_delta) in delta_set.into_iter() {
139 // any announcement chain hash is gonna be the same value. Just set it from the first one.
140 let channel_announcement_delta = channel_delta.announcement.as_ref().unwrap();
142 chain_hash_set = true;
143 serialization_set.chain_hash = channel_announcement_delta.announcement.chain_hash;
146 let current_announcement_seen = channel_announcement_delta.seen;
147 let is_new_announcement = current_announcement_seen >= last_sync_timestamp;
148 let is_newly_included_announcement = if let Some(first_update_seen) = channel_delta.first_bidirectional_updates_seen {
149 first_update_seen >= last_sync_timestamp
153 let send_announcement = is_new_announcement || is_newly_included_announcement;
154 if send_announcement {
155 serialization_set.latest_seen = max(serialization_set.latest_seen, current_announcement_seen);
156 serialization_set.announcements.push(channel_delta.announcement.unwrap().announcement);
159 let direction_a_updates = channel_delta.updates.0;
160 let direction_b_updates = channel_delta.updates.1;
162 let mut categorize_directed_update_serialization = |directed_updates: Option<DirectedUpdateDelta>| {
163 if let Some(updates) = directed_updates {
164 if let Some(latest_update_delta) = updates.latest_update_after_seen {
165 let latest_update = latest_update_delta.update;
166 assert_eq!(latest_update.short_channel_id, scid, "Update in DB had wrong SCID column");
168 // the returned seen timestamp should be the latest of all the returned
169 // announcements and latest updates
170 serialization_set.latest_seen = max(serialization_set.latest_seen, latest_update_delta.seen);
172 if let Some(update_delta) = updates.last_update_before_seen {
173 let mutated_properties = updates.mutated_properties;
174 if send_announcement || mutated_properties.len() == 5 || update_delta.seen <= non_incremental_previous_update_threshold_timestamp {
175 // all five values have changed, it makes more sense to just
176 // serialize the update as a full update instead of as a change
177 // this way, the default values can be computed more efficiently
178 record_full_update_in_histograms(&latest_update);
179 serialization_set.updates.push(UpdateSerialization::Full(latest_update));
180 } else if mutated_properties.len() > 0 || mutated_properties.flags {
181 // we don't count flags as mutated properties
182 serialization_set.updates.push(
183 UpdateSerialization::Incremental(latest_update, mutated_properties));
184 } else if channel_delta.requires_reminder {
185 if let Some(flags) = updates.serialization_update_flags {
186 serialization_set.updates.push(UpdateSerialization::Reminder(scid, flags));
190 // serialize the full update
191 record_full_update_in_histograms(&latest_update);
192 serialization_set.updates.push(UpdateSerialization::Full(latest_update));
194 } else if is_newly_included_announcement {
195 if let Some(unannounced_update) = updates.last_update_before_seen {
196 serialization_set.updates.push(UpdateSerialization::Full(unannounced_update.update));
198 } else if let Some(flags) = updates.serialization_update_flags {
199 serialization_set.updates.push(UpdateSerialization::Reminder(scid, flags));
204 categorize_directed_update_serialization(direction_a_updates);
205 categorize_directed_update_serialization(direction_b_updates);
208 let default_update_values = DefaultUpdateValues {
209 cltv_expiry_delta: find_most_common_histogram_entry_with_default(full_update_histograms.cltv_expiry_delta, 0),
210 htlc_minimum_msat: find_most_common_histogram_entry_with_default(full_update_histograms.htlc_minimum_msat, 0),
211 fee_base_msat: find_most_common_histogram_entry_with_default(full_update_histograms.fee_base_msat, 0),
212 fee_proportional_millionths: find_most_common_histogram_entry_with_default(full_update_histograms.fee_proportional_millionths, 0),
213 htlc_maximum_msat: find_most_common_histogram_entry_with_default(full_update_histograms.htlc_maximum_msat, 0),
216 serialization_set.full_update_defaults = default_update_values;
220 pub fn serialize_stripped_channel_announcement(announcement: &UnsignedChannelAnnouncement, node_id_a_index: usize, node_id_b_index: usize, previous_scid: u64) -> Vec<u8> {
221 let mut stripped_announcement = vec![];
223 announcement.features.write(&mut stripped_announcement).unwrap();
225 if previous_scid > announcement.short_channel_id {
226 panic!("unsorted scids!");
228 let scid_delta = BigSize(announcement.short_channel_id - previous_scid);
229 scid_delta.write(&mut stripped_announcement).unwrap();
231 // write indices of node ids rather than the node IDs themselves
232 BigSize(node_id_a_index as u64).write(&mut stripped_announcement).unwrap();
233 BigSize(node_id_b_index as u64).write(&mut stripped_announcement).unwrap();
235 // println!("serialized CA: {}, \n{:?}\n{:?}\n", announcement.short_channel_id, announcement.node_id_1, announcement.node_id_2);
236 stripped_announcement
239 pub(super) fn serialize_stripped_channel_update(update: &UpdateSerialization, default_values: &DefaultUpdateValues, previous_scid: u64) -> Vec<u8> {
240 let mut serialized_flags = update.flags();
242 if previous_scid > update.scid() {
243 panic!("unsorted scids!");
246 let mut delta_serialization = Vec::new();
247 let mut prefixed_serialization = Vec::new();
250 UpdateSerialization::Full(latest_update) => {
251 if latest_update.cltv_expiry_delta != default_values.cltv_expiry_delta {
252 serialized_flags |= 0b_0100_0000;
253 latest_update.cltv_expiry_delta.write(&mut delta_serialization).unwrap();
256 if latest_update.htlc_minimum_msat != default_values.htlc_minimum_msat {
257 serialized_flags |= 0b_0010_0000;
258 latest_update.htlc_minimum_msat.write(&mut delta_serialization).unwrap();
261 if latest_update.fee_base_msat != default_values.fee_base_msat {
262 serialized_flags |= 0b_0001_0000;
263 latest_update.fee_base_msat.write(&mut delta_serialization).unwrap();
266 if latest_update.fee_proportional_millionths != default_values.fee_proportional_millionths {
267 serialized_flags |= 0b_0000_1000;
268 latest_update.fee_proportional_millionths.write(&mut delta_serialization).unwrap();
271 if latest_update.htlc_maximum_msat != default_values.htlc_maximum_msat {
272 serialized_flags |= 0b_0000_0100;
273 latest_update.htlc_maximum_msat.write(&mut delta_serialization).unwrap();
276 UpdateSerialization::Incremental(latest_update, mutated_properties) => {
277 // indicate that this update is incremental
278 serialized_flags |= 0b_1000_0000;
280 if mutated_properties.cltv_expiry_delta {
281 serialized_flags |= 0b_0100_0000;
282 latest_update.cltv_expiry_delta.write(&mut delta_serialization).unwrap();
285 if mutated_properties.htlc_minimum_msat {
286 serialized_flags |= 0b_0010_0000;
287 latest_update.htlc_minimum_msat.write(&mut delta_serialization).unwrap();
290 if mutated_properties.fee_base_msat {
291 serialized_flags |= 0b_0001_0000;
292 latest_update.fee_base_msat.write(&mut delta_serialization).unwrap();
295 if mutated_properties.fee_proportional_millionths {
296 serialized_flags |= 0b_0000_1000;
297 latest_update.fee_proportional_millionths.write(&mut delta_serialization).unwrap();
300 if mutated_properties.htlc_maximum_msat {
301 serialized_flags |= 0b_0000_0100;
302 latest_update.htlc_maximum_msat.write(&mut delta_serialization).unwrap();
305 UpdateSerialization::Reminder(_, _) => {
306 // indicate that this update is incremental
307 serialized_flags |= 0b_1000_0000;
310 let scid_delta = BigSize(update.scid() - previous_scid);
311 scid_delta.write(&mut prefixed_serialization).unwrap();
313 serialized_flags.write(&mut prefixed_serialization).unwrap();
314 prefixed_serialization.append(&mut delta_serialization);
316 prefixed_serialization
319 pub(super) fn find_most_common_histogram_entry_with_default<T: Copy>(histogram: HashMap<T, usize>, default: T) -> T {
320 let most_frequent_entry = histogram.iter().max_by(|a, b| a.1.cmp(&b.1));
321 if let Some(entry_details) = most_frequent_entry {
323 // .1 is the frequency
324 return entry_details.0.to_owned();
326 // the default should pretty much always be a 0 as T
327 // though for htlc maximum msat it could be a u64::max