Skip to content

Commit 0aadf6f

Browse files
committed
Use proper locktime for HTLC timeout/success transactions
This only applies for such transactions spending our own commitments. The timelocks are fixed due to the counterparty's signature, so we shouldn't be modifying it for such inputs. This wasn't an issue for channels predating anchors since we'd always broadcast the reconstructed pre-signed HTLC transaction. This changes with anchors though, as it'll now be the responsibility of the anchors event handler to ensure the correct transaction locktime is set. To make the experience a bit more user-friendly, a later commit will expose the transaction locktime, so we make sure we start using the correct one in this commit.
1 parent 14ee173 commit 0aadf6f

File tree

1 file changed

+26
-3
lines changed

1 file changed

+26
-3
lines changed

lightning/src/chain/package.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,14 @@ impl PackageSolvingData {
470470
PackageSolvingData::RevokedHTLCOutput(_) => output_conf_height + 1,
471471
PackageSolvingData::CounterpartyOfferedHTLCOutput(_) => output_conf_height + 1,
472472
PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => cmp::max(outp.htlc.cltv_expiry, output_conf_height + 1),
473-
PackageSolvingData::HolderHTLCOutput(ref outp) => cmp::max(outp.cltv_expiry, output_conf_height + 1),
473+
// HTLC timeout/success transactions rely on a fixed timelock due to the counterparty's
474+
// signature.
475+
PackageSolvingData::HolderHTLCOutput(ref outp) => {
476+
if outp.preimage.is_some() {
477+
debug_assert_eq!(outp.cltv_expiry, 0);
478+
}
479+
outp.cltv_expiry
480+
},
474481
PackageSolvingData::HolderFundingOutput(_) => output_conf_height + 1,
475482
};
476483
absolute_timelock
@@ -639,8 +646,24 @@ impl PackageTemplate {
639646
amounts
640647
}
641648
pub(crate) fn package_timelock(&self) -> u32 {
642-
self.inputs.iter().map(|(_, outp)| outp.absolute_tx_timelock(self.height_original))
643-
.max().expect("There must always be at least one output to spend in a PackageTemplate")
649+
let timelock = self.inputs.iter().map(|(_, outp)| outp.absolute_tx_timelock(self.height_original))
650+
.max().expect("There must always be at least one output to spend in a PackageTemplate");
651+
// If we ever try to aggregate a `HolderHTLCOutput` for which we have a preimage with
652+
// another output type, we'll likely end up with an incorrect transaction locktime since
653+
// the counterparty has included it in its HTLC signature. This should never happen unless
654+
// we decide to aggregate outputs across different channel commitments.
655+
#[cfg(debug_assertions)] {
656+
if self.inputs.iter().any(|(_, outp)|
657+
if let PackageSolvingData::HolderHTLCOutput(outp) = outp {
658+
outp.preimage.is_some()
659+
} else {
660+
false
661+
}
662+
) {
663+
debug_assert_eq!(timelock, 0);
664+
};
665+
}
666+
timelock
644667
}
645668
pub(crate) fn package_weight(&self, destination_script: &Script) -> usize {
646669
let mut inputs_weight = 0;

0 commit comments

Comments
 (0)