Skip to content

Commit 6b350f5

Browse files
committed
Introduce LatestHolderCommitment monitor update variant
This new variant is a backwards-incompatible successor to `LatestHolderCommitmentTXInfo` that is capable of handling holder commitment updates while a splice is pending. Since all holder commitment candidates share the same set of non-dust and dust HTLCs (though each non-dust HTLC can have differing output indices), we can share the same set of HTLC source data across all candidates.
1 parent 689d0c1 commit 6b350f5

File tree

2 files changed

+167
-81
lines changed

2 files changed

+167
-81
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,11 @@ pub(crate) enum ChannelMonitorUpdateStep {
586586
claimed_htlcs: Vec<(SentHTLCId, PaymentPreimage)>,
587587
nondust_htlc_sources: Vec<HTLCSource>,
588588
},
589+
LatestHolderCommitment {
590+
commitment_txs: Vec<HolderCommitmentTransaction>,
591+
htlc_data: CommitmentHTLCData,
592+
claimed_htlcs: Vec<(SentHTLCId, PaymentPreimage)>,
593+
},
589594
LatestCounterpartyCommitmentTXInfo {
590595
commitment_txid: Txid,
591596
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
@@ -632,6 +637,7 @@ impl ChannelMonitorUpdateStep {
632637
fn variant_name(&self) -> &'static str {
633638
match self {
634639
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { .. } => "LatestHolderCommitmentTXInfo",
640+
ChannelMonitorUpdateStep::LatestHolderCommitment { .. } => "LatestHolderCommitment",
635641
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. } => "LatestCounterpartyCommitmentTXInfo",
636642
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTX { .. } => "LatestCounterpartyCommitmentTX",
637643
ChannelMonitorUpdateStep::PaymentPreimage { .. } => "PaymentPreimage",
@@ -676,6 +682,10 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
676682
(6, LatestCounterpartyCommitmentTX) => {
677683
(0, htlc_outputs, required_vec),
678684
(2, commitment_tx, required),
685+
(8, LatestHolderCommitment) => {
686+
(1, commitment_txs, required_vec),
687+
(3, htlc_data, required),
688+
(5, claimed_htlcs, required_vec),
679689
},
680690
(10, RenegotiatedFunding) => {
681691
(1, channel_parameters, (required: ReadableArgs, None)),
@@ -932,12 +942,12 @@ impl<Signer: EcdsaChannelSigner> Clone for ChannelMonitor<Signer> where Signer:
932942
}
933943
}
934944

935-
#[derive(Clone, PartialEq)]
936-
struct CommitmentHTLCData {
945+
#[derive(Clone, Debug, PartialEq, Eq)]
946+
pub(crate) struct CommitmentHTLCData {
937947
// These must be sorted in increasing output index order to match the expected order of the
938948
// HTLCs in the `CommitmentTransaction`.
939-
nondust_htlc_sources: Vec<HTLCSource>,
940-
dust_htlcs: Vec<(HTLCOutputInCommitment, Option<HTLCSource>)>,
949+
pub nondust_htlc_sources: Vec<HTLCSource>,
950+
pub dust_htlcs: Vec<(HTLCOutputInCommitment, Option<HTLCSource>)>,
941951
}
942952

943953
impl CommitmentHTLCData {
@@ -946,6 +956,11 @@ impl CommitmentHTLCData {
946956
}
947957
}
948958

959+
impl_writeable_tlv_based!(CommitmentHTLCData, {
960+
(1, nondust_htlc_sources, required_vec),
961+
(3, dust_htlcs, required_vec),
962+
});
963+
949964
impl TryFrom<HolderSignedTx> for CommitmentHTLCData {
950965
type Error = ();
951966
fn try_from(value: HolderSignedTx) -> Result<Self, Self::Error> {
@@ -3192,11 +3207,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
31923207
/// up-to-date as our holder commitment transaction is updated.
31933208
/// Panics if set_on_holder_tx_csv has never been called.
31943209
fn provide_latest_holder_commitment_tx(
3195-
&mut self, mut holder_commitment_tx: HolderCommitmentTransaction,
3210+
&mut self, holder_commitment_tx: HolderCommitmentTransaction,
31963211
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
31973212
claimed_htlcs: &[(SentHTLCId, PaymentPreimage)], mut nondust_htlc_sources: Vec<HTLCSource>,
3198-
) {
3199-
let dust_htlcs: Vec<_> = if htlc_outputs.iter().any(|(_, s, _)| s.is_some()) {
3213+
) -> Result<(), &'static str> {
3214+
let htlc_data = if htlc_outputs.iter().any(|(_, s, _)| s.is_some()) {
32003215
// If we have non-dust HTLCs in htlc_outputs, ensure they match the HTLCs in the
32013216
// `holder_commitment_tx`. In the future, we'll no longer provide the redundant data
32023217
// and just pass in source data via `nondust_htlc_sources`.
@@ -3224,7 +3239,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
32243239
None
32253240
}).collect();
32263241

3227-
dust_htlcs
3242+
CommitmentHTLCData { nondust_htlc_sources, dust_htlcs }
32283243
} else {
32293244
// If we don't have any non-dust HTLCs in htlc_outputs, assume they were all passed via
32303245
// `nondust_htlc_sources`, building up the final htlc_outputs by combining
@@ -3251,30 +3266,67 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
32513266
assert!(sources.next().is_none(), "All HTLC sources should have been exhausted");
32523267

32533268
// This only includes dust HTLCs as checked above.
3254-
htlc_outputs.into_iter().map(|(htlc, _, source)| (htlc, source)).collect()
3269+
let dust_htlcs = htlc_outputs.into_iter().map(|(htlc, _, source)| (htlc, source)).collect();
3270+
3271+
CommitmentHTLCData { nondust_htlc_sources, dust_htlcs }
32553272
};
32563273

3257-
self.current_holder_commitment_number = holder_commitment_tx.trust().commitment_number();
3258-
self.onchain_tx_handler.provide_latest_holder_tx(holder_commitment_tx.clone());
3274+
self.update_holder_commitment_data(
3275+
vec![holder_commitment_tx], htlc_data, claimed_htlcs.to_vec(),
3276+
)
3277+
}
32593278

3260-
mem::swap(&mut holder_commitment_tx, &mut self.funding.current_holder_commitment_tx);
3261-
self.funding.prev_holder_commitment_tx = Some(holder_commitment_tx);
3262-
let mut holder_htlc_data = CommitmentHTLCData { nondust_htlc_sources, dust_htlcs };
3263-
mem::swap(&mut holder_htlc_data, &mut self.current_holder_htlc_data);
3264-
self.prev_holder_htlc_data = Some(holder_htlc_data);
3279+
fn update_holder_commitment_data(
3280+
&mut self, mut commitment_txs: Vec<HolderCommitmentTransaction>,
3281+
mut htlc_data: CommitmentHTLCData, claimed_htlcs: Vec<(SentHTLCId, PaymentPreimage)>,
3282+
) -> Result<(), &'static str> {
3283+
if self.pending_funding.len() + 1 != commitment_txs.len() {
3284+
return Err("Commitment transaction(s) mismatch");
3285+
}
3286+
3287+
let mut current_funding_commitment = commitment_txs.remove(0);
3288+
let holder_commitment_number = current_funding_commitment.commitment_number();
3289+
for (pending_funding, mut commitment_tx) in self.pending_funding.iter_mut().zip(commitment_txs.into_iter()) {
3290+
let trusted_tx = commitment_tx.trust();
3291+
if trusted_tx.commitment_number() != holder_commitment_number {
3292+
return Err("Commitment number mismatch");
3293+
}
3294+
3295+
let funding_outpoint_spent =
3296+
trusted_tx.built_transaction().transaction.tx_in(0).map(|input| input.previous_output).ok();
3297+
let expected_funding_outpoint_spent =
3298+
pending_funding.channel_parameters.funding_outpoint.map(|op| op.into_bitcoin_outpoint());
3299+
if funding_outpoint_spent != expected_funding_outpoint_spent {
3300+
return Err("Funding outpoint mismatch");
3301+
}
3302+
3303+
mem::swap(&mut commitment_tx, &mut pending_funding.current_holder_commitment_tx);
3304+
pending_funding.prev_holder_commitment_tx = Some(commitment_tx);
3305+
}
3306+
3307+
self.current_holder_commitment_number = holder_commitment_number;
3308+
self.onchain_tx_handler.provide_latest_holder_tx(current_funding_commitment.clone());
3309+
mem::swap(&mut current_funding_commitment, &mut self.funding.current_holder_commitment_tx);
3310+
self.funding.prev_holder_commitment_tx = Some(current_funding_commitment);
3311+
3312+
mem::swap(&mut htlc_data, &mut self.current_holder_htlc_data);
3313+
self.prev_holder_htlc_data = Some(htlc_data);
32653314

32663315
for (claimed_htlc_id, claimed_preimage) in claimed_htlcs {
32673316
#[cfg(debug_assertions)] {
32683317
let cur_counterparty_htlcs = self.funding.counterparty_claimable_outpoints.get(
3269-
&self.funding.current_counterparty_commitment_txid.unwrap()).unwrap();
3318+
&self.funding.current_counterparty_commitment_txid.unwrap()
3319+
).unwrap();
32703320
assert!(cur_counterparty_htlcs.iter().any(|(_, source_opt)| {
32713321
if let Some(source) = source_opt {
3272-
SentHTLCId::from_source(source) == *claimed_htlc_id
3322+
SentHTLCId::from_source(source) == claimed_htlc_id
32733323
} else { false }
32743324
}));
32753325
}
3276-
self.counterparty_fulfilled_htlcs.insert(*claimed_htlc_id, *claimed_preimage);
3326+
self.counterparty_fulfilled_htlcs.insert(claimed_htlc_id, claimed_preimage);
32773327
}
3328+
3329+
Ok(())
32783330
}
32793331

32803332
/// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all
@@ -3579,9 +3631,25 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
35793631
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs, claimed_htlcs, nondust_htlc_sources } => {
35803632
log_trace!(logger, "Updating ChannelMonitor with latest holder commitment transaction info");
35813633
if self.lockdown_from_offchain { panic!(); }
3582-
self.provide_latest_holder_commitment_tx(commitment_tx.clone(), htlc_outputs.clone(), &claimed_htlcs, nondust_htlc_sources.clone());
3634+
if let Err(e) = self.provide_latest_holder_commitment_tx(
3635+
commitment_tx.clone(), htlc_outputs.clone(), &claimed_htlcs,
3636+
nondust_htlc_sources.clone()
3637+
) {
3638+
log_error!(logger, "Failed updating latest holder commitment transaction info: {}", e);
3639+
}
35833640
}
3584-
// Soon we will drop the `LatestCounterpartyCommitmentTXInfo` variant in favor of `LatestCounterpartyCommitmentTX`.
3641+
ChannelMonitorUpdateStep::LatestHolderCommitment {
3642+
commitment_txs, htlc_data, claimed_htlcs,
3643+
} => {
3644+
log_trace!(logger, "Updating ChannelMonitor with latest holder commitment");
3645+
assert!(!self.lockdown_from_offchain);
3646+
if let Err(e) = self.update_holder_commitment_data(
3647+
commitment_txs.clone(), htlc_data.clone(), claimed_htlcs.clone(),
3648+
) {
3649+
log_error!(logger, "Failed updating latest holder commitment state: {}", e);
3650+
}
3651+
},
3652+
// Soon we will drop the `LatestCounterpartyCommitmentTXInfo` variant in favor of `LatestCounterpartyCommitment`.
35853653
// For now we just add the code to handle the new updates.
35863654
// Next step: in channel, switch channel monitor updates to use the `LatestCounterpartyCommitmentTX` variant.
35873655
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point, .. } => {
@@ -3664,6 +3732,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36643732
for update in updates.updates.iter() {
36653733
match update {
36663734
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { .. }
3735+
|ChannelMonitorUpdateStep::LatestHolderCommitment { .. }
36673736
|ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. }
36683737
|ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTX { .. }
36693738
|ChannelMonitorUpdateStep::ShutdownScript { .. }

0 commit comments

Comments
 (0)