Skip to content

Commit c7c8ad9

Browse files
committed
Remove/fail uncommitted HTLCs upon peer disconnection
1 parent 9d387c4 commit c7c8ad9

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

src/ln/channel.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,6 +1766,59 @@ impl Channel {
17661766
}
17671767
}
17681768

1769+
/// Removes any uncommitted HTLCs, to be used on peer disconnection, including any pending
1770+
/// HTLCs that we intended to add but haven't as we were waiting on a remote revoke.
1771+
/// Returns the set of PendingHTLCStatuses from remote uncommitted HTLCs (which we're
1772+
/// implicitly dropping) and the payment_hashes of HTLCs we tried to add but are dropping.
1773+
pub fn remove_uncommitted_htlcs(&mut self) -> Vec<(HTLCSource, [u8; 32])> {
1774+
self.pending_inbound_htlcs.retain(|htlc| {
1775+
match htlc.state {
1776+
InboundHTLCState::RemoteAnnounced => {
1777+
// They sent us an update_add_htlc but we never got the commitment_signed.
1778+
// We'll tell them what commitment_signed we're expecting next and they'll drop
1779+
// this HTLC accordingly
1780+
false
1781+
},
1782+
InboundHTLCState::AwaitingRemoteRevokeToAnnounce|InboundHTLCState::AwaitingAnnouncedRemoteRevoke => {
1783+
// Same goes for AwaitingRemoteRevokeToRemove and AwaitingRemovedRemoteRevoke
1784+
// We received a commitment_signed updating this HTLC and (at least hopefully)
1785+
// sent a revoke_and_ack (which we can re-transmit) and have heard nothing
1786+
// in response to it yet, so don't touch it.
1787+
true
1788+
},
1789+
InboundHTLCState::Committed => true,
1790+
InboundHTLCState::LocalRemoved => { // Same goes for LocalAnnounced
1791+
// We (hopefully) sent a commitment_signed updating this HTLC (which we can
1792+
// re-transmit if needed) and they may have even sent a revoke_and_ack back
1793+
// (that we missed). Keep this around for now and if they tell us they missed
1794+
// the commitment_signed we can re-transmit the update then.
1795+
true
1796+
},
1797+
}
1798+
});
1799+
1800+
for htlc in self.pending_outbound_htlcs.iter_mut() {
1801+
if htlc.state == OutboundHTLCState::RemoteRemoved {
1802+
// They sent us an update to remove this but haven't yet sent the corresponding
1803+
// commitment_signed, we need to move it back to Committed and they can re-send
1804+
// the update upon reconnection.
1805+
htlc.state = OutboundHTLCState::Committed;
1806+
}
1807+
}
1808+
1809+
let mut outbound_drops = Vec::new();
1810+
self.holding_cell_htlc_updates.retain(|htlc_update| {
1811+
match htlc_update {
1812+
&HTLCUpdateAwaitingACK::AddHTLC { ref payment_hash, ref source, .. } => {
1813+
outbound_drops.push((source.clone(), payment_hash.clone()));
1814+
false
1815+
},
1816+
&HTLCUpdateAwaitingACK::ClaimHTLC {..} | &HTLCUpdateAwaitingACK::FailHTLC {..} => true,
1817+
}
1818+
});
1819+
outbound_drops
1820+
}
1821+
17691822
pub fn update_fee(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::UpdateFee) -> Result<(), HandleError> {
17701823
if self.channel_outbound {
17711824
return Err(HandleError{err: "Non-funding remote tried to update channel fee", action: None});

src/ln/channelmanager.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,6 +2126,7 @@ impl ChannelMessageHandler for ChannelManager {
21262126
fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool) {
21272127
let mut new_events = Vec::new();
21282128
let mut failed_channels = Vec::new();
2129+
let mut failed_payments = Vec::new();
21292130
{
21302131
let mut channel_state_lock = self.channel_state.lock().unwrap();
21312132
let channel_state = channel_state_lock.borrow_parts();
@@ -2150,9 +2151,12 @@ impl ChannelMessageHandler for ChannelManager {
21502151
} else {
21512152
for chan in channel_state.by_id {
21522153
if chan.1.get_their_node_id() == *their_node_id {
2153-
//TODO: mark channel disabled (and maybe announce such after a timeout). Also
2154-
//fail and wipe any uncommitted outbound HTLCs as those are considered after
2155-
//reconnect.
2154+
//TODO: mark channel disabled (and maybe announce such after a timeout).
2155+
let failed_adds = chan.1.remove_uncommitted_htlcs();
2156+
if !failed_adds.is_empty() {
2157+
let chan_update = self.get_channel_update(&chan.1).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe
2158+
failed_payments.push((chan_update, failed_adds));
2159+
}
21562160
}
21572161
}
21582162
}
@@ -2166,6 +2170,11 @@ impl ChannelMessageHandler for ChannelManager {
21662170
pending_events.push(event);
21672171
}
21682172
}
2173+
for (chan_update, mut htlc_sources) in failed_payments {
2174+
for (htlc_source, payment_hash) in htlc_sources.drain(..) {
2175+
self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), htlc_source, &payment_hash, HTLCFailReason::Reason { failure_code: 0x1000 | 7, data: chan_update.clone() });
2176+
}
2177+
}
21692178
}
21702179

21712180
fn handle_error(&self, their_node_id: &PublicKey, msg: &msgs::ErrorMessage) {

0 commit comments

Comments
 (0)