Skip to content

Commit 32d6e91

Browse files
authored
Merge pull request #2337 from alecchendev/2023-06-watchtower-support
Support third-party watchtowers in persistence pipeline
2 parents 0211daa + b20b1db commit 32d6e91

File tree

7 files changed

+632
-93
lines changed

7 files changed

+632
-93
lines changed

lightning/src/chain/chainmonitor.rs

+11
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,17 @@ impl MonitorUpdateId {
9494
/// [`ChannelMonitorUpdateStatus::PermanentFailure`], in which case the channel will likely be
9595
/// closed without broadcasting the latest state. See
9696
/// [`ChannelMonitorUpdateStatus::PermanentFailure`] for more details.
97+
///
98+
/// Third-party watchtowers may be built as a part of an implementation of this trait, with the
99+
/// advantage that you can control whether to resume channel operation depending on if an update
100+
/// has been persisted to a watchtower. For this, you may find the following methods useful:
101+
/// [`ChannelMonitor::initial_counterparty_commitment_tx`],
102+
/// [`ChannelMonitor::counterparty_commitment_txs_from_update`],
103+
/// [`ChannelMonitor::sign_to_local_justice_tx`], [`TrustedCommitmentTransaction::revokeable_output_index`],
104+
/// [`TrustedCommitmentTransaction::build_to_local_justice_tx`].
105+
///
106+
/// [`TrustedCommitmentTransaction::revokeable_output_index`]: crate::ln::chan_utils::TrustedCommitmentTransaction::revokeable_output_index
107+
/// [`TrustedCommitmentTransaction::build_to_local_justice_tx`]: crate::ln::chan_utils::TrustedCommitmentTransaction::build_to_local_justice_tx
97108
pub trait Persist<ChannelSigner: WriteableEcdsaChannelSigner> {
98109
/// Persist a new channel's data in response to a [`chain::Watch::watch_channel`] call. This is
99110
/// called by [`ChannelManager`] for new channels, or may be called directly, e.g. on startup.

lightning/src/chain/channelmonitor.rs

+213-4
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ 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

36+
use crate::ln::channel::INITIAL_COMMITMENT_NUMBER;
3637
use crate::ln::{PaymentHash, PaymentPreimage};
3738
use crate::ln::msgs::DecodeError;
3839
use crate::ln::chan_utils;
39-
use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction};
40+
use crate::ln::chan_utils::{CommitmentTransaction, CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCClaim, ChannelTransactionParameters, HolderCommitmentTransaction, TxCreationKeys};
4041
use crate::ln::channelmanager::{HTLCSource, SentHTLCId};
4142
use crate::chain;
4243
use crate::chain::{BestBlock, WatchedOutput};
@@ -502,6 +503,9 @@ pub(crate) enum ChannelMonitorUpdateStep {
502503
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
503504
commitment_number: u64,
504505
their_per_commitment_point: PublicKey,
506+
feerate_per_kw: Option<u32>,
507+
to_broadcaster_value_sat: Option<u64>,
508+
to_countersignatory_value_sat: Option<u64>,
505509
},
506510
PaymentPreimage {
507511
payment_preimage: PaymentPreimage,
@@ -544,8 +548,11 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
544548
},
545549
(1, LatestCounterpartyCommitmentTXInfo) => {
546550
(0, commitment_txid, required),
551+
(1, feerate_per_kw, option),
547552
(2, commitment_number, required),
553+
(3, to_broadcaster_value_sat, option),
548554
(4, their_per_commitment_point, required),
555+
(5, to_countersignatory_value_sat, option),
549556
(6, htlc_outputs, required_vec),
550557
},
551558
(2, PaymentPreimage) => {
@@ -882,6 +889,14 @@ pub(crate) struct ChannelMonitorImpl<Signer: WriteableEcdsaChannelSigner> {
882889

883890
/// The node_id of our counterparty
884891
counterparty_node_id: Option<PublicKey>,
892+
893+
/// Initial counterparty commmitment data needed to recreate the commitment tx
894+
/// in the persistence pipeline for third-party watchtowers. This will only be present on
895+
/// monitors created after 0.0.117.
896+
///
897+
/// Ordering of tuple data: (their_per_commitment_point, feerate_per_kw, to_broadcaster_sats,
898+
/// to_countersignatory_sats)
899+
initial_counterparty_commitment_info: Option<(PublicKey, u32, u64, u64)>,
885900
}
886901

887902
/// Transaction outputs to watch for on-chain spends.
@@ -1072,6 +1087,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signe
10721087
(11, self.confirmed_commitment_tx_counterparty_output, option),
10731088
(13, self.spendable_txids_confirmed, required_vec),
10741089
(15, self.counterparty_fulfilled_htlcs, required),
1090+
(17, self.initial_counterparty_commitment_info, option),
10751091
});
10761092

10771093
Ok(())
@@ -1222,6 +1238,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
12221238

12231239
best_block,
12241240
counterparty_node_id: Some(counterparty_node_id),
1241+
initial_counterparty_commitment_info: None,
12251242
})
12261243
}
12271244

@@ -1230,11 +1247,31 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
12301247
self.inner.lock().unwrap().provide_secret(idx, secret)
12311248
}
12321249

1250+
/// A variant of `Self::provide_latest_counterparty_commitment_tx` used to provide
1251+
/// additional information to the monitor to store in order to recreate the initial
1252+
/// counterparty commitment transaction during persistence (mainly for use in third-party
1253+
/// watchtowers).
1254+
///
1255+
/// This is used to provide the counterparty commitment information directly to the monitor
1256+
/// before the initial persistence of a new channel.
1257+
pub(crate) fn provide_initial_counterparty_commitment_tx<L: Deref>(
1258+
&self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
1259+
commitment_number: u64, their_cur_per_commitment_point: PublicKey, feerate_per_kw: u32,
1260+
to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, logger: &L,
1261+
)
1262+
where L::Target: Logger
1263+
{
1264+
self.inner.lock().unwrap().provide_initial_counterparty_commitment_tx(txid,
1265+
htlc_outputs, commitment_number, their_cur_per_commitment_point, feerate_per_kw,
1266+
to_broadcaster_value_sat, to_countersignatory_value_sat, logger);
1267+
}
1268+
12331269
/// Informs this monitor of the latest counterparty (ie non-broadcastable) commitment transaction.
12341270
/// The monitor watches for it to be broadcasted and then uses the HTLC information (and
12351271
/// possibly future revocation/preimage information) to claim outputs where possible.
12361272
/// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers.
1237-
pub(crate) fn provide_latest_counterparty_commitment_tx<L: Deref>(
1273+
#[cfg(test)]
1274+
fn provide_latest_counterparty_commitment_tx<L: Deref>(
12381275
&self,
12391276
txid: Txid,
12401277
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
@@ -1370,6 +1407,67 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitor<Signer> {
13701407
ret
13711408
}
13721409

1410+
/// Gets the counterparty's initial commitment transaction. The returned commitment
1411+
/// transaction is unsigned. This is intended to be called during the initial persistence of
1412+
/// the monitor (inside an implementation of [`Persist::persist_new_channel`]), to allow for
1413+
/// watchtowers in the persistence pipeline to have enough data to form justice transactions.
1414+
///
1415+
/// This is similar to [`Self::counterparty_commitment_txs_from_update`], except
1416+
/// that for the initial commitment transaction, we don't have a corresponding update.
1417+
///
1418+
/// This will only return `Some` for channel monitors that have been created after upgrading
1419+
/// to LDK 0.0.117+.
1420+
///
1421+
/// [`Persist::persist_new_channel`]: crate::chain::chainmonitor::Persist::persist_new_channel
1422+
pub fn initial_counterparty_commitment_tx(&self) -> Option<CommitmentTransaction> {
1423+
self.inner.lock().unwrap().initial_counterparty_commitment_tx()
1424+
}
1425+
1426+
/// Gets all of the counterparty commitment transactions provided by the given update. This
1427+
/// may be empty if the update doesn't include any new counterparty commitments. Returned
1428+
/// commitment transactions are unsigned.
1429+
///
1430+
/// This is provided so that watchtower clients in the persistence pipeline are able to build
1431+
/// justice transactions for each counterparty commitment upon each update. It's intended to be
1432+
/// used within an implementation of [`Persist::update_persisted_channel`], which is provided
1433+
/// with a monitor and an update. Once revoked, signing a justice transaction can be done using
1434+
/// [`Self::sign_to_local_justice_tx`].
1435+
///
1436+
/// It is expected that a watchtower client may use this method to retrieve the latest counterparty
1437+
/// commitment transaction(s), and then hold the necessary data until a later update in which
1438+
/// the monitor has been updated with the corresponding revocation data, at which point the
1439+
/// monitor can sign the justice transaction.
1440+
///
1441+
/// This will only return a non-empty list for monitor updates that have been created after
1442+
/// upgrading to LDK 0.0.117+. Note that no restriction lies on the monitors themselves, which
1443+
/// may have been created prior to upgrading.
1444+
///
1445+
/// [`Persist::update_persisted_channel`]: crate::chain::chainmonitor::Persist::update_persisted_channel
1446+
pub fn counterparty_commitment_txs_from_update(&self, update: &ChannelMonitorUpdate) -> Vec<CommitmentTransaction> {
1447+
self.inner.lock().unwrap().counterparty_commitment_txs_from_update(update)
1448+
}
1449+
1450+
/// Wrapper around [`EcdsaChannelSigner::sign_justice_revoked_output`] to make
1451+
/// signing the justice transaction easier for implementors of
1452+
/// [`chain::chainmonitor::Persist`]. On success this method returns the provided transaction
1453+
/// signing the input at `input_idx`. This method will only produce a valid signature for
1454+
/// a transaction spending the `to_local` output of a commitment transaction, i.e. this cannot
1455+
/// be used for revoked HTLC outputs.
1456+
///
1457+
/// `Value` is the value of the output being spent by the input at `input_idx`, committed
1458+
/// in the BIP 143 signature.
1459+
///
1460+
/// This method will only succeed if this monitor has received the revocation secret for the
1461+
/// provided `commitment_number`. If a commitment number is provided that does not correspond
1462+
/// to the commitment transaction being revoked, this will return a signed transaction, but
1463+
/// the signature will not be valid.
1464+
///
1465+
/// [`EcdsaChannelSigner::sign_justice_revoked_output`]: crate::sign::EcdsaChannelSigner::sign_justice_revoked_output
1466+
/// [`Persist`]: crate::chain::chainmonitor::Persist
1467+
pub fn sign_to_local_justice_tx(&self, justice_tx: Transaction, input_idx: usize, value: u64, commitment_number: u64) -> Result<Transaction, ()> {
1468+
self.inner.lock().unwrap().sign_to_local_justice_tx(justice_tx, input_idx, value, commitment_number)
1469+
}
1470+
13731471
pub(crate) fn get_min_seen_secret(&self) -> u64 {
13741472
self.inner.lock().unwrap().get_min_seen_secret()
13751473
}
@@ -2226,6 +2324,25 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
22262324
Ok(())
22272325
}
22282326

2327+
pub(crate) fn provide_initial_counterparty_commitment_tx<L: Deref>(
2328+
&mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
2329+
commitment_number: u64, their_per_commitment_point: PublicKey, feerate_per_kw: u32,
2330+
to_broadcaster_value: u64, to_countersignatory_value: u64, logger: &L
2331+
)
2332+
where L::Target: Logger
2333+
{
2334+
self.initial_counterparty_commitment_info = Some((their_per_commitment_point.clone(),
2335+
feerate_per_kw, to_broadcaster_value, to_countersignatory_value));
2336+
2337+
#[cfg(debug_assertions)] {
2338+
let rebuilt_commitment_tx = self.initial_counterparty_commitment_tx().unwrap();
2339+
debug_assert_eq!(rebuilt_commitment_tx.trust().txid(), txid);
2340+
}
2341+
2342+
self.provide_latest_counterparty_commitment_tx(txid, htlc_outputs, commitment_number,
2343+
their_per_commitment_point, logger);
2344+
}
2345+
22292346
pub(crate) fn provide_latest_counterparty_commitment_tx<L: Deref>(&mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>, commitment_number: u64, their_per_commitment_point: PublicKey, logger: &L) where L::Target: Logger {
22302347
// TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction
22312348
// so that a remote monitor doesn't learn anything unless there is a malicious close.
@@ -2471,7 +2588,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
24712588
ret = Err(());
24722589
}
24732590
}
2474-
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point } => {
2591+
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point, .. } => {
24752592
log_trace!(logger, "Updating ChannelMonitor with latest counterparty commitment transaction info");
24762593
self.provide_latest_counterparty_commitment_tx(*commitment_txid, htlc_outputs.clone(), *commitment_number, *their_per_commitment_point, logger)
24772594
},
@@ -2543,6 +2660,10 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
25432660
}
25442661
}
25452662

2663+
#[cfg(debug_assertions)] {
2664+
self.counterparty_commitment_txs_from_update(updates);
2665+
}
2666+
25462667
// If the updates succeeded and we were in an already closed channel state, then there's no
25472668
// need to refuse any updates we expect to receive afer seeing a confirmed commitment.
25482669
if ret.is_ok() && updates.update_id == CLOSED_CHANNEL_UPDATE_ID && self.latest_update_id == updates.update_id {
@@ -2651,6 +2772,91 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
26512772
ret
26522773
}
26532774

2775+
pub(crate) fn initial_counterparty_commitment_tx(&mut self) -> Option<CommitmentTransaction> {
2776+
let (their_per_commitment_point, feerate_per_kw, to_broadcaster_value,
2777+
to_countersignatory_value) = self.initial_counterparty_commitment_info?;
2778+
let htlc_outputs = vec![];
2779+
2780+
let commitment_tx = self.build_counterparty_commitment_tx(INITIAL_COMMITMENT_NUMBER,
2781+
&their_per_commitment_point, to_broadcaster_value, to_countersignatory_value,
2782+
feerate_per_kw, htlc_outputs);
2783+
Some(commitment_tx)
2784+
}
2785+
2786+
fn build_counterparty_commitment_tx(
2787+
&self, commitment_number: u64, their_per_commitment_point: &PublicKey,
2788+
to_broadcaster_value: u64, to_countersignatory_value: u64, feerate_per_kw: u32,
2789+
mut nondust_htlcs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>
2790+
) -> CommitmentTransaction {
2791+
let broadcaster_keys = &self.onchain_tx_handler.channel_transaction_parameters
2792+
.counterparty_parameters.as_ref().unwrap().pubkeys;
2793+
let countersignatory_keys =
2794+
&self.onchain_tx_handler.channel_transaction_parameters.holder_pubkeys;
2795+
2796+
let broadcaster_funding_key = broadcaster_keys.funding_pubkey;
2797+
let countersignatory_funding_key = countersignatory_keys.funding_pubkey;
2798+
let keys = TxCreationKeys::from_channel_static_keys(&their_per_commitment_point,
2799+
&broadcaster_keys, &countersignatory_keys, &self.onchain_tx_handler.secp_ctx);
2800+
let channel_parameters =
2801+
&self.onchain_tx_handler.channel_transaction_parameters.as_counterparty_broadcastable();
2802+
2803+
CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number,
2804+
to_broadcaster_value, to_countersignatory_value, broadcaster_funding_key,
2805+
countersignatory_funding_key, keys, feerate_per_kw, &mut nondust_htlcs,
2806+
channel_parameters)
2807+
}
2808+
2809+
pub(crate) fn counterparty_commitment_txs_from_update(&self, update: &ChannelMonitorUpdate) -> Vec<CommitmentTransaction> {
2810+
update.updates.iter().filter_map(|update| {
2811+
match update {
2812+
&ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid,
2813+
ref htlc_outputs, commitment_number, their_per_commitment_point,
2814+
feerate_per_kw: Some(feerate_per_kw),
2815+
to_broadcaster_value_sat: Some(to_broadcaster_value),
2816+
to_countersignatory_value_sat: Some(to_countersignatory_value) } => {
2817+
2818+
let nondust_htlcs = htlc_outputs.iter().filter_map(|(htlc, _)| {
2819+
htlc.transaction_output_index.map(|_| (htlc.clone(), None))
2820+
}).collect::<Vec<_>>();
2821+
2822+
let commitment_tx = self.build_counterparty_commitment_tx(commitment_number,
2823+
&their_per_commitment_point, to_broadcaster_value,
2824+
to_countersignatory_value, feerate_per_kw, nondust_htlcs);
2825+
2826+
debug_assert_eq!(commitment_tx.trust().txid(), commitment_txid);
2827+
2828+
Some(commitment_tx)
2829+
},
2830+
_ => None,
2831+
}
2832+
}).collect()
2833+
}
2834+
2835+
pub(crate) fn sign_to_local_justice_tx(
2836+
&self, mut justice_tx: Transaction, input_idx: usize, value: u64, commitment_number: u64
2837+
) -> Result<Transaction, ()> {
2838+
let secret = self.get_secret(commitment_number).ok_or(())?;
2839+
let per_commitment_key = SecretKey::from_slice(&secret).map_err(|_| ())?;
2840+
let their_per_commitment_point = PublicKey::from_secret_key(
2841+
&self.onchain_tx_handler.secp_ctx, &per_commitment_key);
2842+
2843+
let revocation_pubkey = chan_utils::derive_public_revocation_key(
2844+
&self.onchain_tx_handler.secp_ctx, &their_per_commitment_point,
2845+
&self.holder_revocation_basepoint);
2846+
let delayed_key = chan_utils::derive_public_key(&self.onchain_tx_handler.secp_ctx,
2847+
&their_per_commitment_point,
2848+
&self.counterparty_commitment_params.counterparty_delayed_payment_base_key);
2849+
let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey,
2850+
self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key);
2851+
2852+
let sig = self.onchain_tx_handler.signer.sign_justice_revoked_output(
2853+
&justice_tx, input_idx, value, &per_commitment_key, &self.onchain_tx_handler.secp_ctx)?;
2854+
justice_tx.input[input_idx].witness.push_bitcoin_signature(&sig.serialize_der(), EcdsaSighashType::All);
2855+
justice_tx.input[input_idx].witness.push(&[1u8]);
2856+
justice_tx.input[input_idx].witness.push(revokeable_redeemscript.as_bytes());
2857+
Ok(justice_tx)
2858+
}
2859+
26542860
/// Can only fail if idx is < get_min_seen_secret
26552861
fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
26562862
self.commitment_secrets.get_secret(idx)
@@ -4113,6 +4319,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
41134319
let mut confirmed_commitment_tx_counterparty_output = None;
41144320
let mut spendable_txids_confirmed = Some(Vec::new());
41154321
let mut counterparty_fulfilled_htlcs = Some(HashMap::new());
4322+
let mut initial_counterparty_commitment_info = None;
41164323
read_tlv_fields!(reader, {
41174324
(1, funding_spend_confirmed, option),
41184325
(3, htlcs_resolved_on_chain, optional_vec),
@@ -4122,6 +4329,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
41224329
(11, confirmed_commitment_tx_counterparty_output, option),
41234330
(13, spendable_txids_confirmed, optional_vec),
41244331
(15, counterparty_fulfilled_htlcs, option),
4332+
(17, initial_counterparty_commitment_info, option),
41254333
});
41264334

41274335
Ok((best_block.block_hash(), ChannelMonitor::from_impl(ChannelMonitorImpl {
@@ -4177,6 +4385,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
41774385

41784386
best_block,
41794387
counterparty_node_id,
4388+
initial_counterparty_commitment_info,
41804389
})))
41814390
}
41824391
}

0 commit comments

Comments
 (0)