Skip to content

Commit 56f12c8

Browse files
committed
Add counterparty_node_id to TransactionType variants
This adds `counterparty_node_id` tracking to all `TransactionType` variants, enabling downstream users to identify the channel counterparty associated with each broadcast transaction. For single-channel variants (`CooperativeClose`, `UnilateralClose`, `AnchorBump`, `Claim`, `Splice`), the counterparty is stored directly. For multi-channel variants (`Funding`, `Sweep`), the type now uses `Vec<(PublicKey, ChannelId)>` to pair each channel with its counterparty. The `OnchainTxHandler` now stores `counterparty_node_id` and provides a `set_counterparty_node_id` method for initialization during deserialization of older data. Co-Authored-By: HAL 9000 Signed-off-by: Elias Rohrer <[email protected]>
1 parent da9ddd2 commit 56f12c8

File tree

9 files changed

+124
-56
lines changed

9 files changed

+124
-56
lines changed

lightning-liquidity/src/lsps2/service.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,21 +2020,22 @@ where
20202020
// close could then confirm the commitment and trigger unintended on‑chain handling.
20212021
// To avoid this, we check ChannelManager’s view (`is_channel_ready`) before broadcasting.
20222022
if let Some(ch_id) = jit_channel.get_channel_id() {
2023-
let is_channel_ready = self
2023+
let channel_details = self
20242024
.channel_manager
20252025
.get_cm()
20262026
.list_channels()
20272027
.into_iter()
2028-
.any(|cd| cd.channel_id == ch_id && cd.is_channel_ready);
2028+
.find(|cd| cd.channel_id == ch_id && cd.is_channel_ready);
20292029

2030-
if !is_channel_ready {
2031-
return;
2032-
}
2030+
let counterparty_node_id = match channel_details {
2031+
Some(cd) => cd.counterparty.node_id,
2032+
None => return,
2033+
};
20332034

20342035
if let Some(funding_tx) = jit_channel.get_funding_tx() {
20352036
self.tx_broadcaster.broadcast_transactions(&[(
20362037
funding_tx,
2037-
TransactionType::Funding { channel_ids: vec![ch_id] },
2038+
TransactionType::Funding { channels: vec![(counterparty_node_id, ch_id)] },
20382039
)]);
20392040
}
20402041
}

lightning/src/chain/chaininterface.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use core::{cmp, ops::Deref};
1818
use crate::ln::types::ChannelId;
1919
use crate::prelude::*;
2020

21+
use bitcoin::secp256k1::PublicKey;
2122
use bitcoin::transaction::Transaction;
2223

2324
/// Represents the class of transaction being broadcast.
@@ -33,10 +34,10 @@ pub enum TransactionType {
3334
///
3435
/// [`ChannelManager::funding_transaction_generated`]: crate::ln::channelmanager::ChannelManager::funding_transaction_generated
3536
Funding {
36-
/// The IDs of the channels being funded.
37+
/// The counterparty node IDs and channel IDs of the channels being funded.
3738
///
3839
/// A single funding transaction may establish multiple channels when using batch funding.
39-
channel_ids: Vec<ChannelId>,
40+
channels: Vec<(PublicKey, ChannelId)>,
4041
},
4142
/// A transaction cooperatively closing a channel.
4243
///
@@ -45,6 +46,8 @@ pub enum TransactionType {
4546
///
4647
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
4748
CooperativeClose {
49+
/// The `node_id` of the channel counterparty.
50+
counterparty_node_id: PublicKey,
4851
/// The ID of the channel being closed.
4952
channel_id: ChannelId,
5053
},
@@ -56,6 +59,8 @@ pub enum TransactionType {
5659
///
5760
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
5861
UnilateralClose {
62+
/// The `node_id` of the channel counterparty.
63+
counterparty_node_id: PublicKey,
5964
/// The ID of the channel being force-closed.
6065
channel_id: ChannelId,
6166
},
@@ -66,6 +71,8 @@ pub enum TransactionType {
6671
///
6772
/// [`BumpTransactionEvent`]: crate::events::bump_transaction::BumpTransactionEvent
6873
AnchorBump {
74+
/// The `node_id` of the channel counterparty.
75+
counterparty_node_id: PublicKey,
6976
/// The ID of the channel whose closing transaction is being fee-bumped.
7077
channel_id: ChannelId,
7178
},
@@ -81,6 +88,8 @@ pub enum TransactionType {
8188
/// [`ChannelMonitor`]: crate::chain::ChannelMonitor
8289
/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
8390
Claim {
91+
/// The `node_id` of the channel counterparty.
92+
counterparty_node_id: PublicKey,
8493
/// The ID of the channel from which outputs are being claimed.
8594
channel_id: ChannelId,
8695
},
@@ -90,17 +99,19 @@ pub enum TransactionType {
9099
/// [`OutputSweeper`]: crate::util::sweep::OutputSweeper
91100
/// [`SpendableOutputDescriptor`]: crate::sign::SpendableOutputDescriptor
92101
Sweep {
93-
/// The IDs of the channels from which outputs are being swept, if known.
102+
/// The counterparty node IDs and channel IDs from which outputs are being swept, if known.
94103
///
95104
/// A single sweep transaction may aggregate outputs from multiple channels.
96-
channel_ids: Vec<ChannelId>,
105+
channels: Vec<(PublicKey, ChannelId)>,
97106
},
98107
/// A splice transaction modifying an existing channel's funding.
99108
///
100109
/// A transaction of this type will be broadcast as a result of a [`ChannelManager::splice_channel`] operation.
101110
///
102111
/// [`ChannelManager::splice_channel`]: crate::ln::channelmanager::ChannelManager::splice_channel
103112
Splice {
113+
/// The `node_id` of the channel counterparty.
114+
counterparty_node_id: PublicKey,
104115
/// The ID of the channel being spliced.
105116
channel_id: ChannelId,
106117
},

lightning/src/chain/channelmonitor.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,8 +1879,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
18791879
initial_holder_commitment_tx.trust().commitment_number();
18801880

18811881
let onchain_tx_handler = OnchainTxHandler::new(
1882-
channel_id, channel_parameters.channel_value_satoshis, channel_keys_id,
1883-
destination_script.into(), keys, channel_parameters.clone(),
1882+
channel_id, counterparty_node_id, channel_parameters.channel_value_satoshis,
1883+
channel_keys_id, destination_script.into(), keys, channel_parameters.clone(),
18841884
initial_holder_commitment_tx.clone(), secp_ctx,
18851885
);
18861886

@@ -6644,6 +6644,8 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
66446644
};
66456645

66466646
let dummy_node_id = PublicKey::from_slice(&[2; 33]).unwrap();
6647+
onchain_tx_handler
6648+
.set_counterparty_node_id(counterparty_node_id.unwrap_or(dummy_node_id));
66476649
let monitor = ChannelMonitor::from_impl(ChannelMonitorImpl {
66486650
funding: FundingScope {
66496651
channel_parameters,

lightning/src/chain/onchaintx.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use bitcoin::hashes::Hash;
1818
use bitcoin::locktime::absolute::LockTime;
1919
use bitcoin::script::{Script, ScriptBuf};
2020
use bitcoin::secp256k1;
21-
use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
21+
use bitcoin::secp256k1::{ecdsa::Signature, PublicKey, Secp256k1};
2222
use bitcoin::transaction::OutPoint as BitcoinOutPoint;
2323
use bitcoin::transaction::Transaction;
2424

@@ -224,6 +224,7 @@ pub(crate) enum FeerateStrategy {
224224
#[derive(Clone)]
225225
pub struct OnchainTxHandler<ChannelSigner: EcdsaChannelSigner> {
226226
channel_id: ChannelId,
227+
counterparty_node_id: PublicKey,
227228
channel_value_satoshis: u64, // Deprecated as of 0.2.
228229
channel_keys_id: [u8; 32], // Deprecated as of 0.2.
229230
destination_script: ScriptBuf, // Deprecated as of 0.2.
@@ -287,6 +288,7 @@ impl<ChannelSigner: EcdsaChannelSigner> PartialEq for OnchainTxHandler<ChannelSi
287288
fn eq(&self, other: &Self) -> bool {
288289
// `signer`, `secp_ctx`, and `pending_claim_events` are excluded on purpose.
289290
self.channel_id == other.channel_id &&
291+
self.counterparty_node_id == other.counterparty_node_id &&
290292
self.channel_value_satoshis == other.channel_value_satoshis &&
291293
self.channel_keys_id == other.channel_keys_id &&
292294
self.destination_script == other.destination_script &&
@@ -358,6 +360,14 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
358360
pub(crate) fn set_channel_id(&mut self, channel_id: ChannelId) {
359361
self.channel_id = channel_id;
360362
}
363+
364+
// `ChannelMonitor`s already track the `counterparty_node_id`, however, due to the
365+
// deserialization order there we can't make use of `ReadableArgs` to hand it into
366+
// `OnchainTxHandler`'s deserialization logic directly. Instead we opt to initialize it with a
367+
// dummy key and override it after reading the respective field via this method.
368+
pub(crate) fn set_counterparty_node_id(&mut self, counterparty_node_id: PublicKey) {
369+
self.counterparty_node_id = counterparty_node_id;
370+
}
361371
}
362372

363373
impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP, u64, [u8; 32])>
@@ -433,17 +443,20 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
433443

434444
read_tlv_fields!(reader, {});
435445

436-
// `ChannelMonitor`s already track the `channel_id`, however, due to the derserialization
437-
// order there we can't make use of `ReadableArgs` to hand it in directly. Instead we opt
438-
// to initialize it with 0s and override it after reading the respective field via
439-
// `OnchainTxHandler::set_channel_id`.
446+
// `ChannelMonitor`s already track the `channel_id` and `counterparty_node_id`, however, due
447+
// to the deserialization order there we can't make use of `ReadableArgs` to hand them in
448+
// directly. Instead we opt to initialize them with dummy values and override them after
449+
// reading the respective fields via `OnchainTxHandler::set_channel_id` and
450+
// `OnchainTxHandler::set_counterparty_node_id`.
440451
let channel_id = ChannelId([0u8; 32]);
452+
let counterparty_node_id = PublicKey::from_slice(&[2; 33]).unwrap();
441453

442454
let mut secp_ctx = Secp256k1::new();
443455
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
444456

445457
Ok(OnchainTxHandler {
446458
channel_id,
459+
counterparty_node_id,
447460
channel_value_satoshis,
448461
channel_keys_id,
449462
destination_script,
@@ -463,13 +476,14 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
463476

464477
impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
465478
pub(crate) fn new(
466-
channel_id: ChannelId, channel_value_satoshis: u64, channel_keys_id: [u8; 32],
467-
destination_script: ScriptBuf, signer: ChannelSigner,
479+
channel_id: ChannelId, counterparty_node_id: PublicKey, channel_value_satoshis: u64,
480+
channel_keys_id: [u8; 32], destination_script: ScriptBuf, signer: ChannelSigner,
468481
channel_parameters: ChannelTransactionParameters,
469482
holder_commitment: HolderCommitmentTransaction, secp_ctx: Secp256k1<secp256k1::All>,
470483
) -> Self {
471484
OnchainTxHandler {
472485
channel_id,
486+
counterparty_node_id,
473487
channel_value_satoshis,
474488
channel_keys_id,
475489
destination_script,
@@ -533,7 +547,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
533547
if tx.is_fully_signed() {
534548
let log_start = if feerate_was_bumped { "Broadcasting RBF-bumped" } else { "Rebroadcasting" };
535549
log_info!(logger, "{} onchain {}", log_start, log_tx!(tx.0));
536-
broadcaster.broadcast_transactions(&[(&tx.0, TransactionType::Claim { channel_id: self.channel_id })]);
550+
broadcaster.broadcast_transactions(&[(&tx.0, TransactionType::Claim { counterparty_node_id: self.counterparty_node_id, channel_id: self.channel_id })]);
537551
} else {
538552
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", tx.0.compute_txid());
539553
}
@@ -875,7 +889,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
875889
OnchainClaim::Tx(tx) => {
876890
if tx.is_fully_signed() {
877891
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx.0));
878-
broadcaster.broadcast_transactions(&[(&tx.0, TransactionType::Claim { channel_id: self.channel_id })]);
892+
broadcaster.broadcast_transactions(&[(&tx.0, TransactionType::Claim { counterparty_node_id: self.counterparty_node_id, channel_id: self.channel_id })]);
879893
} else {
880894
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", tx.0.compute_txid());
881895
}
@@ -1093,7 +1107,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
10931107
OnchainClaim::Tx(bump_tx) => {
10941108
if bump_tx.is_fully_signed() {
10951109
log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx.0));
1096-
broadcaster.broadcast_transactions(&[(&bump_tx.0, TransactionType::Claim { channel_id: self.channel_id })]);
1110+
broadcaster.broadcast_transactions(&[(&bump_tx.0, TransactionType::Claim { counterparty_node_id: self.counterparty_node_id, channel_id: self.channel_id })]);
10971111
} else {
10981112
log_info!(logger, "Waiting for signature of RBF-bumped unsigned onchain transaction {}",
10991113
bump_tx.0.compute_txid());
@@ -1190,7 +1204,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
11901204
OnchainClaim::Tx(bump_tx) => {
11911205
if bump_tx.is_fully_signed() {
11921206
log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx.0));
1193-
broadcaster.broadcast_transactions(&[(&bump_tx.0, TransactionType::Claim { channel_id: self.channel_id })]);
1207+
broadcaster.broadcast_transactions(&[(&bump_tx.0, TransactionType::Claim { counterparty_node_id: self.counterparty_node_id, channel_id: self.channel_id })]);
11941208
} else {
11951209
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", bump_tx.0.compute_txid());
11961210
}
@@ -1368,8 +1382,10 @@ mod tests {
13681382
}
13691383
let holder_commit = HolderCommitmentTransaction::dummy(1000000, funding_outpoint, nondust_htlcs);
13701384
let destination_script = ScriptBuf::new();
1385+
let counterparty_node_id = PublicKey::from_slice(&[2; 33]).unwrap();
13711386
let mut tx_handler = OnchainTxHandler::new(
13721387
ChannelId::from_bytes([0; 32]),
1388+
counterparty_node_id,
13731389
1000000,
13741390
[0; 32],
13751391
destination_script.clone(),

lightning/src/events/bump_transaction/mod.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ where
774774
/// transaction spending an anchor output of the commitment transaction to bump its fee and
775775
/// broadcasts them to the network as a package.
776776
async fn handle_channel_close(
777-
&self, channel_id: ChannelId, claim_id: ClaimId,
777+
&self, channel_id: ChannelId, counterparty_node_id: PublicKey, claim_id: ClaimId,
778778
package_target_feerate_sat_per_1000_weight: u32, commitment_tx: &Transaction,
779779
commitment_tx_fee_sat: u64, anchor_descriptor: &AnchorDescriptor,
780780
) -> Result<(), ()> {
@@ -799,7 +799,7 @@ where
799799
package_target_feerate_sat_per_1000_weight);
800800
self.broadcaster.broadcast_transactions(&[(
801801
&commitment_tx,
802-
TransactionType::UnilateralClose { channel_id },
802+
TransactionType::UnilateralClose { counterparty_node_id, channel_id },
803803
)]);
804804
return Ok(());
805805
}
@@ -968,8 +968,11 @@ where
968968
commitment_tx.compute_txid()
969969
);
970970
self.broadcaster.broadcast_transactions(&[
971-
(&commitment_tx, TransactionType::UnilateralClose { channel_id }),
972-
(&anchor_tx, TransactionType::AnchorBump { channel_id }),
971+
(
972+
&commitment_tx,
973+
TransactionType::UnilateralClose { counterparty_node_id, channel_id },
974+
),
975+
(&anchor_tx, TransactionType::AnchorBump { counterparty_node_id, channel_id }),
973976
]);
974977
return Ok(());
975978
}
@@ -978,8 +981,9 @@ where
978981
/// Handles a [`BumpTransactionEvent::HTLCResolution`] event variant by producing a
979982
/// fully-signed, fee-bumped HTLC transaction that is broadcast to the network.
980983
async fn handle_htlc_resolution(
981-
&self, channel_id: ChannelId, claim_id: ClaimId, target_feerate_sat_per_1000_weight: u32,
982-
htlc_descriptors: &[HTLCDescriptor], tx_lock_time: LockTime,
984+
&self, channel_id: ChannelId, counterparty_node_id: PublicKey, claim_id: ClaimId,
985+
target_feerate_sat_per_1000_weight: u32, htlc_descriptors: &[HTLCDescriptor],
986+
tx_lock_time: LockTime,
983987
) -> Result<(), ()> {
984988
let channel_type = &htlc_descriptors[0]
985989
.channel_derivation_parameters
@@ -1205,7 +1209,7 @@ where
12051209
log_info!(self.logger, "Broadcasting {}", log_tx!(htlc_tx));
12061210
self.broadcaster.broadcast_transactions(&[(
12071211
&htlc_tx,
1208-
TransactionType::UnilateralClose { channel_id },
1212+
TransactionType::UnilateralClose { counterparty_node_id, channel_id },
12091213
)]);
12101214
}
12111215

@@ -1217,6 +1221,7 @@ where
12171221
match event {
12181222
BumpTransactionEvent::ChannelClose {
12191223
channel_id,
1224+
counterparty_node_id,
12201225
claim_id,
12211226
package_target_feerate_sat_per_1000_weight,
12221227
commitment_tx,
@@ -1232,6 +1237,7 @@ where
12321237
);
12331238
self.handle_channel_close(
12341239
*channel_id,
1240+
*counterparty_node_id,
12351241
*claim_id,
12361242
*package_target_feerate_sat_per_1000_weight,
12371243
commitment_tx,
@@ -1249,6 +1255,7 @@ where
12491255
},
12501256
BumpTransactionEvent::HTLCResolution {
12511257
channel_id,
1258+
counterparty_node_id,
12521259
claim_id,
12531260
target_feerate_sat_per_1000_weight,
12541261
htlc_descriptors,
@@ -1263,6 +1270,7 @@ where
12631270
);
12641271
self.handle_htlc_resolution(
12651272
*channel_id,
1273+
*counterparty_node_id,
12661274
*claim_id,
12671275
*target_feerate_sat_per_1000_weight,
12681276
htlc_descriptors,

lightning/src/ln/channel.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,6 +2110,7 @@ where
21102110
};
21112111

21122112
let channel_id = context.channel_id;
2113+
let counterparty_node_id = context.counterparty_node_id;
21132114

21142115
let signing_session = if let Some(signing_session) =
21152116
context.interactive_tx_signing_session.as_mut()
@@ -2223,9 +2224,9 @@ where
22232224

22242225
let funding_tx = funding_tx.map(|tx| {
22252226
let tx_type = if splice_negotiated.is_some() {
2226-
TransactionType::Splice { channel_id }
2227+
TransactionType::Splice { counterparty_node_id, channel_id }
22272228
} else {
2228-
TransactionType::Funding { channel_ids: vec![channel_id] }
2229+
TransactionType::Funding { channels: vec![(counterparty_node_id, channel_id)] }
22292230
};
22302231
(tx, tx_type)
22312232
});
@@ -9168,9 +9169,14 @@ where
91689169

91699170
let funding_tx = funding_tx.map(|tx| {
91709171
let tx_type = if splice_negotiated.is_some() {
9171-
TransactionType::Splice { channel_id: self.context.channel_id }
9172+
TransactionType::Splice {
9173+
counterparty_node_id: self.context.counterparty_node_id,
9174+
channel_id: self.context.channel_id,
9175+
}
91729176
} else {
9173-
TransactionType::Funding { channel_ids: vec![self.context.channel_id] }
9177+
TransactionType::Funding {
9178+
channels: vec![(self.context.counterparty_node_id, self.context.channel_id)],
9179+
}
91749180
};
91759181
(tx, tx_type)
91769182
});

0 commit comments

Comments
 (0)