Skip to content

Commit 0ad1f4c

Browse files
committed
Track claimed outbound HTLCs in ChannelMonitors
When we receive an update_fulfill_htlc message, we immediately try to "claim" the HTLC against the HTLCSource. If there is one, this works great, we immediately generate a `ChannelMonitorUpdate` for the corresponding inbound HTLC and persist that before we ever get to processing our counterparty's `commitment_signed` and persisting the corresponding `ChannelMonitorUpdate`. However, if there isn't one (and this is the first successful HTLC for a payment we sent), we immediately generate a `PaymentSent` event and queue it up for the user. Then, a millisecond later, we receive the `commitment_signed` from our peer, removing the HTLC from the latest local commitment transaction as a side-effect of the `ChannelMonitorUpdate` applied. If the user has processed the `PaymentSent` event by that point, great, we're done. However, if they have not, and we crash prior to persisting the `ChannelManager`, on startup we get confused about the state of the payment. We'll force-close the channel for being stale, and see an HTLC which was removed and is no longer present in the latest commitment transaction (which we're broadcasting). Because we claim corresponding inbound HTLCs before updating a `ChannelMonitor`, we assume such HTLCs have failed - attempting to fail after having claimed should be a noop. However, in the sent-payment case we now generate a `PaymentFailed` event for the user, allowing an HTLC to complete without giving the user a preimage. Here we address this issue by storing the payment preimages for claimed outbound HTLCs in the `ChannelMonitor`, in addition to the existing inbound HTLC preimages already stored there. This allows us to fix the specific issue described by checking for a preimage and switching the type of event generated in response. In addition, it reduces the risk of future confusion by ensuring we don't fail HTLCs which were claimed but not fully committed to before a crash. It does not, however, full fix the issue here - because the preimages are removed after the HTLC has been fully removed from available commitment transactions if we are substantially delayed in persisting the `ChannelManager` from the time we receive the `update_fulfill_htlc` until after a full commitment signed dance completes we may still hit this issue. The full fix for this issue is to delay the persistence of the `ChannelMonitorUpdate` until after the `PaymentSent` event has been processed. This avoids the issue entirely, ensuring we process the event before updating the `ChannelMonitor`, the same as we ensure the upstream HTLC has been claimed before updating the `ChannelMonitor` for forwarded payments. The full solution will be implemented in a later work, however this change still makes sense at that point as well - if we were to delay the initial `commitment_signed` `ChannelMonitorUpdate` util after the `PaymentSent` event has been processed (which likely requires a database update on the users' end), we'd hold our `commitment_signed` + `revoke_and_ack` response for two DB writes (i.e. `fsync()` calls), making our commitment transaction processing a full `fsync` slower. By making this change first, we can instead delay the `ChannelMonitorUpdate` from the counterparty's final `revoke_and_ack` message until the event has been processed, giving us a full network roundtrip to do so and avoiding delaying our response as long as an `fsync` is faster than a network roundtrip.
1 parent 33c36d0 commit 0ad1f4c

File tree

6 files changed

+261
-68
lines changed

6 files changed

+261
-68
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use crate::ln::{PaymentHash, PaymentPreimage};
3737
use crate::ln::msgs::DecodeError;
3838
use crate::ln::chan_utils;
3939
use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction};
40-
use crate::ln::channelmanager::HTLCSource;
40+
use crate::ln::channelmanager::{HTLCSource, SentHTLCId};
4141
use crate::chain;
4242
use crate::chain::{BestBlock, WatchedOutput};
4343
use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
@@ -494,6 +494,7 @@ pub(crate) enum ChannelMonitorUpdateStep {
494494
LatestHolderCommitmentTXInfo {
495495
commitment_tx: HolderCommitmentTransaction,
496496
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
497+
claimed_htlcs: Vec<(SentHTLCId, PaymentPreimage)>,
497498
},
498499
LatestCounterpartyCommitmentTXInfo {
499500
commitment_txid: Txid,
@@ -536,6 +537,7 @@ impl ChannelMonitorUpdateStep {
536537
impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
537538
(0, LatestHolderCommitmentTXInfo) => {
538539
(0, commitment_tx, required),
540+
(1, claimed_htlcs, vec_type),
539541
(2, htlc_outputs, vec_type),
540542
},
541543
(1, LatestCounterpartyCommitmentTXInfo) => {
@@ -750,6 +752,8 @@ pub(crate) struct ChannelMonitorImpl<Signer: WriteableEcdsaChannelSigner> {
750752
/// Serialized to disk but should generally not be sent to Watchtowers.
751753
counterparty_hash_commitment_number: HashMap<PaymentHash, u64>,
752754

755+
counterparty_fulfilled_htlcs: HashMap<SentHTLCId, PaymentPreimage>,
756+
753757
// We store two holder commitment transactions to avoid any race conditions where we may update
754758
// some monitors (potentially on watchtowers) but then fail to update others, resulting in the
755759
// various monitors for one channel being out of sync, and us broadcasting a holder
@@ -1033,6 +1037,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signe
10331037
(9, self.counterparty_node_id, option),
10341038
(11, self.confirmed_commitment_tx_counterparty_output, option),
10351039
(13, self.spendable_txids_confirmed, vec_type),
1040+
(15, self.counterparty_fulfilled_htlcs, required),
10361041
});
10371042

10381043
Ok(())
@@ -1120,6 +1125,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
11201125
counterparty_claimable_outpoints: HashMap::new(),
11211126
counterparty_commitment_txn_on_chain: HashMap::new(),
11221127
counterparty_hash_commitment_number: HashMap::new(),
1128+
counterparty_fulfilled_htlcs: HashMap::new(),
11231129

11241130
prev_holder_signed_commitment_tx: None,
11251131
current_holder_commitment_tx: holder_commitment_tx,
@@ -1174,7 +1180,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
11741180
&self, holder_commitment_tx: HolderCommitmentTransaction,
11751181
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
11761182
) -> Result<(), ()> {
1177-
self.inner.lock().unwrap().provide_latest_holder_commitment_tx(holder_commitment_tx, htlc_outputs).map_err(|_| ())
1183+
self.inner.lock().unwrap().provide_latest_holder_commitment_tx(holder_commitment_tx, htlc_outputs, &Vec::new()).map_err(|_| ())
11781184
}
11791185

11801186
/// This is used to provide payment preimage(s) out-of-band during startup without updating the
@@ -1810,9 +1816,10 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
18101816
/// `ChannelMonitor`. This is used to determine if an HTLC was removed from the channel prior
18111817
/// to the `ChannelManager` having been persisted.
18121818
///
1813-
/// This is similar to [`Self::get_pending_outbound_htlcs`] except it includes HTLCs which were
1814-
/// resolved by this `ChannelMonitor`.
1815-
pub(crate) fn get_all_current_outbound_htlcs(&self) -> HashMap<HTLCSource, HTLCOutputInCommitment> {
1819+
/// This is similar to [`Self::get_pending_or_resolved_outbound_htlcs`] except it includes
1820+
/// HTLCs which were resolved on-chain (i.e. where the final HTLC resolution was done by an
1821+
/// event from this `ChannelMonitor`).
1822+
pub(crate) fn get_all_current_outbound_htlcs(&self) -> HashMap<HTLCSource, (HTLCOutputInCommitment, Option<PaymentPreimage>)> {
18161823
let mut res = HashMap::new();
18171824
// Just examine the available counterparty commitment transactions. See docs on
18181825
// `fail_unbroadcast_htlcs`, below, for justification.
@@ -1822,7 +1829,8 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
18221829
if let Some(ref latest_outpoints) = us.counterparty_claimable_outpoints.get($txid) {
18231830
for &(ref htlc, ref source_option) in latest_outpoints.iter() {
18241831
if let &Some(ref source) = source_option {
1825-
res.insert((**source).clone(), htlc.clone());
1832+
res.insert((**source).clone(), (htlc.clone(),
1833+
us.counterparty_fulfilled_htlcs.get(&SentHTLCId::from_source(source)).cloned()));
18261834
}
18271835
}
18281836
}
@@ -1837,9 +1845,14 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
18371845
res
18381846
}
18391847

1840-
/// Gets the set of outbound HTLCs which are pending resolution in this channel.
1848+
/// Gets the set of outbound HTLCs which are pending resolution in this channel or which were
1849+
/// resolved with a preimage from our counterparty.
1850+
///
18411851
/// This is used to reconstruct pending outbound payments on restart in the ChannelManager.
1842-
pub(crate) fn get_pending_outbound_htlcs(&self) -> HashMap<HTLCSource, HTLCOutputInCommitment> {
1852+
///
1853+
/// Currently, the preimage is unused, however if it is present in the relevant internal state
1854+
/// an HTLC is always included even if it has been resolved.
1855+
pub(crate) fn get_pending_or_resolved_outbound_htlcs(&self) -> HashMap<HTLCSource, (HTLCOutputInCommitment, Option<PaymentPreimage>)> {
18431856
let us = self.inner.lock().unwrap();
18441857
// We're only concerned with the confirmation count of HTLC transactions, and don't
18451858
// actually care how many confirmations a commitment transaction may or may not have. Thus,
@@ -1887,8 +1900,10 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
18871900
Some(commitment_tx_output_idx) == htlc.transaction_output_index
18881901
} else { false }
18891902
});
1890-
if !htlc_update_confd {
1891-
res.insert(source.clone(), htlc.clone());
1903+
let counterparty_resolved_preimage_opt =
1904+
us.counterparty_fulfilled_htlcs.get(&SentHTLCId::from_source(source)).cloned();
1905+
if !htlc_update_confd || counterparty_resolved_preimage_opt.is_some() {
1906+
res.insert(source.clone(), (htlc.clone(), counterparty_resolved_preimage_opt));
18921907
}
18931908
}
18941909
}
@@ -1970,6 +1985,9 @@ macro_rules! fail_unbroadcast_htlcs {
19701985
}
19711986
}
19721987
if matched_htlc { continue; }
1988+
if $self.counterparty_fulfilled_htlcs.get(&SentHTLCId::from_source(source)).is_some() {
1989+
continue;
1990+
}
19731991
$self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
19741992
if entry.height != $commitment_tx_conf_height { return true; }
19751993
match entry.event {
@@ -2042,6 +2060,17 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
20422060
// events for now-revoked/fulfilled HTLCs.
20432061
if let Some(txid) = self.prev_counterparty_commitment_txid.take() {
20442062
if self.current_counterparty_commitment_txid.unwrap() != txid {
2063+
let cur_claimables = self.counterparty_claimable_outpoints.get(
2064+
&self.current_counterparty_commitment_txid.unwrap()).unwrap();
2065+
for (_, ref source_opt) in self.counterparty_claimable_outpoints.get(&txid).unwrap() {
2066+
if let Some(source) = source_opt {
2067+
if !cur_claimables.iter()
2068+
.any(|(_, cur_source_opt)| cur_source_opt == source_opt)
2069+
{
2070+
self.counterparty_fulfilled_htlcs.remove(&SentHTLCId::from_source(source));
2071+
}
2072+
}
2073+
}
20452074
for &mut (_, ref mut source_opt) in self.counterparty_claimable_outpoints.get_mut(&txid).unwrap() {
20462075
*source_opt = None;
20472076
}
@@ -2131,7 +2160,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
21312160
/// is important that any clones of this channel monitor (including remote clones) by kept
21322161
/// up-to-date as our holder commitment transaction is updated.
21332162
/// Panics if set_on_holder_tx_csv has never been called.
2134-
fn provide_latest_holder_commitment_tx(&mut self, holder_commitment_tx: HolderCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>) -> Result<(), &'static str> {
2163+
fn provide_latest_holder_commitment_tx(&mut self, holder_commitment_tx: HolderCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>, claimed_htlcs: &[(SentHTLCId, PaymentPreimage)]) -> Result<(), &'static str> {
21352164
// block for Rust 1.34 compat
21362165
let mut new_holder_commitment_tx = {
21372166
let trusted_tx = holder_commitment_tx.trust();
@@ -2153,6 +2182,18 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
21532182
self.onchain_tx_handler.provide_latest_holder_tx(holder_commitment_tx);
21542183
mem::swap(&mut new_holder_commitment_tx, &mut self.current_holder_commitment_tx);
21552184
self.prev_holder_signed_commitment_tx = Some(new_holder_commitment_tx);
2185+
for (claimed_htlc_id, claimed_preimage) in claimed_htlcs {
2186+
#[cfg(debug_assertions)] {
2187+
let cur_counterparty_htlcs = self.counterparty_claimable_outpoints.get(
2188+
&self.current_counterparty_commitment_txid.unwrap()).unwrap();
2189+
assert!(cur_counterparty_htlcs.iter().any(|(_, source_opt)| {
2190+
if let Some(source) = source_opt {
2191+
SentHTLCId::from_source(source) == *claimed_htlc_id
2192+
} else { false }
2193+
}));
2194+
}
2195+
self.counterparty_fulfilled_htlcs.insert(*claimed_htlc_id, *claimed_preimage);
2196+
}
21562197
if self.holder_tx_signed {
21572198
return Err("Latest holder commitment signed has already been signed, update is rejected");
21582199
}
@@ -2247,10 +2288,10 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
22472288
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&*fee_estimator);
22482289
for update in updates.updates.iter() {
22492290
match update {
2250-
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs } => {
2291+
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, claimed_htlcs } => {
22512292
log_trace!(logger, "Updating ChannelMonitor with latest holder commitment transaction info");
22522293
if self.lockdown_from_offchain { panic!(); }
2253-
if let Err(e) = self.provide_latest_holder_commitment_tx(commitment_tx.clone(), htlc_outputs.clone()) {
2294+
if let Err(e) = self.provide_latest_holder_commitment_tx(commitment_tx.clone(), htlc_outputs.clone(), &claimed_htlcs) {
22542295
log_error!(logger, "Providing latest holder commitment transaction failed/was refused:");
22552296
log_error!(logger, " {}", e);
22562297
ret = Err(());
@@ -3872,6 +3913,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
38723913
let mut counterparty_node_id = None;
38733914
let mut confirmed_commitment_tx_counterparty_output = None;
38743915
let mut spendable_txids_confirmed = Some(Vec::new());
3916+
let mut counterparty_fulfilled_htlcs = Some(HashMap::new());
38753917
read_tlv_fields!(reader, {
38763918
(1, funding_spend_confirmed, option),
38773919
(3, htlcs_resolved_on_chain, vec_type),
@@ -3880,6 +3922,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
38803922
(9, counterparty_node_id, option),
38813923
(11, confirmed_commitment_tx_counterparty_output, option),
38823924
(13, spendable_txids_confirmed, vec_type),
3925+
(15, counterparty_fulfilled_htlcs, option),
38833926
});
38843927

38853928
Ok((best_block.block_hash(), ChannelMonitor::from_impl(ChannelMonitorImpl {
@@ -3908,6 +3951,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
39083951
counterparty_claimable_outpoints,
39093952
counterparty_commitment_txn_on_chain,
39103953
counterparty_hash_commitment_number,
3954+
counterparty_fulfilled_htlcs: counterparty_fulfilled_htlcs.unwrap(),
39113955

39123956
prev_holder_signed_commitment_tx,
39133957
current_holder_commitment_tx,
@@ -4081,7 +4125,6 @@ mod tests {
40814125
let fee_estimator = TestFeeEstimator { sat_per_kw: Mutex::new(253) };
40824126

40834127
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
4084-
let dummy_tx = Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() };
40854128

40864129
let mut preimages = Vec::new();
40874130
{
@@ -4171,7 +4214,6 @@ mod tests {
41714214
HolderCommitmentTransaction::dummy(), best_block, dummy_key);
41724215

41734216
monitor.provide_latest_holder_commitment_tx(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..10])).unwrap();
4174-
let dummy_txid = dummy_tx.txid();
41754217
monitor.provide_latest_counterparty_commitment_tx(Txid::from_inner(Sha256::hash(b"1").into_inner()),
41764218
preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key, &logger);
41774219
monitor.provide_latest_counterparty_commitment_tx(Txid::from_inner(Sha256::hash(b"2").into_inner()),

lightning/src/ln/channel.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::ln::features::{ChannelTypeFeatures, InitFeatures};
2727
use crate::ln::msgs;
2828
use crate::ln::msgs::{DecodeError, OptionalField, DataLossProtect};
2929
use crate::ln::script::{self, ShutdownScript};
30-
use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
30+
use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
3131
use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction};
3232
use crate::ln::chan_utils;
3333
use crate::ln::onion_utils::HTLCFailReason;
@@ -192,6 +192,7 @@ enum OutboundHTLCState {
192192

193193
#[derive(Clone)]
194194
enum OutboundHTLCOutcome {
195+
/// LDK version 0.0.105+ will always fill in the preimage here.
195196
Success(Option<PaymentPreimage>),
196197
Failure(HTLCFailReason),
197198
}
@@ -3159,15 +3160,6 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
31593160
}
31603161
}
31613162

3162-
self.latest_monitor_update_id += 1;
3163-
let mut monitor_update = ChannelMonitorUpdate {
3164-
update_id: self.latest_monitor_update_id,
3165-
updates: vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
3166-
commitment_tx: holder_commitment_tx,
3167-
htlc_outputs: htlcs_and_sigs
3168-
}]
3169-
};
3170-
31713163
for htlc in self.pending_inbound_htlcs.iter_mut() {
31723164
let new_forward = if let &InboundHTLCState::RemoteAnnounced(ref forward_info) = &htlc.state {
31733165
Some(forward_info.clone())
@@ -3179,18 +3171,38 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
31793171
need_commitment = true;
31803172
}
31813173
}
3174+
let mut claimed_htlcs = Vec::new();
31823175
for htlc in self.pending_outbound_htlcs.iter_mut() {
31833176
if let &mut OutboundHTLCState::RemoteRemoved(ref mut outcome) = &mut htlc.state {
31843177
log_trace!(logger, "Updating HTLC {} to AwaitingRemoteRevokeToRemove due to commitment_signed in channel {}.",
31853178
log_bytes!(htlc.payment_hash.0), log_bytes!(self.channel_id));
31863179
// Grab the preimage, if it exists, instead of cloning
31873180
let mut reason = OutboundHTLCOutcome::Success(None);
31883181
mem::swap(outcome, &mut reason);
3182+
if let OutboundHTLCOutcome::Success(Some(preimage)) = reason {
3183+
// If a user (a) receives an HTLC claim using LDK 0.0.104 or before, then (b)
3184+
// upgrades to LDK 0.0.114 or later before the HTLC is fully resolved, we could
3185+
// have a `Success(None)` reason. In this case we could forget some HTLC
3186+
// claims, but such an upgrade is unlikely and including claimed HTLCs here
3187+
// fixes a bug which the user was exposed to on 0.0.104 when they started the
3188+
// claim anyway.
3189+
claimed_htlcs.push((SentHTLCId::from_source(&htlc.source), preimage));
3190+
}
31893191
htlc.state = OutboundHTLCState::AwaitingRemoteRevokeToRemove(reason);
31903192
need_commitment = true;
31913193
}
31923194
}
31933195

3196+
self.latest_monitor_update_id += 1;
3197+
let mut monitor_update = ChannelMonitorUpdate {
3198+
update_id: self.latest_monitor_update_id,
3199+
updates: vec![ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo {
3200+
commitment_tx: holder_commitment_tx,
3201+
htlc_outputs: htlcs_and_sigs,
3202+
claimed_htlcs,
3203+
}]
3204+
};
3205+
31943206
self.cur_holder_commitment_transaction_number -= 1;
31953207
// Note that if we need_commitment & !AwaitingRemoteRevoke we'll call
31963208
// build_commitment_no_status_check() next which will reset this to RAAFirst.

0 commit comments

Comments
 (0)