Skip to content

Commit fb69869

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 28dc94a commit fb69869

File tree

1 file changed

+63
-49
lines changed

1 file changed

+63
-49
lines changed

lightning/src/ln/channel.rs

+63-49
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ impl OutboundHTLCState {
367367
OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(preimage))
368368
| OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(preimage))
369369
| OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(preimage)) => {
370-
preimage.as_ref().copied()
370+
Some(*preimage)
371371
},
372372
_ => None,
373373
}
@@ -377,20 +377,12 @@ impl OutboundHTLCState {
377377
#[derive(Clone)]
378378
#[cfg_attr(test, derive(Debug, PartialEq))]
379379
enum OutboundHTLCOutcome {
380-
/// LDK version 0.0.105+ will always fill in the preimage here.
381-
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),
382383
Failure(HTLCFailReason),
383384
}
384385

385-
impl From<Option<HTLCFailReason>> for OutboundHTLCOutcome {
386-
fn from(o: Option<HTLCFailReason>) -> Self {
387-
match o {
388-
None => OutboundHTLCOutcome::Success(None),
389-
Some(r) => OutboundHTLCOutcome::Failure(r)
390-
}
391-
}
392-
}
393-
394386
impl<'a> Into<Option<&'a HTLCFailReason>> for &'a OutboundHTLCOutcome {
395387
fn into(self) -> Option<&'a HTLCFailReason> {
396388
match self {
@@ -3878,7 +3870,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38783870
}
38793871
remote_htlc_total_msat += htlc.amount_msat;
38803872
} else {
3881-
if let InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_preimage)) = htlc.state {
3873+
if htlc.state.preimage().is_some() {
38823874
value_to_self_msat_offset += htlc.amount_msat as i64;
38833875
}
38843876
}
@@ -3891,10 +3883,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38913883
}
38923884
local_htlc_total_msat += htlc.amount_msat;
38933885
} else {
3894-
if let OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_)) |
3895-
OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) |
3896-
OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_))
3897-
= htlc.state {
3886+
if htlc.state.preimage().is_some() {
38983887
value_to_self_msat_offset -= htlc.amount_msat as i64;
38993888
}
39003889
}
@@ -5803,16 +5792,18 @@ impl<SP: Deref> FundedChannel<SP> where
58035792
#[inline]
58045793
fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<PaymentPreimage>, fail_reason: Option<HTLCFailReason>) -> Result<&OutboundHTLCOutput, ChannelError> {
58055794
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");
58065796
for htlc in self.context.pending_outbound_htlcs.iter_mut() {
58075797
if htlc.htlc_id == htlc_id {
58085798
let outcome = match check_preimage {
5809-
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()),
58105801
Some(payment_preimage) => {
58115802
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array());
58125803
if payment_hash != htlc.payment_hash {
58135804
return Err(ChannelError::close(format!("Remote tried to fulfill HTLC ({}) with an incorrect preimage", htlc_id)));
58145805
}
5815-
OutboundHTLCOutcome::Success(Some(payment_preimage))
5806+
OutboundHTLCOutcome::Success(payment_preimage)
58165807
}
58175808
};
58185809
match htlc.state {
@@ -6016,10 +6007,10 @@ impl<SP: Deref> FundedChannel<SP> where
60166007
if let &mut OutboundHTLCState::RemoteRemoved(ref mut outcome) = &mut htlc.state {
60176008
log_trace!(logger, "Updating HTLC {} to AwaitingRemoteRevokeToRemove due to commitment_signed in channel {}.",
60186009
&htlc.payment_hash, &self.context.channel_id);
6019-
// Grab the preimage, if it exists, instead of cloning
6020-
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]));
60216012
mem::swap(outcome, &mut reason);
6022-
if let OutboundHTLCOutcome::Success(Some(preimage)) = reason {
6013+
if let OutboundHTLCOutcome::Success(preimage) = reason {
60236014
// If a user (a) receives an HTLC claim using LDK 0.0.104 or before, then (b)
60246015
// upgrades to LDK 0.0.114 or later before the HTLC is fully resolved, we could
60256016
// have a `Success(None)` reason. In this case we could forget some HTLC
@@ -6437,8 +6428,8 @@ impl<SP: Deref> FundedChannel<SP> where
64376428
}
64386429
if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut outcome) = &mut htlc.state {
64396430
log_trace!(logger, " ...promoting outbound AwaitingRemoteRevokeToRemove {} to AwaitingRemovedRemoteRevoke", &htlc.payment_hash);
6440-
// Grab the preimage, if it exists, instead of cloning
6441-
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]));
64426433
mem::swap(outcome, &mut reason);
64436434
htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(reason);
64446435
require_commitment = true;
@@ -9013,8 +9004,8 @@ impl<SP: Deref> FundedChannel<SP> where
90139004
for htlc in self.context.pending_outbound_htlcs.iter_mut() {
90149005
if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut outcome) = &mut htlc.state {
90159006
log_trace!(logger, " ...promoting outbound AwaitingRemoteRevokeToRemove {} to AwaitingRemovedRemoteRevoke", &htlc.payment_hash);
9016-
// Grab the preimage, if it exists, instead of cloning
9017-
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]));
90189009
mem::swap(outcome, &mut reason);
90199010
htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(reason);
90209011
}
@@ -10639,7 +10630,9 @@ impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider
1063910630
}
1064010631
}
1064110632

10642-
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![];
1064310636
let mut pending_outbound_skimmed_fees: Vec<Option<u64>> = Vec::new();
1064410637
let mut pending_outbound_blinding_points: Vec<Option<PublicKey>> = Vec::new();
1064510638

@@ -10666,15 +10659,15 @@ impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider
1066610659
&OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref outcome) => {
1066710660
3u8.write(writer)?;
1066810661
if let OutboundHTLCOutcome::Success(preimage) = outcome {
10669-
preimages.push(preimage);
10662+
preimages.push(Some(preimage));
1067010663
}
1067110664
let reason: Option<&HTLCFailReason> = outcome.into();
1067210665
reason.write(writer)?;
1067310666
}
1067410667
&OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref outcome) => {
1067510668
4u8.write(writer)?;
1067610669
if let OutboundHTLCOutcome::Success(preimage) = outcome {
10677-
preimages.push(preimage);
10670+
preimages.push(Some(preimage));
1067810671
}
1067910672
let reason: Option<&HTLCFailReason> = outcome.into();
1068010673
reason.write(writer)?;
@@ -11013,15 +11006,30 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1101311006
1 => OutboundHTLCState::Committed,
1101411007
2 => {
1101511008
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11016-
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)
1101711015
},
1101811016
3 => {
1101911017
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11020-
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)
1102111024
},
1102211025
4 => {
1102311026
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11024-
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)
1102511033
},
1102611034
_ => return Err(DecodeError::InvalidValue),
1102711035
},
@@ -11168,7 +11176,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1116811176
// only, so we default to that if none was written.
1116911177
let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key());
1117011178
let mut channel_creation_height = 0u32;
11171-
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();
1117211182

1117311183
// If we read an old Channel, for simplicity we just treat it as "we never sent an
1117411184
// AnnouncementSignatures" which implies we'll re-send it on reconnect, but that's fine.
@@ -11222,7 +11232,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1122211232
(10, monitor_pending_update_adds, option), // Added in 0.0.122
1122311233
(11, monitor_pending_finalized_fulfills, optional_vec),
1122411234
(13, channel_creation_height, required),
11225-
(15, preimages_opt, optional_vec),
11235+
(15, preimages, required_vec), // The preimages transitioned from optional to required in 0.2
1122611236
(17, announcement_sigs_state, required),
1122711237
(19, latest_inbound_scid_alias, option),
1122811238
(21, outbound_scid_alias, required),
@@ -11250,23 +11260,27 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1125011260

1125111261
let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
1125211262

11253-
if let Some(preimages) = preimages_opt {
11254-
let mut iter = preimages.into_iter();
11255-
for htlc in pending_outbound_htlcs.iter_mut() {
11256-
match &htlc.state {
11257-
OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(None)) => {
11258-
htlc.state = OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(iter.next().ok_or(DecodeError::InvalidValue)?));
11259-
}
11260-
OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(None)) => {
11261-
htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(iter.next().ok_or(DecodeError::InvalidValue)?));
11262-
}
11263-
_ => {}
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)?;
1126411271
}
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+
_ => {}
1126511279
}
11266-
// We expect all preimages to be consumed above
11267-
if iter.next().is_some() {
11268-
return Err(DecodeError::InvalidValue);
11269-
}
11280+
}
11281+
// We expect all preimages to be consumed above
11282+
if iter.next().is_some() {
11283+
return Err(DecodeError::InvalidValue);
1127011284
}
1127111285

1127211286
let chan_features = channel_type.unwrap();

0 commit comments

Comments
 (0)