Skip to content

Commit 6fd9488

Browse files
author
Antoine Riard
committed
Remove signing local commitment transaction from ChannelMonitor
Extend external signer interface to sign local commitment transactions on its behalf without seckey passing. This move will allow us to remove key access from ChannelMonitor hot memory in further work. Local commitment transaction should stay half-signed by remote until we need to broadcast for a channel force-close or a HTLC to timeout onchain.
1 parent e5bedc4 commit 6fd9488

File tree

5 files changed

+34
-7
lines changed

5 files changed

+34
-7
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use util::logger::Logger;
2424
use util::ser::{Writeable, Writer, Readable};
2525

2626
use ln::chan_utils;
27-
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys};
27+
use ln::chan_utils::{TxCreationKeys, HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, LocalCommitmentTransaction};
2828
use ln::msgs;
2929

3030
use std::sync::Arc;
@@ -215,6 +215,13 @@ pub trait ChannelKeys : Send+Clone {
215215
/// making the callee generate it via some util function we expose)!
216216
fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()>;
217217

218+
/// Create a signature for a local commitment transaction
219+
///
220+
/// TODO: Document the things someone using this interface should enforce before signing.
221+
/// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and
222+
/// making the callee generate it via some util function we expose)!
223+
fn sign_local_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, local_commitment_tx: &mut LocalCommitmentTransaction, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>);
224+
218225
/// Create a signature for a (proposed) closing transaction.
219226
///
220227
/// Note that, due to rounding, there may be one "missing" satoshi, and either party may have
@@ -342,6 +349,10 @@ impl ChannelKeys for InMemoryChannelKeys {
342349
Ok((commitment_sig, htlc_sigs))
343350
}
344351

352+
fn sign_local_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, local_commitment_tx: &mut LocalCommitmentTransaction, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) {
353+
local_commitment_tx.add_local_sig(&self.funding_key, funding_redeemscript, channel_value_satoshis, secp_ctx);
354+
}
355+
345356
fn sign_closing_transaction<T: secp256k1::Signing>(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
346357
if closing_tx.input.len() != 1 { return Err(()); }
347358
if closing_tx.input[0].witness.len() != 0 { return Err(()); }

lightning/src/ln/chan_utils.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ pub(crate) fn sign_htlc_transaction<T: secp256k1::Signing>(tx: &mut Transaction,
516516
/// We use this to track local commitment transactions and put off signing them until we are ready
517517
/// to broadcast. Eventually this will require a signer which is possibly external, but for now we
518518
/// just pass in the SecretKeys required.
519-
pub(crate) struct LocalCommitmentTransaction {
519+
pub struct LocalCommitmentTransaction {
520520
tx: Transaction
521521
}
522522
impl LocalCommitmentTransaction {
@@ -530,6 +530,7 @@ impl LocalCommitmentTransaction {
530530
} }
531531
}
532532

533+
/// Generate a new LocalCommitmentTransaction based on a raw commitment transaction, remote signature and both parties keys
533534
pub fn new_missing_local_sig(mut tx: Transaction, their_sig: &Signature, our_funding_key: &PublicKey, their_funding_key: &PublicKey) -> LocalCommitmentTransaction {
534535
if tx.input.len() != 1 { panic!("Tried to store a commitment transaction that had input count != 1!"); }
535536
if tx.input[0].witness.len() != 0 { panic!("Tried to store a signed commitment transaction?"); }
@@ -549,10 +550,12 @@ impl LocalCommitmentTransaction {
549550
Self { tx }
550551
}
551552

553+
/// Get the txid of the local commitment transaction contained in this LocalCommitmentTransaction
552554
pub fn txid(&self) -> Sha256dHash {
553555
self.tx.txid()
554556
}
555557

558+
/// Check if LocalCommitmentTransaction has already been signed by us
556559
pub fn has_local_sig(&self) -> bool {
557560
if self.tx.input.len() != 1 { panic!("Commitment transactions must have input count == 1!"); }
558561
if self.tx.input[0].witness.len() == 4 {
@@ -567,6 +570,11 @@ impl LocalCommitmentTransaction {
567570
}
568571
}
569572

573+
/// Add local signature for LocalCommitmentTransaction, do nothing if signature is already present
574+
///
575+
/// Funding key is your key related to the one part of 2-2 funding_outpoint lock. Should be provided by your ChannelKeys.
576+
/// Funding redeemscript is script locking funding_outpoint. Should be computed based on channel keys provided by your ChannelKeys.
577+
/// Channel value is amount locked in funding_outpoint.
570578
pub fn add_local_sig<T: secp256k1::Signing>(&mut self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) {
571579
if self.has_local_sig() { return; }
572580
let sighash = hash_to_message!(&bip143::SighashComponents::new(&self.tx)
@@ -584,7 +592,9 @@ impl LocalCommitmentTransaction {
584592
self.tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec());
585593
}
586594

595+
/// Get raw transaction without asserting if witness is complete
587596
pub fn without_valid_witness(&self) -> &Transaction { &self.tx }
597+
/// Get raw transaction with asserting witness is complete
588598
pub fn with_valid_witness(&self) -> &Transaction {
589599
assert!(self.has_local_sig());
590600
&self.tx

lightning/src/ln/channel.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4433,7 +4433,7 @@ mod tests {
44334433

44344434
assert_eq!(PublicKey::from_secret_key(&secp_ctx, chan_keys.funding_key()).serialize()[..],
44354435
hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]);
4436-
let keys_provider = Keys { chan_keys };
4436+
let keys_provider = Keys { chan_keys: chan_keys.clone() };
44374437

44384438
let their_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
44394439
let mut config = UserConfig::default();
@@ -4490,7 +4490,7 @@ mod tests {
44904490
secp_ctx.verify(&sighash, &their_signature, chan.their_funding_pubkey()).unwrap();
44914491

44924492
let mut localtx = LocalCommitmentTransaction::new_missing_local_sig(unsigned_tx.0.clone(), &their_signature, &PublicKey::from_secret_key(&secp_ctx, chan.local_keys.funding_key()), chan.their_funding_pubkey());
4493-
localtx.add_local_sig(chan.local_keys.funding_key(), &redeemscript, chan.channel_value_satoshis, &chan.secp_ctx);
4493+
chan_keys.sign_local_commitment(&mut localtx, &redeemscript, chan.channel_value_satoshis, &chan.secp_ctx);
44944494

44954495
assert_eq!(serialize(localtx.with_valid_witness())[..],
44964496
hex::decode($tx_hex).unwrap()[..]);

lightning/src/ln/channelmonitor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,7 +1806,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
18061806
// tracking state and panic!()ing if we get an update after force-closure/local-tx signing.
18071807
log_trace!(self, "Getting signed latest local commitment transaction!");
18081808
if let &mut Some(ref mut local_tx) = &mut self.current_local_signed_commitment_tx {
1809-
local_tx.tx.add_local_sig(&self.onchain_detection.keys.funding_key(), self.funding_redeemscript.as_ref().unwrap(), self.channel_value_satoshis.unwrap(), &self.secp_ctx);
1809+
self.onchain_detection.keys.sign_local_commitment(&mut local_tx.tx, self.funding_redeemscript.as_ref().unwrap(), self.channel_value_satoshis.unwrap(), &self.secp_ctx);
18101810
}
18111811
if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx {
18121812
let mut res = vec![local_tx.tx.with_valid_witness().clone()];
@@ -1888,7 +1888,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
18881888
} else { false };
18891889
if let Some(ref mut cur_local_tx) = self.current_local_signed_commitment_tx {
18901890
if should_broadcast {
1891-
cur_local_tx.tx.add_local_sig(&self.onchain_detection.keys.funding_key(), self.funding_redeemscript.as_ref().unwrap(), self.channel_value_satoshis.unwrap(), &self.secp_ctx);
1891+
self.onchain_detection.keys.sign_local_commitment(&mut cur_local_tx.tx, self.funding_redeemscript.as_ref().unwrap(), self.channel_value_satoshis.unwrap(), &mut self.secp_ctx);
18921892
}
18931893
}
18941894
if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {

lightning/src/util/enforcing_trait_impls.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys, ChannelPublicKeys};
1+
use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys, ChannelPublicKeys, LocalCommitmentTransaction};
22
use ln::msgs;
33
use chain::keysinterface::{ChannelKeys, InMemoryChannelKeys};
44

55
use std::cmp;
66
use std::sync::{Mutex, Arc};
77

88
use bitcoin::blockdata::transaction::Transaction;
9+
use bitcoin::blockdata::script::Script;
10+
911

1012
use secp256k1;
1113
use secp256k1::key::{SecretKey, PublicKey};
@@ -78,6 +80,10 @@ impl ChannelKeys for EnforcingChannelKeys {
7880
Ok(self.inner.sign_remote_commitment(feerate_per_kw, commitment_tx, keys, htlcs, to_self_delay, secp_ctx).unwrap())
7981
}
8082

83+
fn sign_local_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, local_commitment_tx: &mut LocalCommitmentTransaction, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) {
84+
self.inner.sign_local_commitment(local_commitment_tx, funding_redeemscript, channel_value_satoshis, secp_ctx)
85+
}
86+
8187
fn sign_closing_transaction<T: secp256k1::Signing>(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
8288
Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap())
8389
}

0 commit comments

Comments
 (0)