Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lightning-background-processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3110,10 +3110,16 @@ mod tests {
let event =
receiver.recv_timeout(EVENT_DEADLINE).expect("Events not handled within deadline");
match event {
Event::SpendableOutputs { outputs, channel_id } => {
Event::SpendableOutputs { outputs, channel_id, counterparty_node_id } => {
nodes[0]
.sweeper
.track_spendable_outputs(outputs, channel_id, false, Some(153))
.track_spendable_outputs(
outputs,
channel_id,
counterparty_node_id,
false,
Some(153),
)
.unwrap();
},
_ => panic!("Unexpected event: {:?}", event),
Expand Down
13 changes: 7 additions & 6 deletions lightning-liquidity/src/lsps2/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2020,21 +2020,22 @@ where
// close could then confirm the commitment and trigger unintended on‑chain handling.
// To avoid this, we check ChannelManager’s view (`is_channel_ready`) before broadcasting.
if let Some(ch_id) = jit_channel.get_channel_id() {
let is_channel_ready = self
let channel_details = self
.channel_manager
.get_cm()
.list_channels()
.into_iter()
.any(|cd| cd.channel_id == ch_id && cd.is_channel_ready);
.find(|cd| cd.channel_id == ch_id && cd.is_channel_ready);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might make sense to filter by UCID here as well. Technically channel id isn't unique for 0confs even if is_channel_ready.


if !is_channel_ready {
return;
}
let counterparty_node_id = match channel_details {
Some(cd) => cd.counterparty.node_id,
None => return,
};

if let Some(funding_tx) = jit_channel.get_funding_tx() {
self.tx_broadcaster.broadcast_transactions(&[(
funding_tx,
TransactionType::Funding { channel_ids: vec![ch_id] },
TransactionType::Funding { channels: vec![(counterparty_node_id, ch_id)] },
)]);
}
}
Expand Down
4 changes: 3 additions & 1 deletion lightning-tests/src/upgrade_downgrade_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,9 @@ fn test_0_1_legacy_remote_key_derivation() {
connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1);
let mut spendable_event = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
assert_eq!(spendable_event.len(), 1);
if let Event::SpendableOutputs { outputs, channel_id: ev_id } = spendable_event.pop().unwrap() {
if let Event::SpendableOutputs { outputs, channel_id: ev_id, counterparty_node_id: _ } =
spendable_event.pop().unwrap()
{
assert_eq!(ev_id.unwrap().0, channel_id);
assert_eq!(outputs.len(), 1);
let spk = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script();
Expand Down
19 changes: 15 additions & 4 deletions lightning/src/chain/chaininterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use core::{cmp, ops::Deref};
use crate::ln::types::ChannelId;
use crate::prelude::*;

use bitcoin::secp256k1::PublicKey;
use bitcoin::transaction::Transaction;

/// Represents the class of transaction being broadcast.
Expand All @@ -33,10 +34,10 @@ pub enum TransactionType {
///
/// [`ChannelManager::funding_transaction_generated`]: crate::ln::channelmanager::ChannelManager::funding_transaction_generated
Funding {
/// The IDs of the channels being funded.
/// The counterparty node IDs and channel IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
channels: Vec<(PublicKey, ChannelId)>,
},
/// A transaction cooperatively closing a channel.
///
Expand All @@ -45,6 +46,8 @@ pub enum TransactionType {
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
CooperativeClose {
/// The `node_id` of the channel counterparty.
counterparty_node_id: PublicKey,
/// The ID of the channel being closed.
channel_id: ChannelId,
},
Expand All @@ -56,6 +59,8 @@ pub enum TransactionType {
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
UnilateralClose {
/// The `node_id` of the channel counterparty.
counterparty_node_id: PublicKey,
/// The ID of the channel being force-closed.
channel_id: ChannelId,
},
Expand All @@ -66,6 +71,8 @@ pub enum TransactionType {
///
/// [`BumpTransactionEvent`]: crate::events::bump_transaction::BumpTransactionEvent
AnchorBump {
/// The `node_id` of the channel counterparty.
counterparty_node_id: PublicKey,
/// The ID of the channel whose closing transaction is being fee-bumped.
channel_id: ChannelId,
},
Expand All @@ -81,6 +88,8 @@ pub enum TransactionType {
/// [`ChannelMonitor`]: crate::chain::ChannelMonitor
/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The `node_id` of the channel counterparty.
counterparty_node_id: PublicKey,
/// The ID of the channel from which outputs are being claimed.
channel_id: ChannelId,
},
Expand All @@ -90,17 +99,19 @@ pub enum TransactionType {
/// [`OutputSweeper`]: crate::util::sweep::OutputSweeper
/// [`SpendableOutputDescriptor`]: crate::sign::SpendableOutputDescriptor
Sweep {
/// The IDs of the channels from which outputs are being swept, if known.
/// The counterparty node IDs and channel IDs from which outputs are being swept, if known.
///
/// A single sweep transaction may aggregate outputs from multiple channels.
channel_ids: Vec<ChannelId>,
channels: Vec<(PublicKey, ChannelId)>,
},
/// A splice transaction modifying an existing channel's funding.
///
/// A transaction of this type will be broadcast as a result of a [`ChannelManager::splice_channel`] operation.
///
/// [`ChannelManager::splice_channel`]: crate::ln::channelmanager::ChannelManager::splice_channel
Splice {
/// The `node_id` of the channel counterparty.
counterparty_node_id: PublicKey,
/// The ID of the channel being spliced.
channel_id: ChannelId,
},
Expand Down
7 changes: 5 additions & 2 deletions lightning/src/chain/channelmonitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1879,8 +1879,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
initial_holder_commitment_tx.trust().commitment_number();

let onchain_tx_handler = OnchainTxHandler::new(
channel_id, channel_parameters.channel_value_satoshis, channel_keys_id,
destination_script.into(), keys, channel_parameters.clone(),
channel_id, counterparty_node_id, channel_parameters.channel_value_satoshis,
channel_keys_id, destination_script.into(), keys, channel_parameters.clone(),
initial_holder_commitment_tx.clone(), secp_ctx,
);

Expand Down Expand Up @@ -5619,6 +5619,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
self.pending_events.push(Event::SpendableOutputs {
outputs: vec![descriptor],
channel_id: Some(self.channel_id()),
counterparty_node_id: Some(self.counterparty_node_id),
});
self.spendable_txids_confirmed.push(entry.txid);
},
Expand Down Expand Up @@ -6643,6 +6644,8 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
};

let dummy_node_id = PublicKey::from_slice(&[2; 33]).unwrap();
onchain_tx_handler
.set_counterparty_node_id(counterparty_node_id.unwrap_or(dummy_node_id));
let monitor = ChannelMonitor::from_impl(ChannelMonitorImpl {
funding: FundingScope {
channel_parameters,
Expand Down
38 changes: 27 additions & 11 deletions lightning/src/chain/onchaintx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use bitcoin::hashes::Hash;
use bitcoin::locktime::absolute::LockTime;
use bitcoin::script::{Script, ScriptBuf};
use bitcoin::secp256k1;
use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
use bitcoin::secp256k1::{ecdsa::Signature, PublicKey, Secp256k1};
use bitcoin::transaction::OutPoint as BitcoinOutPoint;
use bitcoin::transaction::Transaction;

Expand Down Expand Up @@ -224,6 +224,7 @@ pub(crate) enum FeerateStrategy {
#[derive(Clone)]
pub struct OnchainTxHandler<ChannelSigner: EcdsaChannelSigner> {
channel_id: ChannelId,
counterparty_node_id: PublicKey,
channel_value_satoshis: u64, // Deprecated as of 0.2.
channel_keys_id: [u8; 32], // Deprecated as of 0.2.
destination_script: ScriptBuf, // Deprecated as of 0.2.
Expand Down Expand Up @@ -287,6 +288,7 @@ impl<ChannelSigner: EcdsaChannelSigner> PartialEq for OnchainTxHandler<ChannelSi
fn eq(&self, other: &Self) -> bool {
// `signer`, `secp_ctx`, and `pending_claim_events` are excluded on purpose.
self.channel_id == other.channel_id &&
self.counterparty_node_id == other.counterparty_node_id &&
self.channel_value_satoshis == other.channel_value_satoshis &&
self.channel_keys_id == other.channel_keys_id &&
self.destination_script == other.destination_script &&
Expand Down Expand Up @@ -358,6 +360,14 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
pub(crate) fn set_channel_id(&mut self, channel_id: ChannelId) {
self.channel_id = channel_id;
}

// `ChannelMonitor`s already track the `counterparty_node_id`, however, due to the
// deserialization order there we can't make use of `ReadableArgs` to hand it into
// `OnchainTxHandler`'s deserialization logic directly. Instead we opt to initialize it with a
// dummy key and override it after reading the respective field via this method.
pub(crate) fn set_counterparty_node_id(&mut self, counterparty_node_id: PublicKey) {
self.counterparty_node_id = counterparty_node_id;
}
}

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

read_tlv_fields!(reader, {});

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

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

Ok(OnchainTxHandler {
channel_id,
counterparty_node_id,
channel_value_satoshis,
channel_keys_id,
destination_script,
Expand All @@ -463,13 +476,14 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP

impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
pub(crate) fn new(
channel_id: ChannelId, channel_value_satoshis: u64, channel_keys_id: [u8; 32],
destination_script: ScriptBuf, signer: ChannelSigner,
channel_id: ChannelId, counterparty_node_id: PublicKey, channel_value_satoshis: u64,
channel_keys_id: [u8; 32], destination_script: ScriptBuf, signer: ChannelSigner,
channel_parameters: ChannelTransactionParameters,
holder_commitment: HolderCommitmentTransaction, secp_ctx: Secp256k1<secp256k1::All>,
) -> Self {
OnchainTxHandler {
channel_id,
counterparty_node_id,
channel_value_satoshis,
channel_keys_id,
destination_script,
Expand Down Expand Up @@ -533,7 +547,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
if tx.is_fully_signed() {
let log_start = if feerate_was_bumped { "Broadcasting RBF-bumped" } else { "Rebroadcasting" };
log_info!(logger, "{} onchain {}", log_start, log_tx!(tx.0));
broadcaster.broadcast_transactions(&[(&tx.0, TransactionType::Claim { channel_id: self.channel_id })]);
broadcaster.broadcast_transactions(&[(&tx.0, TransactionType::Claim { counterparty_node_id: self.counterparty_node_id, channel_id: self.channel_id })]);
} else {
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", tx.0.compute_txid());
}
Expand Down Expand Up @@ -875,7 +889,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
OnchainClaim::Tx(tx) => {
if tx.is_fully_signed() {
log_info!(logger, "Broadcasting onchain {}", log_tx!(tx.0));
broadcaster.broadcast_transactions(&[(&tx.0, TransactionType::Claim { channel_id: self.channel_id })]);
broadcaster.broadcast_transactions(&[(&tx.0, TransactionType::Claim { counterparty_node_id: self.counterparty_node_id, channel_id: self.channel_id })]);
} else {
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", tx.0.compute_txid());
}
Expand Down Expand Up @@ -1093,7 +1107,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
OnchainClaim::Tx(bump_tx) => {
if bump_tx.is_fully_signed() {
log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx.0));
broadcaster.broadcast_transactions(&[(&bump_tx.0, TransactionType::Claim { channel_id: self.channel_id })]);
broadcaster.broadcast_transactions(&[(&bump_tx.0, TransactionType::Claim { counterparty_node_id: self.counterparty_node_id, channel_id: self.channel_id })]);
} else {
log_info!(logger, "Waiting for signature of RBF-bumped unsigned onchain transaction {}",
bump_tx.0.compute_txid());
Expand Down Expand Up @@ -1190,7 +1204,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
OnchainClaim::Tx(bump_tx) => {
if bump_tx.is_fully_signed() {
log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx.0));
broadcaster.broadcast_transactions(&[(&bump_tx.0, TransactionType::Claim { channel_id: self.channel_id })]);
broadcaster.broadcast_transactions(&[(&bump_tx.0, TransactionType::Claim { counterparty_node_id: self.counterparty_node_id, channel_id: self.channel_id })]);
} else {
log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", bump_tx.0.compute_txid());
}
Expand Down Expand Up @@ -1368,8 +1382,10 @@ mod tests {
}
let holder_commit = HolderCommitmentTransaction::dummy(1000000, funding_outpoint, nondust_htlcs);
let destination_script = ScriptBuf::new();
let counterparty_node_id = PublicKey::from_slice(&[2; 33]).unwrap();
let mut tx_handler = OnchainTxHandler::new(
ChannelId::from_bytes([0; 32]),
counterparty_node_id,
1000000,
[0; 32],
destination_script.clone(),
Expand Down
22 changes: 15 additions & 7 deletions lightning/src/events/bump_transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ where
/// transaction spending an anchor output of the commitment transaction to bump its fee and
/// broadcasts them to the network as a package.
async fn handle_channel_close(
&self, channel_id: ChannelId, claim_id: ClaimId,
&self, channel_id: ChannelId, counterparty_node_id: PublicKey, claim_id: ClaimId,
package_target_feerate_sat_per_1000_weight: u32, commitment_tx: &Transaction,
commitment_tx_fee_sat: u64, anchor_descriptor: &AnchorDescriptor,
) -> Result<(), ()> {
Expand All @@ -799,7 +799,7 @@ where
package_target_feerate_sat_per_1000_weight);
self.broadcaster.broadcast_transactions(&[(
&commitment_tx,
TransactionType::UnilateralClose { channel_id },
TransactionType::UnilateralClose { counterparty_node_id, channel_id },
)]);
return Ok(());
}
Expand Down Expand Up @@ -968,8 +968,11 @@ where
commitment_tx.compute_txid()
);
self.broadcaster.broadcast_transactions(&[
(&commitment_tx, TransactionType::UnilateralClose { channel_id }),
(&anchor_tx, TransactionType::AnchorBump { channel_id }),
(
&commitment_tx,
TransactionType::UnilateralClose { counterparty_node_id, channel_id },
),
(&anchor_tx, TransactionType::AnchorBump { counterparty_node_id, channel_id }),
]);
return Ok(());
}
Expand All @@ -978,8 +981,9 @@ where
/// Handles a [`BumpTransactionEvent::HTLCResolution`] event variant by producing a
/// fully-signed, fee-bumped HTLC transaction that is broadcast to the network.
async fn handle_htlc_resolution(
&self, channel_id: ChannelId, claim_id: ClaimId, target_feerate_sat_per_1000_weight: u32,
htlc_descriptors: &[HTLCDescriptor], tx_lock_time: LockTime,
&self, channel_id: ChannelId, counterparty_node_id: PublicKey, claim_id: ClaimId,
target_feerate_sat_per_1000_weight: u32, htlc_descriptors: &[HTLCDescriptor],
tx_lock_time: LockTime,
) -> Result<(), ()> {
let channel_type = &htlc_descriptors[0]
.channel_derivation_parameters
Expand Down Expand Up @@ -1205,7 +1209,7 @@ where
log_info!(self.logger, "Broadcasting {}", log_tx!(htlc_tx));
self.broadcaster.broadcast_transactions(&[(
&htlc_tx,
TransactionType::UnilateralClose { channel_id },
TransactionType::UnilateralClose { counterparty_node_id, channel_id },
)]);
}

Expand All @@ -1217,6 +1221,7 @@ where
match event {
BumpTransactionEvent::ChannelClose {
channel_id,
counterparty_node_id,
claim_id,
package_target_feerate_sat_per_1000_weight,
commitment_tx,
Expand All @@ -1232,6 +1237,7 @@ where
);
self.handle_channel_close(
*channel_id,
*counterparty_node_id,
*claim_id,
*package_target_feerate_sat_per_1000_weight,
commitment_tx,
Expand All @@ -1249,6 +1255,7 @@ where
},
BumpTransactionEvent::HTLCResolution {
channel_id,
counterparty_node_id,
claim_id,
target_feerate_sat_per_1000_weight,
htlc_descriptors,
Expand All @@ -1263,6 +1270,7 @@ where
);
self.handle_htlc_resolution(
*channel_id,
*counterparty_node_id,
*claim_id,
*target_feerate_sat_per_1000_weight,
htlc_descriptors,
Expand Down
Loading
Loading