Skip to content

Commit b942c81

Browse files
committed
Track HTLCDescriptor in HolderHTLCOutput
The `ChannelMonitor` and `OnchainTxHandler` have historically been tied together, often tracking some of the same state twice. As we introduce support for splices in the `ChannelMonitor`, we'd like to avoid leaking some of those details to the `OnchainTxHandler`. Ultimately, the `OnchainTxHandler` should stand on its own and support claiming funds from multiple `ChannelMonitor`s, allowing us to save on fees by batching aggregatable claims across multiple in-flight closing channels. This commit tracks the `HTLCDescriptor` for the specific `FundingScope` the `HolderHTLCOutput` claim originated from. Previously, when claiming `HolderHTLCOutput`s, the `OnchainTxHandler` had to check which holder commitment the HTLC belonged to in order to produce an `HTLCDescriptor` for signing. We still maintain the legacy logic for existing claims which have not had an `HTLCDescriptor` written yet. Along the way, we refactor the claim process for such outputs to decouple them from the `OnchainTxHandler`. As a result, the `OnchainTxHandler` is only used to obtain references to the signer and secp256k1 context. Once splices are supported, we may run into cases where we are attempting to claim an output from a specific `FundingScope`, while also having an additional pending `FundingScope` for a splice. If the pending splice confirms over the output claim, we need to cancel the claim and re-offer it with the set of relevant parameters in the new `FundingScope`.
1 parent 1551141 commit b942c81

File tree

5 files changed

+283
-239
lines changed

5 files changed

+283
-239
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 78 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3562,29 +3562,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
35623562
} => {
35633563
let channel_id = self.channel_id;
35643564
let counterparty_node_id = self.counterparty_node_id;
3565-
let mut htlc_descriptors = Vec::with_capacity(htlcs.len());
3566-
for htlc in htlcs {
3567-
htlc_descriptors.push(HTLCDescriptor {
3568-
channel_derivation_parameters: ChannelDerivationParameters {
3569-
keys_id: self.channel_keys_id,
3570-
value_satoshis: self.funding.channel_parameters.channel_value_satoshis,
3571-
transaction_parameters: self.funding.channel_parameters.clone(),
3572-
},
3573-
commitment_txid: htlc.commitment_txid,
3574-
per_commitment_number: htlc.per_commitment_number,
3575-
per_commitment_point: htlc.per_commitment_point,
3576-
feerate_per_kw: 0,
3577-
htlc: htlc.htlc,
3578-
preimage: htlc.preimage,
3579-
counterparty_sig: htlc.counterparty_sig,
3580-
});
3581-
}
35823565
ret.push(Event::BumpTransaction(BumpTransactionEvent::HTLCResolution {
35833566
channel_id,
35843567
counterparty_node_id,
35853568
claim_id,
35863569
target_feerate_sat_per_1000_weight,
3587-
htlc_descriptors,
3570+
htlc_descriptors: htlcs,
35883571
tx_lock_time,
35893572
}));
35903573
}
@@ -3973,14 +3956,57 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39733956
(claimable_outpoints, outputs_to_watch)
39743957
}
39753958

3959+
fn get_broadcasted_holder_htlc_descriptors(
3960+
&self, holder_tx: &HolderCommitmentTransaction,
3961+
) -> Vec<HTLCDescriptor> {
3962+
let tx = holder_tx.trust();
3963+
let mut htlcs = Vec::with_capacity(holder_tx.htlcs().len());
3964+
for (idx, htlc) in holder_tx.htlcs().iter().enumerate() {
3965+
assert!(htlc.transaction_output_index.is_some(), "Expected transaction output index for non-dust HTLC");
3966+
3967+
let counterparty_sig =
3968+
if let Some(counterparty_sig) = holder_tx.counterparty_htlc_sigs.get(idx) {
3969+
*counterparty_sig
3970+
} else {
3971+
debug_assert!(false, "All non-dust HTLCs must have a corresponding counterparty signature");
3972+
continue;
3973+
};
3974+
3975+
let preimage = if htlc.offered {
3976+
None
3977+
} else if let Some((preimage, _)) = self.payment_preimages.get(&htlc.payment_hash) {
3978+
Some(*preimage)
3979+
} else {
3980+
// We can't build an HTLC-Success transaction without the preimage
3981+
continue;
3982+
};
3983+
3984+
htlcs.push(HTLCDescriptor {
3985+
// TODO(splicing): Consider alternative funding scopes.
3986+
channel_derivation_parameters: ChannelDerivationParameters {
3987+
value_satoshis: self.funding.channel_parameters.channel_value_satoshis,
3988+
keys_id: self.channel_keys_id,
3989+
transaction_parameters: self.funding.channel_parameters.clone(),
3990+
},
3991+
commitment_txid: tx.txid(),
3992+
per_commitment_number: tx.commitment_number(),
3993+
per_commitment_point: tx.per_commitment_point(),
3994+
feerate_per_kw: tx.feerate_per_kw(),
3995+
htlc: htlc.clone(),
3996+
preimage,
3997+
counterparty_sig,
3998+
});
3999+
}
4000+
4001+
htlcs
4002+
}
4003+
39764004
// Returns (1) `PackageTemplate`s that can be given to the OnchainTxHandler, so that the handler can
39774005
// broadcast transactions claiming holder HTLC commitment outputs and (2) a holder revokable
39784006
// script so we can detect whether a holder transaction has been seen on-chain.
39794007
fn get_broadcasted_holder_claims(
39804008
&self, holder_tx: &HolderCommitmentTransaction, conf_height: u32,
39814009
) -> (Vec<PackageTemplate>, Option<(ScriptBuf, PublicKey, RevocationKey)>) {
3982-
let mut claim_requests = Vec::with_capacity(holder_tx.htlcs().len());
3983-
39844010
let tx = holder_tx.trust();
39854011
let keys = tx.keys();
39864012
let redeem_script = chan_utils::get_revokeable_redeemscript(
@@ -3990,36 +4016,22 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39904016
redeem_script.to_p2wsh(), holder_tx.per_commitment_point(), keys.revocation_key.clone(),
39914017
));
39924018

3993-
let txid = tx.txid();
3994-
for htlc in holder_tx.htlcs() {
3995-
if let Some(transaction_output_index) = htlc.transaction_output_index {
3996-
let (htlc_output, counterparty_spendable_height) = if htlc.offered {
3997-
let htlc_output = HolderHTLCOutput::build_offered(
3998-
htlc.amount_msat, htlc.cltv_expiry, self.channel_type_features().clone()
3999-
);
4000-
(htlc_output, conf_height)
4019+
let claim_requests = self.get_broadcasted_holder_htlc_descriptors(holder_tx).into_iter()
4020+
.map(|htlc_descriptor| {
4021+
let counterparty_spendable_height = if htlc_descriptor.htlc.offered {
4022+
conf_height
40014023
} else {
4002-
let payment_preimage = if let Some((preimage, _)) = self.payment_preimages.get(&htlc.payment_hash) {
4003-
preimage.clone()
4004-
} else {
4005-
// We can't build an HTLC-Success transaction without the preimage
4006-
continue;
4007-
};
4008-
let htlc_output = HolderHTLCOutput::build_accepted(
4009-
payment_preimage, htlc.amount_msat, self.channel_type_features().clone()
4010-
);
4011-
(htlc_output, htlc.cltv_expiry)
4024+
htlc_descriptor.htlc.cltv_expiry
40124025
};
4013-
let htlc_package = PackageTemplate::build_package(
4014-
txid, transaction_output_index,
4015-
PackageSolvingData::HolderHTLCOutput(htlc_output),
4026+
let transaction_output_index = htlc_descriptor.htlc.transaction_output_index
4027+
.expect("Expected transaction output index for non-dust HTLC");
4028+
PackageTemplate::build_package(
4029+
tx.txid(), transaction_output_index,
4030+
PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build(htlc_descriptor)),
40164031
counterparty_spendable_height,
4017-
);
4018-
claim_requests.push(htlc_package);
4019-
} else {
4020-
debug_assert!(false, "Expected transaction output index for non-dust HTLC");
4021-
}
4022-
}
4032+
)
4033+
})
4034+
.collect();
40234035

40244036
(claim_requests, broadcasted_holder_revokable_script)
40254037
}
@@ -4153,33 +4165,36 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
41534165
&mut self, logger: &WithChannelMonitor<L>
41544166
) -> Vec<Transaction> where L::Target: Logger {
41554167
log_debug!(logger, "Getting signed copy of latest holder commitment transaction!");
4156-
let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding.redeem_script);
4157-
let txid = commitment_tx.compute_txid();
4168+
let commitment_tx = {
4169+
let sig = self.onchain_tx_handler.signer.unsafe_sign_holder_commitment(
4170+
&self.funding.channel_parameters, &self.funding.current_holder_commitment.tx,
4171+
&self.onchain_tx_handler.secp_ctx,
4172+
).expect("sign holder commitment");
4173+
self.funding.current_holder_commitment.tx.add_holder_sig(&self.funding.redeem_script, sig)
4174+
};
41584175
let mut holder_transactions = vec![commitment_tx];
41594176
// When anchor outputs are present, the HTLC transactions are only final once the commitment
41604177
// transaction confirms due to the CSV 1 encumberance.
41614178
if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() {
41624179
return holder_transactions;
41634180
}
4164-
for htlc in self.funding.current_holder_commitment.tx.htlcs() {
4165-
if let Some(vout) = htlc.transaction_output_index {
4166-
let preimage = if !htlc.offered {
4167-
if let Some((preimage, _)) = self.payment_preimages.get(&htlc.payment_hash) { Some(preimage.clone()) } else {
4168-
// We can't build an HTLC-Success transaction without the preimage
4169-
continue;
4170-
}
4171-
} else { None };
4172-
if let Some(htlc_tx) = self.onchain_tx_handler.get_maybe_signed_htlc_tx(
4173-
&::bitcoin::OutPoint { txid, vout }, &preimage
4181+
4182+
self.get_broadcasted_holder_htlc_descriptors(&self.funding.current_holder_commitment.tx)
4183+
.into_iter()
4184+
.for_each(|htlc_descriptor| {
4185+
let txid = self.funding.current_holder_commitment.tx.trust().txid();
4186+
let vout = htlc_descriptor.htlc.transaction_output_index
4187+
.expect("Expected transaction output index for non-dust HTLC");
4188+
let htlc_output = HolderHTLCOutput::build(htlc_descriptor);
4189+
if let Some(htlc_tx) = htlc_output.get_maybe_signed_htlc_tx(
4190+
&mut self.onchain_tx_handler, &::bitcoin::OutPoint { txid, vout },
41744191
) {
41754192
if htlc_tx.is_fully_signed() {
41764193
holder_transactions.push(htlc_tx.0);
41774194
}
41784195
}
4179-
} else {
4180-
debug_assert!(false, "Expected transaction output index for non-dust HTLC");
4181-
}
4182-
}
4196+
});
4197+
41834198
holder_transactions
41844199
}
41854200

0 commit comments

Comments
 (0)