Skip to content

Commit e2f216b

Browse files
committed
Track previous ChannelConfig and expire after enough ticks
We do this to prevent payment failures while the `ChannelUpdate` for the new `ChannelConfig` still propagates throughout the network. In a follow up commit, we'll honor forwarding HTLCs that were constructed based on either the previous or current `ChannelConfig`. To handle expiration (when we should stop allowing the previous config), we rely on the ChannelManager's `timer_tick_occurred` method. After enough ticks, the previous config is cleared from memory, and only the current config applies moving forward.
1 parent 3dff4ab commit e2f216b

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

lightning/src/ln/channel.rs

+41
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,16 @@ pub(crate) const CONCURRENT_INBOUND_HTLC_FEE_BUFFER: u32 = 2;
482482
/// transaction (not counting the value of the HTLCs themselves).
483483
pub(crate) const MIN_AFFORDABLE_HTLC_COUNT: usize = 4;
484484

485+
/// When a [`Channel`] has its [`ChannelConfig`] updated, its existing one is stashed for up to this
486+
/// number of ticks to allow forwarding HTLCs by nodes that have yet to receive the new
487+
/// ChannelUpdate prompted by the config update. This value was determined as follows:
488+
///
489+
/// * The expected interval between ticks (1 minute).
490+
/// * The average convergence delay of updates across the network, i.e., ~300 seconds on average
491+
/// for a node to see an update as seen on `<https://arxiv.org/pdf/2205.12737.pdf>`.
492+
/// * `EXPIRE_PREV_CONFIG_TICKS` = convergence_delay / tick_interval
493+
pub(crate) const EXPIRE_PREV_CONFIG_TICKS: usize = 5;
494+
485495
// TODO: We should refactor this to be an Inbound/OutboundChannel until initial setup handshaking
486496
// has been completed, and then turn into a Channel to get compiler-time enforcement of things like
487497
// calling channel_id() before we're set up or things like get_outbound_funding_signed on an
@@ -495,6 +505,11 @@ pub(super) struct Channel<Signer: Sign> {
495505
#[cfg(not(any(test, feature = "_test_utils")))]
496506
config: LegacyChannelConfig,
497507

508+
// Track the previous `ChannelConfig` so that we can continue forwarding HTLCs that were
509+
// constructed using it. The second element in the tuple corresponds to the number of ticks that
510+
// have elapsed since the update occurred.
511+
prev_config: Option<(ChannelConfig, usize)>,
512+
498513
inbound_handshake_limits_override: Option<ChannelHandshakeLimits>,
499514

500515
user_id: u64,
@@ -937,6 +952,8 @@ impl<Signer: Sign> Channel<Signer> {
937952
commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey,
938953
},
939954

955+
prev_config: None,
956+
940957
inbound_handshake_limits_override: Some(config.channel_handshake_limits.clone()),
941958

942959
channel_id: keys_provider.get_secure_random_bytes(),
@@ -1264,6 +1281,8 @@ impl<Signer: Sign> Channel<Signer> {
12641281
commit_upfront_shutdown_pubkey: config.channel_handshake_config.commit_upfront_shutdown_pubkey,
12651282
},
12661283

1284+
prev_config: None,
1285+
12671286
inbound_handshake_limits_override: None,
12681287

12691288
channel_id: msg.temporary_channel_id,
@@ -4491,6 +4510,25 @@ impl<Signer: Sign> Channel<Signer> {
44914510
self.config.options.max_dust_htlc_exposure_msat
44924511
}
44934512

4513+
/// Returns the previous [`ChannelConfig`] applied to this channel, if any.
4514+
pub fn prev_config(&self) -> Option<ChannelConfig> {
4515+
self.prev_config.map(|prev_config| prev_config.0)
4516+
}
4517+
4518+
/// Tracks the number of ticks elapsed since the previous [`ChannelConfig`] was updated. Once
4519+
/// [`EXPIRE_PREV_CONFIG_TICKS`] is reached, the previous config is considered expired and will
4520+
/// no longer be considered when forwarding HTLCs.
4521+
pub fn maybe_expire_prev_config(&mut self) {
4522+
if self.prev_config.is_none() {
4523+
return;
4524+
}
4525+
let prev_config = self.prev_config.as_mut().unwrap();
4526+
prev_config.1 += 1;
4527+
if prev_config.1 == EXPIRE_PREV_CONFIG_TICKS {
4528+
self.prev_config = None;
4529+
}
4530+
}
4531+
44944532
/// Returns the current [`ChannelConfig`] applied to the channel.
44954533
pub fn config(&self) -> ChannelConfig {
44964534
self.config.options
@@ -4504,6 +4542,7 @@ impl<Signer: Sign> Channel<Signer> {
45044542
self.config.options.forwarding_fee_base_msat != config.forwarding_fee_base_msat ||
45054543
self.config.options.cltv_expiry_delta != config.cltv_expiry_delta;
45064544
if did_channel_update {
4545+
self.prev_config = Some((self.config.options, 0));
45074546
// Update the counter, which backs the ChannelUpdate timestamp, to allow the relay
45084547
// policy change to propagate throughout the network.
45094548
self.update_time_counter += 1;
@@ -6360,6 +6399,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<(&'a K, u32)> for Channel<Signer>
63606399

63616400
config: config.unwrap(),
63626401

6402+
prev_config: None,
6403+
63636404
// Note that we don't care about serializing handshake limits as we only ever serialize
63646405
// channel data after the handshake has completed.
63656406
inbound_handshake_limits_override: None,

lightning/src/ln/channelmanager.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3511,6 +3511,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
35113511
/// * Broadcasting `ChannelUpdate` messages if we've been disconnected from our peer for more
35123512
/// than a minute, informing the network that they should no longer attempt to route over
35133513
/// the channel.
3514+
/// * Expiring a channel's previous `ChannelConfig` if necessary to only allow forwarding HTLCs
3515+
/// with the current `ChannelConfig`.
35143516
///
35153517
/// Note that this may cause reentrancy through `chain::Watch::update_channel` calls or feerate
35163518
/// estimate fetches.
@@ -3569,6 +3571,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
35693571
_ => {},
35703572
}
35713573

3574+
chan.maybe_expire_prev_config();
3575+
35723576
true
35733577
});
35743578

0 commit comments

Comments
 (0)