diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index a48f169a4d5..87bdeea6351 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -1566,7 +1566,7 @@ impl ChannelMonitorImpl { debug_assert!(htlc_input_idx_opt.is_some()); BitcoinOutPoint::new(*txid, htlc_input_idx_opt.unwrap_or(0)) } else { - debug_assert!(!self.onchain_tx_handler.opt_anchors()); + debug_assert!(!self.onchain_tx_handler.channel_type().supports_anchors()); BitcoinOutPoint::new(*txid, 0) } } else { @@ -2425,10 +2425,10 @@ impl ChannelMonitorImpl { // If the channel supports anchor outputs, we'll need to emit an external // event to be consumed such that a child transaction is broadcast with a // high enough feerate for the parent commitment transaction to confirm. - if self.onchain_tx_handler.opt_anchors() { + if self.onchain_tx_handler.channel_type().supports_anchors() { let funding_output = HolderFundingOutput::build( self.funding_redeemscript.clone(), self.channel_value_satoshis, - self.onchain_tx_handler.opt_anchors(), + self.onchain_tx_handler.channel_type(), ); let best_block_height = self.best_block.height(); let commitment_package = PackageTemplate::build_package( @@ -2617,7 +2617,7 @@ impl ChannelMonitorImpl { // First, process non-htlc outputs (to_holder & to_counterparty) for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { - let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv, self.onchain_tx_handler.opt_anchors()); + let revk_outp = RevokedOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, outp.value, self.counterparty_commitment_params.on_counterparty_tx_csv, self.onchain_tx_handler.channel_type().supports_anchors()); let justice_package = PackageTemplate::build_package(commitment_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp), height + self.counterparty_commitment_params.on_counterparty_tx_csv as u32, height); claimable_outpoints.push(justice_package); to_counterparty_output_info = @@ -2635,7 +2635,7 @@ impl ChannelMonitorImpl { return (claimable_outpoints, (commitment_txid, watch_outputs), to_counterparty_output_info); } - let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_some()); + let revk_htlc_outp = RevokedHTLCOutput::build(per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, per_commitment_key, htlc.amount_msat / 1000, htlc.clone(), &self.onchain_tx_handler.channel_transaction_parameters.channel_type); let justice_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, PackageSolvingData::RevokedHTLCOutput(revk_htlc_outp), htlc.cltv_expiry, height); claimable_outpoints.push(justice_package); } @@ -2753,13 +2753,13 @@ impl ChannelMonitorImpl { CounterpartyOfferedHTLCOutput::build(*per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, - preimage.unwrap(), htlc.clone(), self.onchain_tx_handler.opt_anchors())) + preimage.unwrap(), htlc.clone(), self.onchain_tx_handler.channel_type())) } else { PackageSolvingData::CounterpartyReceivedHTLCOutput( CounterpartyReceivedHTLCOutput::build(*per_commitment_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, - htlc.clone(), self.onchain_tx_handler.opt_anchors())) + htlc.clone(), self.onchain_tx_handler.channel_type())) }; let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry, 0); claimable_outpoints.push(counterparty_package); @@ -2830,7 +2830,7 @@ impl ChannelMonitorImpl { if let Some(transaction_output_index) = htlc.transaction_output_index { let htlc_output = if htlc.offered { let htlc_output = HolderHTLCOutput::build_offered( - htlc.amount_msat, htlc.cltv_expiry, self.onchain_tx_handler.opt_anchors() + htlc.amount_msat, htlc.cltv_expiry, self.onchain_tx_handler.channel_type() ); htlc_output } else { @@ -2841,7 +2841,7 @@ impl ChannelMonitorImpl { continue; }; let htlc_output = HolderHTLCOutput::build_accepted( - payment_preimage, htlc.amount_msat, self.onchain_tx_handler.opt_anchors() + payment_preimage, htlc.amount_msat, self.onchain_tx_handler.channel_type() ); htlc_output }; @@ -2925,7 +2925,7 @@ impl ChannelMonitorImpl { let mut holder_transactions = vec![commitment_tx]; // When anchor outputs are present, the HTLC transactions are only valid once the commitment // transaction confirms. - if self.onchain_tx_handler.opt_anchors() { + if self.onchain_tx_handler.channel_type().supports_anchors() { return holder_transactions; } for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { @@ -2963,7 +2963,7 @@ impl ChannelMonitorImpl { let mut holder_transactions = vec![commitment_tx]; // When anchor outputs are present, the HTLC transactions are only final once the commitment // transaction confirms due to the CSV 1 encumberance. - if self.onchain_tx_handler.opt_anchors() { + if self.onchain_tx_handler.channel_type().supports_anchors() { return holder_transactions; } for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { @@ -3187,7 +3187,7 @@ impl ChannelMonitorImpl { let should_broadcast = self.should_broadcast_holder_commitment_txn(logger); if should_broadcast { - let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.opt_anchors()); + let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.channel_type()); let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), self.best_block.height(), self.best_block.height()); claimable_outpoints.push(commitment_package); self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0)); @@ -3196,7 +3196,7 @@ impl ChannelMonitorImpl { // We can't broadcast our HTLC transactions while the commitment transaction is // unconfirmed. We'll delay doing so until we detect the confirmed commitment in // `transactions_confirmed`. - if !self.onchain_tx_handler.opt_anchors() { + if !self.onchain_tx_handler.channel_type().supports_anchors() { // Because we're broadcasting a commitment transaction, we should construct the package // assuming it gets confirmed in the next block. Sadly, we have code which considers // "not yet confirmed" things as discardable, so we cannot do that here. @@ -4124,6 +4124,7 @@ mod tests { use crate::sync::{Arc, Mutex}; use crate::io; use bitcoin::{PackedLockTime, Sequence, Witness}; + use crate::ln::channel::ChannelType; use crate::prelude::*; fn do_test_funding_spend_refuses_updates(use_local_txn: bool) { @@ -4297,7 +4298,7 @@ mod tests { selected_contest_delay: 67, }), funding_outpoint: Some(funding_outpoint), - opt_anchors: None, + channel_type: ChannelType::Legacy, opt_non_zero_fee_anchors: None, }; // Prune with one old state and a holder commitment tx holding a few overlaps with the @@ -4414,7 +4415,7 @@ mod tests { let txid = Txid::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d").unwrap(); // Justice tx with 1 to_holder, 2 revoked offered HTLCs, 1 revoked received HTLCs - for &opt_anchors in [false, true].iter() { + for channel_type in [ChannelType::Legacy, ChannelType::Anchors].iter() { let mut claim_tx = Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }; let mut sum_actual_sigs = 0; for i in 0..4 { @@ -4433,12 +4434,12 @@ mod tests { value: 0, }); let base_weight = claim_tx.weight(); - let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT, weight_revoked_offered_htlc(opt_anchors), weight_revoked_offered_htlc(opt_anchors), weight_revoked_received_htlc(opt_anchors)]; + let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT, weight_revoked_offered_htlc(&channel_type), weight_revoked_offered_htlc(&channel_type), weight_revoked_received_htlc(&channel_type)]; let mut inputs_total_weight = 2; // count segwit flags { let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { - sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors); + sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, &channel_type); inputs_total_weight += inp; } } @@ -4446,7 +4447,7 @@ mod tests { } // Claim tx with 1 offered HTLCs, 3 received HTLCs - for &opt_anchors in [false, true].iter() { + for channel_type in [ChannelType::Legacy, ChannelType::Anchors].iter() { let mut claim_tx = Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }; let mut sum_actual_sigs = 0; for i in 0..4 { @@ -4465,12 +4466,12 @@ mod tests { value: 0, }); let base_weight = claim_tx.weight(); - let inputs_weight = vec![weight_offered_htlc(opt_anchors), weight_received_htlc(opt_anchors), weight_received_htlc(opt_anchors), weight_received_htlc(opt_anchors)]; + let inputs_weight = vec![weight_offered_htlc(&channel_type), weight_received_htlc(&channel_type), weight_received_htlc(&channel_type), weight_received_htlc(&channel_type)]; let mut inputs_total_weight = 2; // count segwit flags { let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { - sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors); + sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, &channel_type); inputs_total_weight += inp; } } @@ -4478,7 +4479,7 @@ mod tests { } // Justice tx with 1 revoked HTLC-Success tx output - for &opt_anchors in [false, true].iter() { + for channel_type in [ChannelType::Legacy, ChannelType::Anchors].iter() { let mut claim_tx = Transaction { version: 0, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }; let mut sum_actual_sigs = 0; claim_tx.input.push(TxIn { @@ -4500,7 +4501,7 @@ mod tests { { let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { - sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors); + sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, &channel_type); inputs_total_weight += inp; } } diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index 45968c57e53..d91b1852100 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -49,6 +49,7 @@ use core::mem::replace; #[cfg(anchors)] use core::mem::swap; use bitcoin::hashes::Hash; +use crate::ln::channel::ChannelType; const MAX_ALLOC_SIZE: usize = 64*1024; @@ -1209,8 +1210,8 @@ impl OnchainTxHandler .or_else(|| self.prev_holder_commitment.as_ref().map(|c| find_htlc(c)).flatten()) } - pub(crate) fn opt_anchors(&self) -> bool { - self.channel_transaction_parameters.opt_anchors.is_some() + pub(crate) fn channel_type(&self) -> ChannelType { + self.channel_transaction_parameters.channel_type.clone() } #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index 4604a164cd6..bfafdccd813 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -30,9 +30,10 @@ use crate::sign::WriteableEcdsaChannelSigner; use crate::chain::onchaintx::ExternalHTLCClaim; use crate::chain::onchaintx::OnchainTxHandler; use crate::util::logger::Logger; -use crate::util::ser::{Readable, Writer, Writeable}; +use crate::util::ser::{Readable, Writer, Writeable, RequiredWrapper}; use crate::io; +use crate::io::Read; use crate::prelude::*; use core::cmp; #[cfg(anchors)] @@ -40,38 +41,39 @@ use core::convert::TryInto; use core::mem; use core::ops::Deref; use bitcoin::{PackedLockTime, Sequence, Witness}; +use crate::ln::channel::ChannelType; use super::chaininterface::LowerBoundedFeeEstimator; const MAX_ALLOC_SIZE: usize = 64*1024; -pub(crate) fn weight_revoked_offered_htlc(opt_anchors: bool) -> u64 { +pub(crate) fn weight_revoked_offered_htlc(channel_type: &ChannelType) -> u64 { // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script const WEIGHT_REVOKED_OFFERED_HTLC: u64 = 1 + 1 + 73 + 1 + 33 + 1 + 133; const WEIGHT_REVOKED_OFFERED_HTLC_ANCHORS: u64 = WEIGHT_REVOKED_OFFERED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP - if opt_anchors { WEIGHT_REVOKED_OFFERED_HTLC_ANCHORS } else { WEIGHT_REVOKED_OFFERED_HTLC } + if channel_type.supports_anchors() { WEIGHT_REVOKED_OFFERED_HTLC_ANCHORS } else { WEIGHT_REVOKED_OFFERED_HTLC } } -pub(crate) fn weight_revoked_received_htlc(opt_anchors: bool) -> u64 { +pub(crate) fn weight_revoked_received_htlc(channel_type: &ChannelType) -> u64 { // number_of_witness_elements + sig_length + revocation_sig + pubkey_length + revocationpubkey + witness_script_length + witness_script const WEIGHT_REVOKED_RECEIVED_HTLC: u64 = 1 + 1 + 73 + 1 + 33 + 1 + 139; const WEIGHT_REVOKED_RECEIVED_HTLC_ANCHORS: u64 = WEIGHT_REVOKED_RECEIVED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP - if opt_anchors { WEIGHT_REVOKED_RECEIVED_HTLC_ANCHORS } else { WEIGHT_REVOKED_RECEIVED_HTLC } + if channel_type.supports_anchors() { WEIGHT_REVOKED_RECEIVED_HTLC_ANCHORS } else { WEIGHT_REVOKED_RECEIVED_HTLC } } -pub(crate) fn weight_offered_htlc(opt_anchors: bool) -> u64 { +pub(crate) fn weight_offered_htlc(channel_type: &ChannelType) -> u64 { // number_of_witness_elements + sig_length + counterpartyhtlc_sig + preimage_length + preimage + witness_script_length + witness_script const WEIGHT_OFFERED_HTLC: u64 = 1 + 1 + 73 + 1 + 32 + 1 + 133; const WEIGHT_OFFERED_HTLC_ANCHORS: u64 = WEIGHT_OFFERED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP - if opt_anchors { WEIGHT_OFFERED_HTLC_ANCHORS } else { WEIGHT_OFFERED_HTLC } + if channel_type.supports_anchors() { WEIGHT_OFFERED_HTLC_ANCHORS } else { WEIGHT_OFFERED_HTLC } } -pub(crate) fn weight_received_htlc(opt_anchors: bool) -> u64 { +pub(crate) fn weight_received_htlc(channel_type: &ChannelType) -> u64 { // number_of_witness_elements + sig_length + counterpartyhtlc_sig + empty_vec_length + empty_vec + witness_script_length + witness_script const WEIGHT_RECEIVED_HTLC: u64 = 1 + 1 + 73 + 1 + 1 + 1 + 139; const WEIGHT_RECEIVED_HTLC_ANCHORS: u64 = WEIGHT_RECEIVED_HTLC + 3; // + OP_1 + OP_CSV + OP_DROP - if opt_anchors { WEIGHT_RECEIVED_HTLC_ANCHORS } else { WEIGHT_RECEIVED_HTLC } + if channel_type.supports_anchors() { WEIGHT_RECEIVED_HTLC_ANCHORS } else { WEIGHT_RECEIVED_HTLC } } // number_of_witness_elements + sig_length + revocation_sig + true_length + op_true + witness_script_length + witness_script @@ -147,8 +149,8 @@ pub(crate) struct RevokedHTLCOutput { } impl RevokedHTLCOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self { - let weight = if htlc.offered { weight_revoked_offered_htlc(opt_anchors) } else { weight_revoked_received_htlc(opt_anchors) }; + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, per_commitment_key: SecretKey, amount: u64, htlc: HTLCOutputInCommitment, channel_type: &ChannelType) -> Self { + let weight = if htlc.offered { weight_revoked_offered_htlc(channel_type) } else { weight_revoked_received_htlc(channel_type) }; RevokedHTLCOutput { per_commitment_point, counterparty_delayed_payment_base_key, @@ -184,34 +186,68 @@ pub(crate) struct CounterpartyOfferedHTLCOutput { counterparty_htlc_base_key: PublicKey, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, - opt_anchors: Option<()>, + /// Describes the channel type + pub channel_type: ChannelType, } impl CounterpartyOfferedHTLCOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self { + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, preimage: PaymentPreimage, htlc: HTLCOutputInCommitment, channel_type: ChannelType) -> Self { CounterpartyOfferedHTLCOutput { per_commitment_point, counterparty_delayed_payment_base_key, counterparty_htlc_base_key, preimage, htlc, - opt_anchors: if opt_anchors { Some(()) } else { None }, + channel_type, } } +} - fn opt_anchors(&self) -> bool { - self.opt_anchors.is_some() +impl Writeable for CounterpartyOfferedHTLCOutput { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + let mut channel_type = Some(self.channel_type.clone()); + match self.channel_type { + ChannelType::Legacy => { channel_type = None } + _ => {} + }; + encode_tlv_stream!(w, { + (0, self.per_commitment_point, required), + (2, self.counterparty_delayed_payment_base_key, required), + (4, self.counterparty_htlc_base_key, required), + (6, self.preimage, required), + (8, self.htlc, required), + (10, channel_type, option), + }); + Ok(()) } } -impl_writeable_tlv_based!(CounterpartyOfferedHTLCOutput, { - (0, per_commitment_point, required), - (2, counterparty_delayed_payment_base_key, required), - (4, counterparty_htlc_base_key, required), - (6, preimage, required), - (8, htlc, required), - (10, opt_anchors, option), -}); +impl Readable for CounterpartyOfferedHTLCOutput { + fn read(r: &mut R) -> Result { + let mut per_commitment_point = RequiredWrapper(None); + let mut counterparty_delayed_payment_base_key = RequiredWrapper(None); + let mut counterparty_htlc_base_key = RequiredWrapper(None); + let mut preimage = RequiredWrapper(None); + let mut htlc = RequiredWrapper(None); + let mut channel_type = None; + decode_tlv_stream!(r, { + (0, per_commitment_point, required), + (2, counterparty_delayed_payment_base_key, required), + (4, counterparty_htlc_base_key, required), + (6, preimage, required), + (8, htlc, required), + (10, channel_type, option), + }); + Ok(Self { + per_commitment_point: per_commitment_point.0.unwrap(), + counterparty_delayed_payment_base_key: counterparty_delayed_payment_base_key.0.unwrap(), + counterparty_htlc_base_key: counterparty_htlc_base_key.0.unwrap(), + preimage: preimage.0.unwrap(), + htlc: htlc.0.unwrap(), + channel_type: channel_type.unwrap_or(ChannelType::Legacy), + }) + } +} /// A struct to describe a HTLC output on a counterparty commitment transaction. /// @@ -223,32 +259,62 @@ pub(crate) struct CounterpartyReceivedHTLCOutput { counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, htlc: HTLCOutputInCommitment, - opt_anchors: Option<()>, + channel_type: ChannelType, } impl CounterpartyReceivedHTLCOutput { - pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, htlc: HTLCOutputInCommitment, opt_anchors: bool) -> Self { + pub(crate) fn build(per_commitment_point: PublicKey, counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, htlc: HTLCOutputInCommitment, channel_type: ChannelType) -> Self { CounterpartyReceivedHTLCOutput { per_commitment_point, counterparty_delayed_payment_base_key, counterparty_htlc_base_key, htlc, - opt_anchors: if opt_anchors { Some(()) } else { None }, + channel_type, } } +} - fn opt_anchors(&self) -> bool { - self.opt_anchors.is_some() +impl Writeable for CounterpartyReceivedHTLCOutput { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + let mut channel_type = Some(self.channel_type.clone()); + match self.channel_type { + ChannelType::Legacy => { channel_type = None } + _ => {} + }; + encode_tlv_stream!(w, { + (0, self.per_commitment_point, required), + (2, self.counterparty_delayed_payment_base_key, required), + (4, self.counterparty_htlc_base_key, required), + (6, self.htlc, required), + (8, channel_type, option), + }); + Ok(()) } } -impl_writeable_tlv_based!(CounterpartyReceivedHTLCOutput, { - (0, per_commitment_point, required), - (2, counterparty_delayed_payment_base_key, required), - (4, counterparty_htlc_base_key, required), - (6, htlc, required), - (8, opt_anchors, option), -}); +impl Readable for CounterpartyReceivedHTLCOutput { + fn read(r: &mut R) -> Result { + let mut per_commitment_point = RequiredWrapper(None); + let mut counterparty_delayed_payment_base_key = RequiredWrapper(None); + let mut counterparty_htlc_base_key = RequiredWrapper(None); + let mut htlc = RequiredWrapper(None); + let mut channel_type = None; + decode_tlv_stream!(r, { + (0, per_commitment_point, required), + (2, counterparty_delayed_payment_base_key, required), + (4, counterparty_htlc_base_key, required), + (6, htlc, required), + (8, channel_type, option), + }); + Ok(Self { + per_commitment_point: per_commitment_point.0.unwrap(), + counterparty_delayed_payment_base_key: counterparty_delayed_payment_base_key.0.unwrap(), + counterparty_htlc_base_key: counterparty_htlc_base_key.0.unwrap(), + htlc: htlc.0.unwrap(), + channel_type: channel_type.unwrap_or(ChannelType::Legacy), + }) + } +} /// A struct to describe a HTLC output on holder commitment transaction. /// @@ -260,39 +326,66 @@ pub(crate) struct HolderHTLCOutput { amount_msat: u64, /// Defaults to 0 for HTLC-Success transactions, which have no expiry cltv_expiry: u32, - opt_anchors: Option<()>, + channel_type: ChannelType, } impl HolderHTLCOutput { - pub(crate) fn build_offered(amount_msat: u64, cltv_expiry: u32, opt_anchors: bool) -> Self { + pub(crate) fn build_offered(amount_msat: u64, cltv_expiry: u32, channel_type: ChannelType) -> Self { HolderHTLCOutput { preimage: None, amount_msat, cltv_expiry, - opt_anchors: if opt_anchors { Some(()) } else { None } , + channel_type, } } - pub(crate) fn build_accepted(preimage: PaymentPreimage, amount_msat: u64, opt_anchors: bool) -> Self { + pub(crate) fn build_accepted(preimage: PaymentPreimage, amount_msat: u64, channel_type: ChannelType) -> Self { HolderHTLCOutput { preimage: Some(preimage), amount_msat, cltv_expiry: 0, - opt_anchors: if opt_anchors { Some(()) } else { None } , + channel_type, } } +} - fn opt_anchors(&self) -> bool { - self.opt_anchors.is_some() +impl Writeable for HolderHTLCOutput { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + let mut channel_type = Some(self.channel_type.clone()); + match self.channel_type { + ChannelType::Legacy => { channel_type = None } + _ => {} + }; + encode_tlv_stream!(w, { + (0, self.amount_msat, required), + (2, self.cltv_expiry, required), + (4, self.preimage, option), + (6, channel_type, option) + }); + Ok(()) } } -impl_writeable_tlv_based!(HolderHTLCOutput, { - (0, amount_msat, required), - (2, cltv_expiry, required), - (4, preimage, option), - (6, opt_anchors, option) -}); +impl Readable for HolderHTLCOutput { + fn read(r: &mut R) -> Result { + let mut amount_msat = RequiredWrapper(None); + let mut cltv_expiry = RequiredWrapper(None); + let mut preimage = None; + let mut channel_type = None; + decode_tlv_stream!(r, { + (0, amount_msat, required), + (2, cltv_expiry, required), + (4, preimage, option), + (6, channel_type, option) + }); + Ok(Self { + amount_msat: amount_msat.0.unwrap(), + cltv_expiry: cltv_expiry.0.unwrap(), + preimage, + channel_type: channel_type.unwrap_or(ChannelType::Legacy), + }) + } +} /// A struct to describe the channel output on the funding transaction. /// @@ -301,29 +394,53 @@ impl_writeable_tlv_based!(HolderHTLCOutput, { pub(crate) struct HolderFundingOutput { funding_redeemscript: Script, funding_amount: Option, - opt_anchors: Option<()>, + channel_type: ChannelType, } impl HolderFundingOutput { - pub(crate) fn build(funding_redeemscript: Script, funding_amount: u64, opt_anchors: bool) -> Self { + pub(crate) fn build(funding_redeemscript: Script, funding_amount: u64, channel_type: ChannelType) -> Self { HolderFundingOutput { funding_redeemscript, funding_amount: Some(funding_amount), - opt_anchors: if opt_anchors { Some(()) } else { None }, + channel_type, } } +} - fn opt_anchors(&self) -> bool { - self.opt_anchors.is_some() +impl Writeable for HolderFundingOutput { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + let mut channel_type = Some(self.channel_type.clone()); + match self.channel_type { + ChannelType::Legacy => { channel_type = None } + _ => {} + }; + encode_tlv_stream!(w, { + (0, self.funding_redeemscript, required), + (2, channel_type, option), + (3, self.funding_amount, option), + }); + Ok(()) } } -impl_writeable_tlv_based!(HolderFundingOutput, { - (0, funding_redeemscript, required), - (2, opt_anchors, option), - (3, funding_amount, option), -}); +impl Readable for HolderFundingOutput { + fn read(r: &mut R) -> Result { + let mut funding_redeemscript = RequiredWrapper(None); + let mut channel_type = None; + let mut funding_amount = None; + decode_tlv_stream!(r, { + (0, funding_redeemscript, required), + (2, channel_type, option), + (3, funding_amount, option), + }); + Ok(Self { + funding_redeemscript: funding_redeemscript.0.unwrap(), + channel_type: channel_type.unwrap_or(ChannelType::Legacy), + funding_amount, + }) + } +} /// A wrapper encapsulating all in-protocol differing outputs types. /// @@ -347,11 +464,11 @@ impl PackageSolvingData { PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => outp.htlc.amount_msat / 1000, PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => outp.htlc.amount_msat / 1000, PackageSolvingData::HolderHTLCOutput(ref outp) => { - debug_assert!(outp.opt_anchors()); + debug_assert!(outp.channel_type.supports_anchors()); outp.amount_msat / 1000 }, PackageSolvingData::HolderFundingOutput(ref outp) => { - debug_assert!(outp.opt_anchors()); + debug_assert!(outp.channel_type.supports_anchors()); outp.funding_amount.unwrap() } }; @@ -361,14 +478,14 @@ impl PackageSolvingData { match self { PackageSolvingData::RevokedOutput(ref outp) => outp.weight as usize, PackageSolvingData::RevokedHTLCOutput(ref outp) => outp.weight as usize, - PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => weight_offered_htlc(outp.opt_anchors()) as usize, - PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => weight_received_htlc(outp.opt_anchors()) as usize, + PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => weight_offered_htlc(&outp.channel_type) as usize, + PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => weight_received_htlc(&outp.channel_type) as usize, PackageSolvingData::HolderHTLCOutput(ref outp) => { - debug_assert!(outp.opt_anchors()); + debug_assert!(outp.channel_type.supports_anchors()); if outp.preimage.is_none() { - weight_offered_htlc(true) as usize + weight_offered_htlc(&outp.channel_type) as usize } else { - weight_received_htlc(true) as usize + weight_received_htlc(&outp.channel_type) as usize } }, // Since HolderFundingOutput maps to an untractable package that is already signed, its @@ -411,7 +528,7 @@ impl PackageSolvingData { }, PackageSolvingData::RevokedHTLCOutput(ref outp) => { let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint); - let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); + let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); //TODO: should we panic on signer failure ? if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_htlc(&bumped_tx, i, outp.amount, &outp.per_commitment_key, &outp.htlc, &onchain_handler.secp_ctx) { let mut ser_sig = sig.serialize_der().to_vec(); @@ -423,7 +540,7 @@ impl PackageSolvingData { }, PackageSolvingData::CounterpartyOfferedHTLCOutput(ref outp) => { let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint); - let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); + let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) { let mut ser_sig = sig.serialize_der().to_vec(); @@ -435,7 +552,7 @@ impl PackageSolvingData { }, PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => { let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint); - let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, onchain_handler.opt_anchors(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); + let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) { let mut ser_sig = sig.serialize_der().to_vec(); @@ -453,7 +570,7 @@ impl PackageSolvingData { fn get_finalized_tx(&self, outpoint: &BitcoinOutPoint, onchain_handler: &mut OnchainTxHandler) -> Option { match self { PackageSolvingData::HolderHTLCOutput(ref outp) => { - debug_assert!(!outp.opt_anchors()); + debug_assert!(!outp.channel_type.supports_anchors()); return onchain_handler.get_fully_signed_htlc_tx(outpoint, &outp.preimage); } PackageSolvingData::HolderFundingOutput(ref outp) => { @@ -491,7 +608,7 @@ impl PackageSolvingData { PackageSolvingData::RevokedHTLCOutput(..) => { (PackageMalleability::Malleable, true) }, PackageSolvingData::CounterpartyOfferedHTLCOutput(..) => { (PackageMalleability::Malleable, true) }, PackageSolvingData::CounterpartyReceivedHTLCOutput(..) => { (PackageMalleability::Malleable, false) }, - PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.opt_anchors() { + PackageSolvingData::HolderHTLCOutput(ref outp) => if outp.channel_type.supports_anchors() { (PackageMalleability::Malleable, outp.preimage.is_some()) } else { (PackageMalleability::Untractable, false) @@ -840,8 +957,8 @@ impl PackageTemplate { /// attached to help the spending transaction reach confirmation. pub(crate) fn requires_external_funding(&self) -> bool { self.inputs.iter().find(|input| match input.1 { - PackageSolvingData::HolderFundingOutput(ref outp) => outp.opt_anchors(), - PackageSolvingData::HolderHTLCOutput(ref outp) => outp.opt_anchors(), + PackageSolvingData::HolderFundingOutput(ref outp) => outp.channel_type.supports_anchors(), + PackageSolvingData::HolderHTLCOutput(ref outp) => outp.channel_type.supports_anchors(), _ => false, }).is_some() } @@ -1025,6 +1142,7 @@ mod tests { use bitcoin::secp256k1::{PublicKey,SecretKey}; use bitcoin::secp256k1::Secp256k1; + use crate::ln::channel::ChannelType; macro_rules! dumb_revk_output { ($secp_ctx: expr, $is_counterparty_balance_on_anchors: expr) => { @@ -1065,7 +1183,7 @@ mod tests { () => { { let preimage = PaymentPreimage([2;32]); - PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build_accepted(preimage, 0, false)) + PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build_accepted(preimage, 0, ChannelType::Legacy)) } } } @@ -1153,7 +1271,7 @@ mod tests { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); let revk_outp = dumb_revk_output!(secp_ctx, false); - let counterparty_outp = dumb_counterparty_output!(secp_ctx, 0, false); + let counterparty_outp = dumb_counterparty_output!(secp_ctx, 0, ChannelType::Legacy); let mut revoked_package = PackageTemplate::build_package(txid, 0, revk_outp, 1000, 100); let counterparty_package = PackageTemplate::build_package(txid, 1, counterparty_outp, 1000, 100); @@ -1214,7 +1332,7 @@ mod tests { fn test_package_amounts() { let txid = Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(); let secp_ctx = Secp256k1::new(); - let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, false); + let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, ChannelType::Legacy); let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100); assert_eq!(package.package_amount(), 1000); @@ -1235,18 +1353,18 @@ mod tests { } { - for &opt_anchors in [false, true].iter() { - let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, opt_anchors); + for channel_type in [ChannelType::Legacy, ChannelType::Anchors].iter() { + let counterparty_outp = dumb_counterparty_output!(secp_ctx, 1_000_000, channel_type.clone()); let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100); - assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_received_htlc(opt_anchors) as usize); + assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_received_htlc(&channel_type) as usize); } } { - for &opt_anchors in [false, true].iter() { - let counterparty_outp = dumb_counterparty_offered_output!(secp_ctx, 1_000_000, opt_anchors); + for channel_type in [ChannelType::Legacy, ChannelType::Anchors].iter() { + let counterparty_outp = dumb_counterparty_offered_output!(secp_ctx, 1_000_000, channel_type.clone()); let package = PackageTemplate::build_package(txid, 0, counterparty_outp, 1000, 100); - assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_offered_htlc(opt_anchors) as usize); + assert_eq!(package.package_weight(&Script::new()), weight_sans_output + weight_offered_htlc(&channel_type) as usize); } } } diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index b3b87146792..185a0faff17 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -24,7 +24,7 @@ use bitcoin::hash_types::{Txid, PubkeyHash}; use crate::sign::EntropySource; use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::msgs::DecodeError; -use crate::util::ser::{Readable, Writeable, Writer}; +use crate::util::ser::{Readable, RequiredWrapper, Writeable, Writer}; use crate::util::transaction_utils; use bitcoin::secp256k1::{SecretKey, PublicKey, Scalar}; @@ -33,11 +33,12 @@ use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness}; use bitcoin::PublicKey as BitcoinPublicKey; use crate::io; +use crate::io::Read; use crate::prelude::*; use core::cmp; use crate::ln::chan_utils; use crate::util::transaction_utils::sort_outputs; -use crate::ln::channel::{INITIAL_COMMITMENT_NUMBER, ANCHOR_OUTPUT_VALUE_SATOSHI}; +use crate::ln::channel::{INITIAL_COMMITMENT_NUMBER, ANCHOR_OUTPUT_VALUE_SATOSHI, ChannelType}; use core::ops::Deref; use crate::chain; use crate::util::crypto::{sign, sign_with_aux_rand}; @@ -59,18 +60,18 @@ pub const MAX_ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 143; /// Gets the weight for an HTLC-Success transaction. #[inline] -pub fn htlc_success_tx_weight(opt_anchors: bool) -> u64 { +pub fn htlc_success_tx_weight(channel_type: &ChannelType) -> u64 { const HTLC_SUCCESS_TX_WEIGHT: u64 = 703; const HTLC_SUCCESS_ANCHOR_TX_WEIGHT: u64 = 706; - if opt_anchors { HTLC_SUCCESS_ANCHOR_TX_WEIGHT } else { HTLC_SUCCESS_TX_WEIGHT } + if channel_type.supports_anchors() { HTLC_SUCCESS_ANCHOR_TX_WEIGHT } else { HTLC_SUCCESS_TX_WEIGHT } } /// Gets the weight for an HTLC-Timeout transaction. #[inline] -pub fn htlc_timeout_tx_weight(opt_anchors: bool) -> u64 { +pub fn htlc_timeout_tx_weight(channel_type: &ChannelType) -> u64 { const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663; const HTLC_TIMEOUT_ANCHOR_TX_WEIGHT: u64 = 666; - if opt_anchors { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT } + if channel_type.supports_anchors() { HTLC_TIMEOUT_ANCHOR_TX_WEIGHT } else { HTLC_TIMEOUT_TX_WEIGHT } } /// Describes the type of HTLC claim as determined by analyzing the witness. @@ -574,7 +575,7 @@ impl_writeable_tlv_based!(HTLCOutputInCommitment, { }); #[inline] -pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, opt_anchors: bool, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script { +pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, channel_type: &ChannelType, broadcaster_htlc_key: &PublicKey, countersignatory_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script { let payment_hash160 = Ripemd160::hash(&htlc.payment_hash.0[..]).into_inner(); if htlc.offered { let mut bldr = Builder::new().push_opcode(opcodes::all::OP_DUP) @@ -602,7 +603,7 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_CHECKSIG) .push_opcode(opcodes::all::OP_ENDIF); - if opt_anchors { + if channel_type.supports_anchors() { bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1) .push_opcode(opcodes::all::OP_CSV) .push_opcode(opcodes::all::OP_DROP); @@ -638,7 +639,7 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit .push_opcode(opcodes::all::OP_DROP) .push_opcode(opcodes::all::OP_CHECKSIG) .push_opcode(opcodes::all::OP_ENDIF); - if opt_anchors { + if channel_type.supports_anchors() { bldr = bldr.push_opcode(opcodes::all::OP_PUSHNUM_1) .push_opcode(opcodes::all::OP_CSV) .push_opcode(opcodes::all::OP_DROP); @@ -651,8 +652,8 @@ pub(crate) fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommit /// Gets the witness redeemscript for an HTLC output in a commitment transaction. Note that htlc /// does not need to have its previous_output_index filled. #[inline] -pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, opt_anchors: bool, keys: &TxCreationKeys) -> Script { - get_htlc_redeemscript_with_explicit_keys(htlc, opt_anchors, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key) +pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, channel_type: &ChannelType, keys: &TxCreationKeys) -> Script { + get_htlc_redeemscript_with_explicit_keys(htlc, channel_type, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key) } /// Gets the redeemscript for a funding output from the two funding public keys. @@ -682,13 +683,13 @@ pub(crate) fn make_funding_redeemscript_from_slices(broadcaster_funding_key: &[u /// /// Panics if htlc.transaction_output_index.is_none() (as such HTLCs do not appear in the /// commitment transaction). -pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool, use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { +pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type: &ChannelType, use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { let mut txins: Vec = Vec::new(); - txins.push(build_htlc_input(commitment_txid, htlc, opt_anchors)); + txins.push(build_htlc_input(commitment_txid, htlc, channel_type)); let mut txouts: Vec = Vec::new(); txouts.push(build_htlc_output( - feerate_per_kw, contest_delay, htlc, opt_anchors, use_non_zero_fee_anchors, + feerate_per_kw, contest_delay, htlc, channel_type, use_non_zero_fee_anchors, broadcaster_delayed_payment_key, revocation_key )); @@ -700,28 +701,28 @@ pub fn build_htlc_transaction(commitment_txid: &Txid, feerate_per_kw: u32, conte } } -pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommitment, opt_anchors: bool) -> TxIn { +pub(crate) fn build_htlc_input(commitment_txid: &Txid, htlc: &HTLCOutputInCommitment, channel_type: &ChannelType) -> TxIn { TxIn { previous_output: OutPoint { txid: commitment_txid.clone(), vout: htlc.transaction_output_index.expect("Can't build an HTLC transaction for a dust output"), }, script_sig: Script::new(), - sequence: Sequence(if opt_anchors { 1 } else { 0 }), + sequence: Sequence(if channel_type.supports_anchors() { 1 } else { 0 }), witness: Witness::new(), } } pub(crate) fn build_htlc_output( - feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, opt_anchors: bool, + feerate_per_kw: u32, contest_delay: u16, htlc: &HTLCOutputInCommitment, channel_type: &ChannelType, use_non_zero_fee_anchors: bool, broadcaster_delayed_payment_key: &PublicKey, revocation_key: &PublicKey ) -> TxOut { let weight = if htlc.offered { - htlc_timeout_tx_weight(opt_anchors) + htlc_timeout_tx_weight(channel_type) } else { - htlc_success_tx_weight(opt_anchors) + htlc_success_tx_weight(channel_type) }; - let output_value = if opt_anchors && !use_non_zero_fee_anchors { + let output_value = if channel_type.supports_anchors() && !use_non_zero_fee_anchors { htlc.amount_msat / 1000 } else { let total_fee = feerate_per_kw as u64 * weight / 1000; @@ -737,9 +738,9 @@ pub(crate) fn build_htlc_output( /// Returns the witness required to satisfy and spend a HTLC input. pub fn build_htlc_input_witness( local_sig: &Signature, remote_sig: &Signature, preimage: &Option, - redeem_script: &Script, opt_anchors: bool, + redeem_script: &Script, channel_type: &ChannelType, ) -> Witness { - let remote_sighash_type = if opt_anchors { + let remote_sighash_type = if channel_type.supports_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All @@ -826,9 +827,8 @@ pub struct ChannelTransactionParameters { pub counterparty_parameters: Option, /// The late-bound funding outpoint pub funding_outpoint: Option, - /// Are anchors (zero fee HTLC transaction variant) used for this channel. Boolean is - /// serialization backwards-compatible. - pub opt_anchors: Option<()>, + /// Describes the channel type + pub channel_type: ChannelType, /// Are non-zero-fee anchors are enabled (used in conjuction with opt_anchors) /// It is intended merely for backwards compatibility with signers that need it. /// There is no support for this feature in LDK channel negotiation. @@ -880,15 +880,55 @@ impl_writeable_tlv_based!(CounterpartyChannelTransactionParameters, { (2, selected_contest_delay, required), }); -impl_writeable_tlv_based!(ChannelTransactionParameters, { - (0, holder_pubkeys, required), - (2, holder_selected_contest_delay, required), - (4, is_outbound_from_holder, required), - (6, counterparty_parameters, option), - (8, funding_outpoint, option), - (10, opt_anchors, option), - (12, opt_non_zero_fee_anchors, option), -}); +impl Writeable for ChannelTransactionParameters { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + let mut channel_type = Some(self.channel_type.clone()); + match self.channel_type { + ChannelType::Legacy => { channel_type = None } + _ => {} + }; + encode_tlv_stream!(w, { + (0, self.holder_pubkeys, required), + (2, self.holder_selected_contest_delay, required), + (4, self.is_outbound_from_holder, required), + (6, self.counterparty_parameters, option), + (8, self.funding_outpoint, option), + (10, channel_type, option), + (12, self.opt_non_zero_fee_anchors, option), + }); + Ok(()) + } +} + +impl Readable for ChannelTransactionParameters { + fn read(r: &mut R) -> Result { + let mut holder_pubkeys = RequiredWrapper(None); + let mut holder_selected_contest_delay = RequiredWrapper(None); + let mut is_outbound_from_holder = RequiredWrapper(None); + let mut counterparty_parameters = None; + let mut funding_outpoint = None; + let mut channel_type = None; + let mut opt_non_zero_fee_anchors = None; + decode_tlv_stream!(r, { + (0, holder_pubkeys, required), + (2, holder_selected_contest_delay, required), + (4, is_outbound_from_holder, required), + (6, counterparty_parameters, option), + (8, funding_outpoint, option), + (10, channel_type, option), + (12, opt_non_zero_fee_anchors, option), + }); + Ok(Self { + holder_pubkeys: holder_pubkeys.0.unwrap(), + holder_selected_contest_delay: holder_selected_contest_delay.0.unwrap(), + is_outbound_from_holder: is_outbound_from_holder.0.unwrap(), + counterparty_parameters, + funding_outpoint, + channel_type: channel_type.unwrap_or(ChannelType::Legacy), + opt_non_zero_fee_anchors, + }) + } +} /// Static channel fields used to build transactions given per-commitment fields, organized by /// broadcaster/countersignatory. @@ -941,9 +981,9 @@ impl<'a> DirectedChannelTransactionParameters<'a> { self.inner.funding_outpoint.unwrap().into_bitcoin_outpoint() } - /// Whether to use anchors for this channel - pub fn opt_anchors(&self) -> bool { - self.inner.opt_anchors.is_some() + /// Returns channel type enum + pub fn channel_type(&self) -> ChannelType { + self.inner.channel_type.clone() } } @@ -1010,14 +1050,14 @@ impl HolderCommitmentTransaction { is_outbound_from_holder: false, counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: channel_pubkeys.clone(), selected_contest_delay: 0 }), funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }), - opt_anchors: None, + channel_type: ChannelType::Legacy, opt_non_zero_fee_anchors: None, }; let mut counterparty_htlc_sigs = Vec::new(); for _ in 0..htlcs.len() { counterparty_htlc_sigs.push(dummy_sig); } - let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, false, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters.as_counterparty_broadcastable()); + let inner = CommitmentTransaction::new_with_auxiliary_htlc_data(0, 0, 0, dummy_key.clone(), dummy_key.clone(), keys, 0, htlcs, &channel_parameters.as_counterparty_broadcastable()); htlcs.sort_by_key(|htlc| htlc.0.transaction_output_index); HolderCommitmentTransaction { inner, @@ -1236,7 +1276,7 @@ pub struct CommitmentTransaction { feerate_per_kw: u32, htlcs: Vec, // A boolean that is serialization backwards-compatible - opt_anchors: Option<()>, + channel_type: ChannelType, // Whether non-zero-fee anchors should be used opt_non_zero_fee_anchors: Option<()>, // A cache of the parties' pubkeys required to construct the transaction, see doc for trust() @@ -1253,7 +1293,7 @@ impl PartialEq for CommitmentTransaction { self.to_countersignatory_value_sat == o.to_countersignatory_value_sat && self.feerate_per_kw == o.feerate_per_kw && self.htlcs == o.htlcs && - self.opt_anchors == o.opt_anchors && + self.channel_type == o.channel_type && self.keys == o.keys; if eq { debug_assert_eq!(self.built.transaction, o.built.transaction); @@ -1263,17 +1303,63 @@ impl PartialEq for CommitmentTransaction { } } -impl_writeable_tlv_based!(CommitmentTransaction, { - (0, commitment_number, required), - (2, to_broadcaster_value_sat, required), - (4, to_countersignatory_value_sat, required), - (6, feerate_per_kw, required), - (8, keys, required), - (10, built, required), - (12, htlcs, vec_type), - (14, opt_anchors, option), - (16, opt_non_zero_fee_anchors, option), -}); +impl Writeable for CommitmentTransaction { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + let mut channel_type = Some(self.channel_type.clone()); + match self.channel_type { + ChannelType::Legacy => { channel_type = None } + _ => {} + }; + encode_tlv_stream!(w, { + (0, self.commitment_number, required), + (2, self.to_broadcaster_value_sat, required), + (4, self.to_countersignatory_value_sat, required), + (6, self.feerate_per_kw, required), + (8, self.keys, required), + (10, self.built, required), + (12, self.htlcs, vec_type), + (14, channel_type, option), + (16, self.opt_non_zero_fee_anchors, option), + }); + Ok(()) + } +} + +impl Readable for CommitmentTransaction { + fn read(r: &mut R) -> Result { + let mut commitment_number = RequiredWrapper(None); + let mut to_broadcaster_value_sat = RequiredWrapper(None); + let mut to_countersignatory_value_sat = RequiredWrapper(None); + let mut feerate_per_kw = RequiredWrapper(None); + let mut keys = RequiredWrapper(None); + let mut built = RequiredWrapper(None); + let mut htlcs = None; + let mut channel_type = None; + let mut opt_non_zero_fee_anchors = None; + decode_tlv_stream!(r, { + (0, commitment_number, required), + (2, to_broadcaster_value_sat, required), + (4, to_countersignatory_value_sat, required), + (6, feerate_per_kw, required), + (8, keys, required), + (10, built, required), + (12, htlcs, vec_type), + (14, channel_type, option), + (16, opt_non_zero_fee_anchors, option), + }); + Ok(Self { + commitment_number: commitment_number.0.unwrap(), + to_broadcaster_value_sat: to_broadcaster_value_sat.0.unwrap(), + to_countersignatory_value_sat: to_countersignatory_value_sat.0.unwrap(), + feerate_per_kw: feerate_per_kw.0.unwrap(), + keys: keys.0.unwrap(), + built: built.0.unwrap(), + htlcs: htlcs.unwrap(), + channel_type: channel_type.unwrap_or(ChannelType::Legacy), + opt_non_zero_fee_anchors, + }) + } +} impl CommitmentTransaction { /// Construct an object of the class while assigning transaction output indices to HTLCs. @@ -1286,9 +1372,9 @@ impl CommitmentTransaction { /// Only include HTLCs that are above the dust limit for the channel. /// /// This is not exported to bindings users due to the generic though we likely should expose a version without - pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, opt_anchors: bool, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { + pub fn new_with_auxiliary_htlc_data(commitment_number: u64, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, broadcaster_funding_key: PublicKey, countersignatory_funding_key: PublicKey, keys: TxCreationKeys, feerate_per_kw: u32, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters) -> CommitmentTransaction { // Sort outputs and populate output indices while keeping track of the auxiliary data - let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, opt_anchors, &broadcaster_funding_key, &countersignatory_funding_key).unwrap(); + let (outputs, htlcs) = Self::internal_build_outputs(&keys, to_broadcaster_value_sat, to_countersignatory_value_sat, htlcs_with_aux, channel_parameters, &broadcaster_funding_key, &countersignatory_funding_key).unwrap(); let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(commitment_number, channel_parameters); let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); @@ -1299,7 +1385,7 @@ impl CommitmentTransaction { to_countersignatory_value_sat, feerate_per_kw, htlcs, - opt_anchors: if opt_anchors { Some(()) } else { None }, + channel_type: channel_parameters.channel_type(), keys, built: BuiltCommitmentTransaction { transaction, @@ -1321,7 +1407,7 @@ impl CommitmentTransaction { let (obscured_commitment_transaction_number, txins) = Self::internal_build_inputs(self.commitment_number, channel_parameters); let mut htlcs_with_aux = self.htlcs.iter().map(|h| (h.clone(), ())).collect(); - let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, self.opt_anchors.is_some(), broadcaster_funding_key, countersignatory_funding_key)?; + let (outputs, _) = Self::internal_build_outputs(keys, self.to_broadcaster_value_sat, self.to_countersignatory_value_sat, &mut htlcs_with_aux, channel_parameters, broadcaster_funding_key, countersignatory_funding_key)?; let transaction = Self::make_transaction(obscured_commitment_transaction_number, txins, outputs); let txid = transaction.txid(); @@ -1345,14 +1431,15 @@ impl CommitmentTransaction { // - initial sorting of outputs / HTLCs in the constructor, in which case T is auxiliary data the // caller needs to have sorted together with the HTLCs so it can keep track of the output index // - building of a bitcoin transaction during a verify() call, in which case T is just () - fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, opt_anchors: bool, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec, Vec), ()> { + fn internal_build_outputs(keys: &TxCreationKeys, to_broadcaster_value_sat: u64, to_countersignatory_value_sat: u64, htlcs_with_aux: &mut Vec<(HTLCOutputInCommitment, T)>, channel_parameters: &DirectedChannelTransactionParameters, broadcaster_funding_key: &PublicKey, countersignatory_funding_key: &PublicKey) -> Result<(Vec, Vec), ()> { let countersignatory_pubkeys = channel_parameters.countersignatory_pubkeys(); let contest_delay = channel_parameters.contest_delay(); + let channel_type = channel_parameters.channel_type(); let mut txouts: Vec<(TxOut, Option<&mut HTLCOutputInCommitment>)> = Vec::new(); if to_countersignatory_value_sat > 0 { - let script = if opt_anchors { + let script = if channel_type.supports_anchors() { get_to_countersignatory_with_anchors_redeemscript(&countersignatory_pubkeys.payment_point).to_v0_p2wsh() } else { Payload::p2wpkh(&BitcoinPublicKey::new(countersignatory_pubkeys.payment_point)).unwrap().script_pubkey() @@ -1381,7 +1468,7 @@ impl CommitmentTransaction { )); } - if opt_anchors { + if channel_type.supports_anchors() { if to_broadcaster_value_sat > 0 || !htlcs_with_aux.is_empty() { let anchor_script = get_anchor_redeemscript(broadcaster_funding_key); txouts.push(( @@ -1407,7 +1494,7 @@ impl CommitmentTransaction { let mut htlcs = Vec::with_capacity(htlcs_with_aux.len()); for (htlc, _) in htlcs_with_aux { - let script = chan_utils::get_htlc_redeemscript(&htlc, opt_anchors, &keys); + let script = chan_utils::get_htlc_redeemscript(&htlc, &channel_type, &keys); let txout = TxOut { script_pubkey: script.to_v0_p2wsh(), value: htlc.amount_msat / 1000, @@ -1561,11 +1648,6 @@ impl<'a> TrustedCommitmentTransaction<'a> { &self.inner.keys } - /// Should anchors be used. - pub fn opt_anchors(&self) -> bool { - self.opt_anchors.is_some() - } - /// Get a signature for each HTLC which was included in the commitment transaction (ie for /// which HTLCOutputInCommitment::transaction_output_index.is_some()). /// @@ -1584,9 +1666,9 @@ impl<'a> TrustedCommitmentTransaction<'a> { for this_htlc in inner.htlcs.iter() { assert!(this_htlc.transaction_output_index.is_some()); - let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), self.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); + let htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, &self.channel_type, self.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); + let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, &self.channel_type, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); let sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, EcdsaSighashType::All).unwrap()[..]); ret.push(sign_with_aux_rand(secp_ctx, &sighash, &holder_htlc_key, entropy_source)); @@ -1606,12 +1688,12 @@ impl<'a> TrustedCommitmentTransaction<'a> { // Further, we should never be provided the preimage for an HTLC-Timeout transaction. if this_htlc.offered && preimage.is_some() { unreachable!(); } - let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, self.opt_anchors(), self.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); + let mut htlc_tx = build_htlc_transaction(&txid, inner.feerate_per_kw, channel_parameters.contest_delay(), &this_htlc, &self.channel_type, self.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); + let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, &self.channel_type, &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); htlc_tx.input[0].witness = chan_utils::build_htlc_input_witness( - signature, counterparty_signature, preimage, &htlc_redeemscript, self.opt_anchors(), + signature, counterparty_signature, preimage, &htlc_redeemscript, &self.channel_type, ); htlc_tx } @@ -1662,6 +1744,7 @@ mod tests { use bitcoin::hashes::hex::ToHex; use bitcoin::util::address::Payload; use bitcoin::PublicKey as BitcoinPublicKey; + use crate::ln::channel::ChannelType; #[test] fn test_anchors() { @@ -1685,7 +1768,7 @@ mod tests { is_outbound_from_holder: false, counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 0 }), funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }), - opt_anchors: None, + channel_type: ChannelType::Legacy, opt_non_zero_fee_anchors: None, }; @@ -1694,7 +1777,6 @@ mod tests { // Generate broadcaster and counterparty outputs let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 1000, 2000, - false, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1706,7 +1788,6 @@ mod tests { // Generate broadcaster and counterparty outputs as well as two anchors let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 1000, 2000, - true, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1718,7 +1799,6 @@ mod tests { // Generate broadcaster output and anchor let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 3000, 0, - true, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1729,7 +1809,6 @@ mod tests { // Generate counterparty output and anchor let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 0, 3000, - true, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1756,7 +1835,6 @@ mod tests { // Generate broadcaster output and received and offered HTLC outputs, w/o anchors let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 3000, 0, - false, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1764,18 +1842,17 @@ mod tests { &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 3); - assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh()); - assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh()); - assert_eq!(get_htlc_redeemscript(&received_htlc, false, &keys).to_v0_p2wsh().to_hex(), + assert_eq!(tx.built.transaction.output[0].script_pubkey, get_htlc_redeemscript(&received_htlc, &ChannelType::Legacy, &keys).to_v0_p2wsh()); + assert_eq!(tx.built.transaction.output[1].script_pubkey, get_htlc_redeemscript(&offered_htlc, &ChannelType::Legacy, &keys).to_v0_p2wsh()); + assert_eq!(get_htlc_redeemscript(&received_htlc, &ChannelType::Legacy, &keys).to_v0_p2wsh().to_hex(), "0020e43a7c068553003fe68fcae424fb7b28ec5ce48cd8b6744b3945631389bad2fb"); - assert_eq!(get_htlc_redeemscript(&offered_htlc, false, &keys).to_v0_p2wsh().to_hex(), + assert_eq!(get_htlc_redeemscript(&offered_htlc, &ChannelType::Legacy, &keys).to_v0_p2wsh().to_hex(), "0020215d61bba56b19e9eadb6107f5a85d7f99c40f65992443f69229c290165bc00d"); // Generate broadcaster output and received and offered HTLC outputs, with anchors - channel_parameters.opt_anchors = Some(()); + channel_parameters.channel_type = ChannelType::Anchors; let tx = CommitmentTransaction::new_with_auxiliary_htlc_data( 0, 3000, 0, - true, holder_pubkeys.funding_pubkey, counterparty_pubkeys.funding_pubkey, keys.clone(), 1, @@ -1783,11 +1860,11 @@ mod tests { &channel_parameters.as_holder_broadcastable() ); assert_eq!(tx.built.transaction.output.len(), 5); - assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh()); - assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh()); - assert_eq!(get_htlc_redeemscript(&received_htlc, true, &keys).to_v0_p2wsh().to_hex(), + assert_eq!(tx.built.transaction.output[2].script_pubkey, get_htlc_redeemscript(&received_htlc, &ChannelType::Anchors, &keys).to_v0_p2wsh()); + assert_eq!(tx.built.transaction.output[3].script_pubkey, get_htlc_redeemscript(&offered_htlc, &ChannelType::Anchors, &keys).to_v0_p2wsh()); + assert_eq!(get_htlc_redeemscript(&received_htlc, &ChannelType::Anchors, &keys).to_v0_p2wsh().to_hex(), "0020b70d0649c72b38756885c7a30908d912a7898dd5d79457a7280b8e9a20f3f2bc"); - assert_eq!(get_htlc_redeemscript(&offered_htlc, true, &keys).to_v0_p2wsh().to_hex(), + assert_eq!(get_htlc_redeemscript(&offered_htlc, &ChannelType::Anchors, &keys).to_v0_p2wsh().to_hex(), "002087a3faeb1950a469c0e2db4a79b093a41b9526e5a6fc6ef5cb949bde3be379c7"); } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 11f0261d677..8c1ede75062 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -52,6 +52,34 @@ use core::ops::Deref; use crate::sync::Mutex; use bitcoin::hashes::hex::ToHex; +#[derive(Debug, Clone, PartialEq, Eq)] +/// Enum denoting the type of channel that's being used. +/// +/// It will be serialized within ChannelTransactionParameters. +pub enum ChannelType { + /// A legacy channel, without support for anchors + Legacy, + /// An ECDSA channel with anchor support + Anchors, + /// A Taproot channel. All Taproot channels will be supporting anchors. + Taproot +} + +impl ChannelType { + pub fn supports_anchors(&self) -> bool { + match self { + ChannelType::Legacy => false, + _ => true + } + } +} + +impl_writeable_tlv_based_enum!(ChannelType, + (0, Legacy) => {}, + (1, Anchors) => {}, + (2, Taproot) => {}, ; +); + #[cfg(test)] pub struct ChannelValueStat { pub value_to_self_msat: u64, @@ -773,10 +801,10 @@ struct CommitmentTxInfoCached { pub const DEFAULT_MAX_HTLCS: u16 = 50; -pub(crate) fn commitment_tx_base_weight(opt_anchors: bool) -> u64 { +pub(crate) fn commitment_tx_base_weight(channel_type: &ChannelType) -> u64 { const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; const COMMITMENT_TX_BASE_ANCHOR_WEIGHT: u64 = 1124; - if opt_anchors { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT } + if channel_type.supports_anchors() { COMMITMENT_TX_BASE_ANCHOR_WEIGHT } else { COMMITMENT_TX_BASE_WEIGHT } } #[cfg(not(test))] @@ -891,8 +919,8 @@ impl Channel { cmp::min(channel_value_satoshis, cmp::max(q, 1000)) } - pub(crate) fn opt_anchors(&self) -> bool { - self.channel_transaction_parameters.opt_anchors.is_some() + pub(crate) fn channel_type(&self) -> ChannelType { + self.channel_transaction_parameters.channel_type.clone() } fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures { @@ -942,7 +970,7 @@ impl Channel { if self.channel_type.supports_anchors_zero_fee_htlc_tx() { self.channel_type.clear_anchors_zero_fee_htlc_tx(); assert!(self.channel_transaction_parameters.opt_non_zero_fee_anchors.is_none()); - self.channel_transaction_parameters.opt_anchors = None; + self.channel_transaction_parameters.channel_type = ChannelType::Legacy; } else if self.channel_type.supports_scid_privacy() { self.channel_type.clear_scid_privacy(); } else { @@ -986,13 +1014,19 @@ impl Channel { return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) }); } - let channel_type = Self::get_initial_channel_type(&config, their_features); - debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config))); + let channel_features = Self::get_initial_channel_type(&config, their_features); + debug_assert!(channel_features.is_subset(&channelmanager::provided_channel_type_features(&config))); + + let channel_type = if channel_features.requires_anchors_zero_fee_htlc_tx() { + ChannelType::Anchors + } else { + ChannelType::Legacy + }; let feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::Normal); let value_to_self_msat = channel_value_satoshis * 1000 - push_msat; - let commitment_tx_fee = Self::commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT, channel_type.requires_anchors_zero_fee_htlc_tx()); + let commitment_tx_fee = Self::commit_tx_fee_msat(feerate, MIN_AFFORDABLE_HTLC_COUNT, &channel_type); if value_to_self_msat < commitment_tx_fee { return Err(APIError::APIMisuseError{ err: format!("Funding amount ({}) can't even pay fee for initial commitment transaction fee of {}.", value_to_self_msat / 1000, commitment_tx_fee / 1000) }); } @@ -1106,7 +1140,7 @@ impl Channel { is_outbound_from_holder: true, counterparty_parameters: None, funding_outpoint: None, - opt_anchors: if channel_type.requires_anchors_zero_fee_htlc_tx() { Some(()) } else { None }, + channel_type: if channel_features.requires_anchors_zero_fee_htlc_tx() { ChannelType::Anchors } else { ChannelType::Legacy }, opt_non_zero_fee_anchors: None }, funding_transaction: None, @@ -1140,7 +1174,7 @@ impl Channel { #[cfg(any(test, fuzzing))] historical_inbound_htlc_fulfills: HashSet::new(), - channel_type, + channel_type: channel_features, channel_keys_id, pending_monitor_updates: Vec::new(), @@ -1196,7 +1230,7 @@ impl Channel { // First check the channel type is known, failing before we do anything else if we don't // support this channel type. - let channel_type = if let Some(channel_type) = &msg.channel_type { + let channel_features = if let Some(channel_type) = &msg.channel_type { if channel_type.supports_any_optional_bits() { return Err(ChannelError::Close("Channel Type field contained optional bits - this is not allowed".to_owned())); } @@ -1222,7 +1256,11 @@ impl Channel { } channel_type }; - let opt_anchors = channel_type.supports_anchors_zero_fee_htlc_tx(); + let channel_type = if channel_features.supports_anchors_zero_fee_htlc_tx() { + ChannelType::Anchors + } else { + ChannelType::Legacy + }; let channel_keys_id = signer_provider.generate_channel_keys_id(true, msg.funding_satoshis, user_id); let holder_signer = signer_provider.derive_channel_signer(msg.funding_satoshis, channel_keys_id); @@ -1323,7 +1361,7 @@ impl Channel { // check if the funder's amount for the initial commitment tx is sufficient // for full fee payment plus a few HTLCs to ensure the channel will be useful. let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat; - let commitment_tx_fee = Self::commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, opt_anchors) / 1000; + let commitment_tx_fee = Self::commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, &channel_type) / 1000; if funders_amount_msat / 1000 < commitment_tx_fee { return Err(ChannelError::Close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction fee of {} sats.", funders_amount_msat / 1000, commitment_tx_fee))); } @@ -1465,7 +1503,7 @@ impl Channel { pubkeys: counterparty_pubkeys, }), funding_outpoint: None, - opt_anchors: if opt_anchors { Some(()) } else { None }, + channel_type, opt_non_zero_fee_anchors: None }, funding_transaction: None, @@ -1499,7 +1537,7 @@ impl Channel { #[cfg(any(test, fuzzing))] historical_inbound_htlc_fulfills: HashSet::new(), - channel_type, + channel_type: channel_features, channel_keys_id, pending_monitor_updates: Vec::new(), @@ -1568,10 +1606,10 @@ impl Channel { ($htlc: expr, $outbound: expr, $source: expr, $state_name: expr) => { if $outbound == local { // "offered HTLC output" let htlc_in_tx = get_htlc_in_commitment!($htlc, true); - let htlc_tx_fee = if self.opt_anchors() { + let htlc_tx_fee = if self.channel_type().supports_anchors() { 0 } else { - feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000 + feerate_per_kw as u64 * htlc_timeout_tx_weight(&ChannelType::Legacy) / 1000 }; if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee { log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); @@ -1582,10 +1620,10 @@ impl Channel { } } else { let htlc_in_tx = get_htlc_in_commitment!($htlc, false); - let htlc_tx_fee = if self.opt_anchors() { + let htlc_tx_fee = if self.channel_type().supports_anchors() { 0 } else { - feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000 + feerate_per_kw as u64 * htlc_success_tx_weight(&ChannelType::Legacy) / 1000 }; if $htlc.amount_msat / 1000 >= broadcaster_dust_limit_satoshis + htlc_tx_fee { log_trace!(logger, " ...including {} {} HTLC {} (hash {}) with value {}", if $outbound { "outbound" } else { "inbound" }, $state_name, $htlc.htlc_id, log_bytes!($htlc.payment_hash.0), $htlc.amount_msat); @@ -1690,8 +1728,8 @@ impl Channel { broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64); } - let total_fee_sat = Channel::::commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), self.channel_transaction_parameters.opt_anchors.is_some()); - let anchors_val = if self.channel_transaction_parameters.opt_anchors.is_some() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64; + let total_fee_sat = Channel::::commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), &self.channel_type()); + let anchors_val = if self.channel_transaction_parameters.channel_type.supports_anchors() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64; let (value_to_self, value_to_remote) = if self.is_outbound() { (value_to_self_msat / 1000 - anchors_val - total_fee_sat as i64, value_to_remote_msat / 1000) } else { @@ -1726,7 +1764,6 @@ impl Channel { let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number, value_to_a as u64, value_to_b as u64, - self.channel_transaction_parameters.opt_anchors.is_some(), funding_pubkey_a, funding_pubkey_b, keys.clone(), @@ -2601,12 +2638,13 @@ impl Channel { on_holder_tx_holding_cell_htlcs_count: 0, }; - let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.opt_anchors() { + let channel_type = self.channel_type(); + let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if channel_type.supports_anchors() { (0, 0) } else { let dust_buffer_feerate = self.get_dust_buffer_feerate(outbound_feerate_update) as u64; - (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000, - dust_buffer_feerate * htlc_success_tx_weight(false) / 1000) + (dust_buffer_feerate * htlc_timeout_tx_weight(&channel_type) / 1000, + dust_buffer_feerate * htlc_success_tx_weight(&channel_type) / 1000) }; let counterparty_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.counterparty_dust_limit_satoshis; let holder_dust_limit_success_sat = htlc_success_dust_limit + self.holder_dust_limit_satoshis; @@ -2633,12 +2671,13 @@ impl Channel { on_holder_tx_holding_cell_htlcs_count: 0, }; - let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.opt_anchors() { + let channel_type = self.channel_type(); + let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if channel_type.supports_anchors() { (0, 0) } else { let dust_buffer_feerate = self.get_dust_buffer_feerate(outbound_feerate_update) as u64; - (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000, - dust_buffer_feerate * htlc_success_tx_weight(false) / 1000) + (dust_buffer_feerate * htlc_timeout_tx_weight(&channel_type) / 1000, + dust_buffer_feerate * htlc_success_tx_weight(&channel_type) / 1000) }; let counterparty_dust_limit_success_sat = htlc_success_dust_limit + self.counterparty_dust_limit_satoshis; let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis; @@ -2711,17 +2750,17 @@ impl Channel { // Get the fee cost in MSATS of a commitment tx with a given number of HTLC outputs. // Note that num_htlcs should not include dust HTLCs. - fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 { + fn commit_tx_fee_msat(feerate_per_kw: u32, num_htlcs: usize, channel_type: &ChannelType) -> u64 { // Note that we need to divide before multiplying to round properly, // since the lowest denomination of bitcoin on-chain is the satoshi. - (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000 + (commitment_tx_base_weight(channel_type) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate_per_kw as u64 / 1000 * 1000 } // Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs. // Note that num_htlcs should not include dust HTLCs. #[inline] - fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, opt_anchors: bool) -> u64 { - feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 + fn commit_tx_fee_sat(feerate_per_kw: u32, num_htlcs: usize, channel_type: &ChannelType) -> u64 { + feerate_per_kw as u64 * (commitment_tx_base_weight(channel_type) + num_htlcs as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 } // Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the @@ -2731,11 +2770,12 @@ impl Channel { fn next_local_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 { assert!(self.is_outbound()); - let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.opt_anchors() { + let channel_type = self.channel_type(); + let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if channel_type.supports_anchors() { (0, 0) } else { - (self.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000, - self.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000) + (self.feerate_per_kw as u64 * htlc_success_tx_weight(&channel_type) / 1000, + self.feerate_per_kw as u64 * htlc_timeout_tx_weight(&channel_type) / 1000) }; let real_dust_limit_success_sat = htlc_success_dust_limit + self.holder_dust_limit_satoshis; let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis; @@ -2793,13 +2833,14 @@ impl Channel { } } + let channel_type = self.channel_type(); let num_htlcs = included_htlcs + addl_htlcs; - let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, self.opt_anchors()); + let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, &channel_type); #[cfg(any(test, fuzzing))] { let mut fee = res; if fee_spike_buffer_htlc.is_some() { - fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, self.opt_anchors()); + fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, &channel_type); } let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + self.holding_cell_htlc_updates.len(); @@ -2828,11 +2869,12 @@ impl Channel { fn next_remote_commit_tx_fee_msat(&self, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>) -> u64 { assert!(!self.is_outbound()); - let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.opt_anchors() { + let channel_type = self.channel_type(); + let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if channel_type.supports_anchors() { (0, 0) } else { - (self.feerate_per_kw as u64 * htlc_success_tx_weight(false) / 1000, - self.feerate_per_kw as u64 * htlc_timeout_tx_weight(false) / 1000) + (self.feerate_per_kw as u64 * htlc_success_tx_weight(&channel_type) / 1000, + self.feerate_per_kw as u64 * htlc_timeout_tx_weight(&channel_type) / 1000) }; let real_dust_limit_success_sat = htlc_success_dust_limit + self.counterparty_dust_limit_satoshis; let real_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.counterparty_dust_limit_satoshis; @@ -2878,12 +2920,12 @@ impl Channel { } let num_htlcs = included_htlcs + addl_htlcs; - let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, self.opt_anchors()); + let res = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs, &channel_type); #[cfg(any(test, fuzzing))] { let mut fee = res; if fee_spike_buffer_htlc.is_some() { - fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, self.opt_anchors()); + fee = Self::commit_tx_fee_msat(self.feerate_per_kw, num_htlcs - 1, &channel_type); } let total_pending_htlcs = self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len(); let commitment_tx_info = CommitmentTxInfoCached { @@ -2958,12 +3000,13 @@ impl Channel { } } - let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if self.opt_anchors() { + let channel_type = self.channel_type(); + let (htlc_timeout_dust_limit, htlc_success_dust_limit) = if channel_type.supports_anchors() { (0, 0) } else { let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64; - (dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000, - dust_buffer_feerate * htlc_success_tx_weight(false) / 1000) + (dust_buffer_feerate * htlc_timeout_tx_weight(&channel_type) / 1000, + dust_buffer_feerate * htlc_success_tx_weight(&channel_type) / 1000) }; let exposure_dust_limit_timeout_sats = htlc_timeout_dust_limit + self.counterparty_dust_limit_satoshis; if msg.amount_msat / 1000 < exposure_dust_limit_timeout_sats { @@ -3208,14 +3251,15 @@ impl Channel { let mut nondust_htlc_sources = Vec::with_capacity(htlcs_cloned.len()); let mut htlcs_and_sigs = Vec::with_capacity(htlcs_cloned.len()); + let channel_type = self.channel_type(); for (idx, (htlc, mut source_opt)) in htlcs_cloned.drain(..).enumerate() { if let Some(_) = htlc.transaction_output_index { let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw, - self.get_counterparty_selected_contest_delay().unwrap(), &htlc, self.opt_anchors(), + self.get_counterparty_selected_contest_delay().unwrap(), &htlc, &channel_type, false, &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys); - let htlc_sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; + let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &channel_type, &keys); + let htlc_sighashtype = if channel_type.supports_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]); log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.", log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.serialize()), @@ -3731,7 +3775,7 @@ impl Channel { let outbound_stats = self.get_outbound_pending_htlc_stats(Some(feerate_per_kw)); let keys = self.build_holder_transaction_keys(self.cur_holder_commitment_transaction_number); let commitment_stats = self.build_commitment_transaction(self.cur_holder_commitment_transaction_number, &keys, true, true, logger); - let buffer_fee_msat = Channel::::commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + outbound_stats.on_holder_tx_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.opt_anchors()) * 1000; + let buffer_fee_msat = Channel::::commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + outbound_stats.on_holder_tx_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, &self.channel_type()) * 1000; let holder_balance_msat = commitment_stats.local_balance_msat - outbound_stats.holding_cell_msat; if holder_balance_msat < buffer_fee_msat + self.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000 { //TODO: auto-close after a number of failures? @@ -5869,12 +5913,12 @@ impl Channel { } } - let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.opt_anchors() { + let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if self.channel_type().supports_anchors() { (0, 0) } else { let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64; - (dust_buffer_feerate * htlc_success_tx_weight(false) / 1000, - dust_buffer_feerate * htlc_timeout_tx_weight(false) / 1000) + (dust_buffer_feerate * htlc_success_tx_weight(&self.channel_type()) / 1000, + dust_buffer_feerate * htlc_timeout_tx_weight(&self.channel_type()) / 1000) }; let exposure_dust_limit_success_sats = htlc_success_dust_limit + self.counterparty_dust_limit_satoshis; if amount_msat / 1000 < exposure_dust_limit_success_sats { @@ -6024,7 +6068,7 @@ impl Channel { && info.next_holder_htlc_id == self.next_holder_htlc_id && info.next_counterparty_htlc_id == self.next_counterparty_htlc_id && info.feerate == self.feerate_per_kw { - let actual_fee = Self::commit_tx_fee_msat(self.feerate_per_kw, commitment_stats.num_nondust_htlcs, self.opt_anchors()); + let actual_fee = Self::commit_tx_fee_msat(self.feerate_per_kw, commitment_stats.num_nondust_htlcs, &self.channel_type()); assert_eq!(actual_fee, info.fee); } } @@ -6064,8 +6108,8 @@ impl Channel { for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) { log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}", - encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, self.opt_anchors(), false, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)), - encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &counterparty_keys)), + encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.get_holder_selected_contest_delay(), htlc, &self.channel_type(), false, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)), + encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &self.channel_type(), &counterparty_keys)), log_bytes!(counterparty_keys.broadcaster_htlc_key.serialize()), log_bytes!(htlc_sig.serialize_compact()[..]), log_bytes!(self.channel_id())); } @@ -7320,15 +7364,16 @@ mod tests { // Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass // the dust limit check. + let node_a_channel_type = node_a_chan.channel_type(); let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let local_commit_tx_fee = node_a_chan.next_local_commit_tx_fee_msat(htlc_candidate, None); - let local_commit_fee_0_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 0, node_a_chan.opt_anchors()); + let local_commit_fee_0_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 0, &node_a_channel_type); assert_eq!(local_commit_tx_fee, local_commit_fee_0_htlcs); // Finally, make sure that when Node A calculates the remote's commitment transaction fees, all // of the HTLCs are seen to be above the dust limit. node_a_chan.channel_transaction_parameters.is_outbound_from_holder = false; - let remote_commit_fee_3_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 3, node_a_chan.opt_anchors()); + let remote_commit_fee_3_htlcs = Channel::::commit_tx_fee_msat(node_a_chan.feerate_per_kw, 3, &node_a_channel_type); let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let remote_commit_tx_fee = node_a_chan.next_remote_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(remote_commit_tx_fee, remote_commit_fee_3_htlcs); @@ -7350,18 +7395,19 @@ mod tests { let config = UserConfig::default(); let mut chan = Channel::::new_outbound(&fee_est, &&keys_provider, &&keys_provider, node_id, &channelmanager::provided_init_features(&config), 10000000, 100000, 42, &config, 0, 42).unwrap(); - let commitment_tx_fee_0_htlcs = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 0, chan.opt_anchors()); - let commitment_tx_fee_1_htlc = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 1, chan.opt_anchors()); + let channel_type = chan.channel_type(); + let commitment_tx_fee_0_htlcs = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 0, &channel_type); + let commitment_tx_fee_1_htlc = Channel::::commit_tx_fee_msat(chan.feerate_per_kw, 1, &channel_type); // If HTLC_SUCCESS_TX_WEIGHT and HTLC_TIMEOUT_TX_WEIGHT were swapped: then this HTLC would be // counted as dust when it shouldn't be. - let htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.opt_anchors()) / 1000) + chan.holder_dust_limit_satoshis + 1) * 1000; + let htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(&channel_type) / 1000) + chan.holder_dust_limit_satoshis + 1) * 1000; let htlc_candidate = HTLCCandidate::new(htlc_amt_above_timeout, HTLCInitiator::LocalOffered); let commitment_tx_fee = chan.next_local_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc); // If swapped: this HTLC would be counted as non-dust when it shouldn't be. - let dust_htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.opt_anchors()) / 1000) + chan.holder_dust_limit_satoshis - 1) * 1000; + let dust_htlc_amt_below_success = ((253 * htlc_success_tx_weight(&channel_type) / 1000) + chan.holder_dust_limit_satoshis - 1) * 1000; let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_below_success, HTLCInitiator::RemoteOffered); let commitment_tx_fee = chan.next_local_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs); @@ -7369,13 +7415,13 @@ mod tests { chan.channel_transaction_parameters.is_outbound_from_holder = false; // If swapped: this HTLC would be counted as non-dust when it shouldn't be. - let dust_htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.opt_anchors()) / 1000) + chan.counterparty_dust_limit_satoshis + 1) * 1000; + let dust_htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(&channel_type) / 1000) + chan.counterparty_dust_limit_satoshis + 1) * 1000; let htlc_candidate = HTLCCandidate::new(dust_htlc_amt_above_timeout, HTLCInitiator::LocalOffered); let commitment_tx_fee = chan.next_remote_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs); // If swapped: this HTLC would be counted as dust when it shouldn't be. - let htlc_amt_below_success = ((253 * htlc_success_tx_weight(chan.opt_anchors()) / 1000) + chan.counterparty_dust_limit_satoshis - 1) * 1000; + let htlc_amt_below_success = ((253 * htlc_success_tx_weight(&channel_type) / 1000) + chan.counterparty_dust_limit_satoshis - 1) * 1000; let htlc_candidate = HTLCCandidate::new(htlc_amt_below_success, HTLCInitiator::RemoteOffered); let commitment_tx_fee = chan.next_remote_commit_tx_fee_msat(htlc_candidate, None); assert_eq!(commitment_tx_fee, commitment_tx_fee_1_htlc); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 93841517ba7..1124fa6670f 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -802,7 +802,7 @@ macro_rules! get_opt_anchors { let mut per_peer_state_lock; let mut peer_state_lock; let chan = get_channel_ref!($node, $counterparty_node, per_peer_state_lock, peer_state_lock, $channel_id); - chan.opt_anchors() + chan.channel_type() } } } diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 98fc4bd95b6..1a5e761de56 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -20,7 +20,7 @@ use crate::chain::transaction::OutPoint; use crate::sign::{ChannelSigner, EcdsaChannelSigner, EntropySource}; use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason}; use crate::ln::{PaymentPreimage, PaymentSecret, PaymentHash}; -use crate::ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT}; +use crate::ln::channel::{ChannelType, commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT}; use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA}; use crate::ln::channel::{Channel, ChannelError}; use crate::ln::{chan_utils, onion_utils}; @@ -155,8 +155,8 @@ fn do_test_counterparty_no_reserve(send_from_initiator: bool) { // Have node0 initiate a channel to node1 with aforementioned parameters let mut push_amt = 100_000_000; let feerate_per_kw = 253; - let opt_anchors = false; - push_amt -= feerate_per_kw as u64 * (commitment_tx_base_weight(opt_anchors) + 4 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 * 1000; + let channel_type = ChannelType::Legacy; + push_amt -= feerate_per_kw as u64 * (commitment_tx_base_weight(&channel_type) + 4 * COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 * 1000; push_amt -= Channel::::get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000; let temp_channel_id = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, if send_from_initiator { 0 } else { push_amt }, 42, None).unwrap(); @@ -195,7 +195,7 @@ fn do_test_counterparty_no_reserve(send_from_initiator: bool) { // Note that for outbound channels we have to consider the commitment tx fee and the // "fee spike buffer", which is currently a multiple of the total commitment tx fee as // well as an additional HTLC. - - FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * commit_tx_fee_msat(feerate_per_kw, 2, opt_anchors)); + - FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE * commit_tx_fee_msat(feerate_per_kw, 2, &channel_type)); } else { send_payment(&nodes[1], &[&nodes[0]], push_amt); } @@ -645,14 +645,14 @@ fn test_update_fee_that_funder_cannot_afford() { let default_config = UserConfig::default(); let bs_channel_reserve_sats = Channel::::get_holder_selected_channel_reserve_satoshis(channel_value, &default_config); - let opt_anchors = false; + let channel_type = ChannelType::Legacy; // Calculate the maximum feerate that A can afford. Note that we don't send an update_fee // CONCURRENT_INBOUND_HTLC_FEE_BUFFER HTLCs before actually running out of local balance, so we // calculate two different feerates here - the expected local limit as well as the expected // remote limit. - let feerate = ((channel_value - bs_channel_reserve_sats - push_sats) * 1000 / (commitment_tx_base_weight(opt_anchors) + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC)) as u32; - let non_buffer_feerate = ((channel_value - bs_channel_reserve_sats - push_sats) * 1000 / commitment_tx_base_weight(opt_anchors)) as u32; + let feerate = ((channel_value - bs_channel_reserve_sats - push_sats) * 1000 / (commitment_tx_base_weight(&channel_type) + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as u64 * COMMITMENT_TX_WEIGHT_PER_HTLC)) as u32; + let non_buffer_feerate = ((channel_value - bs_channel_reserve_sats - push_sats) * 1000 / commitment_tx_base_weight(&channel_type)) as u32; { let mut feerate_lock = chanmon_cfgs[0].fee_estimator.sat_per_kw.lock().unwrap(); *feerate_lock = feerate; @@ -671,7 +671,7 @@ fn test_update_fee_that_funder_cannot_afford() { //We made sure neither party's funds are below the dust limit and there are no HTLCs here assert_eq!(commitment_tx.output.len(), 2); - let total_fee: u64 = commit_tx_fee_msat(feerate, 0, opt_anchors) / 1000; + let total_fee: u64 = commit_tx_fee_msat(feerate, 0, &channel_type) / 1000; let mut actual_fee = commitment_tx.output.iter().fold(0, |acc, output| acc + output.value); actual_fee = channel_value - actual_fee; assert_eq!(total_fee, actual_fee); @@ -723,8 +723,8 @@ fn test_update_fee_that_funder_cannot_afford() { let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data( INITIAL_COMMITMENT_NUMBER - 1, push_sats, - channel_value - push_sats - commit_tx_fee_msat(non_buffer_feerate + 4, 0, opt_anchors) / 1000, - opt_anchors, local_funding, remote_funding, + channel_value - push_sats - commit_tx_fee_msat(non_buffer_feerate + 4, 0, &channel_type) / 1000, + local_funding, remote_funding, commit_tx_keys.clone(), non_buffer_feerate + 4, &mut htlcs, @@ -1340,7 +1340,7 @@ fn test_basic_channel_reserve() { let channel_reserve = chan_stat.channel_reserve_msat; // The 2* and +1 are for the fee spike reserve. - let commit_tx_fee = 2 * commit_tx_fee_msat(get_feerate!(nodes[0], nodes[1], chan.2), 1 + 1, get_opt_anchors!(nodes[0], nodes[1], chan.2)); + let commit_tx_fee = 2 * commit_tx_fee_msat(get_feerate!(nodes[0], nodes[1], chan.2), 1 + 1, &get_opt_anchors!(nodes[0], nodes[1], chan.2)); let max_can_send = 5000000 - channel_reserve - commit_tx_fee; let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], max_can_send + 1); let err = nodes[0].node.send_payment_with_route(&route, our_payment_hash, @@ -1453,7 +1453,7 @@ fn test_fee_spike_violation_fails_htlc() { commitment_number, 95000, local_chan_balance, - local_chan.opt_anchors(), local_funding, remote_funding, + local_funding, remote_funding, commit_tx_keys.clone(), feerate_per_kw, &mut vec![(accepted_htlc_info, ())], @@ -1512,10 +1512,10 @@ fn test_chan_reserve_violation_outbound_htlc_inbound_chan() { let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); let default_config = UserConfig::default(); - let opt_anchors = false; + let channel_type = ChannelType::Legacy; let mut push_amt = 100_000_000; - push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors); + push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, &channel_type); push_amt -= Channel::::get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000; @@ -1544,13 +1544,13 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() { let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); let default_config = UserConfig::default(); - let opt_anchors = false; + let channel_type = ChannelType::Legacy; // Set nodes[0]'s balance such that they will consider any above-dust received HTLC to be a // channel reserve violation (so their balance is channel reserve (1000 sats) + commitment // transaction fee with 0 HTLCs (183 sats)). let mut push_amt = 100_000_000; - push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors); + push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, &channel_type); push_amt -= Channel::::get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000; let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, push_amt); @@ -1598,18 +1598,18 @@ fn test_chan_reserve_dust_inbound_htlcs_outbound_chan() { let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None, None]); let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); let default_config = UserConfig::default(); - let opt_anchors = false; + let channel_type = ChannelType::Legacy; // Set nodes[0]'s balance such that they will consider any above-dust received HTLC to be a // channel reserve violation (so their balance is channel reserve (1000 sats) + commitment // transaction fee with 0 HTLCs (183 sats)). let mut push_amt = 100_000_000; - push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors); + push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, &channel_type); push_amt -= Channel::::get_holder_selected_channel_reserve_satoshis(100_000, &default_config) * 1000; create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, push_amt); let dust_amt = crate::ln::channel::MIN_CHAN_DUST_LIMIT_SATOSHIS * 1000 - + feerate_per_kw as u64 * htlc_success_tx_weight(opt_anchors) / 1000 * 1000 - 1; + + feerate_per_kw as u64 * htlc_success_tx_weight(&channel_type) / 1000 * 1000 - 1; // In the previous code, routing this dust payment would cause nodes[0] to perceive a channel // reserve violation even though it's a dust HTLC and therefore shouldn't count towards the // commitment transaction fee. @@ -1638,12 +1638,12 @@ fn test_chan_init_feerate_unaffordability() { let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); let default_config = UserConfig::default(); - let opt_anchors = false; + let channel_type = ChannelType::Legacy; // Set the push_msat amount such that nodes[0] will not be able to afford to add even a single // HTLC. let mut push_amt = 100_000_000; - push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, opt_anchors); + push_amt -= commit_tx_fee_msat(feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT as u64, &channel_type); assert_eq!(nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, push_amt + 1, 42, None).unwrap_err(), APIError::APIMisuseError { err: "Funding amount (356) can't even pay fee for initial commitment transaction fee of 357.".to_string() }); @@ -1708,10 +1708,10 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { let total_routing_fee_msat = (nodes.len() - 2) as u64 * feemsat; let chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2); let feerate = get_feerate!(nodes[0], nodes[1], chan.2); - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan.2); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan.2); // Add a 2* and +1 for the fee spike reserve. - let commit_tx_fee_2_htlc = 2*commit_tx_fee_msat(feerate, 2 + 1, opt_anchors); + let commit_tx_fee_2_htlc = 2*commit_tx_fee_msat(feerate, 2 + 1, &channel_type); let recv_value_1 = (chan_stat.value_to_self_msat - chan_stat.channel_reserve_msat - total_routing_fee_msat - commit_tx_fee_2_htlc)/2; let amt_msat_1 = recv_value_1 + total_routing_fee_msat; @@ -1729,7 +1729,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &payment_event_1.msgs[0]); // Attempt to trigger a channel reserve violation --> payment failure. - let commit_tx_fee_2_htlcs = commit_tx_fee_msat(feerate, 2, opt_anchors); + let commit_tx_fee_2_htlcs = commit_tx_fee_msat(feerate, 2, &channel_type); let recv_value_2 = chan_stat.value_to_self_msat - amt_msat_1 - chan_stat.channel_reserve_msat - total_routing_fee_msat - commit_tx_fee_2_htlcs + 1; let amt_msat_2 = recv_value_2 + total_routing_fee_msat; let (route_2, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[2], amt_msat_2); @@ -1782,8 +1782,8 @@ fn test_inbound_outbound_capacity_is_not_zero() { assert_eq!(channels1[0].inbound_capacity_msat, 100000 * 1000 - 95000000 - reserve*1000); } -fn commit_tx_fee_msat(feerate: u32, num_htlcs: u64, opt_anchors: bool) -> u64 { - (commitment_tx_base_weight(opt_anchors) + num_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate as u64 / 1000 * 1000 +fn commit_tx_fee_msat(feerate: u32, num_htlcs: u64, channel_type: &ChannelType) -> u64 { + (commitment_tx_base_weight(channel_type) + num_htlcs * COMMITMENT_TX_WEIGHT_PER_HTLC) * feerate as u64 / 1000 * 1000 } #[test] @@ -1818,7 +1818,7 @@ fn test_channel_reserve_holding_cell_htlcs() { let feemsat = 239; // set above let total_fee_msat = (nodes.len() - 2) as u64 * feemsat; let feerate = get_feerate!(nodes[0], nodes[1], chan_1.2); - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_1.2); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_1.2); let recv_value_0 = stat01.counterparty_max_htlc_value_in_flight_msat - total_fee_msat; @@ -1845,7 +1845,7 @@ fn test_channel_reserve_holding_cell_htlcs() { // 3 for the 3 HTLCs that will be sent, 2* and +1 for the fee spike reserve. // Also, ensure that each payment has enough to be over the dust limit to // ensure it'll be included in each commit tx fee calculation. - let commit_tx_fee_all_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1, opt_anchors); + let commit_tx_fee_all_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1, &channel_type); let ensure_htlc_amounts_above_dust_buffer = 3 * (stat01.counterparty_dust_limit_msat + 1000); if stat01.value_to_self_msat < stat01.channel_reserve_msat + commit_tx_fee_all_htlcs + ensure_htlc_amounts_above_dust_buffer + amt_msat { break; @@ -1882,7 +1882,7 @@ fn test_channel_reserve_holding_cell_htlcs() { // the amount of the first of these aforementioned 3 payments. The reason we split into 3 payments // is to test the behavior of the holding cell with respect to channel reserve and commit tx fee // policy. - let commit_tx_fee_2_htlcs = 2*commit_tx_fee_msat(feerate, 2 + 1, opt_anchors); + let commit_tx_fee_2_htlcs = 2*commit_tx_fee_msat(feerate, 2 + 1, &channel_type); let recv_value_1 = (stat01.value_to_self_msat - stat01.channel_reserve_msat - total_fee_msat - commit_tx_fee_2_htlcs)/2; let amt_msat_1 = recv_value_1 + total_fee_msat; @@ -1910,7 +1910,7 @@ fn test_channel_reserve_holding_cell_htlcs() { } // split the rest to test holding cell - let commit_tx_fee_3_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1, opt_anchors); + let commit_tx_fee_3_htlcs = 2*commit_tx_fee_msat(feerate, 3 + 1, &channel_type); let additional_htlc_cost_msat = commit_tx_fee_3_htlcs - commit_tx_fee_2_htlcs; let recv_value_21 = recv_value_2/2 - additional_htlc_cost_msat/2; let recv_value_22 = recv_value_2 - recv_value_21 - total_fee_msat - additional_htlc_cost_msat; @@ -2029,11 +2029,11 @@ fn test_channel_reserve_holding_cell_htlcs() { claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage_21); claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), our_payment_preimage_22); - let commit_tx_fee_0_htlcs = 2*commit_tx_fee_msat(feerate, 1, opt_anchors); + let commit_tx_fee_0_htlcs = 2*commit_tx_fee_msat(feerate, 1, &channel_type); let recv_value_3 = commit_tx_fee_2_htlcs - commit_tx_fee_0_htlcs - total_fee_msat; send_payment(&nodes[0], &vec![&nodes[1], &nodes[2]][..], recv_value_3); - let commit_tx_fee_1_htlc = 2*commit_tx_fee_msat(feerate, 1 + 1, opt_anchors); + let commit_tx_fee_1_htlc = 2*commit_tx_fee_msat(feerate, 1 + 1, &channel_type); let expected_value_to_self = stat01.value_to_self_msat - (recv_value_1 + total_fee_msat) - (recv_value_21 + total_fee_msat) - (recv_value_22 + total_fee_msat) - (recv_value_3 + total_fee_msat); let stat0 = get_channel_value_stat!(nodes[0], nodes[1], chan_1.2); assert_eq!(stat0.value_to_self_msat, expected_value_to_self); @@ -5694,10 +5694,10 @@ fn test_fail_holding_cell_htlc_upon_free() { let mut chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2); let channel_reserve = chan_stat.channel_reserve_msat; let feerate = get_feerate!(nodes[0], nodes[1], chan.2); - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan.2); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan.2); // 2* and +1 HTLCs on the commit tx fee calculation for the fee spike reserve. - let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1, opt_anchors); + let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1, &channel_type); let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], max_can_send); // Send a payment which passes reserve checks but gets stuck in the holding cell. @@ -5777,11 +5777,11 @@ fn test_free_and_fail_holding_cell_htlcs() { let mut chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2); let channel_reserve = chan_stat.channel_reserve_msat; let feerate = get_feerate!(nodes[0], nodes[1], chan.2); - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan.2); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan.2); // 2* and +1 HTLCs on the commit tx fee calculation for the fee spike reserve. let amt_1 = 20000; - let amt_2 = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 2 + 1, opt_anchors) - amt_1; + let amt_2 = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 2 + 1, &channel_type) - amt_1; let (route_1, payment_hash_1, payment_preimage_1, payment_secret_1) = get_route_and_payment_hash!(nodes[0], nodes[1], amt_1); let (route_2, payment_hash_2, _, payment_secret_2) = get_route_and_payment_hash!(nodes[0], nodes[1], amt_2); @@ -5910,12 +5910,12 @@ fn test_fail_holding_cell_htlc_upon_free_multihop() { let mut chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan_0_1.2); let channel_reserve = chan_stat.channel_reserve_msat; let feerate = get_feerate!(nodes[0], nodes[1], chan_0_1.2); - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_0_1.2); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_0_1.2); // Send a payment which passes reserve checks but gets stuck in the holding cell. let feemsat = 239; let total_routing_fee_msat = (nodes.len() - 2) as u64 * feemsat; - let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1, opt_anchors) - total_routing_fee_msat; + let max_can_send = 5000000 - channel_reserve - 2*commit_tx_fee_msat(feerate, 1 + 1, &channel_type) - total_routing_fee_msat; let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], max_can_send); let payment_event = { nodes[0].node.send_payment_with_route(&route, our_payment_hash, @@ -6209,9 +6209,9 @@ fn test_update_add_htlc_bolt2_receiver_sender_can_afford_amount_sent() { let chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2); let channel_reserve = chan_stat.channel_reserve_msat; let feerate = get_feerate!(nodes[0], nodes[1], chan.2); - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan.2); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan.2); // The 2* and +1 are for the fee spike reserve. - let commit_tx_fee_outbound = 2 * commit_tx_fee_msat(feerate, 1 + 1, opt_anchors); + let commit_tx_fee_outbound = 2 * commit_tx_fee_msat(feerate, 1 + 1, &channel_type); let max_can_send = 5000000 - channel_reserve - commit_tx_fee_outbound; let (route, our_payment_hash, _, our_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], max_can_send); @@ -9632,7 +9632,7 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()); nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel); - let opt_anchors = false; + let channel_type = ChannelType::Legacy; let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42); @@ -9662,10 +9662,10 @@ fn do_test_max_dust_htlc_exposure(dust_outbound_balance: bool, exposure_breach_e let chan = chan_lock.channel_by_id.get(&channel_id).unwrap(); chan.get_dust_buffer_feerate(None) as u64 }; - let dust_outbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_timeout_tx_weight(opt_anchors) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000; + let dust_outbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_timeout_tx_weight(&channel_type) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000; let dust_outbound_htlc_on_holder_tx: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_outbound_htlc_on_holder_tx_msat; - let dust_inbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_success_tx_weight(opt_anchors) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000; + let dust_inbound_htlc_on_holder_tx_msat: u64 = (dust_buffer_feerate * htlc_success_tx_weight(&channel_type) / 1000 + open_channel.dust_limit_satoshis - 1) * 1000; let dust_inbound_htlc_on_holder_tx: u64 = config.channel_config.max_dust_htlc_exposure_msat / dust_inbound_htlc_on_holder_tx_msat; let dust_htlc_on_counterparty_tx: u64 = 25; diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index 5fa39137cf4..47c5f869a11 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -184,10 +184,10 @@ fn chanmon_claim_value_coop_close() { assert_eq!(funding_outpoint.to_channel_id(), chan_id); let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_id); assert_eq!(vec![Balance::ClaimableOnChannelClose { - claimable_amount_satoshis: 1_000_000 - 1_000 - chan_feerate * channel::commitment_tx_base_weight(opt_anchors) / 1000 + claimable_amount_satoshis: 1_000_000 - 1_000 - chan_feerate * channel::commitment_tx_base_weight(&channel_type) / 1000 }], nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); assert_eq!(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 1_000, }], @@ -222,7 +222,7 @@ fn chanmon_claim_value_coop_close() { assert!(nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty()); assert_eq!(vec![Balance::ClaimableAwaitingConfirmations { - claimable_amount_satoshis: 1_000_000 - 1_000 - chan_feerate * channel::commitment_tx_base_weight(opt_anchors) / 1000, + claimable_amount_satoshis: 1_000_000 - 1_000 - chan_feerate * channel::commitment_tx_base_weight(&channel_type) / 1000, confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, }], nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()); @@ -295,7 +295,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { let htlc_cltv_timeout = nodes[0].best_block_info().1 + TEST_FINAL_CLTV + 1; // Note ChannelManager adds one to CLTV timeouts for safety let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_id); let remote_txn = get_local_commitment_txn!(nodes[1], chan_id); let sent_htlc_balance = Balance::MaybeTimeoutClaimableHTLC { @@ -335,7 +335,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { // as claimable. A lists both its to-self balance and the (possibly-claimable) HTLCs. assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { @@ -382,7 +382,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { 1_000 - // The push_msat value in satoshis 3 - // The dust HTLC value in satoshis // The commitment transaction fee with two HTLC outputs: - chan_feerate * (channel::commitment_tx_base_weight(opt_anchors) + + chan_feerate * (channel::commitment_tx_base_weight(&channel_type) + if prev_commitment_tx { 1 } else { 2 } * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, sent_htlc_timeout_balance.clone()]; @@ -432,7 +432,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 3_000 - 4_000 - 1_000 - 3 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1, }, sent_htlc_balance.clone(), sent_htlc_timeout_balance.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -622,7 +622,7 @@ fn test_balances_on_local_commitment_htlcs() { expect_payment_claimed!(nodes[1], payment_hash_2, 20_000_000); let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_id); // Get nodes[0]'s commitment transaction and HTLC-Timeout transactions let as_txn = get_local_commitment_txn!(nodes[0], chan_id); @@ -652,7 +652,7 @@ fn test_balances_on_local_commitment_htlcs() { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -671,7 +671,7 @@ fn test_balances_on_local_commitment_htlcs() { connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -686,7 +686,7 @@ fn test_balances_on_local_commitment_htlcs() { // call, as described, two hunks down. assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, @@ -700,7 +700,7 @@ fn test_balances_on_local_commitment_htlcs() { expect_payment_sent!(nodes[0], payment_preimage_2); assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, @@ -716,7 +716,7 @@ fn test_balances_on_local_commitment_htlcs() { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, @@ -767,7 +767,7 @@ fn test_no_preimage_inbound_htlc_balances() { let htlc_cltv_timeout = nodes[0].best_block_info().1 + TEST_FINAL_CLTV + 1; // Note ChannelManager adds one to CLTV timeouts for safety let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_id); let a_sent_htlc_balance = Balance::MaybeTimeoutClaimableHTLC { claimable_amount_satoshis: 10_000, @@ -796,7 +796,7 @@ fn test_no_preimage_inbound_htlc_balances() { assert_eq!(sorted_vec(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]), sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances())); @@ -816,7 +816,7 @@ fn test_no_preimage_inbound_htlc_balances() { let node_a_commitment_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32; let as_pre_spend_claims = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, a_received_htlc_balance.clone(), a_sent_htlc_balance.clone()]); @@ -888,7 +888,7 @@ fn test_no_preimage_inbound_htlc_balances() { let as_timeout_claimable_height = nodes[0].best_block_info().1 + (BREAKDOWN_TIMEOUT as u32) - 1; assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, @@ -899,7 +899,7 @@ fn test_no_preimage_inbound_htlc_balances() { mine_transaction(&nodes[0], &bs_htlc_timeout_claim[0]); assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, a_received_htlc_balance.clone(), Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, @@ -915,7 +915,7 @@ fn test_no_preimage_inbound_htlc_balances() { connect_blocks(&nodes[0], 1); assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 500_000 - 10_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: node_a_commitment_claimable, }, Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 10_000, @@ -1024,7 +1024,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo // Get the latest commitment transaction from A and then update the fee to revoke it let as_revoked_txn = get_local_commitment_txn!(nodes[0], chan_id); - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_id); let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; @@ -1123,7 +1123,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo let to_self_unclaimed_balance = Balance::CounterpartyRevokedOutputClaimable { claimable_amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }; let to_self_claimed_avail_height; let largest_htlc_unclaimed_balance = Balance::CounterpartyRevokedOutputClaimable { @@ -1153,7 +1153,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo }; let to_self_claimed_balance = Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 + (channel::commitment_tx_base_weight(&channel_type) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 - chan_feerate * claim_txn[3].weight() as u64 / 1000, confirmation_height: to_self_claimed_avail_height, }; @@ -1185,7 +1185,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo confirmation_height: nodes[1].best_block_info().1 + 1, }, Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 + (channel::commitment_tx_base_weight(&channel_type) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000 - chan_feerate * claim_txn[3].weight() as u64 / 1000, confirmation_height: to_self_claimed_avail_height, }, Balance::ClaimableAwaitingConfirmations { @@ -1263,7 +1263,7 @@ fn test_revoked_counterparty_htlc_tx_balances() { claim_payment(&nodes[0], &[&nodes[1]], payment_preimage); let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_id); // B will generate an HTLC-Success from its revoked commitment tx mine_transaction(&nodes[1], &revoked_local_txn[0]); @@ -1311,7 +1311,7 @@ fn test_revoked_counterparty_htlc_tx_balances() { let as_balances = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output in B's revoked commitment claimable_amount_satoshis: 1_000_000 - 11_000 - 3_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: to_remote_conf_height, }, Balance::CounterpartyRevokedOutputClaimable { // to_self output in B's revoked commitment @@ -1342,7 +1342,7 @@ fn test_revoked_counterparty_htlc_tx_balances() { assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations { // to_remote output in B's revoked commitment claimable_amount_satoshis: 1_000_000 - 11_000 - 3_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, confirmation_height: to_remote_conf_height, }, Balance::CounterpartyRevokedOutputClaimable { // to_self output in B's revoked commitment @@ -1491,7 +1491,7 @@ fn test_revoked_counterparty_aggregated_claims() { check_spends!(as_revoked_txn[0], funding_tx); check_spends!(as_revoked_txn[1], as_revoked_txn[0]); // The HTLC-Claim transaction - let opt_anchors = get_opt_anchors!(nodes[0], nodes[1], chan_id); + let channel_type = get_opt_anchors!(nodes[0], nodes[1], chan_id); let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64; { @@ -1543,7 +1543,7 @@ fn test_revoked_counterparty_aggregated_claims() { }, Balance::CounterpartyRevokedOutputClaimable { // to_self output in A's revoked commitment claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1 claimable_amount_satoshis: 4_000, }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2 @@ -1572,7 +1572,7 @@ fn test_revoked_counterparty_aggregated_claims() { }, Balance::CounterpartyRevokedOutputClaimable { // to_self output in A's revoked commitment claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1 claimable_amount_satoshis: 4_000, }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2 @@ -1589,7 +1589,7 @@ fn test_revoked_counterparty_aggregated_claims() { assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable { // to_self output in A's revoked commitment claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1 claimable_amount_satoshis: 4_000, }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 2 @@ -1606,7 +1606,7 @@ fn test_revoked_counterparty_aggregated_claims() { assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable { // to_self output in A's revoked commitment claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1 claimable_amount_satoshis: 4_000, }, Balance::ClaimableAwaitingConfirmations { // HTLC 2 @@ -1621,7 +1621,7 @@ fn test_revoked_counterparty_aggregated_claims() { assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable { // to_self output in A's revoked commitment claimable_amount_satoshis: 1_000_000 - 100_000 - chan_feerate * - (channel::commitment_tx_base_weight(opt_anchors) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, + (channel::commitment_tx_base_weight(&channel_type) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000, }, Balance::CounterpartyRevokedOutputClaimable { // HTLC 1 claimable_amount_satoshis: 4_000, }]), diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 226a2bab72b..7d1b7e189ce 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -38,7 +38,7 @@ use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs}; use crate::chain::transaction::OutPoint; #[cfg(anchors)] use crate::events::bump_transaction::HTLCDescriptor; -use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; +use crate::ln::channel::{ANCHOR_OUTPUT_VALUE_SATOSHI, ChannelType}; use crate::ln::{chan_utils, PaymentPreimage}; use crate::ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction}; use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; @@ -821,8 +821,8 @@ impl InMemorySigner { /// Returns whether anchors should be used. /// /// Will panic if [`ChannelSigner::provide_channel_parameters`] has not been called before. - pub fn opt_anchors(&self) -> bool { - self.get_channel_parameters().opt_anchors.is_some() + pub fn channel_type(&self) -> ChannelType { + self.get_channel_parameters().channel_type.clone() } /// Sign the single input of `spend_tx` at index `input_idx`, which spends the output described /// by `descriptor`, returning the witness stack for the input. @@ -947,9 +947,9 @@ impl EcdsaChannelSigner for InMemorySigner { let mut htlc_sigs = Vec::with_capacity(commitment_tx.htlcs().len()); for htlc in commitment_tx.htlcs() { let channel_parameters = self.get_channel_parameters(); - let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, self.opt_anchors(), channel_parameters.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, self.opt_anchors(), &keys); - let htlc_sighashtype = if self.opt_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; + let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_tx.feerate_per_kw(), self.holder_selected_contest_delay(), htlc, &self.channel_type(), channel_parameters.opt_non_zero_fee_anchors.is_some(), &keys.broadcaster_delayed_payment_key, &keys.revocation_key); + let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &self.channel_type(), &keys); + let htlc_sighashtype = if self.channel_type().supports_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]); let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key); htlc_sigs.push(sign(secp_ctx, &htlc_sighash, &holder_htlc_key)); @@ -1003,7 +1003,7 @@ impl EcdsaChannelSigner for InMemorySigner { let witness_script = { let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint); let holder_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint); - chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey) + chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &self.channel_type(), &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey) }; let mut sighash_parts = sighash::SighashCache::new(justice_tx); let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); @@ -1033,7 +1033,7 @@ impl EcdsaChannelSigner for InMemorySigner { let revocation_pubkey = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint); let counterparty_htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.counterparty_pubkeys().htlc_basepoint); let htlcpubkey = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint); - let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey); + let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &self.channel_type(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey); let mut sighash_parts = sighash::SighashCache::new(htlc_tx); let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]); Ok(sign_with_aux_rand(secp_ctx, &sighash, &htlc_key, &self)) diff --git a/lightning/src/util/enforcing_trait_impls.rs b/lightning/src/util/enforcing_trait_impls.rs index b96a02afe4b..cd39688d463 100644 --- a/lightning/src/util/enforcing_trait_impls.rs +++ b/lightning/src/util/enforcing_trait_impls.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::ln::channel::{ANCHOR_OUTPUT_VALUE_SATOSHI, MIN_CHAN_DUST_LIMIT_SATOSHIS}; +use crate::ln::channel::{ANCHOR_OUTPUT_VALUE_SATOSHI, ChannelType, MIN_CHAN_DUST_LIMIT_SATOSHIS}; use crate::ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, HolderCommitmentTransaction, CommitmentTransaction, ChannelTransactionParameters, TrustedCommitmentTransaction, ClosingTransaction}; use crate::ln::{chan_utils, msgs, PaymentPreimage}; use crate::sign::{WriteableEcdsaChannelSigner, InMemorySigner, ChannelSigner, EcdsaChannelSigner}; @@ -88,7 +88,7 @@ impl EnforcingSigner { } } - pub fn opt_anchors(&self) -> bool { self.inner.opt_anchors() } + pub fn channel_type(&self) -> ChannelType { self.inner.channel_type() } #[cfg(test)] pub fn get_enforcement_state(&self) -> MutexGuard { @@ -172,11 +172,11 @@ impl EcdsaChannelSigner for EnforcingSigner { for (this_htlc, sig) in trusted_tx.htlcs().iter().zip(&commitment_tx.counterparty_htlc_sigs) { assert!(this_htlc.transaction_output_index.is_some()); let keys = trusted_tx.keys(); - let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, trusted_tx.feerate_per_kw(), holder_csv, &this_htlc, self.opt_anchors(), false, &keys.broadcaster_delayed_payment_key, &keys.revocation_key); + let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, trusted_tx.feerate_per_kw(), holder_csv, &this_htlc, &self.channel_type(), false, &keys.broadcaster_delayed_payment_key, &keys.revocation_key); - let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&this_htlc, self.opt_anchors(), &keys); + let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&this_htlc, &self.channel_type(), &keys); - let sighash_type = if self.opt_anchors() { + let sighash_type = if self.channel_type().supports_anchors() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All