Skip to content

Commit 679795b

Browse files
committed
Include a route hint for public, not-yet-announced channels
If we have a public channel which doesn't yet have six confirmations the network can't possibly know about it as we cannot have announced it yet. However, because we refuse to include route-hints if we have any public channels, we will generate invoices that no one can pay. Thus, if we have any public, not-yet-announced channels, include them as a route-hint.
1 parent 137b77c commit 679795b

File tree

2 files changed

+92
-16
lines changed

2 files changed

+92
-16
lines changed

lightning-invoice/src/utils.rs

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ fn filter_channels<L: Deref>(
522522
let mut min_capacity_channel_exists = false;
523523
let mut online_channel_exists = false;
524524
let mut online_min_capacity_channel_exists = false;
525+
let mut has_pub_unconf_chan = false;
525526

526527
log_trace!(logger, "Considering {} channels for invoice route hints", channels.len());
527528
for channel in channels.into_iter().filter(|chan| chan.is_channel_ready) {
@@ -531,11 +532,18 @@ fn filter_channels<L: Deref>(
531532
}
532533

533534
if channel.is_public {
534-
// If any public channel exists, return no hints and let the sender
535-
// look at the public channels instead.
536-
log_trace!(logger, "Not including channels in invoice route hints on account of public channel {}",
537-
log_bytes!(channel.channel_id));
538-
return vec![]
535+
if channel.confirmations.is_some() && channel.confirmations < Some(7) {
536+
// If we have a public channel, but it doesn't have enough confirmations to (yet)
537+
// be in the public network graph (and have gotten a chance to propagate), include
538+
// route hints but only for public channels to protect private channel privacy.
539+
has_pub_unconf_chan = true;
540+
} else {
541+
// If any public channel exists, return no hints and let the sender
542+
// look at the public channels instead.
543+
log_trace!(logger, "Not including channels in invoice route hints on account of public channel {}",
544+
log_bytes!(channel.channel_id));
545+
return vec![]
546+
}
539547
}
540548

541549
if channel.inbound_capacity_msat >= min_inbound_capacity {
@@ -559,19 +567,26 @@ fn filter_channels<L: Deref>(
559567
match filtered_channels.entry(channel.counterparty.node_id) {
560568
hash_map::Entry::Occupied(mut entry) => {
561569
let current_max_capacity = entry.get().inbound_capacity_msat;
562-
if channel.inbound_capacity_msat < current_max_capacity {
570+
let new_now_public = channel.is_public && !entry.get().is_public;
571+
let new_higher_capacity = channel.is_public == entry.get().is_public &&
572+
channel.inbound_capacity_msat > current_max_capacity;
573+
if !new_now_public && !new_higher_capacity {
563574
log_trace!(logger,
564-
"Preferring counterparty {} channel {} ({} msats) over {} ({} msats) for invoice route hints",
575+
"Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints",
565576
log_pubkey!(channel.counterparty.node_id),
566-
log_bytes!(entry.get().channel_id), current_max_capacity,
567-
log_bytes!(channel.channel_id), channel.inbound_capacity_msat);
577+
log_bytes!(entry.get().channel_id), entry.get().short_channel_id,
578+
current_max_capacity,
579+
log_bytes!(channel.channel_id), channel.short_channel_id,
580+
channel.inbound_capacity_msat);
568581
continue;
569582
}
570583
log_trace!(logger,
571-
"Preferring counterparty {} channel {} ({} msats) over {} ({} msats) for invoice route hints",
584+
"Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints",
572585
log_pubkey!(channel.counterparty.node_id),
573-
log_bytes!(channel.channel_id), channel.inbound_capacity_msat,
574-
log_bytes!(entry.get().channel_id), current_max_capacity);
586+
log_bytes!(channel.channel_id), channel.short_channel_id,
587+
channel.inbound_capacity_msat,
588+
log_bytes!(entry.get().channel_id), entry.get().short_channel_id,
589+
current_max_capacity);
575590
entry.insert(channel);
576591
}
577592
hash_map::Entry::Vacant(entry) => {
@@ -602,7 +617,12 @@ fn filter_channels<L: Deref>(
602617
.map(|(_, channel)| channel)
603618
.filter(|channel| {
604619
let has_enough_capacity = channel.inbound_capacity_msat >= min_inbound_capacity;
605-
let include_channel = if online_min_capacity_channel_exists {
620+
let include_channel = if has_pub_unconf_chan {
621+
// If we have a public channel, but it doesn't have enough confirmations to (yet)
622+
// be in the public network graph (and have gotten a chance to propagate), include
623+
// route hints but only for public channels to protect private channel privacy.
624+
channel.is_public
625+
} else if online_min_capacity_channel_exists {
606626
has_enough_capacity && channel.is_usable
607627
} else if min_capacity_channel_exists && online_channel_exists {
608628
// If there are some online channels and some min_capacity channels, but no
@@ -622,7 +642,7 @@ fn filter_channels<L: Deref>(
622642
log_trace!(logger, "Ignoring channel {} without enough capacity for invoice route hints",
623643
log_bytes!(channel.channel_id));
624644
} else {
625-
debug_assert!(!channel.is_usable);
645+
debug_assert!(!channel.is_usable || (has_pub_unconf_chan && !channel.is_public));
626646
log_trace!(logger, "Ignoring channel {} with disconnected peer",
627647
log_bytes!(channel.channel_id));
628648
}
@@ -792,6 +812,55 @@ mod test {
792812
assert_eq!(invoice.payment_hash(), &sha256::Hash::from_slice(&payment_hash.0[..]).unwrap());
793813
}
794814

815+
#[test]
816+
fn test_hints_has_only_public_confd_channels() {
817+
let chanmon_cfgs = create_chanmon_cfgs(2);
818+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
819+
let mut config = test_default_channel_config();
820+
config.channel_handshake_config.minimum_depth = 1;
821+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), Some(config)]);
822+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
823+
824+
// Create a private channel with lots of capacity and a lower value public channel (without
825+
// confirming the funding tx yet).
826+
let unannounced_scid = create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 0);
827+
let conf_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 10_000, 0);
828+
829+
// Before the channel is available, we should include the unannounced_scid.
830+
let mut scid_aliases = HashSet::new();
831+
scid_aliases.insert(unannounced_scid.0.short_channel_id_alias.unwrap());
832+
match_invoice_routes(Some(5000), &nodes[1], scid_aliases.clone());
833+
834+
// However after we mine the funding tx and exchange channel_ready messages for the public
835+
// channel we'll immediately switch to including it as a route hint, even though isn't yet
836+
// announced.
837+
let pub_channel_scid = mine_transaction(&nodes[0], &conf_tx);
838+
let node_a_pub_channel_ready = get_event_msg!(nodes[0], MessageSendEvent::SendChannelReady, nodes[1].node.get_our_node_id());
839+
nodes[1].node.handle_channel_ready(&nodes[0].node.get_our_node_id(), &node_a_pub_channel_ready);
840+
841+
assert_eq!(mine_transaction(&nodes[1], &conf_tx), pub_channel_scid);
842+
let events = nodes[1].node.get_and_clear_pending_msg_events();
843+
assert_eq!(events.len(), 2);
844+
if let MessageSendEvent::SendChannelReady { msg, .. } = &events[0] {
845+
nodes[0].node.handle_channel_ready(&nodes[1].node.get_our_node_id(), msg);
846+
} else { panic!(); }
847+
if let MessageSendEvent::SendChannelUpdate { msg, .. } = &events[1] {
848+
nodes[0].node.handle_channel_update(&nodes[1].node.get_our_node_id(), msg);
849+
} else { panic!(); }
850+
851+
nodes[1].node.handle_channel_update(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendChannelUpdate, nodes[1].node.get_our_node_id()));
852+
853+
expect_channel_ready_event(&nodes[0], &nodes[1].node.get_our_node_id());
854+
expect_channel_ready_event(&nodes[1], &nodes[0].node.get_our_node_id());
855+
856+
scid_aliases.clear();
857+
scid_aliases.insert(node_a_pub_channel_ready.short_channel_id_alias.unwrap());
858+
match_invoice_routes(Some(5000), &nodes[1], scid_aliases.clone());
859+
// This also applies even if the amount is more than the payment amount, to ensure users
860+
// dont screw up their privacy.
861+
match_invoice_routes(Some(50_000_000), &nodes[1], scid_aliases);
862+
}
863+
795864
#[test]
796865
fn test_hints_includes_single_channels_to_nodes() {
797866
let chanmon_cfgs = create_chanmon_cfgs(3);

lightning/src/ln/functional_test_utils.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,12 @@ pub fn confirm_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Tran
6262
scid
6363
}
6464
/// Mine a single block containing the given transaction
65-
pub fn mine_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transaction) {
65+
///
66+
/// Returns the SCID a channel confirmed in the given transaction will have, assuming the funding
67+
/// output is the 1st output in the transaction.
68+
pub fn mine_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transaction) -> u64 {
6669
let height = node.best_block_info().1 + 1;
67-
confirm_transaction_at(node, tx, height);
70+
confirm_transaction_at(node, tx, height)
6871
}
6972
/// Mine a single block containing the given transactions
7073
pub fn mine_transactions<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, txn: &[&Transaction]) {
@@ -1062,6 +1065,10 @@ pub fn create_unannounced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &
10621065
nodes[a].node.handle_funding_signed(&nodes[b].node.get_our_node_id(), &cs_funding_signed);
10631066
check_added_monitors!(nodes[a], 1);
10641067

1068+
assert_eq!(nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1);
1069+
assert_eq!(nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap()[0], tx);
1070+
nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
1071+
10651072
let conf_height = core::cmp::max(nodes[a].best_block_info().1 + 1, nodes[b].best_block_info().1 + 1);
10661073
confirm_transaction_at(&nodes[a], &tx, conf_height);
10671074
connect_blocks(&nodes[a], CHAN_CONFIRM_DEPTH - 1);

0 commit comments

Comments
 (0)