X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fevents%2Fbump_transaction.rs;h=35e9da60544ddc680535983767117e9faf732afd;hb=a8fa5a1685d84d3b07732e4ecc04e2dc7ba06a00;hp=4e7c3a224c29204d57d43220527ea9ba423b9620;hpb=3dffe54258a374d15571d4ec72f5faa02477b770;p=rust-lightning diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index 4e7c3a22..35e9da60 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -14,7 +14,7 @@ use alloc::collections::BTreeMap; use core::ops::Deref; -use crate::chain::chaininterface::{BroadcasterInterface, compute_feerate_sat_per_1000_weight, fee_for_weight, FEERATE_FLOOR_SATS_PER_KW}; +use crate::chain::chaininterface::{BroadcasterInterface, fee_for_weight}; use crate::chain::ClaimId; use crate::io_extras::sink; use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI; @@ -57,6 +57,12 @@ pub struct ChannelDerivationParameters { pub transaction_parameters: ChannelTransactionParameters, } +impl_writeable_tlv_based!(ChannelDerivationParameters, { + (0, value_satoshis, required), + (2, keys_id, required), + (4, transaction_parameters, required), +}); + /// A descriptor used to sign for a commitment transaction's anchor output. #[derive(Clone, Debug, PartialEq, Eq)] pub struct AnchorDescriptor { @@ -139,6 +145,16 @@ pub struct HTLCDescriptor { pub counterparty_sig: Signature } +impl_writeable_tlv_based!(HTLCDescriptor, { + (0, channel_derivation_parameters, required), + (2, commitment_txid, required), + (4, per_commitment_number, required), + (6, per_commitment_point, required), + (8, htlc, required), + (10, preimage, option), + (12, counterparty_sig, required), +}); + impl HTLCDescriptor { /// Returns the outpoint of the HTLC output in the commitment transaction. This is the outpoint /// being spent by the HTLC input in the HTLC transaction. @@ -526,7 +542,7 @@ where fn select_confirmed_utxos_internal( &self, utxos: &[Utxo], claim_id: ClaimId, force_conflicting_utxo_spend: bool, tolerate_high_network_feerates: bool, target_feerate_sat_per_1000_weight: u32, - preexisting_tx_weight: u64, target_amount_sat: u64, + preexisting_tx_weight: u64, input_amount_sat: u64, target_amount_sat: u64, ) -> Result { let mut locked_utxos = self.locked_utxos.lock().unwrap(); let mut eligible_utxos = utxos.iter().filter_map(|utxo| { @@ -553,7 +569,7 @@ where }).collect::>(); eligible_utxos.sort_unstable_by_key(|(utxo, _)| utxo.output.value); - let mut selected_amount = 0; + let mut selected_amount = input_amount_sat; let mut total_fees = fee_for_weight(target_feerate_sat_per_1000_weight, preexisting_tx_weight); let mut selected_utxos = Vec::new(); for (utxo, fee_to_spend_utxo) in eligible_utxos { @@ -616,13 +632,14 @@ where let preexisting_tx_weight = 2 /* segwit marker & flag */ + total_input_weight + ((BASE_TX_SIZE + total_output_size) * WITNESS_SCALE_FACTOR as u64); + let input_amount_sat: u64 = must_spend.iter().map(|input| input.previous_utxo.value).sum(); let target_amount_sat = must_pay_to.iter().map(|output| output.value).sum(); let do_coin_selection = |force_conflicting_utxo_spend: bool, tolerate_high_network_feerates: bool| { log_debug!(self.logger, "Attempting coin selection targeting {} sat/kW (force_conflicting_utxo_spend = {}, tolerate_high_network_feerates = {})", target_feerate_sat_per_1000_weight, force_conflicting_utxo_spend, tolerate_high_network_feerates); self.select_confirmed_utxos_internal( &utxos, claim_id, force_conflicting_utxo_spend, tolerate_high_network_feerates, - target_feerate_sat_per_1000_weight, preexisting_tx_weight, target_amount_sat, + target_feerate_sat_per_1000_weight, preexisting_tx_weight, input_amount_sat, target_amount_sat, ) }; do_coin_selection(false, false) @@ -708,27 +725,22 @@ where commitment_tx: &Transaction, commitment_tx_fee_sat: u64, anchor_descriptor: &AnchorDescriptor, ) -> Result<(), ()> { // Our commitment transaction already has fees allocated to it, so we should take them into - // account. We compute its feerate and subtract it from the package target, using the result - // as the target feerate for our anchor transaction. Unfortunately, this results in users - // overpaying by a small margin since we don't yet know the anchor transaction size, and - // avoiding the small overpayment only makes our API even more complex. - let commitment_tx_sat_per_1000_weight: u32 = compute_feerate_sat_per_1000_weight( - commitment_tx_fee_sat, commitment_tx.weight() as u64, - ); - let anchor_target_feerate_sat_per_1000_weight = core::cmp::max( - package_target_feerate_sat_per_1000_weight - commitment_tx_sat_per_1000_weight, - FEERATE_FLOOR_SATS_PER_KW, - ); - - log_debug!(self.logger, "Peforming coin selection for anchor transaction targeting {} sat/kW", - anchor_target_feerate_sat_per_1000_weight); + // account. We do so by pretending the commitment tranasction's fee and weight are part of + // the anchor input. + let mut anchor_utxo = anchor_descriptor.previous_utxo(); + anchor_utxo.value += commitment_tx_fee_sat; let must_spend = vec![Input { outpoint: anchor_descriptor.outpoint, - previous_utxo: anchor_descriptor.previous_utxo(), + previous_utxo: anchor_utxo, satisfaction_weight: commitment_tx.weight() as u64 + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT, }]; + #[cfg(debug_assertions)] + let must_spend_amount = must_spend.iter().map(|input| input.previous_utxo.value).sum::(); + + log_debug!(self.logger, "Peforming coin selection for commitment package (commitment and anchor transaction) targeting {} sat/kW", + package_target_feerate_sat_per_1000_weight); let coin_selection = self.utxo_source.select_confirmed_utxos( - claim_id, must_spend, &[], anchor_target_feerate_sat_per_1000_weight, + claim_id, must_spend, &[], package_target_feerate_sat_per_1000_weight, )?; let mut anchor_tx = Transaction { @@ -737,10 +749,13 @@ where input: vec![anchor_descriptor.unsigned_tx_input()], output: vec![], }; + + #[cfg(debug_assertions)] + let total_satisfaction_weight = ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT + + coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum::(); #[cfg(debug_assertions)] - let total_satisfaction_weight = - coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum::() + - ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT; + let total_input_amount = must_spend_amount + + coin_selection.confirmed_utxos.iter().map(|utxo| utxo.output.value).sum::(); self.process_coin_selection(&mut anchor_tx, coin_selection); let anchor_txid = anchor_tx.txid(); @@ -763,6 +778,16 @@ where // never underestimate. assert!(expected_signed_tx_weight >= signed_tx_weight && expected_signed_tx_weight - (expected_signed_tx_weight / 100) <= signed_tx_weight); + + let expected_package_fee = fee_for_weight(package_target_feerate_sat_per_1000_weight, + signed_tx_weight + commitment_tx.weight() as u64); + let package_fee = total_input_amount - + anchor_tx.output.iter().map(|output| output.value).sum::(); + // Our fee should be within a 5% error margin of the expected fee based on the + // feerate and transaction weight and we should never pay less than required. + let fee_error_margin = expected_package_fee * 5 / 100; + assert!(package_fee >= expected_package_fee && + package_fee - fee_error_margin <= expected_package_fee); } log_info!(self.logger, "Broadcasting anchor transaction {} to bump channel close with txid {}", @@ -802,16 +827,24 @@ where log_debug!(self.logger, "Peforming coin selection for HTLC transaction targeting {} sat/kW", target_feerate_sat_per_1000_weight); + #[cfg(debug_assertions)] let must_spend_satisfaction_weight = must_spend.iter().map(|input| input.satisfaction_weight).sum::(); + #[cfg(debug_assertions)] + let must_spend_amount = must_spend.iter().map(|input| input.previous_utxo.value).sum::(); + let coin_selection = self.utxo_source.select_confirmed_utxos( claim_id, must_spend, &htlc_tx.output, target_feerate_sat_per_1000_weight, )?; + + #[cfg(debug_assertions)] + let total_satisfaction_weight = must_spend_satisfaction_weight + + coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum::(); #[cfg(debug_assertions)] - let total_satisfaction_weight = - coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum::() + - must_spend_satisfaction_weight; + let total_input_amount = must_spend_amount + + coin_selection.confirmed_utxos.iter().map(|utxo| utxo.output.value).sum::(); + self.process_coin_selection(&mut htlc_tx, coin_selection); #[cfg(debug_assertions)] @@ -836,6 +869,15 @@ where // never underestimate. assert!(expected_signed_tx_weight >= signed_tx_weight && expected_signed_tx_weight - (expected_signed_tx_weight / 100) <= signed_tx_weight); + + let expected_signed_tx_fee = fee_for_weight(target_feerate_sat_per_1000_weight, signed_tx_weight); + let signed_tx_fee = total_input_amount - + htlc_tx.output.iter().map(|output| output.value).sum::(); + // Our fee should be within a 5% error margin of the expected fee based on the + // feerate and transaction weight and we should never pay less than required. + let fee_error_margin = expected_signed_tx_fee * 5 / 100; + assert!(signed_tx_fee >= expected_signed_tx_fee && + signed_tx_fee - fee_error_margin <= expected_signed_tx_fee); } log_info!(self.logger, "Broadcasting {}", log_tx!(htlc_tx));