Skip to content

Commit ec310b8

Browse files
committed
Enable signing a justice tx using the channel monitor
1 parent 35e06e7 commit ec310b8

File tree

1 file changed

+42
-2
lines changed

1 file changed

+42
-2
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
3131

3232
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
3333
use bitcoin::secp256k1::{SecretKey, PublicKey};
34-
use bitcoin::secp256k1;
34+
use bitcoin::{secp256k1, EcdsaSighashType};
3535

3636
use crate::ln::channel::INITIAL_COMMITMENT_NUMBER;
3737
use crate::ln::{PaymentHash, PaymentPreimage};
@@ -1438,7 +1438,8 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
14381438
/// This is provided so that watchtower clients in the persistence pipeline are able to build
14391439
/// justice transactions for each counterparty commitment upon each update. It's intended to be
14401440
/// used within an implementation of [`Persist::update_persisted_channel`], which is provided
1441-
/// with a monitor and an update.
1441+
/// with a monitor and an update. Once revoked, signing a justice transaction can be done using
1442+
/// [`Self::sign_justice_tx`].
14421443
///
14431444
/// It is expected that a watchtower may use this method to retrieve the latest counterparty
14441445
/// commitment transaction(s), and then hold the necessary data until a later update in which
@@ -1454,6 +1455,20 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
14541455
self.inner.lock().unwrap().counterparty_commitment_txs_from_update(update)
14551456
}
14561457

1458+
/// Wrapper around [`EcdsaChannelSigner::sign_justice_revoked_output`] to make
1459+
/// signing the justice transaction easier for implementors of
1460+
/// [`chain::chainmonitor::Persist`]. On success this method returns a fully signed
1461+
/// transaction that is ready to be broadcasted.
1462+
///
1463+
/// This method will only succeed if this monitor has received the revocation secret for the
1464+
/// provided commitment number.
1465+
///
1466+
/// [`EcdsaChannelSigner::sign_justice_revoked_output`]: crate::sign::EcdsaChannelSigner::sign_justice_revoked_output
1467+
/// [`Persist`]: crate::chain::chainmonitor::Persist
1468+
pub fn sign_justice_tx(&self, justice_tx: Transaction, input_idx: usize, value: u64, commitment_number: u64) -> Result<Transaction, ()> {
1469+
self.inner.lock().unwrap().sign_justice_tx(justice_tx, input_idx, value, commitment_number)
1470+
}
1471+
14571472
pub(crate) fn get_min_seen_secret(&self) -> u64 {
14581473
self.inner.lock().unwrap().get_min_seen_secret()
14591474
}
@@ -2834,6 +2849,31 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
28342849
}).collect()
28352850
}
28362851

2852+
pub(crate) fn sign_justice_tx(
2853+
&self, mut justice_tx: Transaction, input_idx: usize, value: u64, commitment_number: u64
2854+
) -> Result<Transaction, ()> {
2855+
let secret = self.get_secret(commitment_number).ok_or(())?;
2856+
let per_commitment_key = SecretKey::from_slice(&secret).map_err(|_| ())?;
2857+
let their_per_commitment_point = PublicKey::from_secret_key(
2858+
&self.onchain_tx_handler.secp_ctx, &per_commitment_key);
2859+
2860+
let revocation_pubkey = chan_utils::derive_public_revocation_key(
2861+
&self.onchain_tx_handler.secp_ctx, &their_per_commitment_point,
2862+
&self.holder_revocation_basepoint);
2863+
let delayed_key = chan_utils::derive_public_key(&self.onchain_tx_handler.secp_ctx,
2864+
&their_per_commitment_point,
2865+
&self.counterparty_commitment_params.counterparty_delayed_payment_base_key);
2866+
let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey,
2867+
self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key);
2868+
2869+
let sig = self.onchain_tx_handler.signer.sign_justice_revoked_output(
2870+
&justice_tx, input_idx, value, &per_commitment_key, &self.onchain_tx_handler.secp_ctx)?;
2871+
justice_tx.input[input_idx].witness.push_bitcoin_signature(&sig.serialize_der(), EcdsaSighashType::All);
2872+
justice_tx.input[input_idx].witness.push(&[1u8]);
2873+
justice_tx.input[input_idx].witness.push(revokeable_redeemscript.as_bytes());
2874+
Ok(justice_tx)
2875+
}
2876+
28372877
/// Can only fail if idx is < get_min_seen_secret
28382878
fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
28392879
self.commitment_secrets.get_secret(idx)

0 commit comments

Comments
 (0)