From cbac0e768098636e730e73573f5ca7ebb686dc0d Mon Sep 17 00:00:00 2001 From: Leo Nash Date: Fri, 13 Dec 2024 02:15:43 +0000 Subject: [PATCH] Let `ChannelSigner` set `to_local` script pubkey This allows the `to_local` output to easily be changed according to the features of the channel, or the evolution of the LN specification. `to_local` could even be set to completely arbitrary scripts if compatibility with the formal LN spec is not required. Builders of `CommitmentTransaction` now ask a `ChannelSigner` for the appropriate `to_local` script pubkey to use, and then pass it to the `CommitmentTransaction` constructor. External signers now provide the expected `to_local` script pubkey to the `verify` call of `CommitmentTransaction`. --- lightning/src/chain/channelmonitor.rs | 15 ++++--- lightning/src/ln/chan_utils.rs | 54 +++++++++++++---------- lightning/src/ln/channel.rs | 7 ++- lightning/src/ln/functional_tests.rs | 14 +++++- lightning/src/sign/mod.rs | 46 +++++++++++++++++-- lightning/src/util/test_channel_signer.rs | 12 ++++- 6 files changed, 109 insertions(+), 39 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index e0614eee634..d4c9108328b 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -3398,13 +3398,18 @@ impl ChannelMonitorImpl { &broadcaster_keys, &countersignatory_keys, &self.onchain_tx_handler.secp_ctx); let channel_parameters = &self.onchain_tx_handler.channel_transaction_parameters.as_counterparty_broadcastable(); + let to_broadcaster_spk = self.onchain_tx_handler.signer.get_revokeable_spk(false, commitment_number, their_per_commitment_point, &self.onchain_tx_handler.secp_ctx); + let to_broadcaster_txout = TxOut { + script_pubkey: to_broadcaster_spk, + value: Amount::from_sat(to_broadcaster_value), + }; let counterparty_txout = TxOut { script_pubkey: self.counterparty_payment_script.clone(), value: Amount::from_sat(to_countersignatory_value), }; CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number, - to_broadcaster_value, counterparty_txout, broadcaster_funding_key, + to_broadcaster_txout, counterparty_txout, broadcaster_funding_key, countersignatory_funding_key, keys, feerate_per_kw, &mut nondust_htlcs, channel_parameters) } @@ -3507,15 +3512,11 @@ impl ChannelMonitorImpl { let secret = self.get_secret(commitment_number).unwrap(); let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key); - let revocation_pubkey = RevocationKey::from_basepoint(&self.onchain_tx_handler.secp_ctx, &self.holder_revocation_basepoint, &per_commitment_point,); - let delayed_key = DelayedPaymentKey::from_basepoint(&self.onchain_tx_handler.secp_ctx, &self.counterparty_commitment_params.counterparty_delayed_payment_base_key, &PublicKey::from_secret_key(&self.onchain_tx_handler.secp_ctx, &per_commitment_key)); - - let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key); - let revokeable_p2wsh = revokeable_redeemscript.to_p2wsh(); + let revokeable_spk = self.onchain_tx_handler.signer.get_revokeable_spk(false, commitment_number, &per_commitment_point, &self.onchain_tx_handler.secp_ctx); // First, process non-htlc outputs (to_holder & to_counterparty) for (idx, outp) in tx.output.iter().enumerate() { - if outp.script_pubkey == revokeable_p2wsh { + if outp.script_pubkey == revokeable_spk { let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv, self.onchain_tx_handler.channel_type_features().supports_anchors_zero_fee_htlc_tx()); let justice_package = PackageTemplate::build_package( commitment_txid, idx as u32, diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 71bc786993c..6b9a87695e1 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -1137,12 +1137,17 @@ impl HolderCommitmentTransaction { for _ in 0..htlcs.len() { counterparty_htlc_sigs.push(dummy_sig); } + let broadcaster_payment_script = signer.get_revokeable_spk(false, 0, &keys.per_commitment_point, &secp_ctx); + let broadcaster_txout = TxOut { + script_pubkey: broadcaster_payment_script, + value: Amount::ZERO, + }; let counterparty_payment_script = signer.get_counterparty_payment_script(true); let counterparty_txout = TxOut { script_pubkey: counterparty_payment_script, value: Amount::ZERO, }; - let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, counterparty_txout, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters.as_counterparty_broadcastable()); + let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, broadcaster_txout, counterparty_txout, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters.as_counterparty_broadcastable()); htlcs.sort_by_key(|htlc| htlc.0.transaction_output_index); HolderCommitmentTransaction { inner, @@ -1452,12 +1457,12 @@ impl CommitmentTransaction { /// Only include HTLCs that are above the dust limit for the channel. /// /// This is not exported to bindings users due to the generic though we likely should expose a version without - pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_txout: TxOut, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { - let to_broadcaster_value_sat = Amount::from_sat(to_broadcaster_value_sat); + pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_txout: TxOut, to_countersignatory_txout: TxOut, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { + let to_broadcaster_value_sat = to_broadcaster_txout.value; let to_countersignatory_value_sat = to_countersignatory_txout.value; // Sort outputs and populate output indices while keeping track of the auxiliary data - let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_txout, htlcs_with_aux, channel_parameters, &broadcaster_funding_key, &countersignatory_funding_key).unwrap(); + let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_txout, to_countersignatory_txout, htlcs_with_aux, channel_parameters, &broadcaster_funding_key, &countersignatory_funding_key).unwrap(); let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters); let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); @@ -1486,15 +1491,19 @@ impl CommitmentTransaction { self } - fn internal_rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey, to_countersignatory_spk: ScriptBuf) -> Result { + fn internal_rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey, to_broadcaster_spk: ScriptBuf, to_countersignatory_spk: ScriptBuf) -> Result { let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters); + let to_broadcaster_txout = TxOut { + script_pubkey: to_broadcaster_spk, + value: self.to_broadcaster_value_sat, + }; let to_countersignatory_txout = TxOut { script_pubkey: to_countersignatory_spk, value: self.to_countersignatory_value_sat, }; let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect(); - let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, to_countersignatory_txout, &mut htlcs_with_aux, channel_parameters, broadcaster_funding_key, countersignatory_funding_key)?; + let (outputs, _) = Self::internal_build_outputs(keys, to_broadcaster_txout, to_countersignatory_txout, &mut htlcs_with_aux, channel_parameters, broadcaster_funding_key, countersignatory_funding_key)?; let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); let txid = transaction.compute_txid(); @@ -1518,9 +1527,7 @@ impl CommitmentTransaction { // - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the // caller needs to have sorted together with the HTLCs so it can keep track of the output index // - building of a bitcoin transaction during a verify() call, in which case T is just () - fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: Amount, to_countersignatory_txout: TxOut, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec, Vec), ()> { - let contest_delay = channel_parameters.contest_delay(); - + fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_txout: TxOut, to_countersignatory_txout: TxOut, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec, Vec), ()> { let mut txouts: Vec<(TxOut, Option<&mut HTLCOutputInCommitment>)> = Vec::new(); if to_countersignatory_txout.value > Amount::ZERO { @@ -1530,23 +1537,15 @@ impl CommitmentTransaction { )) } - if to_broadcaster_value_sat > Amount::ZERO { - let redeem_script = get_revokeable_redeemscript( - &keys.revocation_key, - contest_delay, - &keys.broadcaster_delayed_payment_key, - ); + if to_broadcaster_txout.value > Amount::ZERO { txouts.push(( - TxOut { - script_pubkey: redeem_script.to_p2wsh(), - value: to_broadcaster_value_sat, - }, + to_broadcaster_txout.clone(), None, )); } if channel_parameters.channel_type_features().supports_anchors_zero_fee_htlc_tx() { - if to_broadcaster_value_sat > Amount::ZERO || !htlcs_with_aux.is_empty() { + if to_broadcaster_txout.value > Amount::ZERO || !htlcs_with_aux.is_empty() { let anchor_script = get_anchor_redeemscript(broadcaster_funding_key); txouts.push(( TxOut { @@ -1682,14 +1681,14 @@ impl CommitmentTransaction { /// /// An external validating signer must call this method before signing /// or using the built transaction. - pub fn verify(&self, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_keys: &ChannelPublicKeys, countersignatory_keys: &ChannelPublicKeys, secp_ctx: &Secp256k1, to_countersignatory_spk: ScriptBuf) -> Result { + pub fn verify(&self, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_keys: &ChannelPublicKeys, countersignatory_keys: &ChannelPublicKeys, secp_ctx: &Secp256k1, to_broadcaster_spk: ScriptBuf, to_countersignatory_spk: ScriptBuf) -> Result { // This is the only field of the key cache that we trust let per_commitment_point = self.keys.per_commitment_point; let keys = TxCreationKeys::from_channel_static_keys(&per_commitment_point, broadcaster_keys, countersignatory_keys, secp_ctx); if keys != self.keys { return Err(()); } - let tx = self.internal_rebuild_transaction(&keys, channel_parameters, &broadcaster_keys.funding_pubkey, &countersignatory_keys.funding_pubkey, to_countersignatory_spk)?; + let tx = self.internal_rebuild_transaction(&keys, channel_parameters, &broadcaster_keys.funding_pubkey, &countersignatory_keys.funding_pubkey, to_broadcaster_spk, to_countersignatory_spk)?; if self.built.transaction != tx.transaction || self.built.txid != tx.txid { return Err(()); } @@ -1897,7 +1896,7 @@ mod tests { use super::{CounterpartyCommitmentSecrets, ChannelPublicKeys}; use crate::chain; use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment}; - use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1}; + use bitcoin::secp256k1::{self, PublicKey, SecretKey, Secp256k1}; use crate::util::test_utils; use crate::sign::{ChannelSigner, SignerProvider}; use bitcoin::{Amount, TxOut, Network, Txid, ScriptBuf, CompressedPublicKey}; @@ -1921,6 +1920,7 @@ mod tests { channel_parameters: ChannelTransactionParameters, counterparty_pubkeys: ChannelPublicKeys, signer: TestChannelSigner, + secp_ctx: Secp256k1::, } impl TestCommitmentTxBuilder { @@ -1957,10 +1957,16 @@ mod tests { channel_parameters, counterparty_pubkeys, signer, + secp_ctx, } } fn build(&mut self, to_broadcaster_sats: u64, to_countersignatory_sats: u64) -> CommitmentTransaction { + let broadcaster_payment_script = self.signer.get_revokeable_spk(true, self.commitment_number, &self.keys.per_commitment_point, &self.secp_ctx); + let broadcaster_txout = TxOut { + script_pubkey: broadcaster_payment_script, + value: Amount::from_sat(to_broadcaster_sats), + }; let counterparty_payment_script = self.signer.get_counterparty_payment_script(false); let counterparty_txout = TxOut { script_pubkey: counterparty_payment_script, @@ -1968,7 +1974,7 @@ mod tests { }; CommitmentTransaction::new_with_auxiliary_htlc_data( self.commitment_number, - to_broadcaster_sats, + broadcaster_txout, counterparty_txout, self.holder_funding_pubkey.clone(), self.counterparty_funding_pubkey.clone(), diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index c3f42585196..206393e3b35 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -3164,13 +3164,18 @@ impl ChannelContext where SP::Target: SignerProvider { let channel_parameters = if local { self.channel_transaction_parameters.as_holder_broadcastable() } else { self.channel_transaction_parameters.as_counterparty_broadcastable() }; + let broadcaster_payment_script = self.holder_signer.as_ref().get_revokeable_spk(local, commitment_number, &keys.per_commitment_point, &self.secp_ctx); + let broadcaster_txout = TxOut { + script_pubkey: broadcaster_payment_script, + value: Amount::from_sat(value_to_a as u64), + }; let counterparty_payment_script = self.holder_signer.as_ref().get_counterparty_payment_script(!local); let counterparty_txout = TxOut { script_pubkey: counterparty_payment_script, value: Amount::from_sat(value_to_b as u64), }; let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number, - value_to_a as u64, + broadcaster_txout, counterparty_txout, funding_pubkey_a, funding_pubkey_b, diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index a0e45389706..fbf2bd57ab3 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -766,6 +766,11 @@ fn test_update_fee_that_funder_cannot_afford() { |phase| if let ChannelPhase::Funded(chan) = phase { Some(chan) } else { None } ).flatten().unwrap(); let local_chan_signer = local_chan.get_signer(); + let broadcaster_payment_script = local_chan_signer.as_ref().get_revokeable_spk(false, INITIAL_COMMITMENT_NUMBER - 1, &commit_tx_keys.per_commitment_point, &secp_ctx); + let broadcaster_txout = TxOut { + script_pubkey: broadcaster_payment_script, + value: Amount::from_sat(push_sats), + }; let counterparty_payment_script = local_chan_signer.as_ref().get_counterparty_payment_script(true); let counterparty_txout = TxOut { script_pubkey: counterparty_payment_script, @@ -774,7 +779,7 @@ fn test_update_fee_that_funder_cannot_afford() { let mut htlcs: Vec<(HTLCOutputInCommitment, ())> = vec![]; let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data( INITIAL_COMMITMENT_NUMBER - 1, - push_sats, + broadcaster_txout, counterparty_txout, local_funding, remote_funding, commit_tx_keys.clone(), @@ -1522,6 +1527,11 @@ fn test_fee_spike_violation_fails_htlc() { |phase| if let ChannelPhase::Funded(chan) = phase { Some(chan) } else { None } ).flatten().unwrap(); let local_chan_signer = local_chan.get_signer(); + let broadcaster_payment_script = local_chan_signer.as_ref().get_revokeable_spk(false, commitment_number, &commit_tx_keys.per_commitment_point, &secp_ctx); + let broadcaster_txout = TxOut { + script_pubkey: broadcaster_payment_script, + value: Amount::from_sat(95000), + }; let counterparty_payment_script = local_chan_signer.as_ref().get_counterparty_payment_script(true); let counterparty_txout = TxOut { script_pubkey: counterparty_payment_script, @@ -1529,7 +1539,7 @@ fn test_fee_spike_violation_fails_htlc() { }; let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data( commitment_number, - 95000, + broadcaster_txout, counterparty_txout, local_funding, remote_funding, commit_tx_keys.clone(), diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 052cab98b99..bc58de7c543 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -64,6 +64,7 @@ use crate::crypto::chacha20::ChaCha20; use crate::io::{self, Error}; use crate::ln::msgs::DecodeError; use crate::prelude::*; +use crate::sign::chan_utils::TxCreationKeys; use crate::sign::ecdsa::EcdsaChannelSigner; #[cfg(taproot)] use crate::sign::taproot::TaprootChannelSigner; @@ -796,13 +797,28 @@ pub trait ChannelSigner { /// channel_parameters.is_populated() MUST be true. fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); - /// Returns the scriptpubkey that should be placed in the `to_remote` output of commitment - /// transactions. Assumes the signer has already been given the channel parameters via + /// Returns the script pubkey that should be placed in the `to_remote` output of commitment + /// transactions. + /// + /// Assumes the signer has already been given the channel parameters via /// `provide_channel_parameters`. /// - /// If `to_self` is set, return the `to_remote` script pubkey for the counterparty's commitment + /// If `to_self` is set, return the `to_remote` script pubkey for the remote party's commitment /// transaction, otherwise, for the local party's. fn get_counterparty_payment_script(&self, to_self: bool) -> ScriptBuf; + + /// Returns the script pubkey that should be placed in the `to_local` output of commitment + /// transactions, and in the output of second level HTLC transactions. + /// + /// Assumes the signer has already been given the channel parameters via + /// `provide_channel_parameters`. + /// + /// If `to_self` is set, return the revokeable script pubkey for local party's + /// commitment / htlc transaction, otherwise, for the remote party's. + fn get_revokeable_spk( + &self, to_self: bool, commitment_number: u64, per_commitment_point: &PublicKey, + secp_ctx: &Secp256k1, + ) -> ScriptBuf; } /// Specifies the recipient of an invoice. @@ -1405,6 +1421,30 @@ impl ChannelSigner for InMemorySigner { let payment_point = ¶ms.countersignatory_pubkeys().payment_point; get_counterparty_payment_script(params.channel_type_features(), payment_point) } + + fn get_revokeable_spk( + &self, to_self: bool, _commitment_number: u64, per_commitment_point: &PublicKey, + secp_ctx: &Secp256k1, + ) -> ScriptBuf { + let params = if to_self { + self.channel_parameters.as_ref().unwrap().as_holder_broadcastable() + } else { + self.channel_parameters.as_ref().unwrap().as_counterparty_broadcastable() + }; + let contest_delay = params.contest_delay(); + let keys = TxCreationKeys::from_channel_static_keys( + per_commitment_point, + params.broadcaster_pubkeys(), + params.countersignatory_pubkeys(), + secp_ctx, + ); + get_revokeable_redeemscript( + &keys.revocation_key, + contest_delay, + &keys.broadcaster_delayed_payment_key, + ) + .to_p2wsh() + } } const MISSING_PARAMS_ERR: &'static str = diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index af50b209bce..ab483185f28 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -222,6 +222,10 @@ impl ChannelSigner for TestChannelSigner { fn get_counterparty_payment_script(&self, to_self: bool) -> ScriptBuf { self.inner.get_counterparty_payment_script(to_self) } + + fn get_revokeable_spk(&self, to_self: bool, commitment_number: u64, per_commitment_point: &PublicKey, secp_ctx: &Secp256k1) -> ScriptBuf { + self.inner.get_revokeable_spk(to_self, commitment_number, per_commitment_point, secp_ctx) + } } impl EcdsaChannelSigner for TestChannelSigner { @@ -424,20 +428,24 @@ impl Writeable for TestChannelSigner { } impl TestChannelSigner { - fn verify_counterparty_commitment_tx<'a, T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1) -> TrustedCommitmentTransaction<'a> { + fn verify_counterparty_commitment_tx<'a>(&self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1) -> TrustedCommitmentTransaction<'a> { + let broadcaster_spk = self.get_revokeable_spk(false, commitment_tx.commitment_number(), &commitment_tx.per_commitment_point(), secp_ctx); let counterparty_spk = self.get_counterparty_payment_script(true); commitment_tx.verify( &self.inner.get_channel_parameters().unwrap().as_counterparty_broadcastable(), self.inner.counterparty_pubkeys().unwrap(), self.inner.pubkeys(), secp_ctx, + broadcaster_spk, counterparty_spk, ).expect("derived different per-tx keys or built transaction") } - fn verify_holder_commitment_tx<'a, T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1) -> TrustedCommitmentTransaction<'a> { + fn verify_holder_commitment_tx<'a>(&self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1) -> TrustedCommitmentTransaction<'a> { + let broadcaster_spk = self.get_revokeable_spk(true, commitment_tx.commitment_number(), &commitment_tx.per_commitment_point(), secp_ctx); let counterparty_spk = self.get_counterparty_payment_script(false); commitment_tx.verify( &self.inner.get_channel_parameters().unwrap().as_holder_broadcastable(), self.inner.pubkeys(), self.inner.counterparty_pubkeys().unwrap(), secp_ctx, + broadcaster_spk, counterparty_spk, ).expect("derived different per-tx keys or built transaction") }