Skip to content

Commit ed62212

Browse files
committed
Store info about claimed payments, incl HTLCs in ChannelMonitors
When we claim an MPP payment, then crash before persisting all the relevant `ChannelMonitor`s, we rely on the payment data being available in the `ChannelManager` on restart to re-claim any parts that haven't yet been claimed. This is fine as long as the `ChannelManager` was persisted before the `PaymentClaimable` event was processed, which is generally the case in our `lightning-background-processor`, but may not be in other cases or in a somewhat rare race. In order to fix this, we need to track where all the MPP parts of a payment are in the `ChannelMonitor`, allowing us to re-claim any missing pieces without reference to any `ChannelManager` data. Further, in order to properly generate a `PaymentClaimed` event against the re-started claim, we have to store various payment metadata with the HTLC list as well. Here we store the required MPP parts and metadata in `ChannelMonitor`s and make them available to `ChannelManager` on load.
1 parent af5bbf8 commit ed62212

File tree

3 files changed

+43
-12
lines changed

3 files changed

+43
-12
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
924924
/// preimages that are not included in any unrevoked local commitment transaction or unrevoked
925925
/// remote commitment transactions are automatically removed when commitment transactions are
926926
/// revoked.
927-
payment_preimages: HashMap<PaymentHash, PaymentPreimage>,
927+
payment_preimages: HashMap<PaymentHash, (PaymentPreimage, Vec<PaymentClaimDetails>)>,
928928

929929
// Note that `MonitorEvent`s MUST NOT be generated during update processing, only generated
930930
// during chain data processing. This prevents a race in `ChainMonitor::update_channel` (and
@@ -1150,7 +1150,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
11501150
writer.write_all(&byte_utils::be48_to_array(self.current_holder_commitment_number))?;
11511151

11521152
writer.write_all(&(self.payment_preimages.len() as u64).to_be_bytes())?;
1153-
for payment_preimage in self.payment_preimages.values() {
1153+
for (payment_preimage, _) in self.payment_preimages.values() {
11541154
writer.write_all(&payment_preimage.0[..])?;
11551155
}
11561156

@@ -1228,6 +1228,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
12281228
(19, self.channel_id, required),
12291229
(21, self.balances_empty_height, option),
12301230
(23, self.holder_pays_commitment_tx_fee, option),
1231+
(25, self.payment_preimages, required),
12311232
});
12321233

12331234
Ok(())
@@ -2201,7 +2202,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
22012202
outbound_payment,
22022203
});
22032204
}
2204-
} else if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
2205+
} else if let Some((payment_preimage, _)) = self.payment_preimages.get(&htlc.payment_hash) {
22052206
// Otherwise (the payment was inbound), only expose it as claimable if
22062207
// we know the preimage.
22072208
// Note that if there is a pending claim, but it did not use the
@@ -2422,7 +2423,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
24222423
outbound_payment,
24232424
});
24242425
}
2425-
} else if us.payment_preimages.get(&htlc.payment_hash).is_some() {
2426+
} else if us.payment_preimages.contains_key(&htlc.payment_hash) {
24262427
inbound_claiming_htlc_rounded_msat += rounded_value_msat;
24272428
if htlc.transaction_output_index.is_some() {
24282429
claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000;
@@ -2577,7 +2578,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
25772578
res
25782579
}
25792580

2580-
pub(crate) fn get_stored_preimages(&self) -> HashMap<PaymentHash, PaymentPreimage> {
2581+
pub(crate) fn get_stored_preimages(&self) -> HashMap<PaymentHash, (PaymentPreimage, Vec<PaymentClaimDetails>)> {
25812582
self.inner.lock().unwrap().payment_preimages.clone()
25822583
}
25832584
}
@@ -2936,6 +2937,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
29362937

29372938
/// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all
29382939
/// commitment_tx_infos which contain the payment hash have been revoked.
2940+
///
2941+
/// Note that this is often called multiple times for the same payment and must be idempotent.
29392942
fn provide_payment_preimage<B: Deref, F: Deref, L: Deref>(
29402943
&mut self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage,
29412944
payment_info: &Option<PaymentClaimDetails>, broadcaster: &B,
@@ -2944,8 +2947,17 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
29442947
F::Target: FeeEstimator,
29452948
L::Target: Logger,
29462949
{
2947-
// TODO: Store payment_info (but do not override any existing values)
2948-
self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
2950+
self.payment_preimages.entry(payment_hash.clone())
2951+
.and_modify(|(_, payment_infos)| {
2952+
if let Some(payment_info) = payment_info {
2953+
if !payment_infos.contains(&payment_info) {
2954+
payment_infos.push(payment_info.clone());
2955+
}
2956+
}
2957+
})
2958+
.or_insert_with(|| {
2959+
(payment_preimage.clone(), payment_info.clone().into_iter().collect())
2960+
});
29492961

29502962
let confirmed_spend_txid = self.funding_spend_confirmed.or_else(|| {
29512963
self.onchain_events_awaiting_threshold_conf.iter().find_map(|event| match event.event {
@@ -3602,7 +3614,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36023614
return (claimable_outpoints, to_counterparty_output_info);
36033615
}
36043616
}
3605-
let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None };
3617+
let preimage = if htlc.offered { if let Some((p, _)) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None };
36063618
if preimage.is_some() || !htlc.offered {
36073619
let counterparty_htlc_outp = if htlc.offered {
36083620
PackageSolvingData::CounterpartyOfferedHTLCOutput(
@@ -3690,7 +3702,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36903702
);
36913703
(htlc_output, conf_height)
36923704
} else {
3693-
let payment_preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
3705+
let payment_preimage = if let Some((preimage, _)) = self.payment_preimages.get(&htlc.payment_hash) {
36943706
preimage.clone()
36953707
} else {
36963708
// We can't build an HTLC-Success transaction without the preimage
@@ -3844,7 +3856,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38443856
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
38453857
if let Some(vout) = htlc.0.transaction_output_index {
38463858
let preimage = if !htlc.0.offered {
3847-
if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
3859+
if let Some((preimage, _)) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
38483860
// We can't build an HTLC-Success transaction without the preimage
38493861
continue;
38503862
}
@@ -4817,7 +4829,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
48174829
for _ in 0..payment_preimages_len {
48184830
let preimage: PaymentPreimage = Readable::read(reader)?;
48194831
let hash = PaymentHash(Sha256::hash(&preimage.0[..]).to_byte_array());
4820-
if let Some(_) = payment_preimages.insert(hash, preimage) {
4832+
if let Some(_) = payment_preimages.insert(hash, (preimage, Vec::new())) {
48214833
return Err(DecodeError::InvalidValue);
48224834
}
48234835
}
@@ -4900,6 +4912,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
49004912
let mut balances_empty_height = None;
49014913
let mut channel_id = None;
49024914
let mut holder_pays_commitment_tx_fee = None;
4915+
let mut payment_preimages_with_info: Option<HashMap<_, _>> = None;
49034916
read_tlv_fields!(reader, {
49044917
(1, funding_spend_confirmed, option),
49054918
(3, htlcs_resolved_on_chain, optional_vec),
@@ -4913,7 +4926,24 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
49134926
(19, channel_id, option),
49144927
(21, balances_empty_height, option),
49154928
(23, holder_pays_commitment_tx_fee, option),
4929+
(25, payment_preimages_with_info, option),
49164930
});
4931+
if let Some(payment_preimages_with_info) = payment_preimages_with_info {
4932+
if payment_preimages_with_info.len() != payment_preimages.len() {
4933+
return Err(DecodeError::InvalidValue);
4934+
}
4935+
for (payment_hash, (payment_preimage, _)) in payment_preimages.iter() {
4936+
// Note that because `payment_preimages` is built back from preimages directly,
4937+
// checking that the two maps have the same hash -> preimage pairs also checks that
4938+
// the payment hashes in `payment_preimages_with_info`'s preimages match its
4939+
// hashes.
4940+
let new_preimage = payment_preimages_with_info.get(payment_hash).map(|(p, _)| p);
4941+
if new_preimage != Some(payment_preimage) {
4942+
return Err(DecodeError::InvalidValue);
4943+
}
4944+
}
4945+
payment_preimages = payment_preimages_with_info;
4946+
}
49174947

49184948
// `HolderForceClosedWithInfo` replaced `HolderForceClosed` in v0.0.122. If we have both
49194949
// events, we can remove the `HolderForceClosed` event and just keep the `HolderForceClosedWithInfo`.

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12987,7 +12987,7 @@ where
1298712987
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(args.fee_estimator);
1298812988

1298912989
for (_, monitor) in args.channel_monitors.iter() {
12990-
for (payment_hash, payment_preimage) in monitor.get_stored_preimages() {
12990+
for (payment_hash, (payment_preimage, _)) in monitor.get_stored_preimages() {
1299112991
if let Some(payment) = claimable_payments.remove(&payment_hash) {
1299212992
log_info!(args.logger, "Re-claiming HTLCs with payment hash {} as we've released the preimage to a ChannelMonitor!", &payment_hash);
1299312993
let mut claimable_amt_msat = 0;

lightning/src/util/ser.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ impl Readable for Vec<u8> {
10011001
impl_for_vec!(ecdsa::Signature);
10021002
impl_for_vec!(crate::chain::channelmonitor::ChannelMonitorUpdate);
10031003
impl_for_vec!(crate::ln::channelmanager::MonitorUpdateCompletionAction);
1004+
impl_for_vec!(crate::ln::channelmanager::PaymentClaimDetails);
10041005
impl_for_vec!(crate::ln::msgs::SocketAddress);
10051006
impl_for_vec!((A, B), A, B);
10061007
impl_writeable_for_vec!(&crate::routing::router::BlindedTail);

0 commit comments

Comments
 (0)