Skip to content

Commit 4a6bc66

Browse files
Add htlc_not_found return value to queue_fail_htlc
Recently, we began generating monitor events when HTLCs fail off-chain. In upcoming commits, we'll begin relying on those events to resolve forwarded HTLC fails on the inbound edge. In some situations, and in part because monitor events are re-provided until they are explicitly acked, we may end up attempting to fail an HTLC upstream when it has already been fully removed from the inbound edge channel. If we hit this case, we know that we don't need the outbound edge monitor event resolution anymore, and can ack it so it doesn't get re-provided again. Here we add a return value to the relevant Channel methods so the ChannelManager knows when we've hit this case. It'll be used in upcoming commits when we start relying on monitor events for off-chain forward fails.
1 parent 2e6a533 commit 4a6bc66

2 files changed

Lines changed: 32 additions & 17 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7861,9 +7861,13 @@ where
78617861

78627862
/// Returns `Err` (always with [`ChannelError::Ignore`]) if the HTLC could not be failed (e.g.
78637863
/// if it was already resolved). Otherwise returns `Ok`.
7864+
///
7865+
/// On `Err`, the returned bool is set if the HTLC was already fully removed from the channel.
7866+
/// Callers may use it to clean up any state that was waiting on this HTLC removal, such as a
7867+
/// pending monitor event on the outbound edge.
78647868
pub fn queue_fail_htlc<L: Logger>(
78657869
&mut self, htlc_id_arg: u64, err_packet: msgs::OnionErrorPacket, logger: &L,
7866-
) -> Result<(), ChannelError> {
7870+
) -> Result<(), (ChannelError, bool)> {
78677871
self.fail_htlc(htlc_id_arg, err_packet, true, logger)
78687872
.map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
78697873
}
@@ -7874,18 +7878,20 @@ where
78747878
/// See [`Self::queue_fail_htlc`] for more info.
78757879
pub fn queue_fail_malformed_htlc<L: Logger>(
78767880
&mut self, htlc_id_arg: u64, failure_code: u16, sha256_of_onion: [u8; 32], logger: &L,
7877-
) -> Result<(), ChannelError> {
7881+
) -> Result<(), (ChannelError, bool)> {
78787882
self.fail_htlc(htlc_id_arg, (sha256_of_onion, failure_code), true, logger)
78797883
.map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
78807884
}
78817885

78827886
/// Returns `Err` (always with [`ChannelError::Ignore`]) if the HTLC could not be failed (e.g.
78837887
/// if it was already resolved). Otherwise returns `Ok`.
7888+
///
7889+
/// On `Err`, the returned bool is set if the HTLC was already fully removed from the channel.
78847890
#[rustfmt::skip]
78857891
fn fail_htlc<L: Logger, E: FailHTLCContents + Clone>(
78867892
&mut self, htlc_id_arg: u64, err_contents: E, mut force_holding_cell: bool,
78877893
logger: &L
7888-
) -> Result<Option<E::Message>, ChannelError> {
7894+
) -> Result<Option<E::Message>, (ChannelError, bool)> {
78897895
if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
78907896
panic!("Was asked to fail an HTLC when channel was not in an operational state");
78917897
}
@@ -7900,18 +7906,18 @@ where
79007906
match htlc.state {
79017907
InboundHTLCState::Committed { .. } => {},
79027908
InboundHTLCState::LocalRemoved(_) => {
7903-
return Err(ChannelError::Ignore(format!("HTLC {} was already resolved", htlc.htlc_id)));
7909+
return Err((ChannelError::Ignore(format!("HTLC {} was already resolved", htlc.htlc_id)), false));
79047910
},
79057911
_ => {
79067912
debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to");
7907-
return Err(ChannelError::Ignore(format!("Unable to find a pending HTLC which matched the given HTLC ID ({})", htlc.htlc_id)));
7913+
return Err((ChannelError::Ignore(format!("Unable to find a pending HTLC which matched the given HTLC ID ({})", htlc.htlc_id)), false));
79087914
}
79097915
}
79107916
pending_idx = idx;
79117917
}
79127918
}
79137919
if pending_idx == core::usize::MAX {
7914-
return Err(ChannelError::Ignore(format!("Unable to find a pending HTLC which matched the given HTLC ID ({})", htlc_id_arg)));
7920+
return Err((ChannelError::Ignore(format!("Unable to find a pending HTLC which matched the given HTLC ID ({})", htlc_id_arg)), true));
79157921
}
79167922

79177923
if !self.context.channel_state.can_generate_new_commitment() {
@@ -7925,14 +7931,14 @@ where
79257931
match pending_update {
79267932
&HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => {
79277933
if htlc_id_arg == htlc_id {
7928-
return Err(ChannelError::Ignore(format!("HTLC {} was already claimed!", htlc_id)));
7934+
return Err((ChannelError::Ignore(format!("HTLC {} was already claimed!", htlc_id)), false));
79297935
}
79307936
},
79317937
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } |
79327938
&HTLCUpdateAwaitingACK::FailMalformedHTLC { htlc_id, .. } =>
79337939
{
79347940
if htlc_id_arg == htlc_id {
7935-
return Err(ChannelError::Ignore(format!("HTLC {} was already pending failure", htlc_id)));
7941+
return Err((ChannelError::Ignore(format!("HTLC {} was already pending failure", htlc_id)), false));
79367942
}
79377943
},
79387944
_ => {}
@@ -9034,18 +9040,27 @@ where
90349040
monitor_update.updates.append(&mut additional_monitor_update.updates);
90359041
None
90369042
},
9037-
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, ref err_packet } => Some(
9038-
self.fail_htlc(htlc_id, err_packet.clone(), false, logger)
9039-
.map(|fail_msg_opt| fail_msg_opt.map(|_| ())),
9040-
),
9043+
&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, ref err_packet } => {
9044+
let res = self.fail_htlc(htlc_id, err_packet.clone(), false, logger);
9045+
debug_assert!(
9046+
!matches!(&res, Err((_, true))),
9047+
"holding cell HTLC fails are always present in pending_inbound_htlcs",
9048+
);
9049+
Some(res.map(|fail_msg_opt| fail_msg_opt.map(|_| ())).map_err(|(e, _)| e))
9050+
},
90419051
&HTLCUpdateAwaitingACK::FailMalformedHTLC {
90429052
htlc_id,
90439053
failure_code,
90449054
sha256_of_onion,
9045-
} => Some(
9046-
self.fail_htlc(htlc_id, (sha256_of_onion, failure_code), false, logger)
9047-
.map(|fail_msg_opt| fail_msg_opt.map(|_| ())),
9048-
),
9055+
} => {
9056+
let res =
9057+
self.fail_htlc(htlc_id, (sha256_of_onion, failure_code), false, logger);
9058+
debug_assert!(
9059+
!matches!(&res, Err((_, true))),
9060+
"holding cell HTLC fail-malformeds are always present in pending_inbound_htlcs",
9061+
);
9062+
Some(res.map(|fail_msg_opt| fail_msg_opt.map(|_| ())).map_err(|(e, _)| e))
9063+
},
90499064
};
90509065
if let Some(res) = fail_htlc_res {
90519066
match res {

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8532,7 +8532,7 @@ impl<
85328532
},
85338533
};
85348534
if let Some((queue_fail_htlc_res, htlc_id)) = queue_fail_htlc_res {
8535-
if let Err(e) = queue_fail_htlc_res {
8535+
if let Err((e, htlc_not_found)) = queue_fail_htlc_res {
85368536
if let ChannelError::Ignore(msg) = e {
85378537
if let Some(chan) = peer_state
85388538
.channel_by_id

0 commit comments

Comments
 (0)