Skip to content

Commit 4a0a1ce

Browse files
committed
Fold sign_holder_commitment_htlc_transactions into sign_holder_commitment
Signing the commitment transaction is almost always followed by signing the attached HTLC transactions, so fold the signing operations into a single method.
1 parent b2f1327 commit 4a0a1ce

File tree

4 files changed

+44
-51
lines changed

4 files changed

+44
-51
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,16 @@ 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 may be the latest
238+
/// tx or it may be the second latest if not revoked and some watchtower/secondary
239+
/// ChannelMonitor decided to broadcast before it had been updated to the latest.
240+
/// This may be called multiple times.
241+
///
239242
/// An external signer implementation should check that the commitment has not been revoked.
240243
//
241244
// 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, ()>;
245+
fn sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
243246

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

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-
263254
/// Create a signature for the given input in a transaction spending an HTLC or commitment
264255
/// transaction output when our counterparty broadcasts an old state.
265256
///
@@ -500,11 +491,14 @@ impl ChannelKeys for InMemoryChannelKeys {
500491
Ok((commitment_sig, htlc_sigs))
501492
}
502493

503-
fn sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
494+
fn sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
504495
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
505496
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
506497
let sig = commitment_tx.trust().built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx);
507-
Ok(sig)
498+
let channel_parameters = self.get_channel_parameters();
499+
let trusted_tx = commitment_tx.trust();
500+
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)?;
501+
Ok((sig, htlc_sigs))
508502
}
509503

510504
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
@@ -514,12 +508,6 @@ impl ChannelKeys for InMemoryChannelKeys {
514508
Ok(commitment_tx.trust().built_transaction().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx))
515509
}
516510

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-
523511
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, ()> {
524512
let revocation_key = match chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key) {
525513
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(&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

lightning/src/ln/onchaintx.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,8 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
490490

491491
/// Lightning security model (i.e being able to redeem/timeout HTLC or penalize coutnerparty onchain) lays on the assumption of claim transactions getting confirmed before timelock expiration
492492
/// (CSV or CLTV following cases). In case of high-fee spikes, claim tx may stuck in the mempool, so you need to bump its feerate quickly using Replace-By-Fee or Child-Pay-For-Parent.
493+
/// Panics if there are signing errors, because signing operations in reaction to on-chain events
494+
/// are not expected to fail, and if they do, we may lose funds.
493495
fn generate_claim_tx<F: Deref, L: Deref>(&mut self, height: u32, cached_claim_datas: &ClaimTxBumpMaterial, fee_estimator: &F, logger: &L) -> Option<(Option<u32>, u32, Transaction)>
494496
where F::Target: FeeEstimator,
495497
L::Target: Logger,
@@ -906,20 +908,29 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
906908

907909
pub(crate) fn provide_latest_holder_tx(&mut self, tx: HolderCommitmentTransaction) {
908910
self.prev_holder_commitment = self.holder_commitment.take();
911+
self.holder_htlc_sigs = None;
909912
self.holder_commitment = Some(tx);
910913
}
911914

915+
// Normally holder HTLCs are signed at the same time as the holder commitment tx. However,
916+
// in some configurations, the holder commitment tx has been signed and broadcast by a secondary
917+
// ChannelMonitor, so we handle that case here.
912918
fn sign_latest_holder_htlcs(&mut self) {
913-
if let Some(ref holder_commitment) = self.holder_commitment {
914-
if let Ok(sigs) = self.key_storage.sign_holder_commitment_htlc_transactions(holder_commitment, &self.secp_ctx) {
919+
if self.holder_htlc_sigs.is_none() {
920+
if let Some(ref holder_commitment) = self.holder_commitment {
921+
let (_sig, sigs) = self.key_storage.sign_holder_commitment(holder_commitment, &self.secp_ctx).expect("sign holder commitment");
915922
self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, sigs));
916923
}
917924
}
918925
}
919926

927+
// Normally only the latest commitment tx and HTLCs need to be signed. However, in some
928+
// configurations we may have updated our holder commtiment but a replica of the ChannelMonitor
929+
// broadcast the previous one before we sync with it. We handle that case here.
920930
fn sign_prev_holder_htlcs(&mut self) {
921-
if let Some(ref holder_commitment) = self.prev_holder_commitment {
922-
if let Ok(sigs) = self.key_storage.sign_holder_commitment_htlc_transactions(holder_commitment, &self.secp_ctx) {
931+
if self.prev_holder_htlc_sigs.is_none() {
932+
if let Some(ref holder_commitment) = self.prev_holder_commitment {
933+
let (_sig, sigs) = self.key_storage.sign_holder_commitment(holder_commitment, &self.secp_ctx).expect("sign previous holder commitment");
923934
self.prev_holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, sigs));
924935
}
925936
}
@@ -941,8 +952,9 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
941952
// to monitor before.
942953
pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Option<Transaction> {
943954
if let Some(ref mut holder_commitment) = self.holder_commitment {
944-
match self.key_storage.sign_holder_commitment(&holder_commitment, &self.secp_ctx) {
945-
Ok(sig) => {
955+
match self.key_storage.sign_holder_commitment(holder_commitment, &self.secp_ctx) {
956+
Ok((sig, htlc_sigs)) => {
957+
self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, htlc_sigs));
946958
Some(holder_commitment.add_holder_sig(funding_redeemscript, sig))
947959
},
948960
Err(_) => return None,
@@ -956,7 +968,8 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
956968
pub(crate) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Option<Transaction> {
957969
if let Some(ref mut holder_commitment) = self.holder_commitment {
958970
match self.key_storage.sign_holder_commitment(holder_commitment, &self.secp_ctx) {
959-
Ok(sig) => {
971+
Ok((sig, htlc_sigs)) => {
972+
self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, htlc_sigs));
960973
Some(holder_commitment.add_holder_sig(funding_redeemscript, sig))
961974
},
962975
Err(_) => return None,
@@ -982,7 +995,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
982995
}
983996
}
984997
}
985-
if self.prev_holder_commitment.is_some() {
998+
if htlc_tx.is_none() && self.prev_holder_commitment.is_some() {
986999
let commitment_txid = self.prev_holder_commitment.as_ref().unwrap().trust().txid();
9871000
if commitment_txid == outp.txid {
9881001
self.sign_prev_holder_htlcs();

lightning/src/util/enforcing_trait_impls.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// licenses.
99

1010
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, HolderCommitmentTransaction, CommitmentTransaction, ChannelTransactionParameters, TrustedCommitmentTransaction};
11-
use ln::{chan_utils, msgs};
11+
use ln::{msgs, chan_utils};
1212
use chain::keysinterface::{ChannelKeys, InMemoryChannelKeys};
1313

1414
use std::cmp;
@@ -72,20 +72,7 @@ impl ChannelKeys for EnforcingChannelKeys {
7272
Ok(self.inner.sign_counterparty_commitment(commitment_tx, secp_ctx).unwrap())
7373
}
7474

75-
fn sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
76-
self.verify_holder_commitment_tx(commitment_tx, secp_ctx);
77-
78-
// TODO: enforce the ChannelKeys contract - error if this commitment was already revoked
79-
// TODO: need the commitment number
80-
Ok(self.inner.sign_holder_commitment(commitment_tx, secp_ctx).unwrap())
81-
}
82-
83-
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
84-
fn unsafe_sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
85-
Ok(self.inner.unsafe_sign_holder_commitment(commitment_tx, secp_ctx).unwrap())
86-
}
87-
88-
fn sign_holder_commitment_htlc_transactions<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Vec<Signature>, ()> {
75+
fn sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
8976
let trusted_tx = self.verify_holder_commitment_tx(commitment_tx, secp_ctx);
9077
let commitment_txid = trusted_tx.txid();
9178
let holder_csv = self.inner.counterparty_selected_contest_delay();
@@ -101,7 +88,14 @@ impl ChannelKeys for EnforcingChannelKeys {
10188
secp_ctx.verify(&sighash, sig, &keys.countersignatory_htlc_key).unwrap();
10289
}
10390

104-
Ok(self.inner.sign_holder_commitment_htlc_transactions(commitment_tx, secp_ctx).unwrap())
91+
// TODO: enforce the ChannelKeys contract - error if this commitment was already revoked
92+
// TODO: need the commitment number
93+
Ok(self.inner.sign_holder_commitment(commitment_tx, secp_ctx).unwrap())
94+
}
95+
96+
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
97+
fn unsafe_sign_holder_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
98+
Ok(self.inner.unsafe_sign_holder_commitment(commitment_tx, secp_ctx).unwrap())
10599
}
106100

107101
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, ()> {

0 commit comments

Comments
 (0)