Skip to content

Commit 89e063b

Browse files
committed
Only disable channels ~10 min after disconnect, rather than one
We correctly send out a gossip channel disable update after one full time tick being down (1-2 minutes). This is pretty nice in that it avoids nodes trying to route through our nodes too often if they're down. Other nodes have a much longer time window, causing them to have much less aggressive channel disables. Sadly, at one minute it's not super uncommon for tor nodes to get disabled (once a day or so on two nodes I looked at), and this causes the lightning terminal scorer to consider the LDK node unstable (even though it's the one doing the disabling - so is online). This causes user frustration and makes LDK look bad (even though it's probably failing fewer payments). Given this, and future switches to block-based `channel_update` timestamp fields, it makes sense to go ahead and switch to delaying channel disable announcements for 10 minutes. This puts us more in line with other implementations and reduces gossip spam, at the cost of less reliable payments. Fixes #2175, at least the currently visible parts.
1 parent 6e7000c commit 89e063b

File tree

4 files changed

+57
-34
lines changed

4 files changed

+57
-34
lines changed

lightning/src/ln/channel.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,9 @@ pub(super) enum ChannelUpdateStatus {
312312
/// We've announced the channel as enabled and are connected to our peer.
313313
Enabled,
314314
/// Our channel is no longer live, but we haven't announced the channel as disabled yet.
315-
DisabledStaged,
315+
DisabledStaged(u8),
316316
/// Our channel is live again, but we haven't announced the channel as enabled yet.
317-
EnabledStaged,
317+
EnabledStaged(u8),
318318
/// We've announced the channel as disabled.
319319
Disabled,
320320
}
@@ -6193,8 +6193,8 @@ impl Writeable for ChannelUpdateStatus {
61936193
// channel as enabled, so we write 0. For EnabledStaged, we similarly write a 1.
61946194
match self {
61956195
ChannelUpdateStatus::Enabled => 0u8.write(writer)?,
6196-
ChannelUpdateStatus::DisabledStaged => 0u8.write(writer)?,
6197-
ChannelUpdateStatus::EnabledStaged => 1u8.write(writer)?,
6196+
ChannelUpdateStatus::DisabledStaged(_) => 0u8.write(writer)?,
6197+
ChannelUpdateStatus::EnabledStaged(_) => 1u8.write(writer)?,
61986198
ChannelUpdateStatus::Disabled => 1u8.write(writer)?,
61996199
}
62006200
Ok(())

lightning/src/ln/channelmanager.rs

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,14 @@ pub(crate) const MPP_TIMEOUT_TICKS: u8 = 3;
10701070
/// [`OutboundPayments::remove_stale_resolved_payments`].
10711071
pub(crate) const IDEMPOTENCY_TIMEOUT_TICKS: u8 = 7;
10721072

1073+
/// The number of ticks of [`ChannelManager::timer_tick_occurred`] where a peer is disconnected
1074+
/// until we mark the channel disabled and gossip the update.
1075+
pub(crate) const DISABLE_GOSSIP_TICKS: u8 = 10;
1076+
1077+
/// The number of ticks of [`ChannelManager::timer_tick_occurred`] where a peer is connected until
1078+
/// we mark the channel enabled and gossip the update.
1079+
pub(crate) const ENABLE_GOSSIP_TICKS: u8 = 5;
1080+
10731081
/// The maximum number of unfunded channels we can have per-peer before we start rejecting new
10741082
/// (inbound) ones. The number of peers with unfunded channels is limited separately in
10751083
/// [`MAX_UNFUNDED_CHANNEL_PEERS`].
@@ -2591,9 +2599,9 @@ where
25912599

25922600
let enabled = chan.is_usable() && match chan.channel_update_status() {
25932601
ChannelUpdateStatus::Enabled => true,
2594-
ChannelUpdateStatus::DisabledStaged => true,
2602+
ChannelUpdateStatus::DisabledStaged(_) => true,
25952603
ChannelUpdateStatus::Disabled => false,
2596-
ChannelUpdateStatus::EnabledStaged => false,
2604+
ChannelUpdateStatus::EnabledStaged(_) => false,
25972605
};
25982606

25992607
let unsigned = msgs::UnsignedChannelUpdate {
@@ -3750,27 +3758,39 @@ where
37503758
}
37513759

37523760
match chan.channel_update_status() {
3753-
ChannelUpdateStatus::Enabled if !chan.is_live() => chan.set_channel_update_status(ChannelUpdateStatus::DisabledStaged),
3754-
ChannelUpdateStatus::Disabled if chan.is_live() => chan.set_channel_update_status(ChannelUpdateStatus::EnabledStaged),
3755-
ChannelUpdateStatus::DisabledStaged if chan.is_live() => chan.set_channel_update_status(ChannelUpdateStatus::Enabled),
3756-
ChannelUpdateStatus::EnabledStaged if !chan.is_live() => chan.set_channel_update_status(ChannelUpdateStatus::Disabled),
3757-
ChannelUpdateStatus::DisabledStaged if !chan.is_live() => {
3758-
chan.set_channel_update_status(ChannelUpdateStatus::Disabled);
3759-
if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
3760-
pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
3761-
msg: update
3762-
});
3761+
ChannelUpdateStatus::Enabled if !chan.is_live() => chan.set_channel_update_status(ChannelUpdateStatus::DisabledStaged(0)),
3762+
ChannelUpdateStatus::Disabled if chan.is_live() => chan.set_channel_update_status(ChannelUpdateStatus::EnabledStaged(0)),
3763+
ChannelUpdateStatus::DisabledStaged(_) if chan.is_live()
3764+
=> chan.set_channel_update_status(ChannelUpdateStatus::Enabled),
3765+
ChannelUpdateStatus::EnabledStaged(_) if !chan.is_live()
3766+
=> chan.set_channel_update_status(ChannelUpdateStatus::Disabled),
3767+
ChannelUpdateStatus::DisabledStaged(mut n) if !chan.is_live() => {
3768+
n += 1;
3769+
if n >= DISABLE_GOSSIP_TICKS {
3770+
chan.set_channel_update_status(ChannelUpdateStatus::Disabled);
3771+
if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
3772+
pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
3773+
msg: update
3774+
});
3775+
}
3776+
should_persist = NotifyOption::DoPersist;
3777+
} else {
3778+
chan.set_channel_update_status(ChannelUpdateStatus::DisabledStaged(n));
37633779
}
3764-
should_persist = NotifyOption::DoPersist;
37653780
},
3766-
ChannelUpdateStatus::EnabledStaged if chan.is_live() => {
3767-
chan.set_channel_update_status(ChannelUpdateStatus::Enabled);
3768-
if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
3769-
pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
3770-
msg: update
3771-
});
3781+
ChannelUpdateStatus::EnabledStaged(mut n) if chan.is_live() => {
3782+
n += 1;
3783+
if n >= ENABLE_GOSSIP_TICKS {
3784+
chan.set_channel_update_status(ChannelUpdateStatus::Enabled);
3785+
if let Ok(update) = self.get_channel_update_for_broadcast(&chan) {
3786+
pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
3787+
msg: update
3788+
});
3789+
}
3790+
should_persist = NotifyOption::DoPersist;
3791+
} else {
3792+
chan.set_channel_update_status(ChannelUpdateStatus::EnabledStaged(n));
37723793
}
3773-
should_persist = NotifyOption::DoPersist;
37743794
},
37753795
_ => {},
37763796
}

lightning/src/ln/functional_tests.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::chain::keysinterface::{ChannelSigner, EcdsaChannelSigner, EntropySour
2121
use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason};
2222
use crate::ln::{PaymentPreimage, PaymentSecret, PaymentHash};
2323
use crate::ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT};
24-
use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA};
24+
use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA};
2525
use crate::ln::channel::{Channel, ChannelError};
2626
use crate::ln::{chan_utils, onion_utils};
2727
use crate::ln::chan_utils::{OFFERED_HTLC_SCRIPT_WEIGHT, htlc_success_tx_weight, htlc_timeout_tx_weight, HTLCOutputInCommitment};
@@ -7100,8 +7100,9 @@ fn test_announce_disable_channels() {
71007100
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id());
71017101
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id());
71027102

7103-
nodes[0].node.timer_tick_occurred(); // Enabled -> DisabledStaged
7104-
nodes[0].node.timer_tick_occurred(); // DisabledStaged -> Disabled
7103+
for _ in 0..DISABLE_GOSSIP_TICKS + 1 {
7104+
nodes[0].node.timer_tick_occurred();
7105+
}
71057106
let msg_events = nodes[0].node.get_and_clear_pending_msg_events();
71067107
assert_eq!(msg_events.len(), 3);
71077108
let mut chans_disabled = HashMap::new();
@@ -7141,7 +7142,9 @@ fn test_announce_disable_channels() {
71417142
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[2]);
71427143
handle_chan_reestablish_msgs!(nodes[1], nodes[0]);
71437144

7144-
nodes[0].node.timer_tick_occurred();
7145+
for _ in 0..ENABLE_GOSSIP_TICKS {
7146+
nodes[0].node.timer_tick_occurred();
7147+
}
71457148
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
71467149
nodes[0].node.timer_tick_occurred();
71477150
let msg_events = nodes[0].node.get_and_clear_pending_msg_events();

lightning/src/ln/onion_route_tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::chain::keysinterface::{EntropySource, NodeSigner, Recipient};
1616
use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason};
1717
use crate::ln::{PaymentHash, PaymentSecret};
1818
use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS;
19-
use crate::ln::channelmanager::{HTLCForwardInfo, FailureCode, CLTV_FAR_FAR_AWAY, MIN_CLTV_EXPIRY_DELTA, PendingAddHTLCInfo, PendingHTLCInfo, PendingHTLCRouting, PaymentId, RecipientOnionFields};
19+
use crate::ln::channelmanager::{HTLCForwardInfo, FailureCode, CLTV_FAR_FAR_AWAY, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA, PendingAddHTLCInfo, PendingHTLCInfo, PendingHTLCRouting, PaymentId, RecipientOnionFields};
2020
use crate::ln::onion_utils;
2121
use crate::routing::gossip::{NetworkUpdate, RoutingFees};
2222
use crate::routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop};
@@ -589,12 +589,12 @@ fn test_onion_failure() {
589589
nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id());
590590
}, true, Some(UPDATE|7), Some(NetworkUpdate::ChannelUpdateMessage{msg: ChannelUpdate::dummy(short_channel_id)}), Some(short_channel_id));
591591
run_onion_failure_test("channel_disabled", 0, &nodes, &route, &payment_hash, &payment_secret, |_| {}, || {
592-
// Tick the timer twice on each node to mark the channel as disabled.
593-
nodes[1].node.timer_tick_occurred();
594-
nodes[1].node.timer_tick_occurred();
592+
// disconnect event to the channel between nodes[1] ~ nodes[2]
593+
for _ in 0..DISABLE_GOSSIP_TICKS + 1 {
594+
nodes[1].node.timer_tick_occurred();
595+
nodes[2].node.timer_tick_occurred();
596+
}
595597
nodes[1].node.get_and_clear_pending_msg_events();
596-
nodes[2].node.timer_tick_occurred();
597-
nodes[2].node.timer_tick_occurred();
598598
nodes[2].node.get_and_clear_pending_msg_events();
599599
}, true, Some(UPDATE|20), Some(NetworkUpdate::ChannelUpdateMessage{msg: ChannelUpdate::dummy(short_channel_id)}), Some(short_channel_id));
600600
reconnect_nodes(&nodes[1], &nodes[2], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (false, false));

0 commit comments

Comments
 (0)