1pub mod sync;
15
16use alloc::collections::BTreeMap;
17use core::ops::Deref;
18
19use crate::chain::chaininterface::{
20 compute_feerate_sat_per_1000_weight, fee_for_weight, BroadcasterInterface,
21};
22use crate::chain::ClaimId;
23use crate::io_extras::sink;
24use crate::ln::chan_utils;
25use crate::ln::chan_utils::{
26 shared_anchor_script_pubkey, HTLCOutputInCommitment, ANCHOR_INPUT_WITNESS_WEIGHT,
27 BASE_INPUT_WEIGHT, BASE_TX_SIZE, EMPTY_SCRIPT_SIG_WEIGHT, EMPTY_WITNESS_WEIGHT,
28 HTLC_SUCCESS_INPUT_KEYED_ANCHOR_WITNESS_WEIGHT, HTLC_SUCCESS_INPUT_P2A_ANCHOR_WITNESS_WEIGHT,
29 HTLC_TIMEOUT_INPUT_KEYED_ANCHOR_WITNESS_WEIGHT, HTLC_TIMEOUT_INPUT_P2A_ANCHOR_WITNESS_WEIGHT,
30 P2WSH_TXOUT_WEIGHT, SEGWIT_MARKER_FLAG_WEIGHT, TRUC_CHILD_MAX_WEIGHT, TRUC_MAX_WEIGHT,
31};
32use crate::ln::types::ChannelId;
33use crate::prelude::*;
34use crate::sign::ecdsa::EcdsaChannelSigner;
35use crate::sign::{
36 ChannelDerivationParameters, HTLCDescriptor, SignerProvider, P2WPKH_WITNESS_WEIGHT,
37};
38use crate::sync::Mutex;
39use crate::util::async_poll::{AsyncResult, MaybeSend, MaybeSync};
40use crate::util::logger::Logger;
41
42use bitcoin::amount::Amount;
43use bitcoin::consensus::Encodable;
44use bitcoin::constants::WITNESS_SCALE_FACTOR;
45use bitcoin::locktime::absolute::LockTime;
46use bitcoin::policy::MAX_STANDARD_TX_WEIGHT;
47use bitcoin::secp256k1;
48use bitcoin::secp256k1::ecdsa::Signature;
49use bitcoin::secp256k1::{PublicKey, Secp256k1};
50use bitcoin::transaction::Version;
51use bitcoin::{
52 OutPoint, Psbt, PubkeyHash, ScriptBuf, Sequence, Transaction, TxIn, TxOut, WPubkeyHash, Witness,
53};
54
55#[derive(Clone, Debug, PartialEq, Eq)]
57pub struct AnchorDescriptor {
58 pub channel_derivation_parameters: ChannelDerivationParameters,
60 pub outpoint: OutPoint,
63 pub value: Amount,
65}
66
67impl AnchorDescriptor {
68 pub fn previous_utxo(&self) -> TxOut {
71 let tx_params = &self.channel_derivation_parameters.transaction_parameters;
72 let script_pubkey = if tx_params.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
73 let channel_params = tx_params.as_holder_broadcastable();
74 chan_utils::get_keyed_anchor_redeemscript(
75 &channel_params.broadcaster_pubkeys().funding_pubkey,
76 )
77 } else {
78 assert!(tx_params.channel_type_features.supports_anchor_zero_fee_commitments());
79 shared_anchor_script_pubkey()
80 };
81 TxOut { script_pubkey, value: self.value }
82 }
83
84 pub fn unsigned_tx_input(&self) -> TxIn {
87 TxIn {
88 previous_output: self.outpoint.clone(),
89 script_sig: ScriptBuf::new(),
90 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
91 witness: Witness::new(),
92 }
93 }
94
95 pub fn tx_input_witness(&self, signature: &Signature) -> Witness {
98 let tx_params = &self.channel_derivation_parameters.transaction_parameters;
99 if tx_params.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
100 let channel_params =
101 self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable();
102 chan_utils::build_keyed_anchor_input_witness(
103 &channel_params.broadcaster_pubkeys().funding_pubkey,
104 signature,
105 )
106 } else {
107 debug_assert!(tx_params.channel_type_features.supports_anchor_zero_fee_commitments());
108 Witness::from_slice(&[&[]])
109 }
110 }
111}
112
113#[derive(Clone, Debug, PartialEq, Eq)]
115pub enum BumpTransactionEvent {
116 ChannelClose {
167 channel_id: ChannelId,
169 counterparty_node_id: PublicKey,
171 claim_id: ClaimId,
177 package_target_feerate_sat_per_1000_weight: u32,
180 commitment_tx: Transaction,
184 commitment_tx_fee_satoshis: u64,
187 anchor_descriptor: AnchorDescriptor,
190 pending_htlcs: Vec<HTLCOutputInCommitment>,
193 },
194 HTLCResolution {
236 channel_id: ChannelId,
238 counterparty_node_id: PublicKey,
240 claim_id: ClaimId,
247 target_feerate_sat_per_1000_weight: u32,
249 htlc_descriptors: Vec<HTLCDescriptor>,
252 tx_lock_time: LockTime,
254 },
255}
256
257#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
261pub struct Input {
262 pub outpoint: OutPoint,
264 pub previous_utxo: TxOut,
266 pub satisfaction_weight: u64,
270}
271
272#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
275pub struct Utxo {
276 pub outpoint: OutPoint,
278 pub output: TxOut,
280 pub satisfaction_weight: u64,
284}
285
286impl_writeable_tlv_based!(Utxo, {
287 (1, outpoint, required),
288 (3, output, required),
289 (5, satisfaction_weight, required),
290});
291
292impl Utxo {
293 pub fn new_p2pkh(outpoint: OutPoint, value: Amount, pubkey_hash: &PubkeyHash) -> Self {
295 let script_sig_size = 1 +
296 1 +
297 73 +
298 1 +
299 33 ;
300 Self {
301 outpoint,
302 output: TxOut { value, script_pubkey: ScriptBuf::new_p2pkh(pubkey_hash) },
303 satisfaction_weight: script_sig_size * WITNESS_SCALE_FACTOR as u64 + 1, }
305 }
306
307 pub fn new_nested_p2wpkh(outpoint: OutPoint, value: Amount, pubkey_hash: &WPubkeyHash) -> Self {
309 let script_sig_size = 1 +
310 1 +
311 1 +
312 20 ;
313 Self {
314 outpoint,
315 output: TxOut {
316 value,
317 script_pubkey: ScriptBuf::new_p2sh(
318 &ScriptBuf::new_p2wpkh(pubkey_hash).script_hash(),
319 ),
320 },
321 satisfaction_weight: script_sig_size * WITNESS_SCALE_FACTOR as u64
322 + P2WPKH_WITNESS_WEIGHT,
323 }
324 }
325
326 pub fn new_v0_p2wpkh(outpoint: OutPoint, value: Amount, pubkey_hash: &WPubkeyHash) -> Self {
328 Self {
329 outpoint,
330 output: TxOut { value, script_pubkey: ScriptBuf::new_p2wpkh(pubkey_hash) },
331 satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + P2WPKH_WITNESS_WEIGHT,
332 }
333 }
334}
335
336#[derive(Clone, Debug)]
339pub struct CoinSelection {
340 pub confirmed_utxos: Vec<Utxo>,
343 pub change_output: Option<TxOut>,
348}
349
350pub trait CoinSelectionSource {
360 fn select_confirmed_utxos<'a>(
395 &'a self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &'a [TxOut],
396 target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64,
397 ) -> AsyncResult<'a, CoinSelection, ()>;
398 fn sign_psbt<'a>(&'a self, psbt: Psbt) -> AsyncResult<'a, Transaction, ()>;
404}
405
406pub trait WalletSource {
414 fn list_confirmed_utxos<'a>(&'a self) -> AsyncResult<'a, Vec<Utxo>, ()>;
416 fn get_change_script<'a>(&'a self) -> AsyncResult<'a, ScriptBuf, ()>;
419 fn sign_psbt<'a>(&'a self, psbt: Psbt) -> AsyncResult<'a, Transaction, ()>;
426}
427
428pub struct Wallet<W: Deref + MaybeSync + MaybeSend, L: Deref + MaybeSync + MaybeSend>
437where
438 W::Target: WalletSource + MaybeSend,
439 L::Target: Logger + MaybeSend,
440{
441 source: W,
442 logger: L,
443 locked_utxos: Mutex<HashMap<OutPoint, ClaimId>>,
447}
448
449impl<W: Deref + MaybeSync + MaybeSend, L: Deref + MaybeSync + MaybeSend> Wallet<W, L>
450where
451 W::Target: WalletSource + MaybeSend,
452 L::Target: Logger + MaybeSend,
453{
454 pub fn new(source: W, logger: L) -> Self {
457 Self { source, logger, locked_utxos: Mutex::new(new_hash_map()) }
458 }
459
460 async fn select_confirmed_utxos_internal(
469 &self, utxos: &[Utxo], claim_id: ClaimId, force_conflicting_utxo_spend: bool,
470 tolerate_high_network_feerates: bool, target_feerate_sat_per_1000_weight: u32,
471 preexisting_tx_weight: u64, input_amount_sat: Amount, target_amount_sat: Amount,
472 max_tx_weight: u64,
473 ) -> Result<CoinSelection, ()> {
474 let max_coin_selection_weight = max_tx_weight
476 .checked_sub(preexisting_tx_weight + P2WSH_TXOUT_WEIGHT)
477 .ok_or_else(|| {
478 log_debug!(
479 self.logger,
480 "max_tx_weight is too small to accommodate the preexisting tx weight plus a P2WSH/P2TR output"
481 );
482 })?;
483
484 let mut selected_amount;
485 let mut total_fees;
486 let mut selected_utxos;
487 {
488 let mut locked_utxos = self.locked_utxos.lock().unwrap();
489 let mut eligible_utxos = utxos
490 .iter()
491 .filter_map(|utxo| {
492 if let Some(utxo_claim_id) = locked_utxos.get(&utxo.outpoint) {
493 if *utxo_claim_id != claim_id && !force_conflicting_utxo_spend {
494 log_trace!(
495 self.logger,
496 "Skipping UTXO {} to prevent conflicting spend",
497 utxo.outpoint
498 );
499 return None;
500 }
501 }
502 let fee_to_spend_utxo = Amount::from_sat(fee_for_weight(
503 target_feerate_sat_per_1000_weight,
504 BASE_INPUT_WEIGHT + utxo.satisfaction_weight,
505 ));
506 let should_spend = if tolerate_high_network_feerates {
507 utxo.output.value > fee_to_spend_utxo
508 } else {
509 utxo.output.value >= fee_to_spend_utxo * 2
510 };
511 if should_spend {
512 Some((utxo, fee_to_spend_utxo))
513 } else {
514 log_trace!(
515 self.logger,
516 "Skipping UTXO {} due to dust proximity after spend",
517 utxo.outpoint
518 );
519 None
520 }
521 })
522 .collect::<Vec<_>>();
523 eligible_utxos.sort_unstable_by_key(|(utxo, fee_to_spend_utxo)| {
524 utxo.output.value - *fee_to_spend_utxo
525 });
526
527 selected_amount = input_amount_sat;
528 total_fees = Amount::from_sat(fee_for_weight(
529 target_feerate_sat_per_1000_weight,
530 preexisting_tx_weight,
531 ));
532 selected_utxos = VecDeque::new();
533 let mut selected_utxos_weight = 0;
535 for (utxo, fee_to_spend_utxo) in eligible_utxos {
536 if selected_amount >= target_amount_sat + total_fees {
537 break;
538 }
539 if BASE_INPUT_WEIGHT + utxo.satisfaction_weight > max_coin_selection_weight {
541 continue;
542 }
543 while selected_utxos_weight + BASE_INPUT_WEIGHT + utxo.satisfaction_weight
547 > max_coin_selection_weight
548 && !selected_utxos.is_empty()
549 {
550 let (smallest_value_after_spend_utxo, fee_to_spend_utxo): (Utxo, Amount) =
551 selected_utxos.pop_front().unwrap();
552 selected_amount -= smallest_value_after_spend_utxo.output.value;
553 total_fees -= fee_to_spend_utxo;
554 selected_utxos_weight -=
555 BASE_INPUT_WEIGHT + smallest_value_after_spend_utxo.satisfaction_weight;
556 }
557 selected_amount += utxo.output.value;
558 total_fees += fee_to_spend_utxo;
559 selected_utxos_weight += BASE_INPUT_WEIGHT + utxo.satisfaction_weight;
560 selected_utxos.push_back((utxo.clone(), fee_to_spend_utxo));
561 }
562 if selected_amount < target_amount_sat + total_fees {
563 log_debug!(
564 self.logger,
565 "Insufficient funds to meet target feerate {} sat/kW while remaining under {} WU",
566 target_feerate_sat_per_1000_weight,
567 max_coin_selection_weight,
568 );
569 return Err(());
570 }
571 while !selected_utxos.is_empty()
575 && selected_amount - selected_utxos.front().unwrap().0.output.value
576 >= target_amount_sat + total_fees - selected_utxos.front().unwrap().1
577 {
578 let (smallest_value_after_spend_utxo, fee_to_spend_utxo) =
579 selected_utxos.pop_front().unwrap();
580 selected_amount -= smallest_value_after_spend_utxo.output.value;
581 total_fees -= fee_to_spend_utxo;
582 }
583 for (utxo, _) in &selected_utxos {
584 locked_utxos.insert(utxo.outpoint, claim_id);
585 }
586 }
587
588 let remaining_amount = selected_amount - target_amount_sat - total_fees;
589 let change_script = self.source.get_change_script().await?;
590 let change_output_fee = fee_for_weight(
591 target_feerate_sat_per_1000_weight,
592 (8 + change_script.consensus_encode(&mut sink()).unwrap() as u64)
593 * WITNESS_SCALE_FACTOR as u64,
594 );
595 let change_output_amount =
596 Amount::from_sat(remaining_amount.to_sat().saturating_sub(change_output_fee));
597 let change_output = if change_output_amount < change_script.minimal_non_dust() {
598 log_debug!(self.logger, "Coin selection attempt did not yield change output");
599 None
600 } else {
601 Some(TxOut { script_pubkey: change_script, value: change_output_amount })
602 };
603
604 Ok(CoinSelection {
605 confirmed_utxos: selected_utxos.into_iter().map(|(utxo, _)| utxo).collect(),
606 change_output,
607 })
608 }
609}
610
611impl<W: Deref + MaybeSync + MaybeSend, L: Deref + MaybeSync + MaybeSend> CoinSelectionSource
612 for Wallet<W, L>
613where
614 W::Target: WalletSource + MaybeSend + MaybeSync,
615 L::Target: Logger + MaybeSend + MaybeSync,
616{
617 fn select_confirmed_utxos<'a>(
618 &'a self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &'a [TxOut],
619 target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64,
620 ) -> AsyncResult<'a, CoinSelection, ()> {
621 Box::pin(async move {
622 let utxos = self.source.list_confirmed_utxos().await?;
623 let total_output_size: u64 = must_pay_to
625 .iter()
626 .map(
627 |output| 8 + 1 + output.script_pubkey.len() as u64,
628 )
629 .sum();
630 let total_satisfaction_weight: u64 =
631 must_spend.iter().map(|input| input.satisfaction_weight).sum();
632 let total_input_weight =
633 (BASE_INPUT_WEIGHT * must_spend.len() as u64) + total_satisfaction_weight;
634
635 let preexisting_tx_weight = SEGWIT_MARKER_FLAG_WEIGHT
636 + total_input_weight
637 + ((BASE_TX_SIZE + total_output_size) * WITNESS_SCALE_FACTOR as u64);
638 let input_amount_sat = must_spend.iter().map(|input| input.previous_utxo.value).sum();
639 let target_amount_sat = must_pay_to.iter().map(|output| output.value).sum();
640
641 let configs = [(false, false), (false, true), (true, false), (true, true)];
642 for (force_conflicting_utxo_spend, tolerate_high_network_feerates) in configs {
643 log_debug!(
644 self.logger,
645 "Attempting coin selection targeting {} sat/kW (force_conflicting_utxo_spend = {}, tolerate_high_network_feerates = {})",
646 target_feerate_sat_per_1000_weight,
647 force_conflicting_utxo_spend,
648 tolerate_high_network_feerates
649 );
650 let attempt = self
651 .select_confirmed_utxos_internal(
652 &utxos,
653 claim_id,
654 force_conflicting_utxo_spend,
655 tolerate_high_network_feerates,
656 target_feerate_sat_per_1000_weight,
657 preexisting_tx_weight,
658 input_amount_sat,
659 target_amount_sat,
660 max_tx_weight,
661 )
662 .await;
663 if attempt.is_ok() {
664 return attempt;
665 }
666 }
667 Err(())
668 })
669 }
670
671 fn sign_psbt<'a>(&'a self, psbt: Psbt) -> AsyncResult<'a, Transaction, ()> {
672 self.source.sign_psbt(psbt)
673 }
674}
675
676pub struct BumpTransactionEventHandler<B: Deref, C: Deref, SP: Deref, L: Deref>
687where
688 B::Target: BroadcasterInterface,
689 C::Target: CoinSelectionSource,
690 SP::Target: SignerProvider,
691 L::Target: Logger,
692{
693 broadcaster: B,
694 utxo_source: C,
695 signer_provider: SP,
696 logger: L,
697 secp: Secp256k1<secp256k1::All>,
698}
699
700impl<B: Deref, C: Deref, SP: Deref, L: Deref> BumpTransactionEventHandler<B, C, SP, L>
701where
702 B::Target: BroadcasterInterface,
703 C::Target: CoinSelectionSource,
704 SP::Target: SignerProvider,
705 L::Target: Logger,
706{
707 pub fn new(broadcaster: B, utxo_source: C, signer_provider: SP, logger: L) -> Self {
711 Self { broadcaster, utxo_source, signer_provider, logger, secp: Secp256k1::new() }
712 }
713
714 fn process_coin_selection(&self, tx: &mut Transaction, coin_selection: &CoinSelection) {
716 for utxo in coin_selection.confirmed_utxos.iter() {
717 tx.input.push(TxIn {
718 previous_output: utxo.outpoint,
719 script_sig: ScriptBuf::new(),
720 sequence: Sequence::ZERO,
721 witness: Witness::new(),
722 });
723 }
724 if let Some(change_output) = coin_selection.change_output.clone() {
725 tx.output.push(change_output);
726 } else if tx.output.is_empty() {
727 if tx.input.len() <= 1 {
732 log_debug!(self.logger, "Including large OP_RETURN output since an output is needed and a change output was not provided and the transaction is small");
735 debug_assert!(!tx.input.is_empty());
736 tx.output.push(TxOut {
737 value: Amount::ZERO,
738 script_pubkey: ScriptBuf::new_op_return(&[0, 0, 0]),
741 });
742 debug_assert_eq!(tx.base_size(), 65);
743 } else {
744 log_debug!(self.logger, "Including dummy OP_RETURN output since an output is needed and a change output was not provided");
745 tx.output.push(TxOut {
746 value: Amount::ZERO,
747 script_pubkey: ScriptBuf::new_op_return(&[]),
748 });
749 }
750 }
751 }
752
753 async fn handle_channel_close(
757 &self, claim_id: ClaimId, package_target_feerate_sat_per_1000_weight: u32,
758 commitment_tx: &Transaction, commitment_tx_fee_sat: u64,
759 anchor_descriptor: &AnchorDescriptor,
760 ) -> Result<(), ()> {
761 let channel_type = &anchor_descriptor
762 .channel_derivation_parameters
763 .transaction_parameters
764 .channel_type_features;
765 let anchor_input_witness_weight = if channel_type.supports_anchor_zero_fee_commitments() {
766 EMPTY_WITNESS_WEIGHT
767 } else {
768 ANCHOR_INPUT_WITNESS_WEIGHT
769 };
770
771 let commitment_tx_feerate_sat_per_1000_weight = compute_feerate_sat_per_1000_weight(
773 commitment_tx_fee_sat,
774 commitment_tx.weight().to_wu(),
775 );
776 if commitment_tx_feerate_sat_per_1000_weight >= package_target_feerate_sat_per_1000_weight {
777 log_debug!(self.logger, "Pre-signed commitment {} already has feerate {} sat/kW above required {} sat/kW, broadcasting.",
778 commitment_tx.compute_txid(), commitment_tx_feerate_sat_per_1000_weight,
779 package_target_feerate_sat_per_1000_weight);
780 self.broadcaster.broadcast_transactions(&[&commitment_tx]);
781 return Ok(());
782 }
783
784 let mut anchor_utxo = anchor_descriptor.previous_utxo();
788 let commitment_tx_fee_sat = Amount::from_sat(commitment_tx_fee_sat);
789 let commitment_tx_weight = commitment_tx.weight().to_wu();
790 anchor_utxo.value += commitment_tx_fee_sat;
791 let starting_package_and_fixed_input_satisfaction_weight =
792 commitment_tx_weight + anchor_input_witness_weight + EMPTY_SCRIPT_SIG_WEIGHT;
793 let mut package_and_fixed_input_satisfaction_weight =
794 starting_package_and_fixed_input_satisfaction_weight;
795
796 loop {
797 let must_spend = vec![Input {
798 outpoint: anchor_descriptor.outpoint,
799 previous_utxo: anchor_utxo.clone(),
800 satisfaction_weight: package_and_fixed_input_satisfaction_weight,
801 }];
802 let must_spend_amount =
803 must_spend.iter().map(|input| input.previous_utxo.value).sum::<Amount>();
804
805 log_debug!(self.logger, "Performing coin selection for commitment package (commitment and anchor transaction) targeting {} sat/kW",
806 package_target_feerate_sat_per_1000_weight);
807 let coin_selection: CoinSelection = self
808 .utxo_source
809 .select_confirmed_utxos(
810 claim_id,
811 must_spend,
812 &[],
813 package_target_feerate_sat_per_1000_weight,
814 if channel_type.supports_anchor_zero_fee_commitments() {
815 TRUC_CHILD_MAX_WEIGHT
816 } else {
817 MAX_STANDARD_TX_WEIGHT as u64
818 }
819 + commitment_tx_weight,
822 )
823 .await?;
824
825 let version = if channel_type.supports_anchor_zero_fee_commitments() {
826 Version::non_standard(3)
827 } else {
828 Version::TWO
829 };
830
831 let mut anchor_tx = Transaction {
832 version,
833 lock_time: LockTime::ZERO, input: vec![anchor_descriptor.unsigned_tx_input()],
835 output: vec![],
836 };
837
838 let input_satisfaction_weight: u64 =
839 coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum();
840 let total_satisfaction_weight =
841 anchor_input_witness_weight + EMPTY_SCRIPT_SIG_WEIGHT + input_satisfaction_weight;
842 let total_input_amount = must_spend_amount
843 + coin_selection.confirmed_utxos.iter().map(|utxo| utxo.output.value).sum();
844
845 self.process_coin_selection(&mut anchor_tx, &coin_selection);
846 let anchor_txid = anchor_tx.compute_txid();
847
848 let mut anchor_psbt = Psbt::from_unsigned_tx(anchor_tx).unwrap();
850 anchor_psbt.inputs[0].witness_utxo = Some(anchor_descriptor.previous_utxo());
852 for (idx, utxo) in coin_selection.confirmed_utxos.into_iter().enumerate() {
854 let index = idx + 1;
856 debug_assert_eq!(
857 anchor_psbt.unsigned_tx.input[index].previous_output,
858 utxo.outpoint
859 );
860 if utxo.output.script_pubkey.is_witness_program() {
861 anchor_psbt.inputs[index].witness_utxo = Some(utxo.output);
862 }
863 }
864
865 debug_assert_eq!(anchor_psbt.unsigned_tx.output.len(), 1);
866 let unsigned_tx_weight = anchor_psbt.unsigned_tx.weight().to_wu()
867 - (anchor_psbt.unsigned_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT);
868
869 let package_fee = total_input_amount
870 - anchor_psbt.unsigned_tx.output.iter().map(|output| output.value).sum();
871 let package_weight = unsigned_tx_weight + 2 + total_satisfaction_weight + commitment_tx.weight().to_wu();
872 if package_fee.to_sat() * 1000 / package_weight
873 < package_target_feerate_sat_per_1000_weight.into()
874 {
875 if package_and_fixed_input_satisfaction_weight
880 == starting_package_and_fixed_input_satisfaction_weight
881 {
882 debug_assert!(
883 anchor_psbt.unsigned_tx.output[0].script_pubkey.is_op_return(),
884 "Coin selection failed to select sufficient coins for its change output"
885 );
886 package_and_fixed_input_satisfaction_weight +=
887 anchor_psbt.unsigned_tx.output[0].weight().to_wu();
888 continue;
889 } else {
890 debug_assert!(false, "Coin selection failed to select sufficient coins");
891 }
892 }
893
894 log_debug!(self.logger, "Signing anchor transaction {}", anchor_txid);
895 anchor_tx = self.utxo_source.sign_psbt(anchor_psbt).await?;
896
897 if channel_type.supports_anchors_zero_fee_htlc_tx() {
899 let signer = self
900 .signer_provider
901 .derive_channel_signer(anchor_descriptor.channel_derivation_parameters.keys_id);
902 let channel_parameters =
903 &anchor_descriptor.channel_derivation_parameters.transaction_parameters;
904 let anchor_sig = signer.sign_holder_keyed_anchor_input(
905 channel_parameters,
906 &anchor_tx,
907 0,
908 &self.secp,
909 )?;
910 anchor_tx.input[0].witness = anchor_descriptor.tx_input_witness(&anchor_sig);
911 }
912
913 #[cfg(debug_assertions)]
914 {
915 let signed_tx_weight = anchor_tx.weight().to_wu();
916 let expected_signed_tx_weight =
917 unsigned_tx_weight + 2 + total_satisfaction_weight;
918 assert!(expected_signed_tx_weight >= signed_tx_weight);
921 assert!(expected_signed_tx_weight * 99 / 100 <= signed_tx_weight);
922
923 let expected_package_fee = Amount::from_sat(fee_for_weight(
924 package_target_feerate_sat_per_1000_weight,
925 signed_tx_weight + commitment_tx.weight().to_wu(),
926 ));
927 assert!(package_fee >= expected_package_fee);
930 }
931
932 #[cfg(debug_assertions)]
933 if channel_type.supports_anchor_zero_fee_commitments() {
934 assert!(commitment_tx.weight().to_wu() < TRUC_MAX_WEIGHT);
935 assert!(anchor_tx.weight().to_wu() < TRUC_CHILD_MAX_WEIGHT);
936 } else {
937 assert!(commitment_tx.weight().to_wu() < MAX_STANDARD_TX_WEIGHT as u64);
938 assert!(anchor_tx.weight().to_wu() < MAX_STANDARD_TX_WEIGHT as u64);
939 }
940
941 log_info!(
942 self.logger,
943 "Broadcasting anchor transaction {} to bump channel close with txid {}",
944 anchor_txid,
945 commitment_tx.compute_txid()
946 );
947 self.broadcaster.broadcast_transactions(&[&commitment_tx, &anchor_tx]);
948 return Ok(());
949 }
950 }
951
952 async fn handle_htlc_resolution(
955 &self, claim_id: ClaimId, target_feerate_sat_per_1000_weight: u32,
956 htlc_descriptors: &[HTLCDescriptor], tx_lock_time: LockTime,
957 ) -> Result<(), ()> {
958 let channel_type = &htlc_descriptors[0]
959 .channel_derivation_parameters
960 .transaction_parameters
961 .channel_type_features;
962 let (htlc_success_witness_weight, htlc_timeout_witness_weight) =
963 if channel_type.supports_anchor_zero_fee_commitments() {
964 (
965 HTLC_SUCCESS_INPUT_P2A_ANCHOR_WITNESS_WEIGHT,
966 HTLC_TIMEOUT_INPUT_P2A_ANCHOR_WITNESS_WEIGHT,
967 )
968 } else if channel_type.supports_anchors_zero_fee_htlc_tx() {
969 (
970 HTLC_SUCCESS_INPUT_KEYED_ANCHOR_WITNESS_WEIGHT,
971 HTLC_TIMEOUT_INPUT_KEYED_ANCHOR_WITNESS_WEIGHT,
972 )
973 } else {
974 panic!("channel type should be either zero-fee HTLCs, or zero-fee commitments");
975 };
976
977 let max_tx_weight = if channel_type.supports_anchor_zero_fee_commitments() {
978 TRUC_MAX_WEIGHT
982 } else {
983 MAX_STANDARD_TX_WEIGHT as u64
990 };
991 const USER_COINS_WEIGHT_BUDGET: u64 = 1000;
994
995 let mut broadcasted_htlcs = 0;
996 let mut batch_size = htlc_descriptors.len() - broadcasted_htlcs;
997 let mut utxo_id = claim_id;
998
999 while broadcasted_htlcs < htlc_descriptors.len() {
1000 let mut htlc_tx = Transaction {
1001 version: if channel_type.supports_anchor_zero_fee_commitments() {
1002 Version::non_standard(3)
1003 } else {
1004 Version::TWO
1005 },
1006 lock_time: tx_lock_time,
1007 input: vec![],
1008 output: vec![],
1009 };
1010 let mut must_spend = Vec::with_capacity(htlc_descriptors.len() - broadcasted_htlcs);
1011 let mut htlc_weight_sum = 0;
1012 for htlc_descriptor in
1013 &htlc_descriptors[broadcasted_htlcs..broadcasted_htlcs + batch_size]
1014 {
1015 let input_output_weight = if htlc_descriptor.preimage.is_some() {
1016 chan_utils::aggregated_htlc_success_input_output_pair_weight(channel_type)
1017 } else {
1018 chan_utils::aggregated_htlc_timeout_input_output_pair_weight(channel_type)
1019 };
1020 if htlc_weight_sum + input_output_weight >= max_tx_weight - USER_COINS_WEIGHT_BUDGET
1021 {
1022 break;
1023 }
1024 htlc_weight_sum += input_output_weight;
1025 let htlc_input = htlc_descriptor.unsigned_tx_input();
1026 must_spend.push(Input {
1027 outpoint: htlc_input.previous_output.clone(),
1028 previous_utxo: htlc_descriptor.previous_utxo(&self.secp),
1029 satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT
1030 + if htlc_descriptor.preimage.is_some() {
1031 htlc_success_witness_weight
1032 } else {
1033 htlc_timeout_witness_weight
1034 },
1035 });
1036 htlc_tx.input.push(htlc_input);
1037 let htlc_output = htlc_descriptor.tx_output(&self.secp);
1038 htlc_tx.output.push(htlc_output);
1039 }
1040 batch_size = htlc_tx.input.len();
1041 let selected_htlcs =
1042 &htlc_descriptors[broadcasted_htlcs..broadcasted_htlcs + batch_size];
1043
1044 log_info!(
1045 self.logger,
1046 "Batch transaction assigned to UTXO id {} contains {} HTLCs: {}",
1047 log_bytes!(utxo_id.0),
1048 batch_size,
1049 log_iter!(selected_htlcs.iter().map(|d| d.outpoint()))
1050 );
1051
1052 log_debug!(
1053 self.logger,
1054 "Performing coin selection for HTLC transaction targeting {} sat/kW",
1055 target_feerate_sat_per_1000_weight
1056 );
1057
1058 #[cfg(debug_assertions)]
1059 let must_spend_satisfaction_weight =
1060 must_spend.iter().map(|input| input.satisfaction_weight).sum::<u64>();
1061 #[cfg(debug_assertions)]
1062 let must_spend_amount =
1063 must_spend.iter().map(|input| input.previous_utxo.value.to_sat()).sum::<u64>();
1064
1065 let coin_selection: CoinSelection = match self
1066 .utxo_source
1067 .select_confirmed_utxos(
1068 utxo_id,
1069 must_spend,
1070 &htlc_tx.output,
1071 target_feerate_sat_per_1000_weight,
1072 max_tx_weight,
1073 )
1074 .await
1075 {
1076 Ok(selection) => selection,
1077 Err(()) => {
1078 let pair_weight =
1079 chan_utils::aggregated_htlc_timeout_input_output_pair_weight(channel_type);
1080 let htlcs_to_remove =
1081 (USER_COINS_WEIGHT_BUDGET + pair_weight - 1) / pair_weight;
1082 batch_size = batch_size.checked_sub(htlcs_to_remove as usize).ok_or(())?;
1083 if batch_size == 0 {
1084 return Err(());
1085 }
1086 continue;
1087 },
1088 };
1089 broadcasted_htlcs += batch_size;
1090 batch_size = htlc_descriptors.len() - broadcasted_htlcs;
1091 utxo_id = claim_id.step_with_bytes(&broadcasted_htlcs.to_be_bytes());
1092
1093 #[cfg(debug_assertions)]
1094 let input_satisfaction_weight: u64 =
1095 coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum();
1096 #[cfg(debug_assertions)]
1097 let total_satisfaction_weight = must_spend_satisfaction_weight + input_satisfaction_weight;
1098 #[cfg(debug_assertions)]
1099 let input_value: u64 =
1100 coin_selection.confirmed_utxos.iter().map(|utxo| utxo.output.value.to_sat()).sum();
1101 #[cfg(debug_assertions)]
1102 let total_input_amount = must_spend_amount + input_value;
1103
1104 self.process_coin_selection(&mut htlc_tx, &coin_selection);
1105
1106 let mut htlc_psbt = Psbt::from_unsigned_tx(htlc_tx).unwrap();
1108 for (i, htlc_descriptor) in selected_htlcs.iter().enumerate() {
1110 debug_assert_eq!(
1111 htlc_psbt.unsigned_tx.input[i].previous_output,
1112 htlc_descriptor.outpoint()
1113 );
1114 htlc_psbt.inputs[i].witness_utxo = Some(htlc_descriptor.previous_utxo(&self.secp));
1115 }
1116
1117 for (idx, utxo) in coin_selection.confirmed_utxos.into_iter().enumerate() {
1119 let index = idx + selected_htlcs.len();
1121 debug_assert_eq!(htlc_psbt.unsigned_tx.input[index].previous_output, utxo.outpoint);
1122 if utxo.output.script_pubkey.is_witness_program() {
1123 htlc_psbt.inputs[index].witness_utxo = Some(utxo.output);
1124 }
1125 }
1126
1127 #[cfg(debug_assertions)]
1128 let unsigned_tx_weight = htlc_psbt.unsigned_tx.weight().to_wu()
1129 - (htlc_psbt.unsigned_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT);
1130
1131 log_debug!(
1132 self.logger,
1133 "Signing HTLC transaction {}",
1134 htlc_psbt.unsigned_tx.compute_txid()
1135 );
1136 htlc_tx = self.utxo_source.sign_psbt(htlc_psbt).await?;
1137
1138 let mut signers = BTreeMap::new();
1139 for (idx, htlc_descriptor) in selected_htlcs.iter().enumerate() {
1140 let keys_id = htlc_descriptor.channel_derivation_parameters.keys_id;
1141 let signer = signers
1142 .entry(keys_id)
1143 .or_insert_with(|| self.signer_provider.derive_channel_signer(keys_id));
1144 let htlc_sig = signer.sign_holder_htlc_transaction(
1145 &htlc_tx,
1146 idx,
1147 htlc_descriptor,
1148 &self.secp,
1149 )?;
1150 let witness_script = htlc_descriptor.witness_script(&self.secp);
1151 htlc_tx.input[idx].witness =
1152 htlc_descriptor.tx_input_witness(&htlc_sig, &witness_script);
1153 }
1154
1155 #[cfg(debug_assertions)]
1156 {
1157 let signed_tx_weight = htlc_tx.weight().to_wu();
1158 let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight;
1159 assert!(expected_signed_tx_weight >= signed_tx_weight);
1162 assert!(expected_signed_tx_weight * 98 / 100 <= signed_tx_weight);
1163
1164 let expected_signed_tx_fee =
1165 fee_for_weight(target_feerate_sat_per_1000_weight, signed_tx_weight);
1166 let signed_tx_fee = total_input_amount
1167 - htlc_tx.output.iter().map(|output| output.value.to_sat()).sum::<u64>();
1168 assert!(signed_tx_fee >= expected_signed_tx_fee);
1171 }
1172
1173 #[cfg(debug_assertions)]
1174 if channel_type.supports_anchor_zero_fee_commitments() {
1175 assert!(htlc_tx.weight().to_wu() < TRUC_MAX_WEIGHT);
1176 } else {
1177 assert!(htlc_tx.weight().to_wu() < MAX_STANDARD_TX_WEIGHT as u64);
1178 }
1179
1180 log_info!(self.logger, "Broadcasting {}", log_tx!(htlc_tx));
1181 self.broadcaster.broadcast_transactions(&[&htlc_tx]);
1182 }
1183
1184 Ok(())
1185 }
1186
1187 pub async fn handle_event(&self, event: &BumpTransactionEvent) {
1189 match event {
1190 BumpTransactionEvent::ChannelClose {
1191 claim_id,
1192 package_target_feerate_sat_per_1000_weight,
1193 commitment_tx,
1194 commitment_tx_fee_satoshis,
1195 anchor_descriptor,
1196 ..
1197 } => {
1198 log_info!(
1199 self.logger,
1200 "Handling channel close bump (claim_id = {}, commitment_txid = {})",
1201 log_bytes!(claim_id.0),
1202 commitment_tx.compute_txid()
1203 );
1204 self.handle_channel_close(
1205 *claim_id,
1206 *package_target_feerate_sat_per_1000_weight,
1207 commitment_tx,
1208 *commitment_tx_fee_satoshis,
1209 anchor_descriptor,
1210 )
1211 .await
1212 .unwrap_or_else(|_| {
1213 log_error!(
1214 self.logger,
1215 "Failed bumping commitment transaction fee for {}",
1216 commitment_tx.compute_txid()
1217 );
1218 });
1219 },
1220 BumpTransactionEvent::HTLCResolution {
1221 claim_id,
1222 target_feerate_sat_per_1000_weight,
1223 htlc_descriptors,
1224 tx_lock_time,
1225 ..
1226 } => {
1227 log_info!(
1228 self.logger,
1229 "Handling HTLC bump (claim_id = {}, htlcs_to_claim = {})",
1230 log_bytes!(claim_id.0),
1231 log_iter!(htlc_descriptors.iter().map(|d| d.outpoint()))
1232 );
1233 self.handle_htlc_resolution(
1234 *claim_id,
1235 *target_feerate_sat_per_1000_weight,
1236 htlc_descriptors,
1237 *tx_lock_time,
1238 )
1239 .await
1240 .unwrap_or_else(|_| {
1241 log_error!(
1242 self.logger,
1243 "Failed bumping HTLC transaction fee for commitment {}",
1244 htlc_descriptors[0].commitment_txid
1245 );
1246 });
1247 },
1248 }
1249 }
1250}
1251
1252#[cfg(test)]
1253mod tests {
1254 use super::*;
1255
1256 use crate::events::bump_transaction::sync::{
1257 BumpTransactionEventHandlerSync, CoinSelectionSourceSync,
1258 };
1259 use crate::io::Cursor;
1260 use crate::ln::chan_utils::ChannelTransactionParameters;
1261 use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
1262 use crate::sign::KeysManager;
1263 use crate::types::features::ChannelTypeFeatures;
1264 use crate::util::ser::Readable;
1265 use crate::util::test_utils::{TestBroadcaster, TestLogger};
1266
1267 use bitcoin::hashes::Hash;
1268 use bitcoin::hex::FromHex;
1269 use bitcoin::{Network, ScriptBuf, Transaction, Txid};
1270
1271 struct TestCoinSelectionSource {
1272 expected_selects: Mutex<Vec<(u64, u64, u32, CoinSelection)>>,
1274 }
1275 impl CoinSelectionSourceSync for TestCoinSelectionSource {
1276 fn select_confirmed_utxos(
1277 &self, _claim_id: ClaimId, must_spend: Vec<Input>, _must_pay_to: &[TxOut],
1278 target_feerate_sat_per_1000_weight: u32, _max_tx_weight: u64,
1279 ) -> Result<CoinSelection, ()> {
1280 let mut expected_selects = self.expected_selects.lock().unwrap();
1281 let (weight, value, feerate, res) = expected_selects.remove(0);
1282 assert_eq!(must_spend.len(), 1);
1283 assert_eq!(must_spend[0].satisfaction_weight, weight);
1284 assert_eq!(must_spend[0].previous_utxo.value.to_sat(), value);
1285 assert_eq!(target_feerate_sat_per_1000_weight, feerate);
1286 Ok(res)
1287 }
1288 fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()> {
1289 let mut tx = psbt.unsigned_tx;
1290 for input in tx.input.iter_mut() {
1291 if input.previous_output.txid != Txid::from_byte_array([44; 32]) {
1292 input.witness = Witness::from_slice(&[vec![42; 162]]);
1294 }
1295 }
1296 Ok(tx)
1297 }
1298 }
1299
1300 impl Drop for TestCoinSelectionSource {
1301 fn drop(&mut self) {
1302 assert!(self.expected_selects.lock().unwrap().is_empty());
1303 }
1304 }
1305
1306 #[test]
1307 fn test_op_return_under_funds() {
1308 let commitment_tx_bytes = Vec::<u8>::from_hex("02000000000101cc6b0a9dd84b52c07340fff6fab002fc37b4bdccfdce9f39c5ec8391a56b652907000000009b948b80044a01000000000000220020b4182433fdfdfbf894897c98f84d92cec815cee222755ffd000ae091c9dadc2d4a01000000000000220020f83f7dbf90e2de325b5bb6bab0ae370151278c6964739242b2e7ce0cb68a5d81cb4a02000000000022002024add256b3dccee772610caef82a601045ab6f98fd6d5df608cc756b891ccfe63ffa490000000000220020894bf32b37906a643625e87131897c3714c71b3ac9b161862c9aa6c8d468b4c70400473044022060abd347bff2cca0212b660e6addff792b3356bd4a1b5b26672dc2e694c3c5f002202b40b7e346b494a7b1d048b4ec33ba99c90a09ab48eb1df64ccdc768066c865c014730440220554d8361e04dc0ee178dcb23d2d23f53ec7a1ae4312a5be76bd9e83ab8981f3d0220501f23ffb18cb81ccea72d30252f88d5e69fd28ba4992803d03c00d06fa8899e0147522102817f6ce189ab7114f89e8d5df58cdbbaf272dc8e71b92982d47456a0b6a0ceee2102c9b4d2f24aca54f65e13f4c83e2a8d8e877e12d3c71a76e81f28a5cabc652aa352ae626c7620").unwrap();
1321 let commitment_tx: Transaction =
1322 Readable::read(&mut Cursor::new(&commitment_tx_bytes)).unwrap();
1323 let commitment_txid = commitment_tx.compute_txid();
1324 let total_commitment_weight =
1325 commitment_tx.weight().to_wu() + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT;
1326 let commitment_and_anchor_fee = 930 + 330;
1327 let op_return_weight =
1328 TxOut { value: Amount::ZERO, script_pubkey: ScriptBuf::new_op_return(&[0; 3]) }
1329 .weight()
1330 .to_wu();
1331
1332 let broadcaster = TestBroadcaster::new(Network::Testnet);
1333 let source = TestCoinSelectionSource {
1334 expected_selects: Mutex::new(vec![
1335 (
1336 total_commitment_weight,
1337 commitment_and_anchor_fee,
1338 868,
1339 CoinSelection { confirmed_utxos: Vec::new(), change_output: None },
1340 ),
1341 (
1342 total_commitment_weight + op_return_weight,
1343 commitment_and_anchor_fee,
1344 868,
1345 CoinSelection {
1346 confirmed_utxos: vec![Utxo {
1347 outpoint: OutPoint { txid: Txid::from_byte_array([44; 32]), vout: 0 },
1348 output: TxOut {
1349 value: Amount::from_sat(200),
1350 script_pubkey: ScriptBuf::new(),
1351 },
1352 satisfaction_weight: 5, }],
1354 change_output: None,
1355 },
1356 ),
1357 ]),
1358 };
1359 let signer = KeysManager::new(&[42; 32], 42, 42, true);
1360 let logger = TestLogger::new();
1361 let handler = BumpTransactionEventHandlerSync::new(&broadcaster, &source, &signer, &logger);
1362
1363 let mut transaction_parameters = ChannelTransactionParameters::test_dummy(42_000_000);
1364 transaction_parameters.channel_type_features =
1365 ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
1366
1367 handler.handle_event(&BumpTransactionEvent::ChannelClose {
1368 channel_id: ChannelId([42; 32]),
1369 counterparty_node_id: PublicKey::from_slice(&[2; 33]).unwrap(),
1370 claim_id: ClaimId([42; 32]),
1371 package_target_feerate_sat_per_1000_weight: 868,
1372 commitment_tx_fee_satoshis: 930,
1373 commitment_tx,
1374 anchor_descriptor: AnchorDescriptor {
1375 channel_derivation_parameters: ChannelDerivationParameters {
1376 value_satoshis: 42_000_000,
1377 keys_id: [42; 32],
1378 transaction_parameters,
1379 },
1380 outpoint: OutPoint { txid: commitment_txid, vout: 0 },
1381 value: Amount::from_sat(ANCHOR_OUTPUT_VALUE_SATOSHI),
1382 },
1383 pending_htlcs: Vec::new(),
1384 });
1385 }
1386}