Skip to content

Commit fcb1164

Browse files
authored
Merge pull request #4117 from TheBlueMatt/2025-09-actually-static-remote_key
Allow `KeysManager` to opt-into the new `remote_key` derivation
2 parents 652f0f1 + 9dbec80 commit fcb1164

File tree

25 files changed

+398
-138
lines changed

25 files changed

+398
-138
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,5 @@ jobs:
287287
rustup component add rustfmt
288288
- name: Run rustfmt checks
289289
run: cargo fmt --check
290+
- name: Run rustfmt checks on lightning-tests
291+
run: cd lightning-tests && cargo fmt --check

ext-functional-test-demo/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ mod tests {
1616

1717
impl TestSignerFactory for BrokenSignerFactory {
1818
fn make_signer(
19-
&self, _seed: &[u8; 32], _now: Duration,
19+
&self, _seed: &[u8; 32], _now: Duration, _v2_remote_key_derivation: bool,
2020
) -> Box<dyn DynKeysInterfaceTrait<EcdsaSigner = DynSigner>> {
2121
panic!()
2222
}

fuzz/src/chanmon_consistency.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,14 +386,16 @@ impl SignerProvider for KeyProvider {
386386
}
387387

388388
fn derive_channel_signer(&self, channel_keys_id: [u8; 32]) -> Self::EcdsaSigner {
389-
let secp_ctx = Secp256k1::signing_only();
390389
let id = channel_keys_id[0];
391390
#[rustfmt::skip]
392391
let keys = InMemorySigner::new(
393-
&secp_ctx,
394392
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, self.node_secret[31]]).unwrap(),
395393
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, self.node_secret[31]]).unwrap(),
394+
// We leave both the v1 and v2 derivation to_remote keys the same as there's not any
395+
// real reason to fuzz differences here.
396+
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, self.node_secret[31]]).unwrap(),
396397
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, self.node_secret[31]]).unwrap(),
398+
true,
397399
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, self.node_secret[31]]).unwrap(),
398400
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, self.node_secret[31]]).unwrap(),
399401
[id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_secret[31]],

fuzz/src/full_stack.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,6 @@ impl SignerProvider for KeyProvider {
458458
}
459459

460460
fn derive_channel_signer(&self, keys_id: [u8; 32]) -> Self::EcdsaSigner {
461-
let secp_ctx = Secp256k1::signing_only();
462461
let ctr = keys_id[0];
463462
let (inbound, state) = self.signer_state.borrow().get(&ctr).unwrap().clone();
464463

@@ -477,7 +476,9 @@ impl SignerProvider for KeyProvider {
477476
e = SecretKey::from_slice(&key).unwrap();
478477
key[30] = 6 + if inbound { 0 } else { 6 };
479478
f = key;
480-
let signer = InMemorySigner::new(&secp_ctx, a, b, c, d, e, f, keys_id, keys_id);
479+
// We leave both the v1 and v2 derivation to_remote keys the same as there's not any real
480+
// reason to fuzz differences here, and it keeps us consistent with past behavior.
481+
let signer = InMemorySigner::new(a, b, c, c, true, d, e, f, keys_id, keys_id);
481482

482483
TestChannelSigner::new_with_revoked(DynSigner::new(signer), state, false, false)
483484
}

fuzz/src/lsps_message.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub fn do_test(data: &[u8]) {
3939
let scorer = Arc::new(LockingWrapper::new(TestScorer::new()));
4040
let now = Duration::from_secs(genesis_block.header.time as u64);
4141
let seed = sha256::Hash::hash(b"lsps-message-seed").to_byte_array();
42-
let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos()));
42+
let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos(), true));
4343
let router = Arc::new(DefaultRouter::new(
4444
Arc::clone(&network_graph),
4545
Arc::clone(&logger),

lightning-background-processor/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,7 +2326,8 @@ mod tests {
23262326
let scorer = Arc::new(LockingWrapper::new(TestScorer::new()));
23272327
let now = Duration::from_secs(genesis_block.header.time as u64);
23282328
let seed = [i as u8; 32];
2329-
let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos()));
2329+
let keys_manager =
2330+
Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos(), true));
23302331
let router = Arc::new(DefaultRouter::new(
23312332
Arc::clone(&network_graph),
23322333
Arc::clone(&logger),
@@ -2342,7 +2343,8 @@ mod tests {
23422343
let kv_store =
23432344
Arc::new(Persister::new(format!("{}_persister_{}", &persist_dir, i).into()));
23442345
let now = Duration::from_secs(genesis_block.header.time as u64);
2345-
let keys_manager = Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos()));
2346+
let keys_manager =
2347+
Arc::new(KeysManager::new(&seed, now.as_secs(), now.subsec_nanos(), true));
23462348
let chain_monitor = Arc::new(chainmonitor::ChainMonitor::new(
23472349
Some(Arc::clone(&chain_source)),
23482350
Arc::clone(&tx_broadcaster),

lightning-dns-resolver/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ mod test {
231231
&self, recipient: PublicKey, local_node_receive_key: ReceiveAuthKey,
232232
context: MessageContext, _peers: Vec<MessageForwardNode>, secp_ctx: &Secp256k1<T>,
233233
) -> Result<Vec<BlindedMessagePath>, ()> {
234-
let keys = KeysManager::new(&[0; 32], 42, 43);
234+
let keys = KeysManager::new(&[0; 32], 42, 43, true);
235235
Ok(vec![BlindedMessagePath::one_hop(
236236
recipient,
237237
local_node_receive_key,
@@ -274,7 +274,7 @@ mod test {
274274
}
275275

276276
fn create_resolver() -> (impl AOnionMessenger, PublicKey) {
277-
let resolver_keys = Arc::new(KeysManager::new(&[99; 32], 42, 43));
277+
let resolver_keys = Arc::new(KeysManager::new(&[99; 32], 42, 43, true));
278278
let resolver_logger = TestLogger { node: "resolver" };
279279
let resolver = OMDomainResolver::ignoring_incoming_proofs("8.8.8.8:53".parse().unwrap());
280280
let resolver = Arc::new(resolver);
@@ -313,7 +313,7 @@ mod test {
313313
let payment_id = PaymentId([42; 32]);
314314
let name = HumanReadableName::from_encoded("[email protected]").unwrap();
315315

316-
let payer_keys = Arc::new(KeysManager::new(&[2; 32], 42, 43));
316+
let payer_keys = Arc::new(KeysManager::new(&[2; 32], 42, 43, true));
317317
let payer_logger = TestLogger { node: "payer" };
318318
let payer_id = payer_keys.get_node_id(Recipient::Node).unwrap();
319319
let payer = Arc::new(URIResolver {

lightning-tests/src/upgrade_downgrade_tests.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//! Tests which test upgrading from previous versions of LDK or downgrading to previous versions of
1111
//! LDK.
1212
13+
use lightning_0_1::events::ClosureReason as ClosureReason_0_1;
1314
use lightning_0_1::get_monitor as get_monitor_0_1;
1415
use lightning_0_1::ln::functional_test_utils as lightning_0_1_utils;
1516
use lightning_0_1::util::ser::Writeable as _;
@@ -28,10 +29,19 @@ use lightning_0_0_125::ln::msgs::ChannelMessageHandler as _;
2829
use lightning_0_0_125::routing::router as router_0_0_125;
2930
use lightning_0_0_125::util::ser::Writeable as _;
3031

32+
use lightning::chain::channelmonitor::ANTI_REORG_DELAY;
33+
use lightning::events::{ClosureReason, Event};
3134
use lightning::ln::functional_test_utils::*;
35+
use lightning::sign::OutputSpender;
3236

3337
use lightning_types::payment::PaymentPreimage;
3438

39+
use bitcoin::opcodes;
40+
use bitcoin::script::Builder;
41+
use bitcoin::secp256k1::Secp256k1;
42+
43+
use std::sync::Arc;
44+
3545
#[test]
3646
fn simple_upgrade() {
3747
// Tests a simple case of upgrading from LDK 0.1 with a pending payment
@@ -213,3 +223,79 @@ fn test_125_dangling_post_update_actions() {
213223
let config = test_default_channel_config();
214224
reload_node!(nodes[3], config, &node_d_ser, &[&mon_ser], persister, chain_mon, node);
215225
}
226+
227+
#[test]
228+
fn test_0_1_legacy_remote_key_derivation() {
229+
// Test that a channel opened with a v1/legacy `remote_key` derivation will be properly spent
230+
// even after upgrading and opting into the new v2 derivation for new channels.
231+
let (node_a_ser, node_b_ser, mon_a_ser, mon_b_ser, commitment_tx, channel_id);
232+
let node_a_blocks;
233+
{
234+
let chanmon_cfgs = lightning_0_1_utils::create_chanmon_cfgs(2);
235+
let node_cfgs = lightning_0_1_utils::create_node_cfgs(2, &chanmon_cfgs);
236+
let node_chanmgrs = lightning_0_1_utils::create_node_chanmgrs(2, &node_cfgs, &[None, None]);
237+
let nodes = lightning_0_1_utils::create_network(2, &node_cfgs, &node_chanmgrs);
238+
239+
let node_a_id = nodes[0].node.get_our_node_id();
240+
241+
let chan_id = lightning_0_1_utils::create_announced_chan_between_nodes(&nodes, 0, 1).2;
242+
channel_id = chan_id.0;
243+
244+
let err = "".to_owned();
245+
nodes[1].node.force_close_broadcasting_latest_txn(&chan_id, &node_a_id, err).unwrap();
246+
commitment_tx = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
247+
assert_eq!(commitment_tx.len(), 1);
248+
249+
lightning_0_1_utils::check_added_monitors(&nodes[1], 1);
250+
let reason = ClosureReason_0_1::HolderForceClosed { broadcasted_latest_txn: Some(true) };
251+
lightning_0_1_utils::check_closed_event(&nodes[1], 1, reason, false, &[node_a_id], 100000);
252+
lightning_0_1_utils::check_closed_broadcast(&nodes[1], 1, true);
253+
254+
node_a_ser = nodes[0].node.encode();
255+
node_b_ser = nodes[1].node.encode();
256+
mon_a_ser = get_monitor_0_1!(nodes[0], chan_id).encode();
257+
mon_b_ser = get_monitor_0_1!(nodes[1], chan_id).encode();
258+
259+
node_a_blocks = Arc::clone(&nodes[0].blocks);
260+
}
261+
262+
// Create a dummy node to reload over with the 0.1 state
263+
let chanmon_cfgs = create_chanmon_cfgs(2);
264+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
265+
let (persister_a, persister_b, chain_mon_a, chain_mon_b);
266+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
267+
let (node_a, node_b);
268+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
269+
270+
let config = test_default_channel_config();
271+
let a_mons = &[&mon_a_ser[..]];
272+
reload_node!(nodes[0], config.clone(), &node_a_ser, a_mons, persister_a, chain_mon_a, node_a);
273+
reload_node!(nodes[1], config, &node_b_ser, &[&mon_b_ser], persister_b, chain_mon_b, node_b);
274+
275+
nodes[0].blocks = node_a_blocks;
276+
277+
let node_b_id = nodes[1].node.get_our_node_id();
278+
279+
mine_transaction(&nodes[0], &commitment_tx[0]);
280+
let reason = ClosureReason::CommitmentTxConfirmed;
281+
check_closed_event(&nodes[0], 1, reason, false, &[node_b_id], 100_000);
282+
check_added_monitors(&nodes[0], 1);
283+
check_closed_broadcast(&nodes[0], 1, false);
284+
285+
connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
286+
let mut spendable_event = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
287+
assert_eq!(spendable_event.len(), 1);
288+
if let Event::SpendableOutputs { outputs, channel_id: ev_id } = spendable_event.pop().unwrap() {
289+
assert_eq!(ev_id.unwrap().0, channel_id);
290+
assert_eq!(outputs.len(), 1);
291+
let spk = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script();
292+
let spend_tx = nodes[0]
293+
.keys_manager
294+
.backing
295+
.spend_spendable_outputs(&[&outputs[0]], Vec::new(), spk, 253, None, &Secp256k1::new())
296+
.unwrap();
297+
check_spends!(spend_tx, commitment_tx[0]);
298+
} else {
299+
panic!("Wrong event");
300+
}
301+
}

lightning/src/chain/channelmonitor.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,7 +1872,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
18721872

18731873
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
18741874
let holder_pubkeys = &channel_parameters.holder_pubkeys;
1875-
let counterparty_payment_script = chan_utils::get_counterparty_payment_script(
1875+
let counterparty_payment_script = chan_utils::get_countersigner_payment_script(
18761876
&channel_parameters.channel_type_features, &holder_pubkeys.payment_point
18771877
);
18781878

@@ -6806,7 +6806,7 @@ mod tests {
68066806
use crate::ln::functional_test_utils::*;
68076807
use crate::ln::script::ShutdownScript;
68086808
use crate::ln::types::ChannelId;
6809-
use crate::sign::InMemorySigner;
6809+
use crate::sign::{ChannelSigner, InMemorySigner};
68106810
use crate::sync::Arc;
68116811
use crate::types::features::ChannelTypeFeatures;
68126812
use crate::types::payment::{PaymentHash, PaymentPreimage};
@@ -6979,11 +6979,12 @@ mod tests {
69796979
}
69806980

69816981
let keys = InMemorySigner::new(
6982-
&secp_ctx,
69836982
SecretKey::from_slice(&[41; 32]).unwrap(),
69846983
SecretKey::from_slice(&[41; 32]).unwrap(),
69856984
SecretKey::from_slice(&[41; 32]).unwrap(),
69866985
SecretKey::from_slice(&[41; 32]).unwrap(),
6986+
true,
6987+
SecretKey::from_slice(&[41; 32]).unwrap(),
69876988
SecretKey::from_slice(&[41; 32]).unwrap(),
69886989
[41; 32],
69896990
[0; 32],
@@ -7000,7 +7001,7 @@ mod tests {
70007001
let funding_outpoint = OutPoint { txid: Txid::all_zeros(), index: u16::MAX };
70017002
let channel_id = ChannelId::v1_from_funding_outpoint(funding_outpoint);
70027003
let channel_parameters = ChannelTransactionParameters {
7003-
holder_pubkeys: keys.holder_channel_pubkeys.clone(),
7004+
holder_pubkeys: keys.new_pubkeys(None, &secp_ctx),
70047005
holder_selected_contest_delay: 66,
70057006
is_outbound_from_holder: true,
70067007
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {
@@ -7241,11 +7242,12 @@ mod tests {
72417242
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
72427243

72437244
let keys = InMemorySigner::new(
7244-
&secp_ctx,
72457245
SecretKey::from_slice(&[41; 32]).unwrap(),
72467246
SecretKey::from_slice(&[41; 32]).unwrap(),
72477247
SecretKey::from_slice(&[41; 32]).unwrap(),
72487248
SecretKey::from_slice(&[41; 32]).unwrap(),
7249+
true,
7250+
SecretKey::from_slice(&[41; 32]).unwrap(),
72497251
SecretKey::from_slice(&[41; 32]).unwrap(),
72507252
[41; 32],
72517253
[0; 32],
@@ -7262,7 +7264,7 @@ mod tests {
72627264
let funding_outpoint = OutPoint { txid: Txid::all_zeros(), index: u16::MAX };
72637265
let channel_id = ChannelId::v1_from_funding_outpoint(funding_outpoint);
72647266
let channel_parameters = ChannelTransactionParameters {
7265-
holder_pubkeys: keys.holder_channel_pubkeys.clone(),
7267+
holder_pubkeys: keys.new_pubkeys(None, &secp_ctx),
72667268
holder_selected_contest_delay: 66,
72677269
is_outbound_from_holder: true,
72687270
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {

lightning/src/chain/onchaintx.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@ mod tests {
12871287
};
12881288
use crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint};
12891289
use crate::ln::functional_test_utils::create_dummy_block;
1290-
use crate::sign::{ChannelDerivationParameters, HTLCDescriptor, InMemorySigner};
1290+
use crate::sign::{ChannelDerivationParameters, ChannelSigner, HTLCDescriptor, InMemorySigner};
12911291
use crate::types::payment::{PaymentHash, PaymentPreimage};
12921292
use crate::util::test_utils::{TestBroadcaster, TestFeeEstimator, TestLogger};
12931293

@@ -1301,11 +1301,12 @@ mod tests {
13011301
fn test_broadcast_height() {
13021302
let secp_ctx = Secp256k1::new();
13031303
let signer = InMemorySigner::new(
1304-
&secp_ctx,
13051304
SecretKey::from_slice(&[41; 32]).unwrap(),
13061305
SecretKey::from_slice(&[41; 32]).unwrap(),
13071306
SecretKey::from_slice(&[41; 32]).unwrap(),
13081307
SecretKey::from_slice(&[41; 32]).unwrap(),
1308+
true,
1309+
SecretKey::from_slice(&[41; 32]).unwrap(),
13091310
SecretKey::from_slice(&[41; 32]).unwrap(),
13101311
[41; 32],
13111312
[0; 32],
@@ -1338,7 +1339,7 @@ mod tests {
13381339
// Use non-anchor channels so that HTLC-Timeouts are broadcast immediately instead of sent
13391340
// to the user for external funding.
13401341
let chan_params = ChannelTransactionParameters {
1341-
holder_pubkeys: signer.holder_channel_pubkeys.clone(),
1342+
holder_pubkeys: signer.new_pubkeys(None, &secp_ctx),
13421343
holder_selected_contest_delay: 66,
13431344
is_outbound_from_holder: true,
13441345
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {

0 commit comments

Comments
 (0)