Skip to content

Commit 21a44da

Browse files
authored
Merge pull request #770 from lightning-signer/holder-htlc-sigs
Fold sign_holder_commitment_htlc_transactions into sign_holder_commitment
2 parents b73e5fc + 0b20cf6 commit 21a44da

File tree

5 files changed

+128
-156
lines changed

5 files changed

+128
-156
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -969,7 +969,6 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
969969

970970
let key_derivation_params = keys.key_derivation_params();
971971
let holder_revocation_basepoint = keys.pubkeys().revocation_basepoint;
972-
let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys, channel_parameters.clone());
973972

974973
let secp_ctx = Secp256k1::new();
975974

@@ -991,7 +990,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
991990
};
992991
(holder_commitment_tx, trusted_tx.commitment_number())
993992
};
994-
onchain_tx_handler.provide_latest_holder_tx(initial_holder_commitment_tx);
993+
994+
let onchain_tx_handler =
995+
OnchainTxHandler::new(destination_script.clone(), keys, channel_parameters.clone(), initial_holder_commitment_tx);
995996

996997
let mut outputs_to_watch = HashMap::new();
997998
outputs_to_watch.insert(funding_info.0.txid, vec![(funding_info.0.index as u32, funding_info.1.clone())]);
@@ -1725,28 +1726,26 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17251726
pub fn get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
17261727
log_trace!(logger, "Getting signed latest holder commitment transaction!");
17271728
self.holder_tx_signed = true;
1728-
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) {
1729-
let txid = commitment_tx.txid();
1730-
let mut res = vec![commitment_tx];
1731-
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
1732-
if let Some(vout) = htlc.0.transaction_output_index {
1733-
let preimage = if !htlc.0.offered {
1734-
if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
1735-
// We can't build an HTLC-Success transaction without the preimage
1736-
continue;
1737-
}
1738-
} else { None };
1739-
if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
1740-
&::bitcoin::OutPoint { txid, vout }, &preimage) {
1741-
res.push(htlc_tx);
1729+
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
1730+
let txid = commitment_tx.txid();
1731+
let mut res = vec![commitment_tx];
1732+
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
1733+
if let Some(vout) = htlc.0.transaction_output_index {
1734+
let preimage = if !htlc.0.offered {
1735+
if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
1736+
// We can't build an HTLC-Success transaction without the preimage
1737+
continue;
17421738
}
1739+
} else { None };
1740+
if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
1741+
&::bitcoin::OutPoint { txid, vout }, &preimage) {
1742+
res.push(htlc_tx);
17431743
}
17441744
}
1745-
// We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
1746-
// The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation.
1747-
return res
17481745
}
1749-
Vec::new()
1746+
// We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
1747+
// The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation.
1748+
return res;
17501749
}
17511750

17521751
/// Unsafe test-only version of get_latest_holder_commitment_txn used by our test framework
@@ -1755,26 +1754,24 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17551754
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
17561755
pub fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
17571756
log_trace!(logger, "Getting signed copy of latest holder commitment transaction!");
1758-
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript) {
1759-
let txid = commitment_tx.txid();
1760-
let mut res = vec![commitment_tx];
1761-
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
1762-
if let Some(vout) = htlc.0.transaction_output_index {
1763-
let preimage = if !htlc.0.offered {
1764-
if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
1765-
// We can't build an HTLC-Success transaction without the preimage
1766-
continue;
1767-
}
1768-
} else { None };
1769-
if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx(
1770-
&::bitcoin::OutPoint { txid, vout }, &preimage) {
1771-
res.push(htlc_tx);
1757+
let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript);
1758+
let txid = commitment_tx.txid();
1759+
let mut res = vec![commitment_tx];
1760+
for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
1761+
if let Some(vout) = htlc.0.transaction_output_index {
1762+
let preimage = if !htlc.0.offered {
1763+
if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
1764+
// We can't build an HTLC-Success transaction without the preimage
1765+
continue;
17721766
}
1767+
} else { None };
1768+
if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx(
1769+
&::bitcoin::OutPoint { txid, vout }, &preimage) {
1770+
res.push(htlc_tx);
17731771
}
17741772
}
1775-
return res
17761773
}
1777-
Vec::new()
1774+
return res
17781775
}
17791776

17801777
/// Processes transactions in a newly connected block, which may result in any of the following:
@@ -1853,15 +1850,14 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
18531850
}
18541851
if should_broadcast {
18551852
self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
1856-
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) {
1857-
self.holder_tx_signed = true;
1858-
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx);
1859-
let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
1860-
if !new_outputs.is_empty() {
1861-
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
1862-
}
1863-
claimable_outpoints.append(&mut new_outpoints);
1864-
}
1853+
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
1854+
self.holder_tx_signed = true;
1855+
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx);
1856+
let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
1857+
if !new_outputs.is_empty() {
1858+
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
1859+
}
1860+
claimable_outpoints.append(&mut new_outpoints);
18651861
}
18661862
if let Some(events) = self.onchain_events_waiting_threshold_conf.remove(&height) {
18671863
for ev in events {

lightning/src/chain/keysinterface.rs

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,21 @@ pub trait ChannelKeys : Send+Clone + Writeable {
233233
// TODO: Document the things someone using this interface should enforce before signing.
234234
fn sign_counterparty_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &CommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
235235

236-
/// Create a signature for a holder's commitment transaction. This will only ever be called with
237-
/// the same commitment_tx (or a copy thereof), though there are currently no guarantees
238-
/// that it will not be called multiple times.
236+
/// Create a signatures for a holder's commitment transaction and its claiming HTLC transactions.
237+
/// This will only ever be called with a non-revoked commitment_tx. This will be called with the
238+
/// latest commitment_tx when we initiate a force-close.
239+
/// This will be called with the previous latest, just to get claiming HTLC signatures, if we are
240+
/// reacting to a ChannelMonitor replica that decided to broadcast before it had been updated to
241+
/// the latest.
242+
/// This may be called multiple times for the same transaction.
243+
///
239244
/// An external signer implementation should check that the commitment has not been revoked.
245+
///
246+
/// May return Err if key derivation fails. Callers, such as ChannelMonitor, will panic in such a case.
240247
//
241248
// TODO: Document the things someone using this interface should enforce before signing.
242-
fn sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
249+
// TODO: Key derivation failure should panic rather than Err
250+
fn sign_holder_commitment_and_htlcs<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
243251

244252
/// Same as sign_holder_commitment, but exists only for tests to get access to holder commitment
245253
/// transactions which will be broadcasted later, after the channel has moved on to a newer
@@ -248,18 +256,6 @@ pub trait ChannelKeys : Send+Clone + Writeable {
248256
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
249257
fn unsafe_sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
250258

251-
/// Create a signature for each HTLC transaction spending a holder's commitment transaction.
252-
///
253-
/// Unlike sign_holder_commitment, this may be called multiple times with *different*
254-
/// commitment_tx values. While this will never be called with a revoked
255-
/// commitment_tx, it is possible that it is called with the second-latest
256-
/// commitment_tx (only if we haven't yet revoked it) if some watchtower/secondary
257-
/// ChannelMonitor decided to broadcast before it had been updated to the latest.
258-
///
259-
/// Either an Err should be returned, or a Vec with one entry for each HTLC which exists in
260-
/// commitment_tx.
261-
fn sign_holder_commitment_htlc_transactions<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Vec<Signature>, ()>;
262-
263259
/// Create a signature for the given input in a transaction spending an HTLC or commitment
264260
/// transaction output when our counterparty broadcasts an old state.
265261
///
@@ -500,11 +496,14 @@ impl ChannelKeys for InMemoryChannelKeys {
500496
Ok((commitment_sig, htlc_sigs))
501497
}
502498

503-
fn sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
499+
fn sign_holder_commitment_and_htlcs<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
504500
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
505501
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
506502
let sig = commitment_tx.trust().built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx);
507-
Ok(sig)
503+
let channel_parameters = self.get_channel_parameters();
504+
let trusted_tx = commitment_tx.trust();
505+
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)?;
506+
Ok((sig, htlc_sigs))
508507
}
509508

510509
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
@@ -514,12 +513,6 @@ impl ChannelKeys for InMemoryChannelKeys {
514513
Ok(commitment_tx.trust().built_transaction().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx))
515514
}
516515

517-
fn sign_holder_commitment_htlc_transactions<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Vec<Signature>, ()> {
518-
let channel_parameters = self.get_channel_parameters();
519-
let trusted_tx = commitment_tx.trust();
520-
trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)
521-
}
522-
523516
fn sign_justice_transaction<T: secp256k1::Signing + secp256k1::Verification>(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &Option<HTLCOutputInCommitment>, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
524517
let revocation_key = match chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key) {
525518
Ok(revocation_key) => revocation_key,

lightning/src/ln/channel.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4742,15 +4742,13 @@ mod tests {
47424742
&chan.holder_keys.pubkeys().funding_pubkey,
47434743
chan.counterparty_funding_pubkey()
47444744
);
4745-
let holder_sig = chan_keys.sign_holder_commitment(&holder_commitment_tx, &secp_ctx).unwrap();
4745+
let (holder_sig, htlc_sigs) = chan_keys.sign_holder_commitment_and_htlcs(&holder_commitment_tx, &secp_ctx).unwrap();
47464746
assert_eq!(Signature::from_der(&hex::decode($sig_hex).unwrap()[..]).unwrap(), holder_sig, "holder_sig");
47474747

47484748
let funding_redeemscript = chan.get_funding_redeemscript();
47494749
let tx = holder_commitment_tx.add_holder_sig(&funding_redeemscript, holder_sig);
47504750
assert_eq!(serialize(&tx)[..], hex::decode($tx_hex).unwrap()[..], "tx");
47514751

4752-
let htlc_sigs = chan_keys.sign_holder_commitment_htlc_transactions(&holder_commitment_tx, &secp_ctx).unwrap();
4753-
47544752
// ((htlc, counterparty_sig), (index, holder_sig))
47554753
let mut htlc_sig_iter = holder_commitment_tx.htlcs().iter().zip(&holder_commitment_tx.counterparty_htlc_sigs).zip(htlc_sigs.iter().enumerate());
47564754

0 commit comments

Comments
 (0)