Skip to content

Commit 9604377

Browse files
committed
Let ChannelSigner set to_remote scriptpubkey
This allows the `to_remote` output to easily be changed according to the features of the channel, or the evolution of the LN specification. `to_remote` 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_remote` script to use, and then pass the script to the `CommitmentTransaction` constructor. External signers now provide the expected `to_remote` script to the `verify` call of `CommitmentTransaction`.
1 parent 1a8bf62 commit 9604377

File tree

6 files changed

+101
-41
lines changed

6 files changed

+101
-41
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,7 +1338,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
13381338
ChannelMonitor { inner: Mutex::new(imp) }
13391339
}
13401340

1341-
pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, keys: Signer, shutdown_script: Option<ScriptBuf>,
1341+
pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, mut keys: Signer, shutdown_script: Option<ScriptBuf>,
13421342
on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, ScriptBuf),
13431343
channel_parameters: &ChannelTransactionParameters, holder_pays_commitment_tx_fee: bool,
13441344
funding_redeemscript: ScriptBuf, channel_value_satoshis: u64,
@@ -1347,10 +1347,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
13471347
best_block: BestBlock, counterparty_node_id: PublicKey, channel_id: ChannelId,
13481348
) -> ChannelMonitor<Signer> {
13491349

1350+
keys.provide_channel_parameters(channel_parameters);
1351+
13501352
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
1351-
let counterparty_payment_script = chan_utils::get_counterparty_payment_script(
1352-
&channel_parameters.channel_type_features, &keys.pubkeys().payment_point
1353-
);
1353+
let counterparty_payment_script = keys.get_counterparty_payment_script(true);
13541354

13551355
let counterparty_channel_parameters = channel_parameters.counterparty_parameters.as_ref().unwrap();
13561356
let counterparty_delayed_payment_base_key = counterparty_channel_parameters.pubkeys.delayed_payment_basepoint;
@@ -3416,9 +3416,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
34163416
&broadcaster_keys, &countersignatory_keys, &self.onchain_tx_handler.secp_ctx);
34173417
let channel_parameters =
34183418
&self.onchain_tx_handler.channel_transaction_parameters.as_counterparty_broadcastable();
3419+
let counterparty_txout = TxOut {
3420+
script_pubkey: self.counterparty_payment_script.clone(),
3421+
value: Amount::from_sat(to_countersignatory_value),
3422+
};
34193423

34203424
CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
3421-
to_broadcaster_value, to_countersignatory_value, broadcaster_funding_key,
3425+
to_broadcaster_value, counterparty_txout, broadcaster_funding_key,
34223426
countersignatory_funding_key, keys, feerate_per_kw, &mut nondust_htlcs,
34233427
channel_parameters)
34243428
}

lightning/src/ln/chan_utils.rs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use bitcoin::sighash::EcdsaSighashType;
2020
use bitcoin::transaction::Version;
2121

2222
use bitcoin::hashes::{Hash, HashEngine};
23-
use bitcoin::hashes::hash160::Hash as Hash160;
2423
use bitcoin::hashes::sha256::Hash as Sha256;
2524
use bitcoin::hashes::ripemd160::Hash as Ripemd160;
2625
use bitcoin::hash_types::Txid;
@@ -1135,7 +1134,13 @@ impl HolderCommitmentTransaction {
11351134
for _ in 0..htlcs.len() {
11361135
counterparty_htlc_sigs.push(dummy_sig);
11371136
}
1138-
let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters.as_counterparty_broadcastable());
1137+
let channel_parameters = channel_parameters.as_counterparty_broadcastable();
1138+
let counterparty_payment_script = get_counterparty_payment_script(&channel_parameters.channel_type_features(), &channel_parameters.countersignatory_pubkeys().payment_point);
1139+
let counterparty_txout = TxOut {
1140+
script_pubkey: counterparty_payment_script,
1141+
value: Amount::ZERO,
1142+
};
1143+
let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, counterparty_txout, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters);
11391144
htlcs.sort_by_key(|htlc| htlc.0.transaction_output_index);
11401145
HolderCommitmentTransaction {
11411146
inner,
@@ -1445,12 +1450,12 @@ impl CommitmentTransaction {
14451450
/// Only include HTLCs that are above the dust limit for the channel.
14461451
///
14471452
/// This is not exported to bindings users due to the generic though we likely should expose a version without
1448-
pub fn new_with_auxiliary_htlc_data<T>(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, 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 {
1453+
pub fn new_with_auxiliary_htlc_data<T>(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 {
14491454
let to_broadcaster_value_sat = Amount::from_sat(to_broadcaster_value_sat);
1450-
let to_countersignatory_value_sat = Amount::from_sat(to_countersignatory_value_sat);
1455+
let to_countersignatory_value_sat = to_countersignatory_txout.value;
14511456

14521457
// Sort outputs and populate output indices while keeping track of the auxiliary data
1453-
let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, &broadcaster_funding_key, &countersignatory_funding_key).unwrap();
1458+
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();
14541459

14551460
let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters);
14561461
let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
@@ -1479,11 +1484,15 @@ impl CommitmentTransaction {
14791484
self
14801485
}
14811486

1482-
fn internal_rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<BuiltCommitmentTransaction, ()> {
1487+
fn internal_rebuild_transaction(&self, keys: &TxCreationKeys, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey, to_countersignatory_spk: ScriptBuf) -> Result<BuiltCommitmentTransaction, ()> {
14831488
let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters);
14841489

1490+
let to_countersignatory_txout = TxOut {
1491+
script_pubkey: to_countersignatory_spk,
1492+
value: self.to_countersignatory_value_sat,
1493+
};
14851494
let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect();
1486-
let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, broadcaster_funding_key, countersignatory_funding_key)?;
1495+
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)?;
14871496

14881497
let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs);
14891498
let txid = transaction.compute_txid();
@@ -1507,23 +1516,14 @@ impl CommitmentTransaction {
15071516
// - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the
15081517
// caller needs to have sorted together with the HTLCs so it can keep track of the output index
15091518
// - building of a bitcoin transaction during a verify() call, in which case T is just ()
1510-
fn internal_build_outputs<T>(keys: &TxCreationKeys, to_broadcaster_value_sat: Amount, to_countersignatory_value_sat: Amount, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec<TxOut>, Vec<HTLCOutputInCommitment>), ()> {
1511-
let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys();
1519+
fn internal_build_outputs<T>(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<TxOut>, Vec<HTLCOutputInCommitment>), ()> {
15121520
let contest_delay = channel_parameters.contest_delay();
15131521

15141522
let mut txouts: Vec<(TxOut, Option<&mut HTLCOutputInCommitment>)> = Vec::new();
15151523

1516-
if to_countersignatory_value_sat > Amount::ZERO {
1517-
let script = if channel_parameters.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
1518-
get_to_countersignatory_with_anchors_redeemscript(&countersignatory_pubkeys.payment_point).to_p2wsh()
1519-
} else {
1520-
ScriptBuf::new_p2wpkh(&Hash160::hash(&countersignatory_pubkeys.payment_point.serialize()).into())
1521-
};
1524+
if to_countersignatory_txout.value > Amount::ZERO {
15221525
txouts.push((
1523-
TxOut {
1524-
script_pubkey: script.clone(),
1525-
value: to_countersignatory_value_sat,
1526-
},
1526+
to_countersignatory_txout.clone(),
15271527
None,
15281528
))
15291529
}
@@ -1555,7 +1555,7 @@ impl CommitmentTransaction {
15551555
));
15561556
}
15571557

1558-
if to_countersignatory_value_sat > Amount::ZERO || !htlcs_with_aux.is_empty() {
1558+
if to_countersignatory_txout.value > Amount::ZERO || !htlcs_with_aux.is_empty() {
15591559
let anchor_script = get_anchor_redeemscript(countersignatory_funding_key);
15601560
txouts.push((
15611561
TxOut {
@@ -1680,14 +1680,14 @@ impl CommitmentTransaction {
16801680
///
16811681
/// An external validating signer must call this method before signing
16821682
/// or using the built transaction.
1683-
pub fn verify<T: secp256k1::Signing + secp256k1::Verification>(&self, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_keys: &ChannelPublicKeys, countersignatory_keys: &ChannelPublicKeys, secp_ctx: &Secp256k1<T>) -> Result<TrustedCommitmentTransaction, ()> {
1683+
pub fn verify<T: secp256k1::Signing + secp256k1::Verification>(&self, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_keys: &ChannelPublicKeys, countersignatory_keys: &ChannelPublicKeys, secp_ctx: &Secp256k1<T>, to_countersignatory_spk: ScriptBuf) -> Result<TrustedCommitmentTransaction, ()> {
16841684
// This is the only field of the key cache that we trust
16851685
let per_commitment_point = self.keys.per_commitment_point;
16861686
let keys = TxCreationKeys::from_channel_static_keys(&per_commitment_point, broadcaster_keys, countersignatory_keys, secp_ctx);
16871687
if keys != self.keys {
16881688
return Err(());
16891689
}
1690-
let tx = self.internal_rebuild_transaction(&keys, channel_parameters, &broadcaster_keys.funding_pubkey, &countersignatory_keys.funding_pubkey)?;
1690+
let tx = self.internal_rebuild_transaction(&keys, channel_parameters, &broadcaster_keys.funding_pubkey, &countersignatory_keys.funding_pubkey, to_countersignatory_spk)?;
16911691
if self.built.transaction != tx.transaction || self.built.txid != tx.txid {
16921692
return Err(());
16931693
}
@@ -1894,11 +1894,11 @@ pub fn get_commitment_transaction_number_obscure_factor(
18941894
mod tests {
18951895
use super::{CounterpartyCommitmentSecrets, ChannelPublicKeys};
18961896
use crate::chain;
1897-
use crate::ln::chan_utils::{get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment};
1897+
use crate::ln::chan_utils::{get_counterparty_payment_script, get_htlc_redeemscript, get_to_countersignatory_with_anchors_redeemscript, CommitmentTransaction, TxCreationKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, HTLCOutputInCommitment};
18981898
use bitcoin::secp256k1::{PublicKey, SecretKey, Secp256k1};
18991899
use crate::util::test_utils;
19001900
use crate::sign::{ChannelSigner, SignerProvider};
1901-
use bitcoin::{Network, Txid, ScriptBuf, CompressedPublicKey};
1901+
use bitcoin::{Amount, TxOut, Network, Txid, ScriptBuf, CompressedPublicKey};
19021902
use bitcoin::hashes::Hash;
19031903
use bitcoin::hex::FromHex;
19041904
use crate::types::payment::PaymentHash;
@@ -1957,12 +1957,20 @@ mod tests {
19571957
}
19581958

19591959
fn build(&mut self, to_broadcaster_sats: u64, to_countersignatory_sats: u64) -> CommitmentTransaction {
1960+
let channel_parameters = self.channel_parameters.as_holder_broadcastable();
1961+
let counterparty_payment_script = get_counterparty_payment_script(&channel_parameters.channel_type_features(), &channel_parameters.countersignatory_pubkeys().payment_point);
1962+
let counterparty_txout = TxOut {
1963+
script_pubkey: counterparty_payment_script,
1964+
value: Amount::from_sat(to_countersignatory_sats),
1965+
};
19601966
CommitmentTransaction::new_with_auxiliary_htlc_data(
1961-
self.commitment_number, to_broadcaster_sats, to_countersignatory_sats,
1967+
self.commitment_number,
1968+
to_broadcaster_sats,
1969+
counterparty_txout,
19621970
self.holder_funding_pubkey.clone(),
19631971
self.counterparty_funding_pubkey.clone(),
19641972
self.keys.clone(), self.feerate_per_kw,
1965-
&mut self.htlcs_with_aux, &self.channel_parameters.as_holder_broadcastable()
1973+
&mut self.htlcs_with_aux, &channel_parameters,
19661974
)
19671975
}
19681976
}

lightning/src/ln/channel.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bitcoin::sighash;
1515
use bitcoin::sighash::EcdsaSighashType;
1616
use bitcoin::consensus::encode;
1717
use bitcoin::absolute::LockTime;
18-
use bitcoin::Weight;
18+
use bitcoin::{TxOut, Weight};
1919

2020
use bitcoin::hashes::Hash;
2121
use bitcoin::hashes::sha256::Hash as Sha256;
@@ -1609,8 +1609,7 @@ trait InitialRemoteCommitmentReceiver<SP: Deref> where SP::Target: SignerProvide
16091609
let funding_txo_script = funding_redeemscript.to_p2wsh();
16101610
let obscure_factor = get_commitment_transaction_number_obscure_factor(&context.get_holder_pubkeys().payment_point, &context.get_counterparty_pubkeys().payment_point, context.is_outbound());
16111611
let shutdown_script = context.shutdown_scriptpubkey.clone().map(|script| script.into_inner());
1612-
let mut monitor_signer = signer_provider.derive_channel_signer(context.channel_value_satoshis, context.channel_keys_id);
1613-
monitor_signer.provide_channel_parameters(&context.channel_transaction_parameters);
1612+
let monitor_signer = signer_provider.derive_channel_signer(context.channel_value_satoshis, context.channel_keys_id);
16141613
let channel_monitor = ChannelMonitor::new(context.secp_ctx.clone(), monitor_signer,
16151614
shutdown_script, context.get_holder_selected_contest_delay(),
16161615
&context.destination_script, (funding_txo, funding_txo_script),
@@ -3165,9 +3164,14 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
31653164
let channel_parameters =
31663165
if local { self.channel_transaction_parameters.as_holder_broadcastable() }
31673166
else { self.channel_transaction_parameters.as_counterparty_broadcastable() };
3167+
let counterparty_payment_script = self.holder_signer.as_ref().get_counterparty_payment_script(!local);
3168+
let counterparty_txout = TxOut {
3169+
script_pubkey: counterparty_payment_script,
3170+
value: Amount::from_sat(value_to_b as u64),
3171+
};
31683172
let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
31693173
value_to_a as u64,
3170-
value_to_b as u64,
3174+
counterparty_txout,
31713175
funding_pubkey_a,
31723176
funding_pubkey_b,
31733177
keys.clone(),
@@ -10863,6 +10867,7 @@ mod tests {
1086310867
use crate::ln::channel::{HTLCOutputInCommitment ,TxCreationKeys};
1086410868
use crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint};
1086510869
use crate::ln::chan_utils::{ChannelPublicKeys, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
10870+
use crate::sign::type_resolver::ChannelSignerType;
1086610871
use crate::util::logger::Logger;
1086710872
use crate::sync::Arc;
1086810873
use core::str::FromStr;
@@ -10936,13 +10941,19 @@ mod tests {
1093610941
macro_rules! test_commitment {
1093710942
( $counterparty_sig_hex: expr, $sig_hex: expr, $tx_hex: expr, $($remain:tt)* ) => {
1093810943
chan.context.channel_transaction_parameters.channel_type_features = ChannelTypeFeatures::only_static_remote_key();
10944+
let mut holder_signer = keys_provider.derive_channel_signer(chan.context.channel_value_satoshis, chan.context.channel_keys_id);
10945+
holder_signer.provide_channel_parameters(&chan.context.channel_transaction_parameters);
10946+
chan.context.holder_signer = ChannelSignerType::Ecdsa(holder_signer);
1093910947
test_commitment_common!($counterparty_sig_hex, $sig_hex, $tx_hex, &ChannelTypeFeatures::only_static_remote_key(), $($remain)*);
1094010948
};
1094110949
}
1094210950

1094310951
macro_rules! test_commitment_with_anchors {
1094410952
( $counterparty_sig_hex: expr, $sig_hex: expr, $tx_hex: expr, $($remain:tt)* ) => {
1094510953
chan.context.channel_transaction_parameters.channel_type_features = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
10954+
let mut holder_signer = keys_provider.derive_channel_signer(chan.context.channel_value_satoshis, chan.context.channel_keys_id);
10955+
holder_signer.provide_channel_parameters(&chan.context.channel_transaction_parameters);
10956+
chan.context.holder_signer = ChannelSignerType::Ecdsa(holder_signer);
1094610957
test_commitment_common!($counterparty_sig_hex, $sig_hex, $tx_hex, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), $($remain)*);
1094710958
};
1094810959
}

lightning/src/ln/functional_tests.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,11 +766,16 @@ fn test_update_fee_that_funder_cannot_afford() {
766766
|phase| if let ChannelPhase::Funded(chan) = phase { Some(chan) } else { None }
767767
).flatten().unwrap();
768768
let local_chan_signer = local_chan.get_signer();
769+
let counterparty_payment_script = local_chan_signer.as_ref().get_counterparty_payment_script(true);
770+
let counterparty_txout = TxOut {
771+
script_pubkey: counterparty_payment_script,
772+
value: Amount::from_sat(channel_value - push_sats - commit_tx_fee_msat(non_buffer_feerate + 4, 0, &channel_type_features) / 1000),
773+
};
769774
let mut htlcs: Vec<(HTLCOutputInCommitment, ())> = vec![];
770775
let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
771776
INITIAL_COMMITMENT_NUMBER - 1,
772777
push_sats,
773-
channel_value - push_sats - commit_tx_fee_msat(non_buffer_feerate + 4, 0, &channel_type_features) / 1000,
778+
counterparty_txout,
774779
local_funding, remote_funding,
775780
commit_tx_keys.clone(),
776781
non_buffer_feerate + 4,
@@ -1521,10 +1526,15 @@ fn test_fee_spike_violation_fails_htlc() {
15211526
|phase| if let ChannelPhase::Funded(chan) = phase { Some(chan) } else { None }
15221527
).flatten().unwrap();
15231528
let local_chan_signer = local_chan.get_signer();
1529+
let counterparty_payment_script = local_chan_signer.as_ref().get_counterparty_payment_script(true);
1530+
let counterparty_txout = TxOut {
1531+
script_pubkey: counterparty_payment_script,
1532+
value: Amount::from_sat(local_chan_balance),
1533+
};
15241534
let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
15251535
commitment_number,
15261536
95000,
1527-
local_chan_balance,
1537+
counterparty_txout,
15281538
local_funding, remote_funding,
15291539
commit_tx_keys.clone(),
15301540
feerate_per_kw,

0 commit comments

Comments
 (0)