Skip to content

Commit 00e8bb3

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 c48e0a8 commit 00e8bb3

File tree

4 files changed

+238
-105
lines changed

4 files changed

+238
-105
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,9 @@ pub(crate) enum ChannelMonitorUpdateStep {
676676
holder_commitment_tx: HolderCommitmentTransaction,
677677
counterparty_commitment_tx: CommitmentTransaction,
678678
},
679+
RenegotiatedFundingLocked {
680+
funding_txid: Txid,
681+
},
679682
}
680683

681684
impl ChannelMonitorUpdateStep {
@@ -690,6 +693,7 @@ impl ChannelMonitorUpdateStep {
690693
ChannelMonitorUpdateStep::ChannelForceClosed { .. } => "ChannelForceClosed",
691694
ChannelMonitorUpdateStep::ShutdownScript { .. } => "ShutdownScript",
692695
ChannelMonitorUpdateStep::RenegotiatedFunding { .. } => "RenegotiatedFunding",
696+
ChannelMonitorUpdateStep::RenegotiatedFundingLocked { .. } => "RenegotiatedFundingLocked",
693697
}
694698
}
695699
}
@@ -733,6 +737,9 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
733737
(3, holder_commitment_tx, required),
734738
(5, counterparty_commitment_tx, required),
735739
},
740+
(12, RenegotiatedFundingLocked) => {
741+
(1, funding_txid, required),
742+
},
736743
);
737744

738745
/// Indicates whether the balance is derived from a cooperative close, a force-close
@@ -1075,6 +1082,10 @@ impl FundingScope {
10751082
fn funding_txid(&self) -> Txid {
10761083
self.funding_outpoint().txid
10771084
}
1085+
1086+
fn is_splice(&self) -> bool {
1087+
self.channel_parameters.splice_parent_funding_txid.is_some()
1088+
}
10781089
}
10791090

10801091
impl Writeable for FundingScope {
@@ -1209,8 +1220,6 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
12091220
// interface knows about the TXOs that we want to be notified of spends of. We could probably
12101221
// be smart and derive them from the above storage fields, but its much simpler and more
12111222
// Obviously Correct (tm) if we just keep track of them explicitly.
1212-
//
1213-
// TODO: Remove entries for stale funding transactions on `splice_locked`.
12141223
outputs_to_watch: HashMap<Txid, Vec<(u32, ScriptBuf)>>,
12151224

12161225
#[cfg(any(test, feature = "_test_utils"))]
@@ -3670,6 +3679,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36703679
);
36713680
return Err(());
36723681
}
3682+
} else if self.funding.is_splice() {
3683+
// If we've already spliced at least once, we're no longer able to RBF the original
3684+
// funding transaction.
3685+
return Err(());
36733686
}
36743687

36753688
self.outputs_to_watch.insert(
@@ -3681,6 +3694,39 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36813694
Ok(())
36823695
}
36833696

3697+
fn promote_funding(&mut self, new_funding_txid: Txid) -> Result<(), ()> {
3698+
let is_pending_splice = self.pending_funding.iter().any(|funding| funding.is_splice());
3699+
3700+
let new_funding = self
3701+
.pending_funding
3702+
.iter_mut()
3703+
.find(|funding| funding.funding_txid() == new_funding_txid);
3704+
if new_funding.is_none() {
3705+
return Err(());
3706+
}
3707+
let mut new_funding = new_funding.unwrap();
3708+
3709+
// `first_confirmed_funding_txo` is set to the first outpoint for the channel upon init.
3710+
// If an RBF happens and it confirms, this will no longer be accurate, so update it now
3711+
// if we know the RBF doesn't belong to a splice.
3712+
if !is_pending_splice && self.first_confirmed_funding_txo == self.funding.funding_outpoint()
3713+
{
3714+
self.first_confirmed_funding_txo = new_funding.funding_outpoint();
3715+
}
3716+
3717+
mem::swap(&mut self.funding, &mut new_funding);
3718+
self.onchain_tx_handler.update_after_renegotiated_funding_locked(
3719+
self.funding.current_holder_commitment_tx.clone(),
3720+
self.funding.prev_holder_commitment_tx.clone(),
3721+
);
3722+
3723+
for funding in self.pending_funding.drain(..) {
3724+
self.outputs_to_watch.remove(&funding.funding_txid());
3725+
}
3726+
3727+
Ok(())
3728+
}
3729+
36843730
#[rustfmt::skip]
36853731
fn update_monitor<B: Deref, F: Deref, L: Deref>(
36863732
&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &WithChannelMonitor<L>
@@ -3771,6 +3817,13 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
37713817
ret = Err(());
37723818
}
37733819
},
3820+
ChannelMonitorUpdateStep::RenegotiatedFundingLocked { funding_txid } => {
3821+
log_trace!(logger, "Updating ChannelMonitor with locked renegotiated funding txid {}", funding_txid);
3822+
if let Err(_) = self.promote_funding(*funding_txid) {
3823+
log_error!(logger, "Unknown funding with txid {} became locked", funding_txid);
3824+
ret = Err(());
3825+
}
3826+
},
37743827
ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } => {
37753828
log_trace!(logger, "Updating ChannelMonitor: channel force closed, should broadcast: {}", should_broadcast);
37763829
self.lockdown_from_offchain = true;
@@ -3823,7 +3876,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
38233876
|ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTX { .. }
38243877
|ChannelMonitorUpdateStep::ShutdownScript { .. }
38253878
|ChannelMonitorUpdateStep::CommitmentSecret { .. }
3826-
|ChannelMonitorUpdateStep::RenegotiatedFunding { .. } =>
3879+
|ChannelMonitorUpdateStep::RenegotiatedFunding { .. }
3880+
|ChannelMonitorUpdateStep::RenegotiatedFundingLocked { .. } =>
38273881
is_pre_close_update = true,
38283882
// After a channel is closed, we don't communicate with our peer about it, so the
38293883
// 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
@@ -1216,6 +1216,15 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
12161216
self.prev_holder_commitment = Some(replace(&mut self.holder_commitment, tx));
12171217
}
12181218

1219+
/// Replaces the current/prev holder commitment transactions spending the currently confirmed
1220+
/// funding outpoint with those spending the new funding outpoint.
1221+
pub(crate) fn update_after_renegotiated_funding_locked(
1222+
&mut self, current: HolderCommitmentTransaction, prev: Option<HolderCommitmentTransaction>,
1223+
) {
1224+
self.holder_commitment = current;
1225+
self.prev_holder_commitment = prev;
1226+
}
1227+
12191228
// Deprecated as of 0.2, only use in cases where it was not previously available.
12201229
pub(crate) fn channel_parameters(&self) -> &ChannelTransactionParameters {
12211230
&self.channel_transaction_parameters

0 commit comments

Comments
 (0)