Skip to content

Commit 107619e

Browse files
committed
Require all HTLC success states to hold their corresponding preimage
This allows us to DRY the code that calculates the `value_to_self_msat_offset` in `ChannelContext::build_commitment_stats`. HTLC success states have held their corresponding preimage since 0.0.105, and the release notes of 0.1 already require users running 0.0.123 and earlier to resolve their HTLCs before upgrading to 0.1. So this change is fully compatible with existing upgrade paths to the yet-to-be-shipped 0.2 release.
1 parent 6b3ab12 commit 107619e

File tree

1 file changed

+67
-51
lines changed

1 file changed

+67
-51
lines changed

lightning/src/ln/channel.rs

+67-51
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,11 @@ impl OutboundHTLCState {
364364

365365
fn preimage(&self) -> Option<PaymentPreimage> {
366366
match self {
367-
OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(p)) |
368-
OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(p)) |
369-
OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(p)) => p.as_ref().copied(),
367+
OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(preimage)) |
368+
OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(preimage)) |
369+
OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(preimage)) => {
370+
Some(*preimage)
371+
},
370372
_ => None,
371373
}
372374
}
@@ -375,20 +377,12 @@ impl OutboundHTLCState {
375377
#[derive(Clone)]
376378
#[cfg_attr(test, derive(Debug, PartialEq))]
377379
enum OutboundHTLCOutcome {
378-
/// LDK version 0.0.105+ will always fill in the preimage here.
379-
Success(Option<PaymentPreimage>),
380+
/// We started always filling in the preimages here in 0.0.105, and the requirement
381+
/// that the preimages always be filled in was added in 0.2.
382+
Success(PaymentPreimage),
380383
Failure(HTLCFailReason),
381384
}
382385

383-
impl From<Option<HTLCFailReason>> for OutboundHTLCOutcome {
384-
fn from(o: Option<HTLCFailReason>) -> Self {
385-
match o {
386-
None => OutboundHTLCOutcome::Success(None),
387-
Some(r) => OutboundHTLCOutcome::Failure(r)
388-
}
389-
}
390-
}
391-
392386
impl<'a> Into<Option<&'a HTLCFailReason>> for &'a OutboundHTLCOutcome {
393387
fn into(self) -> Option<&'a HTLCFailReason> {
394388
match self {
@@ -3876,7 +3870,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38763870
}
38773871
remote_htlc_total_msat += htlc.amount_msat;
38783872
} else {
3879-
if let InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_preimage)) = htlc.state {
3873+
if htlc.state.preimage().is_some() {
38803874
value_to_self_msat_offset += htlc.amount_msat as i64;
38813875
}
38823876
}
@@ -3889,10 +3883,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38893883
}
38903884
local_htlc_total_msat += htlc.amount_msat;
38913885
} else {
3892-
if let OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_)) |
3893-
OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) |
3894-
OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_))
3895-
= htlc.state {
3886+
if htlc.state.preimage().is_some() {
38963887
value_to_self_msat_offset -= htlc.amount_msat as i64;
38973888
}
38983889
}
@@ -5801,16 +5792,18 @@ impl<SP: Deref> FundedChannel<SP> where
58015792
#[inline]
58025793
fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<PaymentPreimage>, fail_reason: Option<HTLCFailReason>) -> Result<&OutboundHTLCOutput, ChannelError> {
58035794
assert!(!(check_preimage.is_some() && fail_reason.is_some()), "cannot fail while we have a preimage");
5795+
assert!(!(check_preimage.is_none() && fail_reason.is_none()), "either provide a preimage, or a failure reason");
58045796
for htlc in self.context.pending_outbound_htlcs.iter_mut() {
58055797
if htlc.htlc_id == htlc_id {
58065798
let outcome = match check_preimage {
5807-
None => fail_reason.into(),
5799+
// We checked that either check_preimage or fail_reason is set above, so we can safely unwrap here
5800+
None => OutboundHTLCOutcome::Failure(fail_reason.unwrap()),
58085801
Some(payment_preimage) => {
58095802
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array());
58105803
if payment_hash != htlc.payment_hash {
58115804
return Err(ChannelError::close(format!("Remote tried to fulfill HTLC ({}) with an incorrect preimage", htlc_id)));
58125805
}
5813-
OutboundHTLCOutcome::Success(Some(payment_preimage))
5806+
OutboundHTLCOutcome::Success(payment_preimage)
58145807
}
58155808
};
58165809
match htlc.state {
@@ -6014,10 +6007,10 @@ impl<SP: Deref> FundedChannel<SP> where
60146007
if let &mut OutboundHTLCState::RemoteRemoved(ref mut outcome) = &mut htlc.state {
60156008
log_trace!(logger, "Updating HTLC {} to AwaitingRemoteRevokeToRemove due to commitment_signed in channel {}.",
60166009
&htlc.payment_hash, &self.context.channel_id);
6017-
// Grab the preimage, if it exists, instead of cloning
6018-
let mut reason = OutboundHTLCOutcome::Success(None);
6010+
// Swap against a dummy variant to avoid a potentially expensive clone of `OutboundHTLCOutcome::Failure(HTLCFailReason)`
6011+
let mut reason = OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32]));
60196012
mem::swap(outcome, &mut reason);
6020-
if let OutboundHTLCOutcome::Success(Some(preimage)) = reason {
6013+
if let OutboundHTLCOutcome::Success(preimage) = reason {
60216014
// If a user (a) receives an HTLC claim using LDK 0.0.104 or before, then (b)
60226015
// upgrades to LDK 0.0.114 or later before the HTLC is fully resolved, we could
60236016
// have a `Success(None)` reason. In this case we could forget some HTLC
@@ -6435,8 +6428,8 @@ impl<SP: Deref> FundedChannel<SP> where
64356428
}
64366429
if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut outcome) = &mut htlc.state {
64376430
log_trace!(logger, " ...promoting outbound AwaitingRemoteRevokeToRemove {} to AwaitingRemovedRemoteRevoke", &htlc.payment_hash);
6438-
// Grab the preimage, if it exists, instead of cloning
6439-
let mut reason = OutboundHTLCOutcome::Success(None);
6431+
// Swap against a dummy variant to avoid a potentially expensive clone of `OutboundHTLCOutcome::Failure(HTLCFailReason)`
6432+
let mut reason = OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32]));
64406433
mem::swap(outcome, &mut reason);
64416434
htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(reason);
64426435
require_commitment = true;
@@ -9011,8 +9004,8 @@ impl<SP: Deref> FundedChannel<SP> where
90119004
for htlc in self.context.pending_outbound_htlcs.iter_mut() {
90129005
if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut outcome) = &mut htlc.state {
90139006
log_trace!(logger, " ...promoting outbound AwaitingRemoteRevokeToRemove {} to AwaitingRemovedRemoteRevoke", &htlc.payment_hash);
9014-
// Grab the preimage, if it exists, instead of cloning
9015-
let mut reason = OutboundHTLCOutcome::Success(None);
9007+
// Swap against a dummy variant to avoid a potentially expensive clone of `OutboundHTLCOutcome::Failure(HTLCFailReason)`
9008+
let mut reason = OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32]));
90169009
mem::swap(outcome, &mut reason);
90179010
htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(reason);
90189011
}
@@ -10637,7 +10630,9 @@ impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider
1063710630
}
1063810631
}
1063910632

10640-
let mut preimages: Vec<&Option<PaymentPreimage>> = vec![];
10633+
// The elements of this vector will always be `Some` starting in 0.2,
10634+
// but we still serialize the option to maintain backwards compatibility
10635+
let mut preimages: Vec<Option<&PaymentPreimage>> = vec![];
1064110636
let mut pending_outbound_skimmed_fees: Vec<Option<u64>> = Vec::new();
1064210637
let mut pending_outbound_blinding_points: Vec<Option<PublicKey>> = Vec::new();
1064310638

@@ -10664,15 +10659,15 @@ impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider
1066410659
&OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref outcome) => {
1066510660
3u8.write(writer)?;
1066610661
if let OutboundHTLCOutcome::Success(preimage) = outcome {
10667-
preimages.push(preimage);
10662+
preimages.push(Some(preimage));
1066810663
}
1066910664
let reason: Option<&HTLCFailReason> = outcome.into();
1067010665
reason.write(writer)?;
1067110666
}
1067210667
&OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref outcome) => {
1067310668
4u8.write(writer)?;
1067410669
if let OutboundHTLCOutcome::Success(preimage) = outcome {
10675-
preimages.push(preimage);
10670+
preimages.push(Some(preimage));
1067610671
}
1067710672
let reason: Option<&HTLCFailReason> = outcome.into();
1067810673
reason.write(writer)?;
@@ -11011,15 +11006,30 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1101111006
1 => OutboundHTLCState::Committed,
1101211007
2 => {
1101311008
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11014-
OutboundHTLCState::RemoteRemoved(option.into())
11009+
let outcome = match option {
11010+
Some(r) => OutboundHTLCOutcome::Failure(r),
11011+
// Initialize this variant with a dummy preimage, the actual preimage will be filled in further down
11012+
None => OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32])),
11013+
};
11014+
OutboundHTLCState::RemoteRemoved(outcome)
1101511015
},
1101611016
3 => {
1101711017
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11018-
OutboundHTLCState::AwaitingRemoteRevokeToRemove(option.into())
11018+
let outcome = match option {
11019+
Some(r) => OutboundHTLCOutcome::Failure(r),
11020+
// Initialize this variant with a dummy preimage, the actual preimage will be filled in further down
11021+
None => OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32])),
11022+
};
11023+
OutboundHTLCState::AwaitingRemoteRevokeToRemove(outcome)
1101911024
},
1102011025
4 => {
1102111026
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11022-
OutboundHTLCState::AwaitingRemovedRemoteRevoke(option.into())
11027+
let outcome = match option {
11028+
Some(r) => OutboundHTLCOutcome::Failure(r),
11029+
// Initialize this variant with a dummy preimage, the actual preimage will be filled in further down
11030+
None => OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32])),
11031+
};
11032+
OutboundHTLCState::AwaitingRemovedRemoteRevoke(outcome)
1102311033
},
1102411034
_ => return Err(DecodeError::InvalidValue),
1102511035
},
@@ -11166,7 +11176,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1116611176
// only, so we default to that if none was written.
1116711177
let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key());
1116811178
let mut channel_creation_height = 0u32;
11169-
let mut preimages_opt: Option<Vec<Option<PaymentPreimage>>> = None;
11179+
// Starting in 0.2, all the elements in this vector will be `Some`, but they are still
11180+
// serialized as options to maintain backwards compatibility
11181+
let mut preimages: Vec<Option<PaymentPreimage>> = Vec::new();
1117011182

1117111183
// If we read an old Channel, for simplicity we just treat it as "we never sent an
1117211184
// AnnouncementSignatures" which implies we'll re-send it on reconnect, but that's fine.
@@ -11220,7 +11232,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1122011232
(10, monitor_pending_update_adds, option), // Added in 0.0.122
1122111233
(11, monitor_pending_finalized_fulfills, optional_vec),
1122211234
(13, channel_creation_height, required),
11223-
(15, preimages_opt, optional_vec),
11235+
(15, preimages, required_vec), // The preimages transitioned from optional to required in 0.2
1122411236
(17, announcement_sigs_state, required),
1122511237
(19, latest_inbound_scid_alias, option),
1122611238
(21, outbound_scid_alias, required),
@@ -11248,23 +11260,27 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1124811260

1124911261
let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
1125011262

11251-
if let Some(preimages) = preimages_opt {
11252-
let mut iter = preimages.into_iter();
11253-
for htlc in pending_outbound_htlcs.iter_mut() {
11254-
match &htlc.state {
11255-
OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(None)) => {
11256-
htlc.state = OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(iter.next().ok_or(DecodeError::InvalidValue)?));
11257-
}
11258-
OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(None)) => {
11259-
htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(iter.next().ok_or(DecodeError::InvalidValue)?));
11260-
}
11261-
_ => {}
11263+
let mut iter = preimages.into_iter();
11264+
for htlc in pending_outbound_htlcs.iter_mut() {
11265+
match &mut htlc.state {
11266+
OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(ref mut preimage)) => {
11267+
// This variant was initialized like this further above
11268+
debug_assert_eq!(preimage, &PaymentPreimage([0u8; 32]));
11269+
// Flatten and unwrap the preimage; they are always set starting in 0.2.
11270+
*preimage = iter.next().flatten().ok_or(DecodeError::InvalidValue)?;
1126211271
}
11272+
OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(ref mut preimage)) => {
11273+
// This variant was initialized like this further above
11274+
debug_assert_eq!(preimage, &PaymentPreimage([0u8; 32]));
11275+
// Flatten and unwrap the preimage; they are always set starting in 0.2.
11276+
*preimage = iter.next().flatten().ok_or(DecodeError::InvalidValue)?;
11277+
}
11278+
_ => {}
1126311279
}
11264-
// We expect all preimages to be consumed above
11265-
if iter.next().is_some() {
11266-
return Err(DecodeError::InvalidValue);
11267-
}
11280+
}
11281+
// We expect all preimages to be consumed above
11282+
if iter.next().is_some() {
11283+
return Err(DecodeError::InvalidValue);
1126811284
}
1126911285

1127011286
let chan_features = channel_type.unwrap();

0 commit comments

Comments
 (0)