@@ -3451,6 +3451,132 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
34513451 !matches!(self.channel_state, ChannelState::AwaitingChannelReady(flags) if flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH))
34523452 }
34533453
3454+ fn validate_commitment_signed<L: Deref>(
3455+ &self, funding: &FundingScope, holder_commitment_point: &HolderCommitmentPoint,
3456+ msg: &msgs::CommitmentSigned, logger: &L,
3457+ ) -> Result<LatestHolderCommitmentTXInfo, ChannelError>
3458+ where
3459+ L::Target: Logger,
3460+ {
3461+ let funding_script = funding.get_funding_redeemscript();
3462+
3463+ let keys = self.build_holder_transaction_keys(funding, holder_commitment_point.current_point());
3464+
3465+ let commitment_stats = self.build_commitment_transaction(funding, holder_commitment_point.transaction_number(), &keys, true, false, logger);
3466+ let commitment_txid = {
3467+ let trusted_tx = commitment_stats.tx.trust();
3468+ let bitcoin_tx = trusted_tx.built_transaction();
3469+ let sighash = bitcoin_tx.get_sighash_all(&funding_script, funding.get_value_satoshis());
3470+
3471+ log_trace!(logger, "Checking commitment tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}",
3472+ log_bytes!(msg.signature.serialize_compact()[..]),
3473+ log_bytes!(funding.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&bitcoin_tx.transaction),
3474+ log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), &self.channel_id());
3475+ if let Err(_) = self.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &funding.counterparty_funding_pubkey()) {
3476+ return Err(ChannelError::close("Invalid commitment tx signature from peer".to_owned()));
3477+ }
3478+ bitcoin_tx.txid
3479+ };
3480+ let mut htlcs_cloned: Vec<_> = commitment_stats.htlcs_included.iter().map(|htlc| (htlc.0.clone(), htlc.1.map(|h| h.clone()))).collect();
3481+
3482+ // If our counterparty updated the channel fee in this commitment transaction, check that
3483+ // they can actually afford the new fee now.
3484+ let update_fee = if let Some((_, update_state)) = self.pending_update_fee {
3485+ update_state == FeeUpdateState::RemoteAnnounced
3486+ } else { false };
3487+ if update_fee {
3488+ debug_assert!(!funding.is_outbound());
3489+ let counterparty_reserve_we_require_msat = funding.holder_selected_channel_reserve_satoshis * 1000;
3490+ if commitment_stats.remote_balance_msat < commitment_stats.total_fee_sat * 1000 + counterparty_reserve_we_require_msat {
3491+ return Err(ChannelError::close("Funding remote cannot afford proposed new fee".to_owned()));
3492+ }
3493+ }
3494+ #[cfg(any(test, fuzzing))]
3495+ {
3496+ if funding.is_outbound() {
3497+ let projected_commit_tx_info = funding.next_local_commitment_tx_fee_info_cached.lock().unwrap().take();
3498+ *funding.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
3499+ if let Some(info) = projected_commit_tx_info {
3500+ let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len()
3501+ + self.holding_cell_htlc_updates.len();
3502+ if info.total_pending_htlcs == total_pending_htlcs
3503+ && info.next_holder_htlc_id == self.next_holder_htlc_id
3504+ && info.next_counterparty_htlc_id == self.next_counterparty_htlc_id
3505+ && info.feerate == self.feerate_per_kw {
3506+ assert_eq!(commitment_stats.total_fee_sat, info.fee / 1000);
3507+ }
3508+ }
3509+ }
3510+ }
3511+
3512+ if msg.htlc_signatures.len() != commitment_stats.num_nondust_htlcs {
3513+ return Err(ChannelError::close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), commitment_stats.num_nondust_htlcs)));
3514+ }
3515+
3516+ // Up to LDK 0.0.115, HTLC information was required to be duplicated in the
3517+ // `htlcs_and_sigs` vec and in the `holder_commitment_tx` itself, both of which were passed
3518+ // in the `ChannelMonitorUpdate`. In 0.0.115, support for having a separate set of
3519+ // outbound-non-dust-HTLCSources in the `ChannelMonitorUpdate` was added, however for
3520+ // backwards compatibility, we never use it in production. To provide test coverage, here,
3521+ // we randomly decide (in test/fuzzing builds) to use the new vec sometimes.
3522+ #[allow(unused_assignments, unused_mut)]
3523+ let mut separate_nondust_htlc_sources = false;
3524+ #[cfg(all(feature = "std", any(test, fuzzing)))] {
3525+ use core::hash::{BuildHasher, Hasher};
3526+ // Get a random value using the only std API to do so - the DefaultHasher
3527+ let rand_val = std::collections::hash_map::RandomState::new().build_hasher().finish();
3528+ separate_nondust_htlc_sources = rand_val % 2 == 0;
3529+ }
3530+
3531+ let mut nondust_htlc_sources = Vec::with_capacity(htlcs_cloned.len());
3532+ let mut htlcs_and_sigs = Vec::with_capacity(htlcs_cloned.len());
3533+ for (idx, (htlc, mut source_opt)) in htlcs_cloned.drain(..).enumerate() {
3534+ if let Some(_) = htlc.transaction_output_index {
3535+ let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw,
3536+ funding.get_counterparty_selected_contest_delay().unwrap(), &htlc, &self.channel_type,
3537+ &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
3538+
3539+ let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &self.channel_type, &keys);
3540+ let htlc_sighashtype = if self.channel_type.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
3541+ let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).p2wsh_signature_hash(0, &htlc_redeemscript, htlc.to_bitcoin_amount(), htlc_sighashtype).unwrap()[..]);
3542+ log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.",
3543+ log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.to_public_key().serialize()),
3544+ encode::serialize_hex(&htlc_tx), log_bytes!(htlc_sighash[..]), encode::serialize_hex(&htlc_redeemscript), &self.channel_id());
3545+ if let Err(_) = self.secp_ctx.verify_ecdsa(&htlc_sighash, &msg.htlc_signatures[idx], &keys.countersignatory_htlc_key.to_public_key()) {
3546+ return Err(ChannelError::close("Invalid HTLC tx signature from peer".to_owned()));
3547+ }
3548+ if !separate_nondust_htlc_sources {
3549+ htlcs_and_sigs.push((htlc, Some(msg.htlc_signatures[idx]), source_opt.take()));
3550+ }
3551+ } else {
3552+ htlcs_and_sigs.push((htlc, None, source_opt.take()));
3553+ }
3554+ if separate_nondust_htlc_sources {
3555+ if let Some(source) = source_opt.take() {
3556+ nondust_htlc_sources.push(source);
3557+ }
3558+ }
3559+ debug_assert!(source_opt.is_none(), "HTLCSource should have been put somewhere");
3560+ }
3561+
3562+ let holder_commitment_tx = HolderCommitmentTransaction::new(
3563+ commitment_stats.tx,
3564+ msg.signature,
3565+ msg.htlc_signatures.clone(),
3566+ &funding.get_holder_pubkeys().funding_pubkey,
3567+ funding.counterparty_funding_pubkey()
3568+ );
3569+
3570+ self.holder_signer.as_ref().validate_holder_commitment(&holder_commitment_tx, commitment_stats.outbound_htlc_preimages)
3571+ .map_err(|_| ChannelError::close("Failed to validate our commitment".to_owned()))?;
3572+
3573+ Ok(LatestHolderCommitmentTXInfo {
3574+ commitment_tx: holder_commitment_tx,
3575+ htlc_outputs: htlcs_and_sigs,
3576+ nondust_htlc_sources,
3577+ })
3578+ }
3579+
34543580 /// Transaction nomenclature is somewhat confusing here as there are many different cases - a
34553581 /// transaction is referred to as "a's transaction" implying that a will be able to broadcast
34563582 /// the transaction. Thus, b will generally be sending a signature over such a transaction to
@@ -4706,7 +4832,7 @@ struct CommitmentTxInfoCached {
47064832}
47074833
47084834/// Partial data from ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo used to simplify the
4709- /// return type of `FundedChannel ::validate_commitment_signed`.
4835+ /// return type of `ChannelContext ::validate_commitment_signed`.
47104836struct LatestHolderCommitmentTXInfo {
47114837 pub commitment_tx: HolderCommitmentTransaction,
47124838 pub htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
@@ -5501,128 +5627,6 @@ impl<SP: Deref> FundedChannel<SP> where
55015627 Ok(channel_monitor)
55025628 }
55035629
5504- fn validate_commitment_signed<L: Deref>(&self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<LatestHolderCommitmentTXInfo, ChannelError>
5505- where L::Target: Logger
5506- {
5507- let funding_script = self.funding.get_funding_redeemscript();
5508-
5509- let keys = self.context.build_holder_transaction_keys(&self.funding, self.holder_commitment_point.current_point());
5510-
5511- let commitment_stats = self.context.build_commitment_transaction(&self.funding, self.holder_commitment_point.transaction_number(), &keys, true, false, logger);
5512- let commitment_txid = {
5513- let trusted_tx = commitment_stats.tx.trust();
5514- let bitcoin_tx = trusted_tx.built_transaction();
5515- let sighash = bitcoin_tx.get_sighash_all(&funding_script, self.funding.get_value_satoshis());
5516-
5517- log_trace!(logger, "Checking commitment tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}",
5518- log_bytes!(msg.signature.serialize_compact()[..]),
5519- log_bytes!(self.funding.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&bitcoin_tx.transaction),
5520- log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), &self.context.channel_id());
5521- if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.funding.counterparty_funding_pubkey()) {
5522- return Err(ChannelError::close("Invalid commitment tx signature from peer".to_owned()));
5523- }
5524- bitcoin_tx.txid
5525- };
5526- let mut htlcs_cloned: Vec<_> = commitment_stats.htlcs_included.iter().map(|htlc| (htlc.0.clone(), htlc.1.map(|h| h.clone()))).collect();
5527-
5528- // If our counterparty updated the channel fee in this commitment transaction, check that
5529- // they can actually afford the new fee now.
5530- let update_fee = if let Some((_, update_state)) = self.context.pending_update_fee {
5531- update_state == FeeUpdateState::RemoteAnnounced
5532- } else { false };
5533- if update_fee {
5534- debug_assert!(!self.funding.is_outbound());
5535- let counterparty_reserve_we_require_msat = self.funding.holder_selected_channel_reserve_satoshis * 1000;
5536- if commitment_stats.remote_balance_msat < commitment_stats.total_fee_sat * 1000 + counterparty_reserve_we_require_msat {
5537- return Err(ChannelError::close("Funding remote cannot afford proposed new fee".to_owned()));
5538- }
5539- }
5540- #[cfg(any(test, fuzzing))]
5541- {
5542- if self.funding.is_outbound() {
5543- let projected_commit_tx_info = self.funding.next_local_commitment_tx_fee_info_cached.lock().unwrap().take();
5544- *self.funding.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
5545- if let Some(info) = projected_commit_tx_info {
5546- let total_pending_htlcs = self.context.pending_inbound_htlcs.len() + self.context.pending_outbound_htlcs.len()
5547- + self.context.holding_cell_htlc_updates.len();
5548- if info.total_pending_htlcs == total_pending_htlcs
5549- && info.next_holder_htlc_id == self.context.next_holder_htlc_id
5550- && info.next_counterparty_htlc_id == self.context.next_counterparty_htlc_id
5551- && info.feerate == self.context.feerate_per_kw {
5552- assert_eq!(commitment_stats.total_fee_sat, info.fee / 1000);
5553- }
5554- }
5555- }
5556- }
5557-
5558- if msg.htlc_signatures.len() != commitment_stats.num_nondust_htlcs {
5559- return Err(ChannelError::close(format!("Got wrong number of HTLC signatures ({}) from remote. It must be {}", msg.htlc_signatures.len(), commitment_stats.num_nondust_htlcs)));
5560- }
5561-
5562- // Up to LDK 0.0.115, HTLC information was required to be duplicated in the
5563- // `htlcs_and_sigs` vec and in the `holder_commitment_tx` itself, both of which were passed
5564- // in the `ChannelMonitorUpdate`. In 0.0.115, support for having a separate set of
5565- // outbound-non-dust-HTLCSources in the `ChannelMonitorUpdate` was added, however for
5566- // backwards compatibility, we never use it in production. To provide test coverage, here,
5567- // we randomly decide (in test/fuzzing builds) to use the new vec sometimes.
5568- #[allow(unused_assignments, unused_mut)]
5569- let mut separate_nondust_htlc_sources = false;
5570- #[cfg(all(feature = "std", any(test, fuzzing)))] {
5571- use core::hash::{BuildHasher, Hasher};
5572- // Get a random value using the only std API to do so - the DefaultHasher
5573- let rand_val = std::collections::hash_map::RandomState::new().build_hasher().finish();
5574- separate_nondust_htlc_sources = rand_val % 2 == 0;
5575- }
5576-
5577- let mut nondust_htlc_sources = Vec::with_capacity(htlcs_cloned.len());
5578- let mut htlcs_and_sigs = Vec::with_capacity(htlcs_cloned.len());
5579- for (idx, (htlc, mut source_opt)) in htlcs_cloned.drain(..).enumerate() {
5580- if let Some(_) = htlc.transaction_output_index {
5581- let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw,
5582- self.funding.get_counterparty_selected_contest_delay().unwrap(), &htlc, &self.context.channel_type,
5583- &keys.broadcaster_delayed_payment_key, &keys.revocation_key);
5584-
5585- let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &self.context.channel_type, &keys);
5586- let htlc_sighashtype = if self.context.channel_type.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All };
5587- let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).p2wsh_signature_hash(0, &htlc_redeemscript, htlc.to_bitcoin_amount(), htlc_sighashtype).unwrap()[..]);
5588- log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.",
5589- log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.to_public_key().serialize()),
5590- encode::serialize_hex(&htlc_tx), log_bytes!(htlc_sighash[..]), encode::serialize_hex(&htlc_redeemscript), &self.context.channel_id());
5591- if let Err(_) = self.context.secp_ctx.verify_ecdsa(&htlc_sighash, &msg.htlc_signatures[idx], &keys.countersignatory_htlc_key.to_public_key()) {
5592- return Err(ChannelError::close("Invalid HTLC tx signature from peer".to_owned()));
5593- }
5594- if !separate_nondust_htlc_sources {
5595- htlcs_and_sigs.push((htlc, Some(msg.htlc_signatures[idx]), source_opt.take()));
5596- }
5597- } else {
5598- htlcs_and_sigs.push((htlc, None, source_opt.take()));
5599- }
5600- if separate_nondust_htlc_sources {
5601- if let Some(source) = source_opt.take() {
5602- nondust_htlc_sources.push(source);
5603- }
5604- }
5605- debug_assert!(source_opt.is_none(), "HTLCSource should have been put somewhere");
5606- }
5607-
5608- let holder_commitment_tx = HolderCommitmentTransaction::new(
5609- commitment_stats.tx,
5610- msg.signature,
5611- msg.htlc_signatures.clone(),
5612- &self.funding.get_holder_pubkeys().funding_pubkey,
5613- self.funding.counterparty_funding_pubkey()
5614- );
5615-
5616- self.context.holder_signer.as_ref().validate_holder_commitment(&holder_commitment_tx, commitment_stats.outbound_htlc_preimages)
5617- .map_err(|_| ChannelError::close("Failed to validate our commitment".to_owned()))?;
5618-
5619- Ok(LatestHolderCommitmentTXInfo {
5620- commitment_tx: holder_commitment_tx,
5621- htlc_outputs: htlcs_and_sigs,
5622- nondust_htlc_sources,
5623- })
5624- }
5625-
56265630 pub fn commitment_signed<L: Deref>(&mut self, msg: &msgs::CommitmentSigned, logger: &L) -> Result<Option<ChannelMonitorUpdate>, ChannelError>
56275631 where L::Target: Logger
56285632 {
@@ -5639,7 +5643,7 @@ impl<SP: Deref> FundedChannel<SP> where
56395643 return Err(ChannelError::close("Peer sent commitment_signed after we'd started exchanging closing_signeds".to_owned()));
56405644 }
56415645
5642- let commitment_tx_info = self.validate_commitment_signed(msg, logger)?;
5646+ let commitment_tx_info = self.context. validate_commitment_signed(&self.funding, &self.holder_commitment_point, msg, logger)?;
56435647
56445648 // Update state now that we've passed all the can-fail calls...
56455649 let mut need_commitment = false;
0 commit comments