Skip to content

Commit 671c4b0

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 671c4b0

File tree

1 file changed

+68
-61
lines changed

1 file changed

+68
-61
lines changed

lightning/src/ln/channel.rs

+68-61
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
}
@@ -5801,20 +5790,15 @@ impl<SP: Deref> FundedChannel<SP> where
58015790

58025791
/// Marks an outbound HTLC which we have received update_fail/fulfill/malformed
58035792
#[inline]
5804-
fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<PaymentPreimage>, fail_reason: Option<HTLCFailReason>) -> Result<&OutboundHTLCOutput, ChannelError> {
5805-
assert!(!(check_preimage.is_some() && fail_reason.is_some()), "cannot fail while we have a preimage");
5793+
fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, outcome: OutboundHTLCOutcome) -> Result<&OutboundHTLCOutput, ChannelError> {
58065794
for htlc in self.context.pending_outbound_htlcs.iter_mut() {
58075795
if htlc.htlc_id == htlc_id {
5808-
let outcome = match check_preimage {
5809-
None => fail_reason.into(),
5810-
Some(payment_preimage) => {
5811-
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array());
5812-
if payment_hash != htlc.payment_hash {
5813-
return Err(ChannelError::close(format!("Remote tried to fulfill HTLC ({}) with an incorrect preimage", htlc_id)));
5814-
}
5815-
OutboundHTLCOutcome::Success(Some(payment_preimage))
5796+
if let OutboundHTLCOutcome::Success(ref payment_preimage) = outcome {
5797+
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array());
5798+
if payment_hash != htlc.payment_hash {
5799+
return Err(ChannelError::close(format!("Remote tried to fulfill HTLC ({}) with an incorrect preimage", htlc_id)));
58165800
}
5817-
};
5801+
}
58185802
match htlc.state {
58195803
OutboundHTLCState::LocalAnnounced(_) =>
58205804
return Err(ChannelError::close(format!("Remote tried to fulfill/fail HTLC ({}) before it had been committed", htlc_id))),
@@ -5841,7 +5825,7 @@ impl<SP: Deref> FundedChannel<SP> where
58415825
return Err(ChannelError::close("Peer sent update_fulfill_htlc when we needed a channel_reestablish".to_owned()));
58425826
}
58435827

5844-
self.mark_outbound_htlc_removed(msg.htlc_id, Some(msg.payment_preimage), None).map(|htlc| (htlc.source.clone(), htlc.amount_msat, htlc.skimmed_fee_msat))
5828+
self.mark_outbound_htlc_removed(msg.htlc_id, OutboundHTLCOutcome::Success(msg.payment_preimage)).map(|htlc| (htlc.source.clone(), htlc.amount_msat, htlc.skimmed_fee_msat))
58455829
}
58465830

58475831
pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<(), ChannelError> {
@@ -5855,7 +5839,7 @@ impl<SP: Deref> FundedChannel<SP> where
58555839
return Err(ChannelError::close("Peer sent update_fail_htlc when we needed a channel_reestablish".to_owned()));
58565840
}
58575841

5858-
self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?;
5842+
self.mark_outbound_htlc_removed(msg.htlc_id, OutboundHTLCOutcome::Failure(fail_reason))?;
58595843
Ok(())
58605844
}
58615845

@@ -5870,7 +5854,7 @@ impl<SP: Deref> FundedChannel<SP> where
58705854
return Err(ChannelError::close("Peer sent update_fail_malformed_htlc when we needed a channel_reestablish".to_owned()));
58715855
}
58725856

5873-
self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?;
5857+
self.mark_outbound_htlc_removed(msg.htlc_id, OutboundHTLCOutcome::Failure(fail_reason))?;
58745858
Ok(())
58755859
}
58765860

@@ -6016,10 +6000,10 @@ impl<SP: Deref> FundedChannel<SP> where
60166000
if let &mut OutboundHTLCState::RemoteRemoved(ref mut outcome) = &mut htlc.state {
60176001
log_trace!(logger, "Updating HTLC {} to AwaitingRemoteRevokeToRemove due to commitment_signed in channel {}.",
60186002
&htlc.payment_hash, &self.context.channel_id);
6019-
// Grab the preimage, if it exists, instead of cloning
6020-
let mut reason = OutboundHTLCOutcome::Success(None);
6003+
// Swap against a dummy variant to avoid a potentially expensive clone of `OutboundHTLCOutcome::Failure(HTLCFailReason)`
6004+
let mut reason = OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32]));
60216005
mem::swap(outcome, &mut reason);
6022-
if let OutboundHTLCOutcome::Success(Some(preimage)) = reason {
6006+
if let OutboundHTLCOutcome::Success(preimage) = reason {
60236007
// If a user (a) receives an HTLC claim using LDK 0.0.104 or before, then (b)
60246008
// upgrades to LDK 0.0.114 or later before the HTLC is fully resolved, we could
60256009
// have a `Success(None)` reason. In this case we could forget some HTLC
@@ -6437,8 +6421,8 @@ impl<SP: Deref> FundedChannel<SP> where
64376421
}
64386422
if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut outcome) = &mut htlc.state {
64396423
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);
6424+
// Swap against a dummy variant to avoid a potentially expensive clone of `OutboundHTLCOutcome::Failure(HTLCFailReason)`
6425+
let mut reason = OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32]));
64426426
mem::swap(outcome, &mut reason);
64436427
htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(reason);
64446428
require_commitment = true;
@@ -9013,8 +8997,8 @@ impl<SP: Deref> FundedChannel<SP> where
90138997
for htlc in self.context.pending_outbound_htlcs.iter_mut() {
90148998
if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut outcome) = &mut htlc.state {
90158999
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);
9000+
// Swap against a dummy variant to avoid a potentially expensive clone of `OutboundHTLCOutcome::Failure(HTLCFailReason)`
9001+
let mut reason = OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32]));
90189002
mem::swap(outcome, &mut reason);
90199003
htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(reason);
90209004
}
@@ -10639,7 +10623,9 @@ impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider
1063910623
}
1064010624
}
1064110625

10642-
let mut preimages: Vec<&Option<PaymentPreimage>> = vec![];
10626+
// The elements of this vector will always be `Some` starting in 0.2,
10627+
// but we still serialize the option to maintain backwards compatibility
10628+
let mut preimages: Vec<Option<&PaymentPreimage>> = vec![];
1064310629
let mut pending_outbound_skimmed_fees: Vec<Option<u64>> = Vec::new();
1064410630
let mut pending_outbound_blinding_points: Vec<Option<PublicKey>> = Vec::new();
1064510631

@@ -10666,15 +10652,15 @@ impl<SP: Deref> Writeable for FundedChannel<SP> where SP::Target: SignerProvider
1066610652
&OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref outcome) => {
1066710653
3u8.write(writer)?;
1066810654
if let OutboundHTLCOutcome::Success(preimage) = outcome {
10669-
preimages.push(preimage);
10655+
preimages.push(Some(preimage));
1067010656
}
1067110657
let reason: Option<&HTLCFailReason> = outcome.into();
1067210658
reason.write(writer)?;
1067310659
}
1067410660
&OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref outcome) => {
1067510661
4u8.write(writer)?;
1067610662
if let OutboundHTLCOutcome::Success(preimage) = outcome {
10677-
preimages.push(preimage);
10663+
preimages.push(Some(preimage));
1067810664
}
1067910665
let reason: Option<&HTLCFailReason> = outcome.into();
1068010666
reason.write(writer)?;
@@ -11013,15 +10999,30 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1101310999
1 => OutboundHTLCState::Committed,
1101411000
2 => {
1101511001
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11016-
OutboundHTLCState::RemoteRemoved(option.into())
11002+
let outcome = match option {
11003+
Some(r) => OutboundHTLCOutcome::Failure(r),
11004+
// Initialize this variant with a dummy preimage, the actual preimage will be filled in further down
11005+
None => OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32])),
11006+
};
11007+
OutboundHTLCState::RemoteRemoved(outcome)
1101711008
},
1101811009
3 => {
1101911010
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11020-
OutboundHTLCState::AwaitingRemoteRevokeToRemove(option.into())
11011+
let outcome = match option {
11012+
Some(r) => OutboundHTLCOutcome::Failure(r),
11013+
// Initialize this variant with a dummy preimage, the actual preimage will be filled in further down
11014+
None => OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32])),
11015+
};
11016+
OutboundHTLCState::AwaitingRemoteRevokeToRemove(outcome)
1102111017
},
1102211018
4 => {
1102311019
let option: Option<HTLCFailReason> = Readable::read(reader)?;
11024-
OutboundHTLCState::AwaitingRemovedRemoteRevoke(option.into())
11020+
let outcome = match option {
11021+
Some(r) => OutboundHTLCOutcome::Failure(r),
11022+
// Initialize this variant with a dummy preimage, the actual preimage will be filled in further down
11023+
None => OutboundHTLCOutcome::Success(PaymentPreimage([0u8; 32])),
11024+
};
11025+
OutboundHTLCState::AwaitingRemovedRemoteRevoke(outcome)
1102511026
},
1102611027
_ => return Err(DecodeError::InvalidValue),
1102711028
},
@@ -11168,7 +11169,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1116811169
// only, so we default to that if none was written.
1116911170
let mut channel_type = Some(ChannelTypeFeatures::only_static_remote_key());
1117011171
let mut channel_creation_height = 0u32;
11171-
let mut preimages_opt: Option<Vec<Option<PaymentPreimage>>> = None;
11172+
// Starting in 0.2, all the elements in this vector will be `Some`, but they are still
11173+
// serialized as options to maintain backwards compatibility
11174+
let mut preimages: Vec<Option<PaymentPreimage>> = Vec::new();
1117211175

1117311176
// If we read an old Channel, for simplicity we just treat it as "we never sent an
1117411177
// AnnouncementSignatures" which implies we'll re-send it on reconnect, but that's fine.
@@ -11222,7 +11225,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1122211225
(10, monitor_pending_update_adds, option), // Added in 0.0.122
1122311226
(11, monitor_pending_finalized_fulfills, optional_vec),
1122411227
(13, channel_creation_height, required),
11225-
(15, preimages_opt, optional_vec),
11228+
(15, preimages, required_vec), // The preimages transitioned from optional to required in 0.2
1122611229
(17, announcement_sigs_state, required),
1122711230
(19, latest_inbound_scid_alias, option),
1122811231
(21, outbound_scid_alias, required),
@@ -11250,23 +11253,27 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1125011253

1125111254
let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
1125211255

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-
_ => {}
11256+
let mut iter = preimages.into_iter();
11257+
for htlc in pending_outbound_htlcs.iter_mut() {
11258+
match &mut htlc.state {
11259+
OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(ref mut preimage)) => {
11260+
// This variant was initialized like this further above
11261+
debug_assert_eq!(preimage, &PaymentPreimage([0u8; 32]));
11262+
// Flatten and unwrap the preimage; they are always set starting in 0.2.
11263+
*preimage = iter.next().flatten().ok_or(DecodeError::InvalidValue)?;
1126411264
}
11265+
OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(ref mut preimage)) => {
11266+
// This variant was initialized like this further above
11267+
debug_assert_eq!(preimage, &PaymentPreimage([0u8; 32]));
11268+
// Flatten and unwrap the preimage; they are always set starting in 0.2.
11269+
*preimage = iter.next().flatten().ok_or(DecodeError::InvalidValue)?;
11270+
}
11271+
_ => {}
1126511272
}
11266-
// We expect all preimages to be consumed above
11267-
if iter.next().is_some() {
11268-
return Err(DecodeError::InvalidValue);
11269-
}
11273+
}
11274+
// We expect all preimages to be consumed above
11275+
if iter.next().is_some() {
11276+
return Err(DecodeError::InvalidValue);
1127011277
}
1127111278

1127211279
let chan_features = channel_type.unwrap();

0 commit comments

Comments
 (0)