Skip to content

Commit bcd929d

Browse files
committed
Generalize with_known_relevant_init_flags
Converting from InitFeatures to other Features is accomplished using Features::with_known_relevant_init_flags. Define a more general to_context method which converts from Features of one Context to another. Additionally, ensure the source context only has known flags before selecting flags for the target context.
1 parent bfdc1b4 commit bcd929d

File tree

3 files changed

+35
-34
lines changed

3 files changed

+35
-34
lines changed

lightning/src/ln/features.rs

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -288,18 +288,19 @@ impl<T: sealed::Context> Features<T> {
288288
}
289289
}
290290

291-
/// Takes the flags that we know how to interpret in an init-context features that are also
292-
/// relevant in a node-context features and creates a node-context features from them.
293-
/// Be sure to blank out features that are unknown to us.
294-
pub(crate) fn with_known_relevant_init_flags(init_ctx: &InitFeatures) -> Self {
295-
let byte_count = T::KNOWN_FEATURE_MASK.len();
291+
/// Converts `Features<T>` to `Features<C>`. Only known `T` features relevant to `C` are
292+
/// included in the result.
293+
pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
294+
let byte_count = C::KNOWN_FEATURE_MASK.len();
296295
let mut flags = Vec::new();
297-
for (i, feature_byte) in init_ctx.flags.iter().enumerate() {
296+
for (i, byte) in self.flags.iter().enumerate() {
298297
if i < byte_count {
299-
flags.push(feature_byte & T::KNOWN_FEATURE_MASK[i]);
298+
let known_source_features = T::KNOWN_FEATURE_MASK[i];
299+
let known_target_features = C::KNOWN_FEATURE_MASK[i];
300+
flags.push(byte & known_source_features & known_target_features);
300301
}
301302
}
302-
Self { flags, mark: PhantomData, }
303+
Features::<C> { flags, mark: PhantomData, }
303304
}
304305

305306
#[cfg(test)]
@@ -384,8 +385,9 @@ impl<T: sealed::UpfrontShutdownScript> Features<T> {
384385
<T as sealed::UpfrontShutdownScript>::supports_feature(&self.flags)
385386
}
386387
#[cfg(test)]
387-
pub(crate) fn unset_upfront_shutdown_script(&mut self) {
388-
<T as sealed::UpfrontShutdownScript>::clear_bits(&mut self.flags)
388+
pub(crate) fn clear_upfront_shutdown_script(mut self) -> Self {
389+
<T as sealed::UpfrontShutdownScript>::clear_bits(&mut self.flags);
390+
self
389391
}
390392
}
391393

@@ -446,7 +448,7 @@ impl<T: sealed::Context> Readable for Features<T> {
446448

447449
#[cfg(test)]
448450
mod tests {
449-
use super::{ChannelFeatures, InitFeatures, NodeFeatures, Features};
451+
use super::{ChannelFeatures, InitFeatures, NodeFeatures};
450452

451453
#[test]
452454
fn sanity_test_our_features() {
@@ -488,26 +490,26 @@ mod tests {
488490
}
489491

490492
#[test]
491-
fn test_node_with_known_relevant_init_flags() {
492-
// Create an InitFeatures with initial_routing_sync supported.
493-
let init_features = InitFeatures::known();
493+
fn convert_to_context_with_relevant_flags() {
494+
let init_features = InitFeatures::known().clear_upfront_shutdown_script();
494495
assert!(init_features.initial_routing_sync());
496+
assert!(!init_features.supports_upfront_shutdown_script());
495497

496-
// Attempt to pull out non-node-context feature flags from these InitFeatures.
497-
let res = NodeFeatures::with_known_relevant_init_flags(&init_features);
498-
498+
let node_features: NodeFeatures = init_features.to_context();
499499
{
500-
// Check that the flags are as expected: optional_data_loss_protect,
501-
// option_upfront_shutdown_script, var_onion_optin, payment_secret, and
502-
// basic_mpp.
503-
assert_eq!(res.flags.len(), 3);
504-
assert_eq!(res.flags[0], 0b00100010);
505-
assert_eq!(res.flags[1], 0b10000010);
506-
assert_eq!(res.flags[2], 0b00000010);
500+
// Check that the flags are as expected:
501+
// - option_data_loss_protect
502+
// - var_onion_optin | payment_secret
503+
// - basic_mpp
504+
assert_eq!(node_features.flags.len(), 3);
505+
assert_eq!(node_features.flags[0], 0b00000010);
506+
assert_eq!(node_features.flags[1], 0b10000010);
507+
assert_eq!(node_features.flags[2], 0b00000010);
507508
}
508509

509-
// Check that the initial_routing_sync feature was correctly blanked out.
510-
let new_features: InitFeatures = Features::from_le_bytes(res.flags);
511-
assert!(!new_features.initial_routing_sync());
510+
// Check that cleared flags are kept blank when converting back.
511+
let features: InitFeatures = node_features.to_context();
512+
assert!(!features.initial_routing_sync());
513+
assert!(!features.supports_upfront_shutdown_script());
512514
}
513515
}

lightning/src/ln/functional_tests.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6648,8 +6648,7 @@ fn test_upfront_shutdown_script() {
66486648
}
66496649

66506650
// We test that if case of peer non-signaling we don't enforce committed script at channel opening
6651-
let mut flags_no = InitFeatures::known();
6652-
flags_no.unset_upfront_shutdown_script();
6651+
let flags_no = InitFeatures::known().clear_upfront_shutdown_script();
66536652
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, flags_no, flags.clone());
66546653
nodes[0].node.close_channel(&OutPoint::new(chan.3.txid(), 0).to_channel_id()).unwrap();
66556654
let mut node_1_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());

lightning/src/ln/router.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -893,9 +893,9 @@ impl Router {
893893
return Ok(Route {
894894
paths: vec![vec![RouteHop {
895895
pubkey: chan.remote_network_id,
896-
node_features: NodeFeatures::with_known_relevant_init_flags(&chan.counterparty_features),
896+
node_features: chan.counterparty_features.to_context(),
897897
short_channel_id,
898-
channel_features: ChannelFeatures::with_known_relevant_init_flags(&chan.counterparty_features),
898+
channel_features: chan.counterparty_features.to_context(),
899899
fee_msat: final_value_msat,
900900
cltv_expiry_delta: final_cltv,
901901
}]],
@@ -972,7 +972,7 @@ impl Router {
972972
( $node: expr, $node_id: expr, $fee_to_target_msat: expr ) => {
973973
if first_hops.is_some() {
974974
if let Some(&(ref first_hop, ref features)) = first_hop_targets.get(&$node_id) {
975-
add_entry!(first_hop, $node_id, dummy_directional_info, ChannelFeatures::with_known_relevant_init_flags(&features), $fee_to_target_msat);
975+
add_entry!(first_hop, $node_id, dummy_directional_info, features.to_context(), $fee_to_target_msat);
976976
}
977977
}
978978

@@ -1016,7 +1016,7 @@ impl Router {
10161016
// bit lazy here. In the future, we should pull them out via our
10171017
// ChannelManager, but there's no reason to waste the space until we
10181018
// need them.
1019-
add_entry!(first_hop, hop.src_node_id, dummy_directional_info, ChannelFeatures::with_known_relevant_init_flags(&features), 0);
1019+
add_entry!(first_hop, hop.src_node_id, dummy_directional_info, features.to_context(), 0);
10201020
}
10211021
}
10221022
// BOLT 11 doesn't allow inclusion of features for the last hop hints, which
@@ -1031,7 +1031,7 @@ impl Router {
10311031
let mut res = vec!(dist.remove(&network.our_node_id).unwrap().3);
10321032
loop {
10331033
if let Some(&(_, ref features)) = first_hop_targets.get(&res.last().unwrap().pubkey) {
1034-
res.last_mut().unwrap().node_features = NodeFeatures::with_known_relevant_init_flags(&features);
1034+
res.last_mut().unwrap().node_features = features.to_context();
10351035
} else if let Some(node) = network.nodes.get(&res.last().unwrap().pubkey) {
10361036
res.last_mut().unwrap().node_features = node.features.clone();
10371037
} else {

0 commit comments

Comments
 (0)