diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index a4fb00e61f9..af29a0221a9 100644 --- a/fuzz/src/router.rs +++ b/fuzz/src/router.rs @@ -229,6 +229,7 @@ pub fn do_test(data: &[u8], out: Out) { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0, }), + funding_redeem_script: None, channel_type: None, short_channel_id: Some(scid), inbound_scid_alias: None, diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index 9f7e4c5620d..b9c4b1ca1ef 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -1413,6 +1413,10 @@ pub enum Event { /// /// Will be `None` for channels created prior to LDK version 0.0.122. channel_type: Option, + /// The witness script that is used to lock the channel's funding output to commitment transactions. + /// + /// This field will be `None` for objects serialized with LDK versions prior to 0.2.0. + funding_redeem_script: Option, }, /// Used to indicate that a channel with the given `channel_id` is ready to be used. This event /// is emitted when @@ -1532,6 +1536,8 @@ pub enum Event { /// The features that this channel will operate with. Currently, these will be the same /// features that the channel was opened with, but in the future splices may change them. channel_type: ChannelTypeFeatures, + /// The witness script that is used to lock the channel's funding output to commitment transactions. + new_funding_redeem_script: ScriptBuf, }, /// Used to indicate that a splice for the given `channel_id` has failed. /// @@ -2234,6 +2240,7 @@ impl Writeable for Event { ref counterparty_node_id, ref funding_txo, ref channel_type, + ref funding_redeem_script, } => { 31u8.write(writer)?; write_tlv_fields!(writer, { @@ -2243,6 +2250,7 @@ impl Writeable for Event { (4, former_temporary_channel_id, required), (6, counterparty_node_id, required), (8, funding_txo, required), + (9, funding_redeem_script, option), }); }, &Event::ConnectionNeeded { .. } => { @@ -2307,6 +2315,7 @@ impl Writeable for Event { ref counterparty_node_id, ref new_funding_txo, ref channel_type, + ref new_funding_redeem_script, } => { 50u8.write(writer)?; write_tlv_fields!(writer, { @@ -2315,6 +2324,7 @@ impl Writeable for Event { (5, user_channel_id, required), (7, counterparty_node_id, required), (9, new_funding_txo, required), + (11, new_funding_redeem_script, required), }); }, &Event::SpliceFailed { @@ -2815,6 +2825,7 @@ impl MaybeReadable for Event { let mut counterparty_node_id = RequiredWrapper(None); let mut funding_txo = RequiredWrapper(None); let mut channel_type = None; + let mut funding_redeem_script = None; read_tlv_fields!(reader, { (0, channel_id, required), (1, channel_type, option), @@ -2822,6 +2833,7 @@ impl MaybeReadable for Event { (4, former_temporary_channel_id, required), (6, counterparty_node_id, required), (8, funding_txo, required), + (9, funding_redeem_script, option), }); Ok(Some(Event::ChannelPending { @@ -2831,6 +2843,7 @@ impl MaybeReadable for Event { counterparty_node_id: counterparty_node_id.0.unwrap(), funding_txo: funding_txo.0.unwrap(), channel_type, + funding_redeem_script, })) }; f() @@ -2927,6 +2940,7 @@ impl MaybeReadable for Event { (5, user_channel_id, required), (7, counterparty_node_id, required), (9, new_funding_txo, required), + (11, new_funding_redeem_script, required), }); Ok(Some(Event::SplicePending { @@ -2935,6 +2949,7 @@ impl MaybeReadable for Event { counterparty_node_id: counterparty_node_id.0.unwrap(), new_funding_txo: new_funding_txo.0.unwrap(), channel_type: channel_type.0.unwrap(), + new_funding_redeem_script: new_funding_redeem_script.0.unwrap(), })) }; f() diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index e759a4b54cb..13b39f6cabd 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -1120,12 +1120,17 @@ impl ChannelTransactionParameters { } } - #[rustfmt::skip] pub(crate) fn make_funding_redeemscript(&self) -> ScriptBuf { - make_funding_redeemscript( - &self.holder_pubkeys.funding_pubkey, - &self.counterparty_parameters.as_ref().unwrap().pubkeys.funding_pubkey - ) + self.make_funding_redeemscript_opt().unwrap() + } + + pub(crate) fn make_funding_redeemscript_opt(&self) -> Option { + self.counterparty_parameters.as_ref().map(|p| { + make_funding_redeemscript( + &self.holder_pubkeys.funding_pubkey, + &p.pubkeys.funding_pubkey, + ) + }) } /// Returns the counterparty's pubkeys. diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 62b108fd20a..e47b5492efd 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -6853,6 +6853,9 @@ pub struct SpliceFundingNegotiated { /// The features that this channel will operate with. pub channel_type: ChannelTypeFeatures, + + /// The redeem script of the funding output. + pub funding_redeem_script: ScriptBuf, } /// Information about a splice funding negotiation that has failed. @@ -8936,12 +8939,14 @@ where let funding_txo = funding.get_funding_txo().expect("funding outpoint should be set"); let channel_type = funding.get_channel_type().clone(); + let funding_redeem_script = funding.get_funding_redeemscript(); pending_splice.negotiated_candidates.push(funding); let splice_negotiated = SpliceFundingNegotiated { funding_txo: funding_txo.into_bitcoin_outpoint(), channel_type, + funding_redeem_script, }; let splice_locked = pending_splice.check_get_splice_locked( diff --git a/lightning/src/ln/channel_state.rs b/lightning/src/ln/channel_state.rs index c28b4687631..81a7cb4755e 100644 --- a/lightning/src/ln/channel_state.rs +++ b/lightning/src/ln/channel_state.rs @@ -450,6 +450,10 @@ pub struct ChannelDetails { /// /// This field is empty for objects serialized with LDK versions prior to 0.0.122. pub pending_outbound_htlcs: Vec, + /// The witness script that is used to lock the channel's funding output to commitment transactions. + /// + /// This field will be `None` for objects serialized with LDK versions prior to 0.2.0. + pub funding_redeem_script: Option, } impl ChannelDetails { @@ -475,6 +479,21 @@ impl ChannelDetails { self.short_channel_id.or(self.outbound_scid_alias) } + /// Gets the funding output for this channel, if available. + /// + /// During a splice, the funding output will change and this value will be updated + /// after the splice transaction has reached sufficient confirmations and we've + /// exchanged `splice_locked` messages. + pub fn get_funding_output(&self) -> Option { + match self.funding_redeem_script.as_ref() { + None => None, + Some(redeem_script) => Some(bitcoin::TxOut { + value: bitcoin::Amount::from_sat(self.channel_value_satoshis), + script_pubkey: redeem_script.to_p2wsh(), + }), + } + } + pub(super) fn from_channel( channel: &Channel, best_block_height: u32, latest_features: InitFeatures, fee_estimator: &LowerBoundedFeeEstimator, @@ -509,6 +528,9 @@ impl ChannelDetails { outbound_htlc_maximum_msat: context.get_counterparty_htlc_maximum_msat(funding), }, funding_txo: funding.get_funding_txo(), + funding_redeem_script: funding + .channel_transaction_parameters + .make_funding_redeemscript_opt(), // Note that accept_channel (or open_channel) is always the first message, so // `have_received_message` indicates that type negotiation has completed. channel_type: if context.have_received_message() { @@ -583,6 +605,7 @@ impl_writeable_tlv_based!(ChannelDetails, { (41, channel_shutdown_state, option), (43, pending_inbound_htlcs, optional_vec), (45, pending_outbound_htlcs, optional_vec), + (47, funding_redeem_script, option), (_unused, user_channel_id, (static_value, _user_channel_id_low.unwrap_or(0) as u128 | ((_user_channel_id_high.unwrap_or(0) as u128) << 64) )), @@ -627,6 +650,7 @@ mod tests { use crate::{ chain::transaction::OutPoint, ln::{ + chan_utils::make_funding_redeemscript, channel_state::{ InboundHTLCDetails, InboundHTLCStateDetails, OutboundHTLCDetails, OutboundHTLCStateDetails, @@ -658,6 +682,10 @@ mod tests { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 1, }), + funding_redeem_script: Some(make_funding_redeemscript( + &PublicKey::from_slice(&[2; 33]).unwrap(), + &PublicKey::from_slice(&[2; 33]).unwrap(), + )), channel_type: None, short_channel_id: None, outbound_scid_alias: None, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 632d897043e..6bab5911a26 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -3491,6 +3491,8 @@ macro_rules! emit_channel_pending_event { ($locked_events: expr, $channel: expr) => { if $channel.context.should_emit_channel_pending_event() { let funding_txo = $channel.funding.get_funding_txo().unwrap(); + let funding_redeem_script = + Some($channel.funding.channel_transaction_parameters.make_funding_redeemscript()); $locked_events.push_back(( events::Event::ChannelPending { channel_id: $channel.context.channel_id(), @@ -3499,6 +3501,7 @@ macro_rules! emit_channel_pending_event { user_channel_id: $channel.context.get_user_id(), funding_txo: funding_txo.into_bitcoin_outpoint(), channel_type: Some($channel.funding.get_channel_type().clone()), + funding_redeem_script, }, None, )); @@ -6456,6 +6459,8 @@ where user_channel_id: chan.context.get_user_id(), new_funding_txo: splice_negotiated.funding_txo, channel_type: splice_negotiated.channel_type, + new_funding_redeem_script: splice_negotiated + .funding_redeem_script, }, None, )); @@ -9612,6 +9617,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ user_channel_id: channel.context.get_user_id(), new_funding_txo: splice_negotiated.funding_txo, channel_type: splice_negotiated.channel_type, + new_funding_redeem_script: splice_negotiated.funding_redeem_script, }, None, )); @@ -10641,6 +10647,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ user_channel_id: chan.context.get_user_id(), new_funding_txo: splice_negotiated.funding_txo, channel_type: splice_negotiated.channel_type, + new_funding_redeem_script: splice_negotiated.funding_redeem_script, }, None, )); diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 77396c783e3..8ea3ea068b3 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -3893,6 +3893,7 @@ mod tests { use crate::blinded_path::BlindedHop; use crate::chain::transaction::OutPoint; use crate::crypto::chacha20::ChaCha20; + use crate::ln::chan_utils::make_funding_redeemscript; use crate::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelShutdownState}; use crate::ln::channelmanager; use crate::ln::msgs::{UnsignedChannelUpdate, MAX_VALUE_MSAT}; @@ -3950,6 +3951,10 @@ mod tests { outbound_htlc_maximum_msat: None, }, funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }), + funding_redeem_script: Some(make_funding_redeemscript( + &PublicKey::from_slice(&[2; 33]).unwrap(), + &PublicKey::from_slice(&[2; 33]).unwrap(), + )), channel_type: None, short_channel_id, outbound_scid_alias: None, @@ -9250,6 +9255,7 @@ pub(crate) mod bench_utils { use std::io::Read; use crate::chain::transaction::OutPoint; + use crate::ln::chan_utils::make_funding_redeemscript; use crate::ln::channel_state::{ChannelCounterparty, ChannelShutdownState}; use crate::ln::channelmanager; use crate::ln::types::ChannelId; @@ -9345,6 +9351,10 @@ pub(crate) mod bench_utils { funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }), + funding_redeem_script: Some(make_funding_redeemscript( + &PublicKey::from_slice(&[2; 33]).unwrap(), + &PublicKey::from_slice(&[2; 33]).unwrap(), + )), channel_type: None, short_channel_id: Some(1), inbound_scid_alias: None,