Skip to content

Commit 6f023f8

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 6f023f8

File tree

2 files changed

+152
-35
lines changed

2 files changed

+152
-35
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 146 additions & 35 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};
@@ -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 forwarded by LDK 0.0.123 or before must be resolved. It appears at least the HTLC with payment_hash {} (preimage {}) was not resolved. Please downgrade to LDK 0.0.125 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,97 @@ 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+
let balance_could_incl_htlc = |bal| match bal {
12971+
&Balance::ClaimableOnChannelClose { .. } => {
12972+
// The channel is still open, assume we can still
12973+
// claim against it
12974+
true
12975+
},
12976+
&Balance::MaybePreimageClaimableHTLC { payment_hash, .. } => {
12977+
payment_hash == htlc_payment_hash
12978+
},
12979+
_ => false,
12980+
};
12981+
let htlc_may_be_in_balances =
12982+
inbound_edge_balances.iter().any(balance_could_incl_htlc);
12983+
if !htlc_may_be_in_balances {
12984+
return None;
12985+
}
12986+
12987+
// First check if we're absolutely going to fail - if we need
12988+
// to replay this claim to get the preimage into the inbound
12989+
// edge monitor but the channel is closed (and thus we'll
12990+
// immediately panic if we call claim_funds_from_hop).
12991+
if short_to_chan_info.get(&prev_hop.short_channel_id).is_none() {
12992+
log_error!(args.logger,
12993+
"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.\
12994+
All HTLCs that were forwarded by LDK 0.0.123 and prior must be resolved prior to upgrading to LDK 0.1",
12995+
htlc_payment_hash,
12996+
payment_preimage,
12997+
);
12998+
fail_read = true;
12999+
}
13000+
13001+
// At this point we're confident we need the claim, but the
13002+
// inbound edge channel is still live. As long as this remains
13003+
// the case, we can conceivably proceed, but we run some risk
13004+
// of panicking at runtime. The user ideally should have read
13005+
// the release notes and we wouldn't be here, but we go ahead
13006+
// and let things run in the hope that it'll all just work out.
13007+
log_error!(args.logger,
13008+
"We need to replay the HTLC claim for payment_hash {} (preimage {}) but don't have all the required information to do so reliably.\
13009+
As long as the channel for the inbound edge of the forward remains open, this may work okay, but we may panic at runtime!\
13010+
All HTLCs that were forwarded by LDK 0.0.123 and prior must be resolved prior to upgrading to LDK 0.1\
13011+
Continuing anyway, though panics may occur!",
13012+
htlc_payment_hash,
13013+
payment_preimage,
13014+
);
13015+
}
13016+
1293613017
Some((htlc_source, payment_preimage, htlc.amount_msat,
1293713018
// Check if `counterparty_opt.is_none()` to see if the
1293813019
// downstream chan is closed (because we don't have a
@@ -12952,6 +13033,9 @@ where
1295213033
for tuple in outbound_claimed_htlcs_iter {
1295313034
pending_claims_to_replay.push(tuple);
1295413035
}
13036+
if fail_read {
13037+
return Err(DecodeError::InvalidValue);
13038+
}
1295513039
}
1295613040
}
1295713041

@@ -13028,6 +13112,33 @@ where
1302813112
}
1302913113
}
1303013114

13115+
// Similar to the above cases for forwarded payments, if we have any pending inbound HTLCs
13116+
// which haven't yet been claimed, we may be missing counterparty_node_id info and would
13117+
// panic if we attempted to claim them at this point.
13118+
for (payment_hash, payment) in claimable_payments.iter() {
13119+
for htlc in payment.htlcs.iter() {
13120+
if htlc.prev_hop.counterparty_node_id.is_some() {
13121+
continue;
13122+
}
13123+
if short_to_chan_info.get(&htlc.prev_hop.short_channel_id).is_some() {
13124+
log_error!(args.logger,
13125+
"We do not have the required information to claim a pending payment with payment hash {} reliably.\
13126+
As long as the channel for the inbound edge of the forward remains open, this may work okay, but we may panic at runtime!\
13127+
All HTLCs that were received by LDK 0.0.123 and prior must be resolved prior to upgrading to LDK 0.1\
13128+
Continuing anyway, though panics may occur!",
13129+
payment_hash,
13130+
);
13131+
} else {
13132+
log_error!(args.logger,
13133+
"We do not have the required information to claim a pending payment with payment hash {}.\
13134+
All HTLCs that were received by LDK 0.0.123 and prior must be resolved prior to upgrading to LDK 0.1",
13135+
payment_hash,
13136+
);
13137+
return Err(DecodeError::InvalidValue);
13138+
}
13139+
}
13140+
}
13141+
1303113142
let mut secp_ctx = Secp256k1::new();
1303213143
secp_ctx.seeded_randomize(&args.entropy_source.get_secure_random_bytes());
1303313144

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 or unclaimed payments cannot be
3+
upgraded directly from 0.0.123 or earlier to 0.1. Instead, they must
4+
first either resolve all pending HTLCs (including those pending
5+
resolution on-chain), or run 0.0.124 and resolve any HTLCs that were
6+
originally forwarded or received running 0.0.123 or earlier.

0 commit comments

Comments
 (0)