Skip to content

Commit 94fff25

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 c0e22ef commit 94fff25

File tree

3 files changed

+35
-35
lines changed

3 files changed

+35
-35
lines changed

lightning/src/ln/features.rs

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -272,19 +272,19 @@ impl<T: sealed::Context> Features<T> {
272272
}
273273
}
274274

275-
/// Takes the flags that we know how to interpret in an init-context features that are also
276-
/// relevant in a node-context features and creates a node-context features from them.
277-
/// Be sure to blank out features that are unknown to us.
278-
pub(crate) fn with_known_relevant_init_flags(init_ctx: &InitFeatures) -> Self {
279-
let byte_count = T::KNOWN_FEATURE_MASK.len();
275+
/// Converts `Features<T>` to `Features<C>`. Only known `T` features relevant to `C` are
276+
/// included in the result.
277+
pub(crate) fn to_context<C: sealed::Context>(&self) -> Features<C> {
278+
let byte_count = C::KNOWN_FEATURE_MASK.len();
280279
let mut flags = Vec::new();
281-
for (i, feature_byte) in init_ctx.flags.iter().enumerate() {
280+
for (i, byte) in self.flags.iter().enumerate() {
282281
if i < byte_count {
283-
let known_features = T::KNOWN_FEATURE_MASK[i];
284-
flags.push(feature_byte & known_features);
282+
let known_source_features = T::KNOWN_FEATURE_MASK[i];
283+
let known_target_features = C::KNOWN_FEATURE_MASK[i];
284+
flags.push(byte & known_source_features & known_target_features);
285285
}
286286
}
287-
Self { flags, mark: PhantomData, }
287+
Features::<C> { flags, mark: PhantomData, }
288288
}
289289

290290
#[cfg(test)]
@@ -369,8 +369,9 @@ impl<T: sealed::UpfrontShutdownScript> Features<T> {
369369
<T as sealed::UpfrontShutdownScript>::supports_feature(&self.flags)
370370
}
371371
#[cfg(test)]
372-
pub(crate) fn unset_upfront_shutdown_script(&mut self) {
373-
<T as sealed::UpfrontShutdownScript>::clear_bits(&mut self.flags)
372+
pub(crate) fn clear_upfront_shutdown_script(mut self) -> Self {
373+
<T as sealed::UpfrontShutdownScript>::clear_bits(&mut self.flags);
374+
self
374375
}
375376
}
376377

@@ -431,7 +432,7 @@ impl<T: sealed::Context> Readable for Features<T> {
431432

432433
#[cfg(test)]
433434
mod tests {
434-
use super::{ChannelFeatures, InitFeatures, NodeFeatures, Features};
435+
use super::{ChannelFeatures, InitFeatures, NodeFeatures};
435436

436437
#[test]
437438
fn sanity_test_our_features() {
@@ -470,26 +471,26 @@ mod tests {
470471
}
471472

472473
#[test]
473-
fn test_node_with_known_relevant_init_flags() {
474-
// Create an InitFeatures with initial_routing_sync supported.
475-
let init_features = InitFeatures::known();
474+
fn convert_to_context_with_relevant_flags() {
475+
let init_features = InitFeatures::known().clear_upfront_shutdown_script();
476476
assert!(init_features.initial_routing_sync());
477+
assert!(!init_features.supports_upfront_shutdown_script());
477478

478-
// Attempt to pull out non-node-context feature flags from these InitFeatures.
479-
let res = NodeFeatures::with_known_relevant_init_flags(&init_features);
480-
479+
let node_features: NodeFeatures = init_features.to_context();
481480
{
482-
// Check that the flags are as expected: optional_data_loss_protect,
483-
// option_upfront_shutdown_script, var_onion_optin, payment_secret, and
484-
// basic_mpp.
485-
assert_eq!(res.flags.len(), 3);
486-
assert_eq!(res.flags[0], 0b00100010);
487-
assert_eq!(res.flags[1], 0b10000010);
488-
assert_eq!(res.flags[2], 0b00000010);
481+
// Check that the flags are as expected:
482+
// - option_data_loss_protect
483+
// - var_onion_optin | payment_secret
484+
// - basic_mpp
485+
assert_eq!(node_features.flags.len(), 3);
486+
assert_eq!(node_features.flags[0], 0b00000010);
487+
assert_eq!(node_features.flags[1], 0b10000010);
488+
assert_eq!(node_features.flags[2], 0b00000010);
489489
}
490490

491-
// Check that the initial_routing_sync feature was correctly blanked out.
492-
let new_features: InitFeatures = Features::from_le_bytes(res.flags);
493-
assert!(!new_features.initial_routing_sync());
491+
// Check that cleared flags are kept blank when converting back.
492+
let features: InitFeatures = node_features.to_context();
493+
assert!(!features.initial_routing_sync());
494+
assert!(!features.supports_upfront_shutdown_script());
494495
}
495496
}

lightning/src/ln/functional_tests.rs

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

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