Skip to content

Commit 24d89ab

Browse files
authored
Merge pull request #3794 from TheBlueMatt/2025-05-0.1.4-backports
[0.1] Backports for 0.1.4
2 parents b4d5fe2 + edcd376 commit 24d89ab

15 files changed

+435
-67
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ members = [
2121

2222
exclude = [
2323
"lightning-transaction-sync",
24+
"lightning-tests",
2425
"no-std-check",
2526
"msrv-no-dev-deps-check",
2627
"bench",

ci/ci-tests.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ for DIR in "${WORKSPACE_MEMBERS[@]}"; do
5757
cargo doc -p "$DIR" --document-private-items
5858
done
5959

60+
echo -e "\n\nTesting upgrade from prior versions of LDK"
61+
pushd lightning-tests
62+
[ "$RUSTC_MINOR_VERSION" -lt 65 ] && cargo update -p regex --precise "1.9.6" --verbose
63+
cargo test
64+
popd
65+
6066
echo -e "\n\nChecking and testing Block Sync Clients with features"
6167

6268
cargo test -p lightning-block-sync --verbose --color always --features rest-client

fuzz/src/chanmon_consistency.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ impl SignerProvider for KeyProvider {
382382
channel_keys_id,
383383
);
384384
let revoked_commitment = self.make_enforcement_state_cell(keys.commitment_seed);
385-
TestChannelSigner::new_with_revoked(keys, revoked_commitment, false)
385+
TestChannelSigner::new_with_revoked(keys, revoked_commitment, false, false)
386386
}
387387

388388
fn read_chan_signer(&self, buffer: &[u8]) -> Result<Self::EcdsaSigner, DecodeError> {
@@ -391,7 +391,7 @@ impl SignerProvider for KeyProvider {
391391
let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?;
392392
let state = self.make_enforcement_state_cell(inner.commitment_seed);
393393

394-
Ok(TestChannelSigner::new_with_revoked(inner, state, false))
394+
Ok(TestChannelSigner::new_with_revoked(inner, state, false, false))
395395
}
396396

397397
fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result<ScriptBuf, ()> {

fuzz/src/full_stack.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,14 +522,15 @@ impl SignerProvider for KeyProvider {
522522
},
523523
state,
524524
false,
525+
false,
525526
)
526527
}
527528

528529
fn read_chan_signer(&self, mut data: &[u8]) -> Result<TestChannelSigner, DecodeError> {
529530
let inner: InMemorySigner = ReadableArgs::read(&mut data, self)?;
530531
let state = Arc::new(Mutex::new(EnforcementState::new()));
531532

532-
Ok(TestChannelSigner::new_with_revoked(inner, state, false))
533+
Ok(TestChannelSigner::new_with_revoked(inner, state, false, false))
533534
}
534535

535536
fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result<ScriptBuf, ()> {

lightning-tests/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "lightning-tests"
3+
version = "0.0.1"
4+
authors = ["Matt Corallo"]
5+
license = "MIT OR Apache-2.0"
6+
repository = "https://github.com/lightningdevkit/rust-lightning/"
7+
description = "Tests for LDK crates"
8+
edition = "2021"
9+
10+
[features]
11+
12+
[dependencies]
13+
lightning-types = { path = "../lightning-types", features = ["_test_utils"] }
14+
lightning-invoice = { path = "../lightning-invoice", default-features = false }
15+
lightning-macros = { path = "../lightning-macros" }
16+
lightning = { path = "../lightning", features = ["_test_utils"] }
17+
lightning_0_1 = { package = "lightning", version = "0.1.1", features = ["_test_utils"] }
18+
lightning_0_0_125 = { package = "lightning", version = "0.0.125", features = ["_test_utils"] }
19+
20+
bitcoin = { version = "0.32.2", default-features = false }
21+
22+
[dev-dependencies]

lightning-tests/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#[cfg_attr(test, macro_use)]
2+
extern crate lightning;
3+
4+
#[cfg(all(test, not(taproot)))]
5+
pub mod upgrade_downgrade_tests;
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// This file is Copyright its original authors, visible in version control
2+
// history.
3+
//
4+
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5+
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7+
// You may not use this file except in accordance with one or both of these
8+
// licenses.
9+
10+
//! Tests which test upgrading from previous versions of LDK or downgrading to previous versions of
11+
//! LDK.
12+
13+
use lightning_0_1::get_monitor as get_monitor_0_1;
14+
use lightning_0_1::ln::functional_test_utils as lightning_0_1_utils;
15+
use lightning_0_1::util::ser::Writeable as _;
16+
17+
use lightning_0_0_125::chain::ChannelMonitorUpdateStatus as ChannelMonitorUpdateStatus_0_0_125;
18+
use lightning_0_0_125::check_added_monitors as check_added_monitors_0_0_125;
19+
use lightning_0_0_125::events::ClosureReason as ClosureReason_0_0_125;
20+
use lightning_0_0_125::expect_payment_claimed as expect_payment_claimed_0_0_125;
21+
use lightning_0_0_125::get_htlc_update_msgs as get_htlc_update_msgs_0_0_125;
22+
use lightning_0_0_125::get_monitor as get_monitor_0_0_125;
23+
use lightning_0_0_125::get_revoke_commit_msgs as get_revoke_commit_msgs_0_0_125;
24+
use lightning_0_0_125::ln::channelmanager::PaymentId as PaymentId_0_0_125;
25+
use lightning_0_0_125::ln::channelmanager::RecipientOnionFields as RecipientOnionFields_0_0_125;
26+
use lightning_0_0_125::ln::functional_test_utils as lightning_0_0_125_utils;
27+
use lightning_0_0_125::ln::msgs::ChannelMessageHandler as _;
28+
use lightning_0_0_125::routing::router as router_0_0_125;
29+
use lightning_0_0_125::util::ser::Writeable as _;
30+
31+
use lightning::ln::functional_test_utils::*;
32+
33+
use lightning_types::payment::PaymentPreimage;
34+
35+
#[test]
36+
fn simple_upgrade() {
37+
// Tests a simple case of upgrading from LDK 0.1 with a pending payment
38+
let (node_a_ser, node_b_ser, mon_a_ser, mon_b_ser, preimage);
39+
{
40+
let chanmon_cfgs = lightning_0_1_utils::create_chanmon_cfgs(2);
41+
let node_cfgs = lightning_0_1_utils::create_node_cfgs(2, &chanmon_cfgs);
42+
let node_chanmgrs = lightning_0_1_utils::create_node_chanmgrs(2, &node_cfgs, &[None, None]);
43+
let nodes = lightning_0_1_utils::create_network(2, &node_cfgs, &node_chanmgrs);
44+
45+
let chan_id = lightning_0_1_utils::create_announced_chan_between_nodes(&nodes, 0, 1).2;
46+
47+
let payment_preimage =
48+
lightning_0_1_utils::route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
49+
preimage = PaymentPreimage(payment_preimage.0 .0);
50+
51+
node_a_ser = nodes[0].node.encode();
52+
node_b_ser = nodes[1].node.encode();
53+
mon_a_ser = get_monitor_0_1!(nodes[0], chan_id).encode();
54+
mon_b_ser = get_monitor_0_1!(nodes[1], chan_id).encode();
55+
}
56+
57+
// Create a dummy node to reload over with the 0.1 state
58+
59+
let mut chanmon_cfgs = create_chanmon_cfgs(2);
60+
61+
// Our TestChannelSigner will fail as we're jumping ahead, so disable its state-based checks
62+
chanmon_cfgs[0].keys_manager.disable_all_state_policy_checks = true;
63+
chanmon_cfgs[1].keys_manager.disable_all_state_policy_checks = true;
64+
65+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
66+
let (persister_a, persister_b, chain_mon_a, chain_mon_b);
67+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
68+
let (node_a, node_b);
69+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
70+
71+
let config = test_default_channel_config();
72+
let a_mons = &[&mon_a_ser[..]];
73+
reload_node!(nodes[0], config.clone(), &node_a_ser, a_mons, persister_a, chain_mon_a, node_a);
74+
reload_node!(nodes[1], config, &node_b_ser, &[&mon_b_ser], persister_b, chain_mon_b, node_b);
75+
76+
reconnect_nodes(ReconnectArgs::new(&nodes[0], &nodes[1]));
77+
78+
claim_payment(&nodes[0], &[&nodes[1]], preimage);
79+
}
80+
81+
#[test]
82+
fn test_125_dangling_post_update_actions() {
83+
// Tests a failure of upgrading from 0.0.125 to 0.1 when there's a dangling
84+
// `MonitorUpdateCompletionAction` due to the bug fixed in
85+
// 93b4479e472e6767af5df90fecdcdfb79074e260.
86+
let (node_d_ser, mon_ser);
87+
{
88+
// First, we get RAA-source monitor updates held by using async persistence (note that this
89+
// issue was first identified as a consequence of the bug fixed in
90+
// 93b4479e472e6767af5df90fecdcdfb79074e260 but in order to replicate that bug we need a
91+
// complicated multi-threaded race that is not deterministic, thus we "cheat" here by using
92+
// async persistence). We do this by simply claiming an MPP payment and not completing the
93+
// second channel's `ChannelMonitorUpdate`, blocking RAA `ChannelMonitorUpdate`s from the
94+
// first (which is ultimately a very similar bug to the one fixed in 93b4479e472e6767af5df).
95+
//
96+
// Then, we claim a second payment on the channel, which ultimately doesn't have its
97+
// `ChannelMonitorUpdate` completion handled due to the presence of the blocked
98+
// `ChannelMonitorUpdate`. The claim also generates a post-update completion action, but
99+
// the `ChannelMonitorUpdate` isn't queued due to the RAA-update block.
100+
let chanmon_cfgs = lightning_0_0_125_utils::create_chanmon_cfgs(4);
101+
let node_cfgs = lightning_0_0_125_utils::create_node_cfgs(4, &chanmon_cfgs);
102+
let node_chanmgrs =
103+
lightning_0_0_125_utils::create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
104+
let nodes = lightning_0_0_125_utils::create_network(4, &node_cfgs, &node_chanmgrs);
105+
106+
let node_b_id = nodes[1].node.get_our_node_id();
107+
let node_d_id = nodes[3].node.get_our_node_id();
108+
109+
lightning_0_0_125_utils::create_announced_chan_between_nodes_with_value(
110+
&nodes, 0, 1, 100_000, 0,
111+
);
112+
lightning_0_0_125_utils::create_announced_chan_between_nodes_with_value(
113+
&nodes, 0, 2, 100_000, 0,
114+
);
115+
let chan_id_1_3 = lightning_0_0_125_utils::create_announced_chan_between_nodes_with_value(
116+
&nodes, 1, 3, 100_000, 0,
117+
)
118+
.2;
119+
let chan_id_2_3 = lightning_0_0_125_utils::create_announced_chan_between_nodes_with_value(
120+
&nodes, 2, 3, 100_000, 0,
121+
)
122+
.2;
123+
124+
let (preimage, hash, secret) =
125+
lightning_0_0_125_utils::get_payment_preimage_hash(&nodes[3], Some(15_000_000), None);
126+
127+
let pay_params = router_0_0_125::PaymentParameters::from_node_id(
128+
node_d_id,
129+
lightning_0_0_125_utils::TEST_FINAL_CLTV,
130+
)
131+
.with_bolt11_features(nodes[3].node.bolt11_invoice_features())
132+
.unwrap();
133+
134+
let route_params =
135+
router_0_0_125::RouteParameters::from_payment_params_and_value(pay_params, 15_000_000);
136+
let route = lightning_0_0_125_utils::get_route(&nodes[0], &route_params).unwrap();
137+
138+
let onion = RecipientOnionFields_0_0_125::secret_only(secret);
139+
let id = PaymentId_0_0_125(hash.0);
140+
nodes[0].node.send_payment_with_route(route, hash, onion, id).unwrap();
141+
142+
check_added_monitors_0_0_125!(nodes[0], 2);
143+
let paths = &[&[&nodes[1], &nodes[3]][..], &[&nodes[2], &nodes[3]]];
144+
lightning_0_0_125_utils::pass_along_route(&nodes[0], paths, 15_000_000, hash, secret);
145+
146+
let preimage_2 = lightning_0_0_125_utils::route_payment(&nodes[1], &[&nodes[3]], 100_000).0;
147+
148+
chanmon_cfgs[3].persister.set_update_ret(ChannelMonitorUpdateStatus_0_0_125::InProgress);
149+
chanmon_cfgs[3].persister.set_update_ret(ChannelMonitorUpdateStatus_0_0_125::InProgress);
150+
nodes[3].node.claim_funds(preimage);
151+
check_added_monitors_0_0_125!(nodes[3], 2);
152+
153+
let (outpoint, update_id, _) = {
154+
let latest_monitors = nodes[3].chain_monitor.latest_monitor_update_id.lock().unwrap();
155+
latest_monitors.get(&chan_id_1_3).unwrap().clone()
156+
};
157+
nodes[3].chain_monitor.chain_monitor.channel_monitor_updated(outpoint, update_id).unwrap();
158+
expect_payment_claimed_0_0_125!(nodes[3], hash, 15_000_000);
159+
160+
let ds_fulfill = get_htlc_update_msgs_0_0_125!(nodes[3], node_b_id);
161+
// Due to an unrelated test bug in 0.0.125, we have to leave the `ChannelMonitorUpdate` for
162+
// the previous node un-completed or we will panic when dropping the `Node`.
163+
chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus_0_0_125::InProgress);
164+
nodes[1].node.handle_update_fulfill_htlc(&node_d_id, &ds_fulfill.update_fulfill_htlcs[0]);
165+
check_added_monitors_0_0_125!(nodes[1], 1);
166+
167+
nodes[1].node.handle_commitment_signed(&node_d_id, &ds_fulfill.commitment_signed);
168+
check_added_monitors_0_0_125!(nodes[1], 1);
169+
170+
// The `ChannelMonitorUpdate` generated by the RAA from node B to node D will be blocked.
171+
let (bs_raa, _) = get_revoke_commit_msgs_0_0_125!(nodes[1], node_d_id);
172+
nodes[3].node.handle_revoke_and_ack(&node_b_id, &bs_raa);
173+
check_added_monitors_0_0_125!(nodes[3], 0);
174+
175+
// Now that there is a blocked update in the B <-> D channel, we can claim the second
176+
// payment across it, which, while it will generate a `ChannelMonitorUpdate`, will not
177+
// complete its post-update actions.
178+
nodes[3].node.claim_funds(preimage_2);
179+
check_added_monitors_0_0_125!(nodes[3], 1);
180+
181+
// Finally, we set up the failure by force-closing the channel in question, ensuring that
182+
// 0.1 will not create a per-peer state for node B.
183+
let err = "Force Closing Channel".to_owned();
184+
nodes[3].node.force_close_without_broadcasting_txn(&chan_id_1_3, &node_b_id, err).unwrap();
185+
let reason =
186+
ClosureReason_0_0_125::HolderForceClosed { broadcasted_latest_txn: Some(false) };
187+
let peers = &[node_b_id];
188+
lightning_0_0_125_utils::check_closed_event(&nodes[3], 1, reason, false, peers, 100_000);
189+
lightning_0_0_125_utils::check_closed_broadcast(&nodes[3], 1, true);
190+
check_added_monitors_0_0_125!(nodes[3], 1);
191+
192+
node_d_ser = nodes[3].node.encode();
193+
mon_ser = get_monitor_0_0_125!(nodes[3], chan_id_2_3).encode();
194+
}
195+
196+
// Create a dummy node to reload over with the 0.0.125 state
197+
198+
let mut chanmon_cfgs = create_chanmon_cfgs(4);
199+
200+
// Our TestChannelSigner will fail as we're jumping ahead, so disable its state-based checks
201+
chanmon_cfgs[0].keys_manager.disable_all_state_policy_checks = true;
202+
chanmon_cfgs[1].keys_manager.disable_all_state_policy_checks = true;
203+
chanmon_cfgs[2].keys_manager.disable_all_state_policy_checks = true;
204+
chanmon_cfgs[3].keys_manager.disable_all_state_policy_checks = true;
205+
206+
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
207+
let (persister, chain_mon);
208+
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
209+
let node;
210+
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
211+
212+
// Finally, reload the node in the latest LDK. This previously failed.
213+
let config = test_default_channel_config();
214+
reload_node!(nodes[3], config, &node_d_ser, &[&mon_ser], persister, chain_mon, node);
215+
}

lightning/src/ln/channel.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5039,7 +5039,12 @@ impl<SP: Deref> Channel<SP> where
50395039
if update_fee {
50405040
debug_assert!(!self.context.is_outbound());
50415041
let counterparty_reserve_we_require_msat = self.context.holder_selected_channel_reserve_satoshis * 1000;
5042-
if commitment_stats.remote_balance_msat < commitment_stats.total_fee_sat * 1000 + counterparty_reserve_we_require_msat {
5042+
let total_anchor_sats = if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() {
5043+
ANCHOR_OUTPUT_VALUE_SATOSHI * 2
5044+
} else {
5045+
0
5046+
};
5047+
if commitment_stats.remote_balance_msat < commitment_stats.total_fee_sat * 1000 + total_anchor_sats * 1000 + counterparty_reserve_we_require_msat {
50435048
return Err(ChannelError::close("Funding remote cannot afford proposed new fee".to_owned()));
50445049
}
50455050
}
@@ -5772,7 +5777,12 @@ impl<SP: Deref> Channel<SP> where
57725777
let commitment_stats = self.context.build_commitment_transaction(self.holder_commitment_point.transaction_number(), &keys, true, true, logger);
57735778
let buffer_fee_msat = commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + htlc_stats.on_holder_tx_outbound_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.get_channel_type()) * 1000;
57745779
let holder_balance_msat = commitment_stats.local_balance_msat - htlc_stats.outbound_holding_cell_msat;
5775-
if holder_balance_msat < buffer_fee_msat + self.context.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
5780+
let total_anchor_sats = if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() {
5781+
ANCHOR_OUTPUT_VALUE_SATOSHI * 2
5782+
} else {
5783+
0
5784+
};
5785+
if holder_balance_msat < buffer_fee_msat + total_anchor_sats * 1000 + self.context.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 {
57765786
//TODO: auto-close after a number of failures?
57775787
log_debug!(logger, "Cannot afford to send new feerate at {}", feerate_per_kw);
57785788
return None;

0 commit comments

Comments
 (0)