Skip to content

Commit bee53fa

Browse files
committed
Provide redeem scripts to sign_remote_commitment
1 parent f8b06ec commit bee53fa

File tree

4 files changed

+51
-26
lines changed

4 files changed

+51
-26
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ pub trait ChannelKeys : Send {
142142
/// TODO: Document the things someone using this interface should enforce before signing.
143143
/// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
144144
/// making the callee generate it via some util function we expose)!
145-
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
145+
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>, redeem_scripts: &Vec<Script>) -> Result<(Signature, Vec<Signature>), ()>;
146146

147147
/// Create a signature for a (proposed) closing transaction.
148148
///
@@ -184,8 +184,9 @@ impl ChannelKeys for InMemoryChannelKeys {
184184
fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key }
185185
fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed }
186186

187-
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
187+
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>, redeem_scripts: &Vec<Script>) -> Result<(Signature, Vec<Signature>), ()> {
188188
if commitment_tx.input.len() != 1 { return Err(()); }
189+
if commitment_tx.output.len() != redeem_scripts.len() { return Err(()); }
189190
let commitment_sighash = hash_to_message!(&bip143::SighashComponents::new(&commitment_tx).sighash_all(&commitment_tx.input[0], &channel_funding_redeemscript, channel_value_satoshis)[..]);
190191
let commitment_sig = secp_ctx.sign(&commitment_sighash, &self.funding_key);
191192

lightning/src/ln/channel.rs

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
800800
/// Note that below-dust HTLCs are included in the third return value, but not the second, and
801801
/// sources are provided only for outbound HTLCs in the third return value.
802802
#[inline]
803-
fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) {
803+
fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, usize, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>, Vec<Script>) {
804804
let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number);
805805

806806
let txins = {
@@ -814,7 +814,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
814814
ins
815815
};
816816

817-
let mut txouts: Vec<(TxOut, Option<(HTLCOutputInCommitment, Option<&HTLCSource>)>)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2);
817+
let mut txouts: Vec<(TxOut, Option<(HTLCOutputInCommitment, Option<&HTLCSource>)>, Script)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2);
818818
let mut included_dust_htlcs: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::new();
819819

820820
let dust_limit_satoshis = if local { self.our_dust_limit_satoshis } else { self.their_dust_limit_satoshis };
@@ -842,10 +842,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
842842
let htlc_in_tx = get_htlc_in_commitment!($htlc, true);
843843
if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) {
844844
log_trace!(self, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
845+
let script = chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys);
845846
txouts.push((TxOut {
846-
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
847+
script_pubkey: script.to_v0_p2wsh(),
847848
value: $htlc.amount_msat / 1000
848-
}, Some((htlc_in_tx, $source))));
849+
}, Some((htlc_in_tx, $source)), script));
849850
} else {
850851
log_trace!(self, " ...including {} {} dust HTLC {} (hash {}) with value {} due to dust limit", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
851852
included_dust_htlcs.push((htlc_in_tx, $source));
@@ -854,10 +855,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
854855
let htlc_in_tx = get_htlc_in_commitment!($htlc, false);
855856
if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) {
856857
log_trace!(self, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
858+
let script = chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys);
857859
txouts.push((TxOut { // "received HTLC output"
858-
script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(),
860+
script_pubkey: script.to_v0_p2wsh(),
859861
value: $htlc.amount_msat / 1000
860-
}, Some((htlc_in_tx, $source))));
862+
}, Some((htlc_in_tx, $source)), script));
861863
} else {
862864
log_trace!(self, " ...including {} {} dust HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat);
863865
included_dust_htlcs.push((htlc_in_tx, $source));
@@ -957,25 +959,29 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
957959

958960
if value_to_a >= (dust_limit_satoshis as i64) {
959961
log_trace!(self, " ...including {} output with value {}", if local { "to_local" } else { "to_remote" }, value_to_a);
962+
let script = chan_utils::get_revokeable_redeemscript(&keys.revocation_key,
963+
if local { self.their_to_self_delay } else { self.our_to_self_delay },
964+
&keys.a_delayed_payment_key);
960965
txouts.push((TxOut {
961-
script_pubkey: chan_utils::get_revokeable_redeemscript(&keys.revocation_key,
962-
if local { self.their_to_self_delay } else { self.our_to_self_delay },
963-
&keys.a_delayed_payment_key).to_v0_p2wsh(),
966+
script_pubkey: script.to_v0_p2wsh(),
964967
value: value_to_a as u64
965-
}, None));
968+
}, None, script));
966969
}
967970

968971
if value_to_b >= (dust_limit_satoshis as i64) {
969972
log_trace!(self, " ...including {} output with value {}", if local { "to_remote" } else { "to_local" }, value_to_b);
973+
let script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0)
974+
.push_slice(&Hash160::hash(&keys.b_payment_key.serialize())[..])
975+
.into_script();
976+
// p2wpkh doesn't need a redeem script. Provide a placeholder.
977+
let redeem_script = Builder::new().into_script();
970978
txouts.push((TxOut {
971-
script_pubkey: Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0)
972-
.push_slice(&Hash160::hash(&keys.b_payment_key.serialize())[..])
973-
.into_script(),
979+
script_pubkey: script,
974980
value: value_to_b as u64
975-
}, None));
981+
}, None, redeem_script));
976982
}
977983

978-
transaction_utils::sort_outputs(&mut txouts, |a, b| {
984+
transaction_utils::sort_outputs2(&mut txouts, |a, b| {
979985
if let &Some(ref a_htlc) = a {
980986
if let &Some(ref b_htlc) = b {
981987
a_htlc.0.cltv_expiry.cmp(&b_htlc.0.cltv_expiry)
@@ -990,9 +996,11 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
990996
});
991997

992998
let mut outputs: Vec<TxOut> = Vec::with_capacity(txouts.len());
999+
let mut scripts: Vec<Script> = Vec::with_capacity(txouts.len());
9931000
let mut htlcs_included: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(txouts.len() + included_dust_htlcs.len());
9941001
for (idx, mut out) in txouts.drain(..).enumerate() {
9951002
outputs.push(out.0);
1003+
scripts.push(out.2);
9961004
if let Some((mut htlc, source_option)) = out.1.take() {
9971005
htlc.transaction_output_index = Some(idx as u32);
9981006
htlcs_included.push((htlc, source_option));
@@ -1006,7 +1014,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
10061014
lock_time: ((0x20 as u32) << 8*3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32),
10071015
input: txins,
10081016
output: outputs,
1009-
}, non_dust_htlc_count, htlcs_included)
1017+
}, non_dust_htlc_count, htlcs_included, scripts)
10101018
}
10111019

10121020
#[inline]
@@ -1423,8 +1431,10 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
14231431
let localtx = LocalCommitmentTransaction::new_missing_local_sig(local_initial_commitment_tx, sig, &PublicKey::from_secret_key(&self.secp_ctx, self.local_keys.funding_key()), self.their_funding_pubkey.as_ref().unwrap());
14241432

14251433
let remote_keys = self.build_remote_transaction_keys()?;
1426-
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
1427-
let remote_signature = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
1434+
let commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw);
1435+
let remote_initial_commitment_tx = commitment_tx.0;
1436+
let scripts = commitment_tx.3;
1437+
let remote_signature = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx, &scripts)
14281438
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0;
14291439

14301440
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
@@ -1743,7 +1753,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
17431753
let mut local_commitment_tx = {
17441754
let mut commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, feerate_per_kw);
17451755
let htlcs_cloned: Vec<_> = commitment_tx.2.drain(..).map(|htlc| (htlc.0, htlc.1.map(|h| h.clone()))).collect();
1746-
(commitment_tx.0, commitment_tx.1, htlcs_cloned)
1756+
(commitment_tx.0, commitment_tx.1, htlcs_cloned, commitment_tx.3)
17471757
};
17481758
let local_commitment_txid = local_commitment_tx.0.txid();
17491759
let local_sighash = hash_to_message!(&bip143::SighashComponents::new(&local_commitment_tx.0).sighash_all(&local_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]);
@@ -3149,8 +3159,10 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
31493159
/// If an Err is returned, it is a ChannelError::Close (for get_outbound_funding_created)
31503160
fn get_outbound_funding_created_signature(&mut self) -> Result<(Signature, Transaction), ChannelError> {
31513161
let remote_keys = self.build_remote_transaction_keys()?;
3152-
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
3153-
Ok((self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx)
3162+
let commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw);
3163+
let remote_initial_commitment_tx = commitment_tx.0;
3164+
let scripts = commitment_tx.3;
3165+
Ok((self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), self.feerate_per_kw, &remote_initial_commitment_tx, &remote_keys, &Vec::new(), self.our_to_self_delay, &self.secp_ctx, &scripts)
31543166
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?.0, remote_initial_commitment_tx))
31553167
}
31563168

@@ -3458,7 +3470,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
34583470
htlcs.push(htlc);
34593471
}
34603472

3461-
let res = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), feerate_per_kw, &remote_commitment_tx.0, &remote_keys, &htlcs, self.our_to_self_delay, &self.secp_ctx)
3473+
let res = self.local_keys.sign_remote_commitment(self.channel_value_satoshis, &self.get_funding_redeemscript(), feerate_per_kw, &remote_commitment_tx.0, &remote_keys, &htlcs, self.our_to_self_delay, &self.secp_ctx, &remote_commitment_tx.3)
34623474
.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed"))?;
34633475
signature = res.0;
34643476
htlc_signatures = res.1;

lightning/src/util/enforcing_trait_impls.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ impl ChannelKeys for EnforcingChannelKeys {
3535
fn htlc_base_key(&self) -> &SecretKey { self.inner.htlc_base_key() }
3636
fn commitment_seed(&self) -> &[u8; 32] { self.inner.commitment_seed() }
3737

38-
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_script: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
38+
fn sign_remote_commitment<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_script: &Script, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>, redeem_scripts: &Vec<Script>) -> Result<(Signature, Vec<Signature>), ()> {
3939
if commitment_tx.input.len() != 1 { panic!(); }
40+
if commitment_tx.output.len() != redeem_scripts.len() { panic!(); }
41+
4042
let obscured_commitment_transaction_number = (commitment_tx.lock_time & 0xffffff) as u64 | ((commitment_tx.input[0].sequence as u64 & 0xffffff) << 3*8);
4143

4244
{
@@ -49,7 +51,7 @@ impl ChannelKeys for EnforcingChannelKeys {
4951
commitment_data.1 = cmp::max(commitment_number, commitment_data.1)
5052
}
5153

52-
Ok(self.inner.sign_remote_commitment(channel_value_satoshis, channel_funding_script, feerate_per_kw, commitment_tx, keys, htlcs, to_self_delay, secp_ctx).unwrap())
54+
Ok(self.inner.sign_remote_commitment(channel_value_satoshis, channel_funding_script, feerate_per_kw, commitment_tx, keys, htlcs, to_self_delay, secp_ctx, redeem_scripts).unwrap())
5355
}
5456

5557
fn sign_closing_transaction<T: secp256k1::Signing>(&self, channel_value_satoshis: u64, channel_funding_redeemscript: &Script, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {

lightning/src/util/transaction_utils.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ pub fn sort_outputs<T, C : Fn(&T, &T) -> Ordering>(outputs: &mut Vec<(TxOut, T)>
1212
});
1313
}
1414

15+
pub fn sort_outputs2<T, T1, C : Fn(&T, &T) -> Ordering>(outputs: &mut Vec<(TxOut, T, T1)>, tie_breaker: C) {
16+
outputs.sort_unstable_by(|a, b| {
17+
a.0.value.cmp(&b.0.value).then_with(|| {
18+
a.0.script_pubkey[..].cmp(&b.0.script_pubkey[..]).then_with(|| {
19+
tie_breaker(&a.1, &b.1)
20+
})
21+
})
22+
});
23+
}
24+
1525
#[cfg(test)]
1626
mod tests {
1727
use super::*;

0 commit comments

Comments
 (0)