Skip to content

Commit 6c78591

Browse files
committed
Introduce RenegotiatedFunding monitor update variant
This is a new `ChannelMonitorUpdateStep` variant intended to be used whenever a new funding transaction for the channel has been negotiated via the `InteractiveTxConstructor`. This commit primarily focuses on its use for splices, but future work will expand where needed to support RBFs (both for the initial dual funding transaction, and splice transactions). To draw a parallel to channel open, we generally want to have the commitment transactions negotiated for the funding transaction and committed to the respective `ChannelMonitor` before attempting to sign the funding transaction itself. This monitor update fulfills this need for a newly negotiated splice; it includes both the new holder and counterparty commitment transactions, and the new set of applicable `ChannelTransactionParameters`. Once the monitor update has been applied to the monitor and persisted, we allow the release of our `tx_signatures` for the splice transaction to wait for its confirmation.
1 parent 2f431d6 commit 6c78591

File tree

3 files changed

+299
-7
lines changed

3 files changed

+299
-7
lines changed

lightning/src/chain/chainmonitor.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
3131
use crate::chain;
3232
use crate::chain::{ChannelMonitorUpdateStatus, Filter, WatchedOutput};
3333
use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
34-
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, Balance, MonitorEvent, TransactionOutputs, WithChannelMonitor};
34+
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, Balance, MonitorEvent, TransactionOutputs, WithChannelMonitor};
3535
use crate::chain::transaction::{OutPoint, TransactionData};
3636
use crate::ln::types::ChannelId;
3737
use crate::sign::ecdsa::EcdsaChannelSigner;
@@ -867,6 +867,16 @@ where C::Target: chain::Filter,
867867
panic!("{}", err_str);
868868
},
869869
}
870+
871+
// We may need to start monitoring for any alternative funding transactions.
872+
if let Some(ref chain_source) = self.chain_source {
873+
if update.updates.iter()
874+
.any(|update| matches!(update, ChannelMonitorUpdateStep::RenegotiatedFunding { .. }))
875+
{
876+
monitor.load_outputs_to_watch(chain_source, &self.logger);
877+
}
878+
}
879+
870880
if update_res.is_err() {
871881
ChannelMonitorUpdateStatus::InProgress
872882
} else {

lightning/src/chain/channelmonitor.rs

Lines changed: 202 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,11 @@ pub(crate) enum ChannelMonitorUpdateStep {
621621
ShutdownScript {
622622
scriptpubkey: ScriptBuf,
623623
},
624+
RenegotiatedFunding {
625+
channel_parameters: ChannelTransactionParameters,
626+
holder_commitment_tx: HolderCommitmentTransaction,
627+
counterparty_commitment_tx: CommitmentTransaction,
628+
},
624629
}
625630

626631
impl ChannelMonitorUpdateStep {
@@ -633,6 +638,7 @@ impl ChannelMonitorUpdateStep {
633638
ChannelMonitorUpdateStep::CommitmentSecret { .. } => "CommitmentSecret",
634639
ChannelMonitorUpdateStep::ChannelForceClosed { .. } => "ChannelForceClosed",
635640
ChannelMonitorUpdateStep::ShutdownScript { .. } => "ShutdownScript",
641+
ChannelMonitorUpdateStep::RenegotiatedFunding { .. } => "RenegotiatedFunding",
636642
}
637643
}
638644
}
@@ -671,6 +677,11 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
671677
(0, htlc_outputs, required_vec),
672678
(2, commitment_tx, required),
673679
},
680+
(10, RenegotiatedFunding) => {
681+
(1, channel_parameters, (required: ReadableArgs, None)),
682+
(3, holder_commitment_tx, required),
683+
(5, counterparty_commitment_tx, required),
684+
},
674685
);
675686

676687
/// Indicates whether the balance is derived from a cooperative close, a force-close
@@ -997,9 +1008,69 @@ struct FundingScope {
9971008
prev_holder_commitment_tx: Option<HolderCommitmentTransaction>,
9981009
}
9991010

1011+
impl FundingScope {
1012+
fn funding_outpoint(&self) -> OutPoint {
1013+
*self.channel_parameters.funding_outpoint.as_ref()
1014+
.expect("Funding outpoint must be set for active monitor")
1015+
}
1016+
1017+
fn funding_txid(&self) -> Txid {
1018+
self.channel_parameters.funding_outpoint.as_ref().unwrap().txid
1019+
}
1020+
}
1021+
1022+
impl Writeable for FundingScope {
1023+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1024+
write_tlv_fields!(w, {
1025+
(1, self.channel_parameters, (required: ReadableArgs, None)),
1026+
(3, self.current_counterparty_commitment_txid, required),
1027+
(5, self.prev_counterparty_commitment_txid, option),
1028+
(7, self.current_holder_commitment_tx, required),
1029+
(9, self.prev_holder_commitment_tx, option),
1030+
(11, self.counterparty_claimable_outpoints, required),
1031+
});
1032+
Ok(())
1033+
}
1034+
}
1035+
1036+
impl Readable for FundingScope {
1037+
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
1038+
let mut channel_parameters = RequiredWrapper(None);
1039+
let mut current_counterparty_commitment_txid = RequiredWrapper(None);
1040+
let mut prev_counterparty_commitment_txid = None;
1041+
let mut current_holder_commitment_tx = RequiredWrapper(None);
1042+
let mut prev_holder_commitment_tx = None;
1043+
let mut counterparty_claimable_outpoints = RequiredWrapper(None);
1044+
1045+
read_tlv_fields!(r, {
1046+
(1, channel_parameters, (required: ReadableArgs, None)),
1047+
(3, current_counterparty_commitment_txid, required),
1048+
(5, prev_counterparty_commitment_txid, option),
1049+
(7, current_holder_commitment_tx, required),
1050+
(9, prev_holder_commitment_tx, option),
1051+
(11, counterparty_claimable_outpoints, required),
1052+
});
1053+
1054+
let channel_parameters: ChannelTransactionParameters = channel_parameters.0.unwrap();
1055+
let redeem_script = channel_parameters.make_funding_redeemscript();
1056+
1057+
Ok(Self {
1058+
script_pubkey: redeem_script.to_p2wsh(),
1059+
redeem_script,
1060+
channel_parameters,
1061+
current_counterparty_commitment_txid: current_counterparty_commitment_txid.0.unwrap(),
1062+
prev_counterparty_commitment_txid,
1063+
current_holder_commitment_tx: current_holder_commitment_tx.0.unwrap(),
1064+
prev_holder_commitment_tx,
1065+
counterparty_claimable_outpoints: counterparty_claimable_outpoints.0.unwrap(),
1066+
})
1067+
}
1068+
}
1069+
10001070
#[derive(Clone, PartialEq)]
10011071
pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
10021072
funding: FundingScope,
1073+
pending_funding: Vec<FundingScope>,
10031074

10041075
latest_update_id: u64,
10051076
commitment_transaction_number_obscure_factor: u64,
@@ -1433,6 +1504,7 @@ impl<Signer: EcdsaChannelSigner> Writeable for ChannelMonitorImpl<Signer> {
14331504
(27, self.first_confirmed_funding_txo, required),
14341505
(29, self.initial_counterparty_commitment_tx, option),
14351506
(31, self.funding.channel_parameters, required),
1507+
(32, self.pending_funding, optional_vec),
14361508
});
14371509

14381510
Ok(())
@@ -1588,6 +1660,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
15881660
current_holder_commitment_tx: initial_holder_commitment_tx,
15891661
prev_holder_commitment_tx: None,
15901662
},
1663+
pending_funding: vec![],
15911664

15921665
latest_update_id: 0,
15931666
commitment_transaction_number_obscure_factor,
@@ -1812,14 +1885,17 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
18121885
{
18131886
let lock = self.inner.lock().unwrap();
18141887
let logger = WithChannelMonitor::from_impl(logger, &*lock, None);
1815-
log_trace!(&logger, "Registering funding outpoint {}", &lock.get_funding_txo());
1816-
let funding_outpoint = lock.get_funding_txo();
1817-
filter.register_tx(&funding_outpoint.txid, &lock.funding.script_pubkey);
1888+
for funding in core::iter::once(&lock.funding).chain(&lock.pending_funding) {
1889+
let funding_outpoint = funding.channel_parameters.funding_outpoint
1890+
.as_ref().unwrap().into_bitcoin_outpoint();
1891+
log_trace!(&logger, "Registering funding outpoint {} with the filter to monitor confirmations", &funding_outpoint);
1892+
filter.register_tx(&funding_outpoint.txid, &funding.script_pubkey);
1893+
}
18181894
for (txid, outputs) in lock.get_outputs_to_watch().iter() {
18191895
for (index, script_pubkey) in outputs.iter() {
18201896
assert!(*index <= u16::MAX as u32);
18211897
let outpoint = OutPoint { txid: *txid, index: *index as u16 };
1822-
log_trace!(logger, "Registering outpoint {} with the filter for monitoring spends", outpoint);
1898+
log_trace!(logger, "Registering outpoint {} with the filter to monitor spend", outpoint);
18231899
filter.register_output(WatchedOutput {
18241900
block_hash: None,
18251901
outpoint,
@@ -3364,6 +3440,109 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
33643440
);
33653441
}
33663442

3443+
fn renegotiated_funding<L: Deref>(
3444+
&mut self, logger: &WithChannelMonitor<L>,
3445+
channel_parameters: &ChannelTransactionParameters,
3446+
alternative_holder_commitment_tx: &HolderCommitmentTransaction,
3447+
alternative_counterparty_commitment_tx: &CommitmentTransaction,
3448+
) -> Result<(), ()>
3449+
where
3450+
L::Target: Logger,
3451+
{
3452+
let redeem_script = channel_parameters.make_funding_redeemscript();
3453+
let script_pubkey = redeem_script.to_p2wsh();
3454+
let alternative_counterparty_commitment_txid =
3455+
alternative_counterparty_commitment_tx.trust().txid();
3456+
3457+
// Both the current counterparty commitment and the alternative one share the same set of
3458+
// non-dust and dust HTLCs in the same order, though the index of each non-dust HTLC may be
3459+
// different.
3460+
//
3461+
// We clone all HTLCs and their sources to use in the alternative funding scope, and update
3462+
// each non-dust HTLC with their corresponding index in the alternative counterparty
3463+
// commitment.
3464+
let current_counterparty_commitment_htlcs =
3465+
if let Some(txid) = &self.funding.current_counterparty_commitment_txid {
3466+
self.funding.counterparty_claimable_outpoints.get(txid).unwrap()
3467+
} else {
3468+
debug_assert!(false);
3469+
log_error!(logger, "Received funding renegotiation while initial funding negotiation is still pending");
3470+
return Err(());
3471+
};
3472+
let mut htlcs_with_sources = current_counterparty_commitment_htlcs.clone();
3473+
let mut alternative_htlcs = alternative_counterparty_commitment_tx.nondust_htlcs().iter();
3474+
while let Some(alternative_htlc) = alternative_htlcs.next() {
3475+
if alternative_htlc.transaction_output_index.is_none() {
3476+
continue;
3477+
}
3478+
let htlc_count = htlcs_with_sources.iter_mut()
3479+
.filter(|htlc_with_source| {
3480+
htlc_with_source.0.transaction_output_index.is_some()
3481+
&& alternative_htlc.is_data_equal(&htlc_with_source.0)
3482+
})
3483+
.enumerate()
3484+
.map(|(idx, htlc_with_source)| {
3485+
htlc_with_source.0.transaction_output_index =
3486+
Some(alternative_htlc.transaction_output_index.unwrap() + idx as u32);
3487+
})
3488+
.count();
3489+
3490+
// Advance the iterator until we get to the next HTLC that does not share the same data,
3491+
// as we already updated all of those indices above.
3492+
for _ in 0..htlc_count - 1 {
3493+
if let Some(next_alternative_htlc) = alternative_htlcs.next() {
3494+
debug_assert!(alternative_htlc.is_data_equal(next_alternative_htlc));
3495+
}
3496+
}
3497+
}
3498+
let mut counterparty_claimable_outpoints = new_hash_map();
3499+
counterparty_claimable_outpoints.insert(
3500+
alternative_counterparty_commitment_txid, htlcs_with_sources,
3501+
);
3502+
3503+
// TODO(splicing): Enforce any necessary RBF validity checks.
3504+
let alternative_funding = FundingScope {
3505+
script_pubkey: script_pubkey.clone(),
3506+
redeem_script,
3507+
channel_parameters: channel_parameters.clone(),
3508+
current_counterparty_commitment_txid: Some(alternative_counterparty_commitment_txid),
3509+
prev_counterparty_commitment_txid: None,
3510+
counterparty_claimable_outpoints,
3511+
current_holder_commitment_tx: alternative_holder_commitment_tx.clone(),
3512+
prev_holder_commitment_tx: None,
3513+
};
3514+
let alternative_funding_outpoint = alternative_funding.funding_outpoint();
3515+
3516+
if self.pending_funding.iter()
3517+
.any(|funding| funding.funding_txid() == alternative_funding_outpoint.txid)
3518+
{
3519+
log_error!(logger, "Renegotiated funding transaction with a duplicate funding txid {}",
3520+
alternative_funding_outpoint.txid);
3521+
return Err(());
3522+
}
3523+
3524+
if let Some(parent_funding_txid) = channel_parameters.splice_parent_funding_txid.as_ref() {
3525+
// Only one splice can be negotiated at a time after we've exchanged `channel_ready`
3526+
// (implying our funding is confirmed) that spends our currently locked funding.
3527+
if !self.pending_funding.is_empty() {
3528+
log_error!(logger, "Negotiated splice while channel is pending channel_ready/splice_locked");
3529+
return Err(());
3530+
}
3531+
if *parent_funding_txid != self.funding.funding_txid() {
3532+
log_error!(logger, "Negotiated splice that does not spend currently locked funding transaction");
3533+
return Err(());
3534+
}
3535+
}
3536+
3537+
self.outputs_to_watch.insert(
3538+
alternative_funding_outpoint.txid,
3539+
vec![(alternative_funding_outpoint.index as u32, script_pubkey)],
3540+
);
3541+
self.pending_funding.push(alternative_funding);
3542+
3543+
Ok(())
3544+
}
3545+
33673546
fn update_monitor<B: Deref, F: Deref, L: Deref>(
33683547
&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &WithChannelMonitor<L>
33693548
) -> Result<(), ()>
@@ -3442,6 +3621,17 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
34423621
ret = Err(());
34433622
}
34443623
},
3624+
ChannelMonitorUpdateStep::RenegotiatedFunding {
3625+
channel_parameters, holder_commitment_tx, counterparty_commitment_tx,
3626+
} => {
3627+
log_trace!(logger, "Updating ChannelMonitor with alternative holder and counterparty commitment transactions for funding txid {}",
3628+
channel_parameters.funding_outpoint.unwrap().txid);
3629+
if let Err(_) = self.renegotiated_funding(
3630+
logger, channel_parameters, holder_commitment_tx, counterparty_commitment_tx,
3631+
) {
3632+
ret = Err(());
3633+
}
3634+
},
34453635
ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } => {
34463636
log_trace!(logger, "Updating ChannelMonitor: channel force closed, should broadcast: {}", should_broadcast);
34473637
self.lockdown_from_offchain = true;
@@ -3493,7 +3683,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
34933683
|ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. }
34943684
|ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTX { .. }
34953685
|ChannelMonitorUpdateStep::ShutdownScript { .. }
3496-
|ChannelMonitorUpdateStep::CommitmentSecret { .. } =>
3686+
|ChannelMonitorUpdateStep::CommitmentSecret { .. }
3687+
|ChannelMonitorUpdateStep::RenegotiatedFunding { .. } =>
34973688
is_pre_close_update = true,
34983689
// After a channel is closed, we don't communicate with our peer about it, so the
34993690
// only things we will update is getting a new preimage (from a different channel)
@@ -3671,6 +3862,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
36713862
} => {
36723863
Some(commitment_tx.clone())
36733864
},
3865+
&ChannelMonitorUpdateStep::RenegotiatedFunding { ref counterparty_commitment_tx, .. } => {
3866+
Some(counterparty_commitment_tx.clone())
3867+
},
36743868
_ => None,
36753869
}
36763870
}).collect()
@@ -5303,6 +5497,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
53035497
let mut payment_preimages_with_info: Option<HashMap<_, _>> = None;
53045498
let mut first_confirmed_funding_txo = RequiredWrapper(None);
53055499
let mut channel_parameters = None;
5500+
let mut pending_funding = None;
53065501
read_tlv_fields!(reader, {
53075502
(1, funding_spend_confirmed, option),
53085503
(3, htlcs_resolved_on_chain, optional_vec),
@@ -5320,6 +5515,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
53205515
(27, first_confirmed_funding_txo, (default_value, outpoint)),
53215516
(29, initial_counterparty_commitment_tx, option),
53225517
(31, channel_parameters, (option: ReadableArgs, None)),
5518+
(32, pending_funding, optional_vec),
53235519
});
53245520
if let Some(payment_preimages_with_info) = payment_preimages_with_info {
53255521
if payment_preimages_with_info.len() != payment_preimages.len() {
@@ -5435,6 +5631,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
54355631
current_holder_commitment_tx,
54365632
prev_holder_commitment_tx,
54375633
},
5634+
pending_funding: pending_funding.unwrap_or(vec![]),
54385635

54395636
latest_update_id,
54405637
commitment_transaction_number_obscure_factor,

0 commit comments

Comments
 (0)