Skip to content

Commit cc5b193

Browse files
authored
Merge pull request #3613 from TheBlueMatt/2025-02-0.1.2-backports
0.1 Backports for 0.1.2
2 parents fe45095 + 6749a07 commit cc5b193

19 files changed

+609
-760
lines changed

.github/workflows/semver.yml

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: SemVer checks
2+
on:
3+
push:
4+
branches-ignore:
5+
- master
6+
pull_request:
7+
branches-ignore:
8+
- master
9+
10+
jobs:
11+
semver-checks:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout source code
15+
uses: actions/checkout@v4
16+
- name: Install Rust stable toolchain
17+
run: |
18+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain stable
19+
rustup override set stable
20+
- name: Check SemVer with default features
21+
uses: obi1kenobi/cargo-semver-checks-action@v2
22+
with:
23+
feature-group: default-features
24+
- name: Check SemVer *without* default features
25+
uses: obi1kenobi/cargo-semver-checks-action@v2
26+
with:
27+
feature-group: only-explicit-features
28+
- name: Check lightning-background-processor SemVer
29+
uses: obi1kenobi/cargo-semver-checks-action@v2
30+
with:
31+
package: lightning-background-processor
32+
feature-group: only-explicit-features
33+
features: futures
34+
- name: Check lightning-block-sync SemVer
35+
uses: obi1kenobi/cargo-semver-checks-action@v2
36+
with:
37+
package: lightning-block-sync
38+
feature-group: only-explicit-features
39+
features: rpc-client,rest-client
40+
- name: Check lightning-transaction-sync electrum SemVer
41+
uses: obi1kenobi/cargo-semver-checks-action@v2
42+
with:
43+
manifest-path: lightning-transaction-sync/Cargo.toml
44+
feature-group: only-explicit-features
45+
features: electrum
46+
- name: Check lightning-transaction-sync esplora-blocking SemVer
47+
uses: obi1kenobi/cargo-semver-checks-action@v2
48+
with:
49+
manifest-path: lightning-transaction-sync/Cargo.toml
50+
feature-group: only-explicit-features
51+
features: esplora-blocking
52+
- name: Check lightning-transaction-sync esplora-async SemVer
53+
uses: obi1kenobi/cargo-semver-checks-action@v2
54+
with:
55+
manifest-path: lightning-transaction-sync/Cargo.toml
56+
feature-group: only-explicit-features
57+
features: esplora-async

lightning-background-processor/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2379,8 +2379,8 @@ mod tests {
23792379
42,
23802380
53,
23812381
features,
2382-
$nodes[0].node.get_our_node_id(),
2383-
$nodes[1].node.get_our_node_id(),
2382+
$nodes[0].node.get_our_node_id().into(),
2383+
$nodes[1].node.get_our_node_id().into(),
23842384
)
23852385
.expect("Failed to update channel from partial announcement");
23862386
let original_graph_description = $nodes[0].network_graph.to_string();

lightning/src/chain/channelmonitor.rs

+46-44
Original file line numberDiff line numberDiff line change
@@ -1509,8 +1509,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
15091509
fn provide_latest_holder_commitment_tx(
15101510
&self, holder_commitment_tx: HolderCommitmentTransaction,
15111511
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
1512-
) -> Result<(), ()> {
1513-
self.inner.lock().unwrap().provide_latest_holder_commitment_tx(holder_commitment_tx, htlc_outputs, &Vec::new(), Vec::new()).map_err(|_| ())
1512+
) {
1513+
self.inner.lock().unwrap().provide_latest_holder_commitment_tx(holder_commitment_tx, htlc_outputs, &Vec::new(), Vec::new())
15141514
}
15151515

15161516
/// This is used to provide payment preimage(s) out-of-band during startup without updating the
@@ -1737,10 +1737,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
17371737
self.inner.lock().unwrap().get_cur_holder_commitment_number()
17381738
}
17391739

1740-
/// Gets whether we've been notified that this channel is closed by the `ChannelManager` (i.e.
1741-
/// via a [`ChannelMonitorUpdateStep::ChannelForceClosed`]).
1742-
pub(crate) fn offchain_closed(&self) -> bool {
1743-
self.inner.lock().unwrap().lockdown_from_offchain
1740+
/// Fetches whether this monitor has marked the channel as closed and will refuse any further
1741+
/// updates to the commitment transactions.
1742+
///
1743+
/// It can be marked closed in a few different ways, including via a
1744+
/// [`ChannelMonitorUpdateStep::ChannelForceClosed`] or if the channel has been closed
1745+
/// on-chain.
1746+
pub(crate) fn no_further_updates_allowed(&self) -> bool {
1747+
self.inner.lock().unwrap().no_further_updates_allowed()
17441748
}
17451749

17461750
/// Gets the `node_id` of the counterparty for this channel.
@@ -2901,7 +2905,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
29012905
/// is important that any clones of this channel monitor (including remote clones) by kept
29022906
/// up-to-date as our holder commitment transaction is updated.
29032907
/// Panics if set_on_holder_tx_csv has never been called.
2904-
fn provide_latest_holder_commitment_tx(&mut self, holder_commitment_tx: HolderCommitmentTransaction, mut htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>, claimed_htlcs: &[(SentHTLCId, PaymentPreimage)], nondust_htlc_sources: Vec<HTLCSource>) -> Result<(), &'static str> {
2908+
fn provide_latest_holder_commitment_tx(&mut self, holder_commitment_tx: HolderCommitmentTransaction, mut htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>, claimed_htlcs: &[(SentHTLCId, PaymentPreimage)], nondust_htlc_sources: Vec<HTLCSource>) {
29052909
if htlc_outputs.iter().any(|(_, s, _)| s.is_some()) {
29062910
// If we have non-dust HTLCs in htlc_outputs, ensure they match the HTLCs in the
29072911
// `holder_commitment_tx`. In the future, we'll no longer provide the redundant data
@@ -2978,10 +2982,6 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
29782982
}
29792983
self.counterparty_fulfilled_htlcs.insert(*claimed_htlc_id, *claimed_preimage);
29802984
}
2981-
if self.holder_tx_signed {
2982-
return Err("Latest holder commitment signed has already been signed, update is rejected");
2983-
}
2984-
Ok(())
29852985
}
29862986

29872987
/// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all
@@ -3202,11 +3202,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
32023202
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, claimed_htlcs, nondust_htlc_sources } => {
32033203
log_trace!(logger, "Updating ChannelMonitor with latest holder commitment transaction info");
32043204
if self.lockdown_from_offchain { panic!(); }
3205-
if let Err(e) = self.provide_latest_holder_commitment_tx(commitment_tx.clone(), htlc_outputs.clone(), &claimed_htlcs, nondust_htlc_sources.clone()) {
3206-
log_error!(logger, "Providing latest holder commitment transaction failed/was refused:");
3207-
log_error!(logger, " {}", e);
3208-
ret = Err(());
3209-
}
3205+
self.provide_latest_holder_commitment_tx(commitment_tx.clone(), htlc_outputs.clone(), &claimed_htlcs, nondust_htlc_sources.clone());
32103206
}
32113207
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point, .. } => {
32123208
log_trace!(logger, "Updating ChannelMonitor with latest counterparty commitment transaction info");
@@ -3286,12 +3282,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
32863282
}
32873283
}
32883284

3289-
if ret.is_ok() && (self.funding_spend_seen || self.lockdown_from_offchain || self.holder_tx_signed) && is_pre_close_update {
3285+
if ret.is_ok() && self.no_further_updates_allowed() && is_pre_close_update {
32903286
log_error!(logger, "Refusing Channel Monitor Update as counterparty attempted to update commitment after funding was spent");
32913287
Err(())
32923288
} else { ret }
32933289
}
32943290

3291+
fn no_further_updates_allowed(&self) -> bool {
3292+
self.funding_spend_seen || self.lockdown_from_offchain || self.holder_tx_signed
3293+
}
3294+
32953295
fn get_latest_update_id(&self) -> u64 {
32963296
self.latest_update_id
32973297
}
@@ -3564,11 +3564,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
35643564
return (claimable_outpoints, to_counterparty_output_info);
35653565
}
35663566
let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), &self.onchain_tx_handler.channel_transaction_parameters.channel_type_features);
3567+
let counterparty_spendable_height = if htlc.offered {
3568+
htlc.cltv_expiry
3569+
} else {
3570+
height
3571+
};
35673572
let justice_package = PackageTemplate::build_package(
35683573
commitment_txid,
35693574
transaction_output_index,
35703575
PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp),
3571-
htlc.cltv_expiry,
3576+
counterparty_spendable_height,
35723577
);
35733578
claimable_outpoints.push(justice_package);
35743579
}
@@ -3869,35 +3874,32 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38693874
}
38703875
}
38713876
}
3872-
if self.holder_tx_signed {
3873-
// If we've signed, we may have broadcast either commitment (prev or current), and
3874-
// attempted to claim from it immediately without waiting for a confirmation.
3875-
if self.current_holder_commitment_tx.txid != *confirmed_commitment_txid {
3877+
// Cancel any pending claims for any holder commitments in case they had previously
3878+
// confirmed or been signed (in which case we will start attempting to claim without
3879+
// waiting for confirmation).
3880+
if self.current_holder_commitment_tx.txid != *confirmed_commitment_txid {
3881+
log_trace!(logger, "Canceling claims for previously broadcast holder commitment {}",
3882+
self.current_holder_commitment_tx.txid);
3883+
let mut outpoint = BitcoinOutPoint { txid: self.current_holder_commitment_tx.txid, vout: 0 };
3884+
for (htlc, _, _) in &self.current_holder_commitment_tx.htlc_outputs {
3885+
if let Some(vout) = htlc.transaction_output_index {
3886+
outpoint.vout = vout;
3887+
self.onchain_tx_handler.abandon_claim(&outpoint);
3888+
}
3889+
}
3890+
}
3891+
if let Some(prev_holder_commitment_tx) = &self.prev_holder_signed_commitment_tx {
3892+
if prev_holder_commitment_tx.txid != *confirmed_commitment_txid {
38763893
log_trace!(logger, "Canceling claims for previously broadcast holder commitment {}",
3877-
self.current_holder_commitment_tx.txid);
3878-
let mut outpoint = BitcoinOutPoint { txid: self.current_holder_commitment_tx.txid, vout: 0 };
3879-
for (htlc, _, _) in &self.current_holder_commitment_tx.htlc_outputs {
3894+
prev_holder_commitment_tx.txid);
3895+
let mut outpoint = BitcoinOutPoint { txid: prev_holder_commitment_tx.txid, vout: 0 };
3896+
for (htlc, _, _) in &prev_holder_commitment_tx.htlc_outputs {
38803897
if let Some(vout) = htlc.transaction_output_index {
38813898
outpoint.vout = vout;
38823899
self.onchain_tx_handler.abandon_claim(&outpoint);
38833900
}
38843901
}
38853902
}
3886-
if let Some(prev_holder_commitment_tx) = &self.prev_holder_signed_commitment_tx {
3887-
if prev_holder_commitment_tx.txid != *confirmed_commitment_txid {
3888-
log_trace!(logger, "Canceling claims for previously broadcast holder commitment {}",
3889-
prev_holder_commitment_tx.txid);
3890-
let mut outpoint = BitcoinOutPoint { txid: prev_holder_commitment_tx.txid, vout: 0 };
3891-
for (htlc, _, _) in &prev_holder_commitment_tx.htlc_outputs {
3892-
if let Some(vout) = htlc.transaction_output_index {
3893-
outpoint.vout = vout;
3894-
self.onchain_tx_handler.abandon_claim(&outpoint);
3895-
}
3896-
}
3897-
}
3898-
}
3899-
} else {
3900-
// No previous claim.
39013903
}
39023904
}
39033905

@@ -4233,7 +4235,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
42334235
}
42344236
}
42354237

4236-
if self.lockdown_from_offchain || self.funding_spend_seen || self.holder_tx_signed {
4238+
if self.no_further_updates_allowed() {
42374239
// Fail back HTLCs on backwards channels if they expire within
42384240
// `LATENCY_GRACE_PERIOD_BLOCKS` blocks and the channel is closed (i.e. we're at a
42394241
// point where no further off-chain updates will be accepted). If we haven't seen the
@@ -5384,7 +5386,7 @@ mod tests {
53845386
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(&mut htlcs);
53855387

53865388
monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx.clone(),
5387-
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect()).unwrap();
5389+
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect());
53885390
monitor.provide_latest_counterparty_commitment_tx(Txid::from_byte_array(Sha256::hash(b"1").to_byte_array()),
53895391
preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key, &logger);
53905392
monitor.provide_latest_counterparty_commitment_tx(Txid::from_byte_array(Sha256::hash(b"2").to_byte_array()),
@@ -5422,7 +5424,7 @@ mod tests {
54225424
let mut htlcs = preimages_slice_to_htlcs!(preimages[0..5]);
54235425
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(&mut htlcs);
54245426
monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx.clone(),
5425-
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect()).unwrap();
5427+
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect());
54265428
secret[0..32].clone_from_slice(&<Vec<u8>>::from_hex("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
54275429
monitor.provide_secret(281474976710653, secret.clone()).unwrap();
54285430
assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 12);
@@ -5433,7 +5435,7 @@ mod tests {
54335435
let mut htlcs = preimages_slice_to_htlcs!(preimages[0..3]);
54345436
let dummy_commitment_tx = HolderCommitmentTransaction::dummy(&mut htlcs);
54355437
monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx,
5436-
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect()).unwrap();
5438+
htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect());
54375439
secret[0..32].clone_from_slice(&<Vec<u8>>::from_hex("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
54385440
monitor.provide_secret(281474976710652, secret.clone()).unwrap();
54395441
assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 5);

lightning/src/chain/package.rs

+29-17
Original file line numberDiff line numberDiff line change
@@ -699,8 +699,13 @@ impl PackageSolvingData {
699699
match self {
700700
PackageSolvingData::RevokedOutput(RevokedOutput { .. }) =>
701701
PackageMalleability::Malleable(AggregationCluster::Unpinnable),
702-
PackageSolvingData::RevokedHTLCOutput(..) =>
703-
PackageMalleability::Malleable(AggregationCluster::Pinnable),
702+
PackageSolvingData::RevokedHTLCOutput(RevokedHTLCOutput { htlc, .. }) => {
703+
if htlc.offered {
704+
PackageMalleability::Malleable(AggregationCluster::Unpinnable)
705+
} else {
706+
PackageMalleability::Malleable(AggregationCluster::Pinnable)
707+
}
708+
},
704709
PackageSolvingData::CounterpartyOfferedHTLCOutput(..) =>
705710
PackageMalleability::Malleable(AggregationCluster::Unpinnable),
706711
PackageSolvingData::CounterpartyReceivedHTLCOutput(..) =>
@@ -771,10 +776,12 @@ pub struct PackageTemplate {
771776
/// Block height at which our counterparty can potentially claim this output as well (assuming
772777
/// they have the keys or information required to do so).
773778
///
774-
/// This is used primarily by external consumers to decide when an output becomes "pinnable"
775-
/// because the counterparty can potentially spend it. It is also used internally by
776-
/// [`Self::get_height_timer`] to identify when an output must be claimed by, depending on the
777-
/// type of output.
779+
/// This is used primarily to decide when an output becomes "pinnable" because the counterparty
780+
/// can potentially spend it. It is also used internally by [`Self::get_height_timer`] to
781+
/// identify when an output must be claimed by, depending on the type of output.
782+
///
783+
/// Note that for revoked counterparty HTLC outputs the value may be zero in some cases where
784+
/// we upgraded from LDK 0.1 or prior.
778785
counterparty_spendable_height: u32,
779786
// Cache of package feerate committed at previous (re)broadcast. If bumping resources
780787
// (either claimed output value or external utxo), it will keep increasing until holder
@@ -834,17 +841,17 @@ impl PackageTemplate {
834841
// Now check that we only merge packages if they are both unpinnable or both
835842
// pinnable.
836843
let self_pinnable = self_cluster == AggregationCluster::Pinnable ||
837-
self.counterparty_spendable_height() <= cur_height + COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE;
844+
self.counterparty_spendable_height <= cur_height + COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE;
838845
let other_pinnable = other_cluster == AggregationCluster::Pinnable ||
839-
other.counterparty_spendable_height() <= cur_height + COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE;
846+
other.counterparty_spendable_height <= cur_height + COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE;
840847
if self_pinnable && other_pinnable {
841848
return true;
842849
}
843850

844851
let self_unpinnable = self_cluster == AggregationCluster::Unpinnable &&
845-
self.counterparty_spendable_height() > cur_height + COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE;
852+
self.counterparty_spendable_height > cur_height + COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE;
846853
let other_unpinnable = other_cluster == AggregationCluster::Unpinnable &&
847-
other.counterparty_spendable_height() > cur_height + COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE;
854+
other.counterparty_spendable_height > cur_height + COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE;
848855
if self_unpinnable && other_unpinnable {
849856
return true;
850857
}
@@ -855,13 +862,6 @@ impl PackageTemplate {
855862
pub(crate) fn is_malleable(&self) -> bool {
856863
matches!(self.malleability, PackageMalleability::Malleable(..))
857864
}
858-
/// The height at which our counterparty may be able to spend this output.
859-
///
860-
/// This is an important limit for aggregation as after this height our counterparty may be
861-
/// able to pin transactions spending this output in the mempool.
862-
pub(crate) fn counterparty_spendable_height(&self) -> u32 {
863-
self.counterparty_spendable_height
864-
}
865865
pub(crate) fn previous_feerate(&self) -> u64 {
866866
self.feerate_previous
867867
}
@@ -1225,6 +1225,18 @@ impl Readable for PackageTemplate {
12251225
(4, _height_original, option), // Written with a dummy value since 0.1
12261226
(6, height_timer, option),
12271227
});
1228+
for (_, input) in &inputs {
1229+
if let PackageSolvingData::RevokedHTLCOutput(RevokedHTLCOutput { htlc, .. }) = input {
1230+
// LDK versions through 0.1 set the wrong counterparty_spendable_height for
1231+
// non-offered revoked HTLCs (ie HTLCs we sent to our counterparty which they can
1232+
// claim with a preimage immediately). Here we detect this and reset the value to
1233+
// zero, as the value is unused except for merging decisions which doesn't care
1234+
// about any values below the current height.
1235+
if !htlc.offered && htlc.cltv_expiry == counterparty_spendable_height {
1236+
counterparty_spendable_height = 0;
1237+
}
1238+
}
1239+
}
12281240
Ok(PackageTemplate {
12291241
inputs,
12301242
malleability,

lightning/src/ln/channelmanager.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13364,8 +13364,8 @@ where
1336413364
// claim.
1336513365
// Note that a `ChannelMonitor` is created with `update_id` 0 and after we
1336613366
// provide it with a closure update its `update_id` will be at 1.
13367-
if !monitor.offchain_closed() || monitor.get_latest_update_id() > 1 {
13368-
should_queue_fc_update = !monitor.offchain_closed();
13367+
if !monitor.no_further_updates_allowed() || monitor.get_latest_update_id() > 1 {
13368+
should_queue_fc_update = !monitor.no_further_updates_allowed();
1336913369
let mut latest_update_id = monitor.get_latest_update_id();
1337013370
if should_queue_fc_update {
1337113371
latest_update_id += 1;

0 commit comments

Comments
 (0)