Skip to content

Commit 120a677

Browse files
committed
Introduce RenegotiatedFundingLocked monitor update variant
This is a new `ChannelMonitorUpdateStep` variant intended to be used whenever a new funding transaction that was negotiated and applied via the `RenegotiatedFunding` update reaches its intended confirmation depth and both sides of the channel exchange `channel_ready`/`splice_locked`. This commit primarily focuses on its use for splices, but future work will expand where needed to support RBFs for a dual funded channel. This monitor update ensures that the monitor can safely drop all prior commitment data since it is now considered invalid/unnecessary. Once the update is applied, only state for the new funding transaction is tracked going forward, until the monitor receives another `RenegotiatedFunding` update.
1 parent eae2bb1 commit 120a677

File tree

4 files changed

+247
-128
lines changed

4 files changed

+247
-128
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,9 @@ pub(crate) enum ChannelMonitorUpdateStep {
678678
holder_commitment_tx: HolderCommitmentTransaction,
679679
counterparty_commitment_tx: CommitmentTransaction,
680680
},
681+
RenegotiatedFundingLocked {
682+
funding_txid: Txid,
683+
},
681684
}
682685

683686
impl ChannelMonitorUpdateStep {
@@ -693,6 +696,7 @@ impl ChannelMonitorUpdateStep {
693696
ChannelMonitorUpdateStep::ChannelForceClosed { .. } => "ChannelForceClosed",
694697
ChannelMonitorUpdateStep::ShutdownScript { .. } => "ShutdownScript",
695698
ChannelMonitorUpdateStep::RenegotiatedFunding { .. } => "RenegotiatedFunding",
699+
ChannelMonitorUpdateStep::RenegotiatedFundingLocked { .. } => "RenegotiatedFundingLocked",
696700
}
697701
}
698702
}
@@ -741,6 +745,9 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
741745
(3, holder_commitment_tx, required),
742746
(5, counterparty_commitment_tx, required),
743747
},
748+
(12, RenegotiatedFundingLocked) => {
749+
(1, funding_txid, required),
750+
},
744751
);
745752

746753
/// Indicates whether the balance is derived from a cooperative close, a force-close
@@ -1086,6 +1093,10 @@ impl FundingScope {
10861093
fn funding_txid(&self) -> Txid {
10871094
self.funding_outpoint().txid
10881095
}
1096+
1097+
fn is_splice(&self) -> bool {
1098+
self.channel_parameters.splice_parent_funding_txid.is_some()
1099+
}
10891100
}
10901101

10911102
impl_writeable_tlv_based!(FundingScope, {
@@ -1181,8 +1192,6 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
11811192
// interface knows about the TXOs that we want to be notified of spends of. We could probably
11821193
// be smart and derive them from the above storage fields, but its much simpler and more
11831194
// Obviously Correct (tm) if we just keep track of them explicitly.
1184-
//
1185-
// TODO: Remove entries for stale funding transactions on `splice_locked`.
11861195
outputs_to_watch: HashMap<Txid, Vec<(u32, ScriptBuf)>>,
11871196

11881197
#[cfg(any(test, feature = "_test_utils"))]
@@ -3768,6 +3777,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
37683777
);
37693778
return Err(());
37703779
}
3780+
} else if self.funding.is_splice() {
3781+
// If we've already spliced at least once, we're no longer able to RBF the original
3782+
// funding transaction.
3783+
return Err(());
37713784
}
37723785

37733786
let script_pubkey = channel_parameters.make_funding_redeemscript().to_p2wsh();
@@ -3780,6 +3793,30 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
37803793
Ok(())
37813794
}
37823795

3796+
fn promote_funding(&mut self, new_funding_txid: Txid) -> Result<(), ()> {
3797+
let new_funding = self
3798+
.pending_funding
3799+
.iter_mut()
3800+
.find(|funding| funding.funding_txid() == new_funding_txid);
3801+
if new_funding.is_none() {
3802+
return Err(());
3803+
}
3804+
let mut new_funding = new_funding.unwrap();
3805+
3806+
mem::swap(&mut self.funding, &mut new_funding);
3807+
self.onchain_tx_handler.update_after_renegotiated_funding_locked(
3808+
self.funding.current_holder_commitment_tx.clone(),
3809+
self.funding.prev_holder_commitment_tx.clone(),
3810+
);
3811+
3812+
// The swap above places the previous `FundingScope` into `pending_funding`.
3813+
for funding in self.pending_funding.drain(..) {
3814+
self.outputs_to_watch.remove(&funding.funding_txid());
3815+
}
3816+
3817+
Ok(())
3818+
}
3819+
37833820
#[rustfmt::skip]
37843821
fn update_monitor<B: Deref, F: Deref, L: Deref>(
37853822
&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &WithChannelMonitor<L>
@@ -3898,6 +3935,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38983935
ret = Err(());
38993936
}
39003937
},
3938+
ChannelMonitorUpdateStep::RenegotiatedFundingLocked { funding_txid } => {
3939+
log_trace!(logger, "Updating ChannelMonitor with locked renegotiated funding txid {}", funding_txid);
3940+
if let Err(_) = self.promote_funding(*funding_txid) {
3941+
log_error!(logger, "Unknown funding with txid {} became locked", funding_txid);
3942+
ret = Err(());
3943+
}
3944+
},
39013945
ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } => {
39023946
log_trace!(logger, "Updating ChannelMonitor: channel force closed, should broadcast: {}", should_broadcast);
39033947
self.lockdown_from_offchain = true;
@@ -3951,7 +3995,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39513995
|ChannelMonitorUpdateStep::LatestCounterpartyCommitment { .. }
39523996
|ChannelMonitorUpdateStep::ShutdownScript { .. }
39533997
|ChannelMonitorUpdateStep::CommitmentSecret { .. }
3954-
|ChannelMonitorUpdateStep::RenegotiatedFunding { .. } =>
3998+
|ChannelMonitorUpdateStep::RenegotiatedFunding { .. }
3999+
|ChannelMonitorUpdateStep::RenegotiatedFundingLocked { .. } =>
39554000
is_pre_close_update = true,
39564001
// After a channel is closed, we don't communicate with our peer about it, so the
39574002
// only things we will update is getting a new preimage (from a different channel)

lightning/src/chain/onchaintx.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,15 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
12381238
self.prev_holder_commitment = Some(replace(&mut self.holder_commitment, tx));
12391239
}
12401240

1241+
/// Replaces the current/prev holder commitment transactions spending the currently confirmed
1242+
/// funding outpoint with those spending the new funding outpoint.
1243+
pub(crate) fn update_after_renegotiated_funding_locked(
1244+
&mut self, current: HolderCommitmentTransaction, prev: Option<HolderCommitmentTransaction>,
1245+
) {
1246+
self.holder_commitment = current;
1247+
self.prev_holder_commitment = prev;
1248+
}
1249+
12411250
// Deprecated as of 0.2, only use in cases where it was not previously available.
12421251
pub(crate) fn channel_parameters(&self) -> &ChannelTransactionParameters {
12431252
&self.channel_transaction_parameters

0 commit comments

Comments
 (0)