Skip to content

Commit e4ca3ee

Browse files
committed
Req the counterparty node id when claiming against a closed chan
Currently we store in-flight `ChannelMonitorUpdate`s in the per-peer structure in `ChannelManager`. This is nice and simple as we're generally updating it when we're updating other per-peer data, so we already have the relevant lock(s) and map entries. Sadly, when we're claiming an HTLC against a closed channel, we didn't have the `counterparty_node_id` available until it was added in 0.0.124 (and now we only have it for HTLCs which were forwarded in 0.0.124). This means we can't look up the per-peer structure when claiming old HTLCs, making it difficult to track the new `ChannelMonitorUpdate` as in-flight. While we could transition the in-flight `ChannelMonitorUpdate` tracking to a new global map indexed by `OutPoint`, doing so would result in a major lock which would be highly contended across channels with different peers. Instead, as we move towards tracking in-flight `ChannelMonitorUpdate`s for closed channels we'll keep our existing storage, leaving only the `counterparty_node_id` issue to contend with. Here we simply accept the issue, requiring that `counterparty_node_id` be available when claiming HTLCs against a closed channel. On startup, we explicitly check for any forwarded HTLCs which came from a closed channel where the forward happened prior to 0.0.124, failing to deserialize, or logging an warning if the channel is still open (implying things may work out, but panics may occur if the channel closes prior to HTLC resolution). While this is a somewhat dissapointing resolution, LDK nodes which forward HTLCs are generally fairly well-upgraded, so it is not anticipated to be an issue in practice.
1 parent c7b12ff commit e4ca3ee

File tree

2 files changed

+131
-41
lines changed

2 files changed

+131
-41
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 125 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt1
4040
use crate::chain;
4141
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
4242
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
43-
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, WithChannelMonitor, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID};
43+
use crate::chain::channelmonitor::{Balance, ChannelMonitor, ChannelMonitorUpdate, WithChannelMonitor, ChannelMonitorUpdateStep, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID};
4444
use crate::chain::transaction::{OutPoint, TransactionData};
4545
use crate::events;
4646
use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination, PaymentFailureReason, ReplayEvent};
@@ -6836,15 +6836,16 @@ where
68366836
debug_assert_ne!(self.pending_events.held_by_thread(), LockHeldState::HeldByThread);
68376837
debug_assert_ne!(self.claimable_payments.held_by_thread(), LockHeldState::HeldByThread);
68386838

6839+
let counterparty_node_id_opt = prev_hop.counterparty_node_id.or_else(|| {
6840+
match self.short_to_chan_info.read().unwrap().get(&prev_hop.short_channel_id) {
6841+
Some((cp_id, _dup_chan_id)) => Some(cp_id.clone()),
6842+
None => None
6843+
}
6844+
});
6845+
68396846
{
68406847
let per_peer_state = self.per_peer_state.read().unwrap();
68416848
let chan_id = prev_hop.channel_id;
6842-
let counterparty_node_id_opt = prev_hop.counterparty_node_id.or_else(|| {
6843-
match self.short_to_chan_info.read().unwrap().get(&prev_hop.short_channel_id) {
6844-
Some((cp_id, _dup_chan_id)) => Some(cp_id.clone()),
6845-
None => None
6846-
}
6847-
});
68486849

68496850
let peer_state_opt = counterparty_node_id_opt.as_ref().map(
68506851
|counterparty_node_id| per_peer_state.get(counterparty_node_id)
@@ -6950,6 +6951,16 @@ where
69506951
channel_id: Some(prev_hop.channel_id),
69516952
};
69526953

6954+
if counterparty_node_id_opt.is_none() {
6955+
let payment_hash: PaymentHash = payment_preimage.into();
6956+
panic!(
6957+
"Prior to upgrading to LDK 0.1, all pending HTLCs must be resolved. It appears at least the HTLC with payment_hash {} (preimage {}) was not resolved. Please downgrade to LDK 0.0.124 and resolve the HTLC prior to upgrading.",
6958+
payment_hash,
6959+
payment_preimage,
6960+
);
6961+
}
6962+
let counterparty_node_id = counterparty_node_id_opt.expect("Checked immediately above");
6963+
69536964
if !during_init {
69546965
// We update the ChannelMonitor on the backward link, after
69556966
// receiving an `update_fulfill_htlc` from the forward link.
@@ -6987,40 +6998,25 @@ where
69876998
let (action_opt, raa_blocker_opt) = completion_action(None, false);
69886999

69897000
if let Some(raa_blocker) = raa_blocker_opt {
6990-
let counterparty_node_id = prev_hop.counterparty_node_id.or_else(||
6991-
// prev_hop.counterparty_node_id is always available for payments received after
6992-
// LDK 0.0.123, but for those received on 0.0.123 and claimed later, we need to
6993-
// look up the counterparty in the `action_opt`, if possible.
6994-
action_opt.as_ref().and_then(|action|
6995-
if let MonitorUpdateCompletionAction::PaymentClaimed { pending_mpp_claim, .. } = action {
6996-
pending_mpp_claim.as_ref().map(|(node_id, _, _, _)| *node_id)
6997-
} else { None }
6998-
)
6999-
);
7000-
if let Some(counterparty_node_id) = counterparty_node_id {
7001-
// TODO: Avoid always blocking the world for the write lock here.
7002-
let mut per_peer_state = self.per_peer_state.write().unwrap();
7003-
let peer_state_mutex = per_peer_state.entry(counterparty_node_id).or_insert_with(||
7004-
Mutex::new(PeerState {
7005-
channel_by_id: new_hash_map(),
7006-
inbound_channel_request_by_id: new_hash_map(),
7007-
latest_features: InitFeatures::empty(),
7008-
pending_msg_events: Vec::new(),
7009-
in_flight_monitor_updates: BTreeMap::new(),
7010-
monitor_update_blocked_actions: BTreeMap::new(),
7011-
actions_blocking_raa_monitor_updates: BTreeMap::new(),
7012-
is_connected: false,
7013-
}));
7014-
let mut peer_state = peer_state_mutex.lock().unwrap();
7001+
// TODO: Avoid always blocking the world for the write lock here.
7002+
let mut per_peer_state = self.per_peer_state.write().unwrap();
7003+
let peer_state_mutex = per_peer_state.entry(counterparty_node_id).or_insert_with(||
7004+
Mutex::new(PeerState {
7005+
channel_by_id: new_hash_map(),
7006+
inbound_channel_request_by_id: new_hash_map(),
7007+
latest_features: InitFeatures::empty(),
7008+
pending_msg_events: Vec::new(),
7009+
in_flight_monitor_updates: BTreeMap::new(),
7010+
monitor_update_blocked_actions: BTreeMap::new(),
7011+
actions_blocking_raa_monitor_updates: BTreeMap::new(),
7012+
is_connected: false,
7013+
}));
7014+
let mut peer_state = peer_state_mutex.lock().unwrap();
70157015

7016-
peer_state.actions_blocking_raa_monitor_updates
7017-
.entry(prev_hop.channel_id)
7018-
.or_default()
7019-
.push(raa_blocker);
7020-
} else {
7021-
debug_assert!(false,
7022-
"RAA ChannelMonitorUpdate blockers are only set with PaymentClaimed completion actions, so we should always have a counterparty node id");
7023-
}
7016+
peer_state.actions_blocking_raa_monitor_updates
7017+
.entry(prev_hop.channel_id)
7018+
.or_default()
7019+
.push(raa_blocker);
70247020
}
70257021

70267022
self.handle_monitor_update_completion_actions(action_opt);
@@ -12773,11 +12769,96 @@ where
1277312769
// Whether the downstream channel was closed or not, try to re-apply any payment
1277412770
// preimages from it which may be needed in upstream channels for forwarded
1277512771
// payments.
12772+
let mut fail_read = false;
1277612773
let outbound_claimed_htlcs_iter = monitor.get_all_current_outbound_htlcs()
1277712774
.into_iter()
1277812775
.filter_map(|(htlc_source, (htlc, preimage_opt))| {
12779-
if let HTLCSource::PreviousHopData(_) = htlc_source {
12776+
if let HTLCSource::PreviousHopData(prev_hop) = &htlc_source {
1278012777
if let Some(payment_preimage) = preimage_opt {
12778+
let inbound_edge_monitor = args.channel_monitors.get(&prev_hop.outpoint);
12779+
// Note that for channels which have gone to chain,
12780+
// `get_all_current_outbound_htlcs` is never pruned and always returns
12781+
// a constant set until the monitor is removed/archived. Thus, we
12782+
// want to skip replaying claims that have definitely been resolved
12783+
// on-chain.
12784+
12785+
// If the inbound monitor is not present, we assume it was fully
12786+
// resolved and properly archived, implying this payment had plenty
12787+
// of time to get claimed and we can safely skip any further
12788+
// attempts to claim it (they wouldn't succeed anyway as we don't
12789+
// have a monitor against which to do so).
12790+
let inbound_edge_monitor = if let Some(monitor) = inbound_edge_monitor {
12791+
monitor
12792+
} else {
12793+
return None;
12794+
};
12795+
// Second, if the inbound edge of the payment's monitor has been
12796+
// fully claimed we've had at least `ANTI_REORG_DELAY` blocks to
12797+
// get any PaymentForwarded event(s) to the user and assume that
12798+
// there's no need to try to replay the claim just for that.
12799+
let inbound_edge_balances = inbound_edge_monitor.get_claimable_balances();
12800+
if inbound_edge_balances.is_empty() {
12801+
return None;
12802+
}
12803+
12804+
if prev_hop.counterparty_node_id.is_none() {
12805+
// We no longer support claiming an HTLC where we don't have
12806+
// the counterparty_node_id available if the claim has to go to
12807+
// a closed channel. Its possible we can get away with it if
12808+
// the channel is not yet closed, but its by no means a
12809+
// guarantee.
12810+
12811+
// Thus, in this case we are a bit more aggressive with our
12812+
// pruning - if we have no use for the claim (because the
12813+
// inbound edge of the payment's monitor has already claimed
12814+
// the HTLC) we skip trying to replay the claim.
12815+
let htlc_payment_hash: PaymentHash = payment_preimage.into();
12816+
if !inbound_edge_balances.iter().all(|bal| {
12817+
match bal {
12818+
Balance::ClaimableOnChannelClose { .. } => {
12819+
// The channel is still open, assume we can still
12820+
// claim against it
12821+
false
12822+
},
12823+
Balance::MaybePreimageClaimableHTLC { payment_hash, .. } => {
12824+
*payment_hash != htlc_payment_hash
12825+
},
12826+
_ => true,
12827+
}
12828+
}) {
12829+
return None;
12830+
}
12831+
12832+
// First check if we're absolutely going to fail - if we need
12833+
// to replay this claim to get the preimage into the inbound
12834+
// edge monitor but the channel is closed (and thus we'll
12835+
// immediately panic if we call claim_funds_from_hop).
12836+
if outpoint_to_peer.get(&prev_hop.outpoint).is_none() {
12837+
log_error!(args.logger,
12838+
"We need to replay the HTLC claim for payment_hash {} (preimage {}) but cannot do so as the HTLC was forwarded prior to LDK 0.0.124.\
12839+
All HTLCs which were forwarded by LDK 0.0.123 and prior must be resolved prior to upgrading to LDK 0.1",
12840+
htlc_payment_hash,
12841+
payment_preimage,
12842+
);
12843+
fail_read = true;
12844+
}
12845+
12846+
// At this point we're confident we need the claim, but the
12847+
// inbound edge channel is still live. As long as this remains
12848+
// the case, we can conceivably proceed, but we run some risk
12849+
// of panicking at runtime. The user ideally should have read
12850+
// the release notes and we wouldn't be here, but we go ahead
12851+
// and let things run in the hope that it'll all just work out.
12852+
log_error!(args.logger,
12853+
"We need to replay the HTLC claim for payment_hash {} (preimage {}) but don't have all the required information to do so reliably.\
12854+
As long as the channel for the inbound edge of the forward remains open, this may work okay, but we may panic at runtime!\
12855+
All HTLCs which were forwarded by LDK 0.0.123 and prior must be resolved prior to upgrading to LDK 0.1\
12856+
Continuing anyway, though panics may occur!",
12857+
htlc_payment_hash,
12858+
payment_preimage,
12859+
);
12860+
}
12861+
1278112862
Some((htlc_source, payment_preimage, htlc.amount_msat,
1278212863
// Check if `counterparty_opt.is_none()` to see if the
1278312864
// downstream chan is closed (because we don't have a
@@ -12797,6 +12878,9 @@ where
1279712878
for tuple in outbound_claimed_htlcs_iter {
1279812879
pending_claims_to_replay.push(tuple);
1279912880
}
12881+
if fail_read {
12882+
return Err(DecodeError::InvalidValue);
12883+
}
1280012884
}
1280112885
}
1280212886

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## Backwards Compatibility
2+
* Nodes with pending forwarded HTLCs cannot be upgraded directly from 0.0.123
3+
or earlier to 0.1. Instead, they must first either resolve all pending
4+
forwarded HTLCs (including those pending resolution on-chain), or run
5+
0.0.124 and resolve any HTLCs which were originally forwarded running
6+
0.0.123 or earlier.

0 commit comments

Comments
 (0)