Skip to content

Commit 4bd2c97

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 65ff1bf commit 4bd2c97

File tree

3 files changed

+43
-34
lines changed

3 files changed

+43
-34
lines changed

lightning/src/ln/features.rs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,12 @@ impl InitFeatures {
282282
}
283283
self
284284
}
285+
286+
/// Converts `InitFeatures` to `Features<C>`. Only known `InitFeatures` relevant to context `C`
287+
/// are included in the result.
288+
pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
289+
self.to_context_internal()
290+
}
285291
}
286292

287293
impl<T: sealed::Context> Features<T> {
@@ -303,18 +309,19 @@ impl<T: sealed::Context> Features<T> {
303309
}
304310
}
305311

306-
/// Takes the flags that we know how to interpret in an init-context features that are also
307-
/// relevant in a node-context features and creates a node-context features from them.
308-
/// Be sure to blank out features that are unknown to us.
309-
pub(crate) fn with_known_relevant_init_flags(init_ctx: &InitFeatures) -> Self {
310-
let byte_count = T::KNOWN_FEATURE_MASK.len();
312+
/// Converts `Features<T>` to `Features<C>`. Only known `T` features relevant to context `C` are
313+
/// included in the result.
314+
fn to_context_internal<C: sealed::Context>(&self) -> Features<C> {
315+
let byte_count = C::KNOWN_FEATURE_MASK.len();
311316
let mut flags = Vec::new();
312-
for (i, feature_byte) in init_ctx.flags.iter().enumerate() {
317+
for (i, byte) in self.flags.iter().enumerate() {
313318
if i < byte_count {
314-
flags.push(feature_byte & T::KNOWN_FEATURE_MASK[i]);
319+
let known_source_features = T::KNOWN_FEATURE_MASK[i];
320+
let known_target_features = C::KNOWN_FEATURE_MASK[i];
321+
flags.push(byte & known_source_features & known_target_features);
315322
}
316323
}
317-
Self { flags, mark: PhantomData, }
324+
Features::<C> { flags, mark: PhantomData, }
318325
}
319326

320327
#[cfg(test)]
@@ -399,8 +406,9 @@ impl<T: sealed::UpfrontShutdownScript> Features<T> {
399406
<T as sealed::UpfrontShutdownScript>::supports_feature(&self.flags)
400407
}
401408
#[cfg(test)]
402-
pub(crate) fn unset_upfront_shutdown_script(&mut self) {
403-
<T as sealed::UpfrontShutdownScript>::clear_bits(&mut self.flags)
409+
pub(crate) fn clear_upfront_shutdown_script(mut self) -> Self {
410+
<T as sealed::UpfrontShutdownScript>::clear_bits(&mut self.flags);
411+
self
404412
}
405413
}
406414

@@ -461,7 +469,7 @@ impl<T: sealed::Context> Readable for Features<T> {
461469

462470
#[cfg(test)]
463471
mod tests {
464-
use super::{ChannelFeatures, InitFeatures, NodeFeatures, Features};
472+
use super::{ChannelFeatures, InitFeatures, NodeFeatures};
465473

466474
#[test]
467475
fn sanity_test_our_features() {
@@ -503,26 +511,28 @@ mod tests {
503511
}
504512

505513
#[test]
506-
fn test_node_with_known_relevant_init_flags() {
507-
// Create an InitFeatures with initial_routing_sync supported.
508-
let init_features = InitFeatures::known();
514+
fn convert_to_context_with_relevant_flags() {
515+
let init_features = InitFeatures::known().clear_upfront_shutdown_script();
509516
assert!(init_features.initial_routing_sync());
517+
assert!(!init_features.supports_upfront_shutdown_script());
510518

511-
// Attempt to pull out non-node-context feature flags from these InitFeatures.
512-
let res = NodeFeatures::with_known_relevant_init_flags(&init_features);
513-
519+
let node_features: NodeFeatures = init_features.to_context();
514520
{
515-
// Check that the flags are as expected: optional_data_loss_protect,
516-
// option_upfront_shutdown_script, var_onion_optin, payment_secret, and
517-
// basic_mpp.
518-
assert_eq!(res.flags.len(), 3);
519-
assert_eq!(res.flags[0], 0b00100010);
520-
assert_eq!(res.flags[1], 0b10000010);
521-
assert_eq!(res.flags[2], 0b00000010);
521+
// Check that the flags are as expected:
522+
// - option_data_loss_protect
523+
// - var_onion_optin | payment_secret
524+
// - basic_mpp
525+
assert_eq!(node_features.flags.len(), 3);
526+
assert_eq!(node_features.flags[0], 0b00000010);
527+
assert_eq!(node_features.flags[1], 0b10000010);
528+
assert_eq!(node_features.flags[2], 0b00000010);
522529
}
523530

524-
// Check that the initial_routing_sync feature was correctly blanked out.
525-
let new_features: InitFeatures = Features::from_le_bytes(res.flags);
526-
assert!(!new_features.initial_routing_sync());
531+
// Check that cleared flags are kept blank when converting back:
532+
// - initial_routing_sync was not applicable to NodeContext
533+
// - upfront_shutdown_script was cleared before converting
534+
let features: InitFeatures = node_features.to_context_internal();
535+
assert!(!features.initial_routing_sync());
536+
assert!(!features.supports_upfront_shutdown_script());
527537
}
528538
}

lightning/src/ln/functional_tests.rs

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

66966696
// We test that if case of peer non-signaling we don't enforce committed script at channel opening
6697-
let mut flags_no = InitFeatures::known();
6698-
flags_no.unset_upfront_shutdown_script();
6697+
let flags_no = InitFeatures::known().clear_upfront_shutdown_script();
66996698
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, flags_no, flags.clone());
67006699
nodes[0].node.close_channel(&OutPoint::new(chan.3.txid(), 0).to_channel_id()).unwrap();
67016700
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)