Skip to content
Open
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: 9 additions & 1 deletion lightning/src/chain/chaininterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@

use core::{cmp, ops::Deref};

use crate::ln::funding::FundingContribution;
use crate::ln::types::ChannelId;
use crate::prelude::*;

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

/// Represents the class of transaction being broadcast.
///
/// This is used to provide context about the type of transaction being broadcast, which may be
/// useful for logging, filtering, or prioritization purposes.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TransactionType {
/// A funding transaction establishing a new channel.
///
Expand Down Expand Up @@ -114,6 +116,12 @@ pub enum TransactionType {
counterparty_node_id: PublicKey,
/// The ID of the channel being spliced.
channel_id: ChannelId,
/// The local node's contribution to this splice/RBF round, or `None` if we did not
/// contribute (e.g., a pure acceptor with zero value added).
contribution: Option<FundingContribution>,
/// For an RBF replacement, the txid of the prior negotiated splice candidate being
/// replaced. `None` for the first splice attempt.
replaced_txid: Option<Txid>,
Copy link
Copy Markdown
Contributor

@tnull tnull Apr 27, 2026

Choose a reason for hiding this comment

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

Hmm, what happens when we make multiple subsequent RBFs? Could/should we make this a Vec and track all prior conflicting Txids to make sure we're not losing any intermediary step when tracking these events?

Also, when integrating BDK's RBF events in LDK Node we found that it would be nice if the API clearly defined an ordering for the replaced_txids, i.e., so we can always identify the 'original' txid (under which we started tracking a certain payment). That is, if we make this a Vec it would be great if the API could guarantee that replaced_txids[0] is always the 'original'.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

That seems reasonable, though things get hairy if we have multiple splice-RBFs that conflict across channels. ISTM LDK Node might need to track that somehow, but maybe we can just avoid ever building such things?

},
}

Expand Down
7 changes: 7 additions & 0 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9394,9 +9394,16 @@ where
);
}

let replaced_txid =
pending_splice.negotiated_candidates.len().checked_sub(2).and_then(|idx| {
pending_splice.negotiated_candidates[idx].get_funding_txid()
});
let contribution = pending_splice.contributions.last().cloned();
let tx_type = TransactionType::Splice {
counterparty_node_id: self.context.counterparty_node_id,
channel_id: self.context.channel_id,
contribution,
replaced_txid,
};
funding_tx_signed.funding_tx = Some((funding_tx, tx_type));
funding_tx_signed.splice_negotiated = Some(splice_negotiated);
Expand Down
25 changes: 21 additions & 4 deletions lightning/src/ln/funding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,10 +578,6 @@ impl_writeable_tlv_based!(FundingContribution, {
});

impl FundingContribution {
pub(super) fn feerate(&self) -> FeeRate {
self.feerate
}

pub(super) fn is_splice(&self) -> bool {
self.is_splice
}
Expand Down Expand Up @@ -610,6 +606,16 @@ impl FundingContribution {
.unwrap_or(Amount::ZERO)
}

/// Returns the estimated on-chain fee this contribution is responsible for paying.
pub fn estimated_fee(&self) -> Amount {
self.estimated_fee
}

/// Returns the inputs included in this contribution.
pub fn inputs(&self) -> &[FundingTxInput] {
&self.inputs
}

/// Returns the outputs (e.g., withdrawal destinations) included in this contribution.
///
/// This does not include the change output; see [`FundingContribution::change_output`].
Expand All @@ -625,6 +631,17 @@ impl FundingContribution {
self.change_output.as_ref()
}

/// Returns the fee rate used to select `inputs` (the minimum feerate).
pub fn feerate(&self) -> FeeRate {
self.feerate
}

/// Returns the maximum fee rate this contribution will accept as acceptor before rejecting
/// the splice.
pub fn max_feerate(&self) -> FeeRate {
self.max_feerate
}

/// Tries to satisfy a new request using only this contribution's existing inputs.
///
/// For input-backed contributions, this reuses the current inputs, adjusts the explicit
Expand Down
Loading
Loading