Skip to content

Commit 303a435

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 ebf1de5 commit 303a435

File tree

2 files changed

+124
-35
lines changed

2 files changed

+124
-35
lines changed

lightning/src/ln/channelmanager.rs

+118-35
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};
@@ -7082,6 +7082,16 @@ where
70827082
channel_id: Some(prev_hop.channel_id),
70837083
};
70847084

7085+
if prev_hop.counterparty_node_id.is_none() {
7086+
let payment_hash: PaymentHash = payment_preimage.into();
7087+
panic!(
7088+
"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.",
7089+
payment_hash,
7090+
payment_preimage,
7091+
);
7092+
}
7093+
let counterparty_node_id = prev_hop.counterparty_node_id.expect("Checked immediately above");
7094+
70857095
if !during_init {
70867096
// We update the ChannelMonitor on the backward link, after
70877097
// receiving an `update_fulfill_htlc` from the forward link.
@@ -7119,40 +7129,25 @@ where
71197129
let (action_opt, raa_blocker_opt) = completion_action(None, false);
71207130

71217131
if let Some(raa_blocker) = raa_blocker_opt {
7122-
let counterparty_node_id = prev_hop.counterparty_node_id.or_else(||
7123-
// prev_hop.counterparty_node_id is always available for payments received after
7124-
// LDK 0.0.123, but for those received on 0.0.123 and claimed later, we need to
7125-
// look up the counterparty in the `action_opt`, if possible.
7126-
action_opt.as_ref().and_then(|action|
7127-
if let MonitorUpdateCompletionAction::PaymentClaimed { pending_mpp_claim, .. } = action {
7128-
pending_mpp_claim.as_ref().map(|(node_id, _, _, _)| *node_id)
7129-
} else { None }
7130-
)
7131-
);
7132-
if let Some(counterparty_node_id) = counterparty_node_id {
7133-
// TODO: Avoid always blocking the world for the write lock here.
7134-
let mut per_peer_state = self.per_peer_state.write().unwrap();
7135-
let peer_state_mutex = per_peer_state.entry(counterparty_node_id).or_insert_with(||
7136-
Mutex::new(PeerState {
7137-
channel_by_id: new_hash_map(),
7138-
inbound_channel_request_by_id: new_hash_map(),
7139-
latest_features: InitFeatures::empty(),
7140-
pending_msg_events: Vec::new(),
7141-
in_flight_monitor_updates: BTreeMap::new(),
7142-
monitor_update_blocked_actions: BTreeMap::new(),
7143-
actions_blocking_raa_monitor_updates: BTreeMap::new(),
7144-
is_connected: false,
7145-
}));
7146-
let mut peer_state = peer_state_mutex.lock().unwrap();
7132+
// TODO: Avoid always blocking the world for the write lock here.
7133+
let mut per_peer_state = self.per_peer_state.write().unwrap();
7134+
let peer_state_mutex = per_peer_state.entry(counterparty_node_id).or_insert_with(||
7135+
Mutex::new(PeerState {
7136+
channel_by_id: new_hash_map(),
7137+
inbound_channel_request_by_id: new_hash_map(),
7138+
latest_features: InitFeatures::empty(),
7139+
pending_msg_events: Vec::new(),
7140+
in_flight_monitor_updates: BTreeMap::new(),
7141+
monitor_update_blocked_actions: BTreeMap::new(),
7142+
actions_blocking_raa_monitor_updates: BTreeMap::new(),
7143+
is_connected: false,
7144+
}));
7145+
let mut peer_state = peer_state_mutex.lock().unwrap();
71477146

7148-
peer_state.actions_blocking_raa_monitor_updates
7149-
.entry(prev_hop.channel_id)
7150-
.or_default()
7151-
.push(raa_blocker);
7152-
} else {
7153-
debug_assert!(false,
7154-
"RAA ChannelMonitorUpdate blockers are only set with PaymentClaimed completion actions, so we should always have a counterparty node id");
7155-
}
7147+
peer_state.actions_blocking_raa_monitor_updates
7148+
.entry(prev_hop.channel_id)
7149+
.or_default()
7150+
.push(raa_blocker);
71567151
}
71577152

71587153
self.handle_monitor_update_completion_actions(action_opt);
@@ -12928,11 +12923,96 @@ where
1292812923
// Whether the downstream channel was closed or not, try to re-apply any payment
1292912924
// preimages from it which may be needed in upstream channels for forwarded
1293012925
// payments.
12926+
let mut fail_read = false;
1293112927
let outbound_claimed_htlcs_iter = monitor.get_all_current_outbound_htlcs()
1293212928
.into_iter()
1293312929
.filter_map(|(htlc_source, (htlc, preimage_opt))| {
12934-
if let HTLCSource::PreviousHopData(_) = htlc_source {
12930+
if let HTLCSource::PreviousHopData(prev_hop) = &htlc_source {
1293512931
if let Some(payment_preimage) = preimage_opt {
12932+
let inbound_edge_monitor = args.channel_monitors.get(&prev_hop.outpoint);
12933+
// Note that for channels which have gone to chain,
12934+
// `get_all_current_outbound_htlcs` is never pruned and always returns
12935+
// a constant set until the monitor is removed/archived. Thus, we
12936+
// want to skip replaying claims that have definitely been resolved
12937+
// on-chain.
12938+
12939+
// If the inbound monitor is not present, we assume it was fully
12940+
// resolved and properly archived, implying this payment had plenty
12941+
// of time to get claimed and we can safely skip any further
12942+
// attempts to claim it (they wouldn't succeed anyway as we don't
12943+
// have a monitor against which to do so).
12944+
let inbound_edge_monitor = if let Some(monitor) = inbound_edge_monitor {
12945+
monitor
12946+
} else {
12947+
return None;
12948+
};
12949+
// Second, if the inbound edge of the payment's monitor has been
12950+
// fully claimed we've had at least `ANTI_REORG_DELAY` blocks to
12951+
// get any PaymentForwarded event(s) to the user and assume that
12952+
// there's no need to try to replay the claim just for that.
12953+
let inbound_edge_balances = inbound_edge_monitor.get_claimable_balances();
12954+
if inbound_edge_balances.is_empty() {
12955+
return None;
12956+
}
12957+
12958+
if prev_hop.counterparty_node_id.is_none() {
12959+
// We no longer support claiming an HTLC where we don't have
12960+
// the counterparty_node_id available if the claim has to go to
12961+
// a closed channel. Its possible we can get away with it if
12962+
// the channel is not yet closed, but its by no means a
12963+
// guarantee.
12964+
12965+
// Thus, in this case we are a bit more aggressive with our
12966+
// pruning - if we have no use for the claim (because the
12967+
// inbound edge of the payment's monitor has already claimed
12968+
// the HTLC) we skip trying to replay the claim.
12969+
let htlc_payment_hash: PaymentHash = payment_preimage.into();
12970+
if inbound_edge_balances.iter().any(|bal| {
12971+
match bal {
12972+
Balance::ClaimableOnChannelClose { .. } => {
12973+
// The channel is still open, assume we can still
12974+
// claim against it
12975+
true
12976+
},
12977+
Balance::MaybePreimageClaimableHTLC { payment_hash, .. } => {
12978+
*payment_hash == htlc_payment_hash
12979+
},
12980+
_ => false,
12981+
}
12982+
}) {
12983+
return None;
12984+
}
12985+
12986+
// First check if we're absolutely going to fail - if we need
12987+
// to replay this claim to get the preimage into the inbound
12988+
// edge monitor but the channel is closed (and thus we'll
12989+
// immediately panic if we call claim_funds_from_hop).
12990+
if outpoint_to_peer.get(&prev_hop.outpoint).is_none() {
12991+
log_error!(args.logger,
12992+
"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.\
12993+
All HTLCs that were forwarded by LDK 0.0.123 and prior must be resolved prior to upgrading to LDK 0.1",
12994+
htlc_payment_hash,
12995+
payment_preimage,
12996+
);
12997+
fail_read = true;
12998+
}
12999+
13000+
// At this point we're confident we need the claim, but the
13001+
// inbound edge channel is still live. As long as this remains
13002+
// the case, we can conceivably proceed, but we run some risk
13003+
// of panicking at runtime. The user ideally should have read
13004+
// the release notes and we wouldn't be here, but we go ahead
13005+
// and let things run in the hope that it'll all just work out.
13006+
log_error!(args.logger,
13007+
"We need to replay the HTLC claim for payment_hash {} (preimage {}) but don't have all the required information to do so reliably.\
13008+
As long as the channel for the inbound edge of the forward remains open, this may work okay, but we may panic at runtime!\
13009+
All HTLCs that were forwarded by LDK 0.0.123 and prior must be resolved prior to upgrading to LDK 0.1\
13010+
Continuing anyway, though panics may occur!",
13011+
htlc_payment_hash,
13012+
payment_preimage,
13013+
);
13014+
}
13015+
1293613016
Some((htlc_source, payment_preimage, htlc.amount_msat,
1293713017
// Check if `counterparty_opt.is_none()` to see if the
1293813018
// downstream chan is closed (because we don't have a
@@ -12952,6 +13032,9 @@ where
1295213032
for tuple in outbound_claimed_htlcs_iter {
1295313033
pending_claims_to_replay.push(tuple);
1295413034
}
13035+
if fail_read {
13036+
return Err(DecodeError::InvalidValue);
13037+
}
1295513038
}
1295613039
}
1295713040

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 that were originally forwarded running
6+
0.0.123 or earlier.

0 commit comments

Comments
 (0)