1use alloc::collections::BTreeMap;
15use core::ops::Deref;
16
17use crate::chain::chaininterface::{BroadcasterInterface, fee_for_weight};
18use crate::chain::ClaimId;
19use crate::io_extras::sink;
20use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
21use crate::ln::types::ChannelId;
22use crate::ln::chan_utils;
23use crate::ln::chan_utils::{
24 ANCHOR_INPUT_WITNESS_WEIGHT, HTLC_SUCCESS_INPUT_ANCHOR_WITNESS_WEIGHT,
25 HTLC_TIMEOUT_INPUT_ANCHOR_WITNESS_WEIGHT, HTLCOutputInCommitment
26};
27use crate::prelude::*;
28use crate::sign::{
29 ChannelDerivationParameters, HTLCDescriptor, SignerProvider, P2WPKH_WITNESS_WEIGHT
30};
31use crate::sign::ecdsa::EcdsaChannelSigner;
32use crate::sync::Mutex;
33use crate::util::logger::Logger;
34
35use bitcoin::{OutPoint, Psbt, PubkeyHash, Sequence, ScriptBuf, Transaction, TxIn, TxOut, Witness, WPubkeyHash};
36use bitcoin::amount::Amount;
37use bitcoin::constants::WITNESS_SCALE_FACTOR;
38use bitcoin::locktime::absolute::LockTime;
39use bitcoin::consensus::Encodable;
40use bitcoin::secp256k1;
41use bitcoin::secp256k1::{PublicKey, Secp256k1};
42use bitcoin::secp256k1::ecdsa::Signature;
43use bitcoin::transaction::Version;
44
45pub(crate) const EMPTY_SCRIPT_SIG_WEIGHT: u64 = 1 * WITNESS_SCALE_FACTOR as u64;
46
47const BASE_INPUT_SIZE: u64 = 32 + 4 + 4 ;
48
49pub(crate) const BASE_INPUT_WEIGHT: u64 = BASE_INPUT_SIZE * WITNESS_SCALE_FACTOR as u64;
50
51#[derive(Clone, Debug, PartialEq, Eq)]
53pub struct AnchorDescriptor {
54 pub channel_derivation_parameters: ChannelDerivationParameters,
56 pub outpoint: OutPoint,
59}
60
61impl AnchorDescriptor {
62 pub fn previous_utxo(&self) -> TxOut {
65 TxOut {
66 script_pubkey: self.witness_script().to_p2wsh(),
67 value: Amount::from_sat(ANCHOR_OUTPUT_VALUE_SATOSHI),
68 }
69 }
70
71 pub fn unsigned_tx_input(&self) -> TxIn {
74 TxIn {
75 previous_output: self.outpoint.clone(),
76 script_sig: ScriptBuf::new(),
77 sequence: Sequence::ENABLE_RBF_NO_LOCKTIME,
78 witness: Witness::new(),
79 }
80 }
81
82 pub fn witness_script(&self) -> ScriptBuf {
84 let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable();
85 chan_utils::get_anchor_redeemscript(&channel_params.broadcaster_pubkeys().funding_pubkey)
86 }
87
88 pub fn tx_input_witness(&self, signature: &Signature) -> Witness {
91 let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable();
92 chan_utils::build_anchor_input_witness(&channel_params.broadcaster_pubkeys().funding_pubkey, signature)
93 }
94
95 pub fn derive_channel_signer<S: EcdsaChannelSigner, SP: Deref>(&self, signer_provider: &SP) -> S
97 where
98 SP::Target: SignerProvider<EcdsaSigner= S>
99 {
100 let mut signer = signer_provider.derive_channel_signer(
101 self.channel_derivation_parameters.value_satoshis,
102 self.channel_derivation_parameters.keys_id,
103 );
104 signer.provide_channel_parameters(&self.channel_derivation_parameters.transaction_parameters);
105 signer
106 }
107}
108
109#[derive(Clone, Debug, PartialEq, Eq)]
111pub enum BumpTransactionEvent {
112 ChannelClose {
152 channel_id: ChannelId,
154 counterparty_node_id: PublicKey,
156 claim_id: ClaimId,
162 package_target_feerate_sat_per_1000_weight: u32,
165 commitment_tx: Transaction,
169 commitment_tx_fee_satoshis: u64,
172 anchor_descriptor: AnchorDescriptor,
175 pending_htlcs: Vec<HTLCOutputInCommitment>,
178 },
179 HTLCResolution {
209 channel_id: ChannelId,
211 counterparty_node_id: PublicKey,
213 claim_id: ClaimId,
220 target_feerate_sat_per_1000_weight: u32,
222 htlc_descriptors: Vec<HTLCDescriptor>,
225 tx_lock_time: LockTime,
227 },
228}
229
230#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
234pub struct Input {
235 pub outpoint: OutPoint,
237 pub previous_utxo: TxOut,
239 pub satisfaction_weight: u64,
243}
244
245#[derive(Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
248pub struct Utxo {
249 pub outpoint: OutPoint,
251 pub output: TxOut,
253 pub satisfaction_weight: u64,
257}
258
259impl Utxo {
260 pub fn new_p2pkh(outpoint: OutPoint, value: Amount, pubkey_hash: &PubkeyHash) -> Self {
262 let script_sig_size = 1 +
263 1 +
264 73 +
265 1 +
266 33 ;
267 Self {
268 outpoint,
269 output: TxOut {
270 value,
271 script_pubkey: ScriptBuf::new_p2pkh(pubkey_hash),
272 },
273 satisfaction_weight: script_sig_size * WITNESS_SCALE_FACTOR as u64 + 1 ,
274 }
275 }
276
277 pub fn new_nested_p2wpkh(outpoint: OutPoint, value: Amount, pubkey_hash: &WPubkeyHash) -> Self {
279 let script_sig_size = 1 +
280 1 +
281 1 +
282 20 ;
283 Self {
284 outpoint,
285 output: TxOut {
286 value,
287 script_pubkey: ScriptBuf::new_p2sh(&ScriptBuf::new_p2wpkh(pubkey_hash).script_hash()),
288 },
289 satisfaction_weight: script_sig_size * WITNESS_SCALE_FACTOR as u64 + P2WPKH_WITNESS_WEIGHT,
290 }
291 }
292
293 pub fn new_v0_p2wpkh(outpoint: OutPoint, value: Amount, pubkey_hash: &WPubkeyHash) -> Self {
295 Self {
296 outpoint,
297 output: TxOut {
298 value,
299 script_pubkey: ScriptBuf::new_p2wpkh(pubkey_hash),
300 },
301 satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + P2WPKH_WITNESS_WEIGHT,
302 }
303 }
304}
305
306#[derive(Clone, Debug)]
309pub struct CoinSelection {
310 pub confirmed_utxos: Vec<Utxo>,
313 pub change_output: Option<TxOut>,
318}
319
320pub trait CoinSelectionSource {
325 fn select_confirmed_utxos(
352 &self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &[TxOut],
353 target_feerate_sat_per_1000_weight: u32,
354 ) -> Result<CoinSelection, ()>;
355 fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()>;
361}
362
363pub trait WalletSource {
366 fn list_confirmed_utxos(&self) -> Result<Vec<Utxo>, ()>;
368 fn get_change_script(&self) -> Result<ScriptBuf, ()>;
371 fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()>;
378}
379
380pub struct Wallet<W: Deref, L: Deref>
384where
385 W::Target: WalletSource,
386 L::Target: Logger
387{
388 source: W,
389 logger: L,
390 locked_utxos: Mutex<HashMap<OutPoint, ClaimId>>,
394}
395
396impl<W: Deref, L: Deref> Wallet<W, L>
397where
398 W::Target: WalletSource,
399 L::Target: Logger
400{
401 pub fn new(source: W, logger: L) -> Self {
404 Self { source, logger, locked_utxos: Mutex::new(new_hash_map()) }
405 }
406
407 fn select_confirmed_utxos_internal(
416 &self, utxos: &[Utxo], claim_id: ClaimId, force_conflicting_utxo_spend: bool,
417 tolerate_high_network_feerates: bool, target_feerate_sat_per_1000_weight: u32,
418 preexisting_tx_weight: u64, input_amount_sat: Amount, target_amount_sat: Amount,
419 ) -> Result<CoinSelection, ()> {
420 let mut locked_utxos = self.locked_utxos.lock().unwrap();
421 let mut eligible_utxos = utxos.iter().filter_map(|utxo| {
422 if let Some(utxo_claim_id) = locked_utxos.get(&utxo.outpoint) {
423 if *utxo_claim_id != claim_id && !force_conflicting_utxo_spend {
424 log_trace!(self.logger, "Skipping UTXO {} to prevent conflicting spend", utxo.outpoint);
425 return None;
426 }
427 }
428 let fee_to_spend_utxo = Amount::from_sat(fee_for_weight(
429 target_feerate_sat_per_1000_weight, BASE_INPUT_WEIGHT + utxo.satisfaction_weight,
430 ));
431 let should_spend = if tolerate_high_network_feerates {
432 utxo.output.value > fee_to_spend_utxo
433 } else {
434 utxo.output.value >= fee_to_spend_utxo * 2
435 };
436 if should_spend {
437 Some((utxo, fee_to_spend_utxo))
438 } else {
439 log_trace!(self.logger, "Skipping UTXO {} due to dust proximity after spend", utxo.outpoint);
440 None
441 }
442 }).collect::<Vec<_>>();
443 eligible_utxos.sort_unstable_by_key(|(utxo, _)| utxo.output.value);
444
445 let mut selected_amount = input_amount_sat;
446 let mut total_fees = Amount::from_sat(fee_for_weight(target_feerate_sat_per_1000_weight, preexisting_tx_weight));
447 let mut selected_utxos = Vec::new();
448 for (utxo, fee_to_spend_utxo) in eligible_utxos {
449 if selected_amount >= target_amount_sat + total_fees {
450 break;
451 }
452 selected_amount += utxo.output.value;
453 total_fees += fee_to_spend_utxo;
454 selected_utxos.push(utxo.clone());
455 }
456 if selected_amount < target_amount_sat + total_fees {
457 log_debug!(self.logger, "Insufficient funds to meet target feerate {} sat/kW",
458 target_feerate_sat_per_1000_weight);
459 return Err(());
460 }
461 for utxo in &selected_utxos {
462 locked_utxos.insert(utxo.outpoint, claim_id);
463 }
464 core::mem::drop(locked_utxos);
465
466 let remaining_amount = selected_amount - target_amount_sat - total_fees;
467 let change_script = self.source.get_change_script()?;
468 let change_output_fee = fee_for_weight(
469 target_feerate_sat_per_1000_weight,
470 (8 + change_script.consensus_encode(&mut sink()).unwrap() as u64) *
471 WITNESS_SCALE_FACTOR as u64,
472 );
473 let change_output_amount = Amount::from_sat(remaining_amount.to_sat().saturating_sub(change_output_fee));
474 let change_output = if change_output_amount < change_script.minimal_non_dust() {
475 log_debug!(self.logger, "Coin selection attempt did not yield change output");
476 None
477 } else {
478 Some(TxOut { script_pubkey: change_script, value: change_output_amount })
479 };
480
481 Ok(CoinSelection {
482 confirmed_utxos: selected_utxos,
483 change_output,
484 })
485 }
486}
487
488impl<W: Deref, L: Deref> CoinSelectionSource for Wallet<W, L>
489where
490 W::Target: WalletSource,
491 L::Target: Logger
492{
493 fn select_confirmed_utxos(
494 &self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &[TxOut],
495 target_feerate_sat_per_1000_weight: u32,
496 ) -> Result<CoinSelection, ()> {
497 let utxos = self.source.list_confirmed_utxos()?;
498 const BASE_TX_SIZE: u64 = 4 + 1 + 1 + 4 ;
500 let total_output_size: u64 = must_pay_to.iter().map(|output|
501 8 + 1 + output.script_pubkey.len() as u64
502 ).sum();
503 let total_satisfaction_weight: u64 = must_spend.iter().map(|input| input.satisfaction_weight).sum();
504 let total_input_weight = (BASE_INPUT_WEIGHT * must_spend.len() as u64) + total_satisfaction_weight;
505
506 let preexisting_tx_weight = 2 + total_input_weight +
507 ((BASE_TX_SIZE + total_output_size) * WITNESS_SCALE_FACTOR as u64);
508 let input_amount_sat = must_spend.iter().map(|input| input.previous_utxo.value).sum();
509 let target_amount_sat = must_pay_to.iter().map(|output| output.value).sum();
510 let do_coin_selection = |force_conflicting_utxo_spend: bool, tolerate_high_network_feerates: bool| {
511 log_debug!(self.logger, "Attempting coin selection targeting {} sat/kW (force_conflicting_utxo_spend = {}, tolerate_high_network_feerates = {})",
512 target_feerate_sat_per_1000_weight, force_conflicting_utxo_spend, tolerate_high_network_feerates);
513 self.select_confirmed_utxos_internal(
514 &utxos, claim_id, force_conflicting_utxo_spend, tolerate_high_network_feerates,
515 target_feerate_sat_per_1000_weight, preexisting_tx_weight, input_amount_sat, target_amount_sat,
516 )
517 };
518 do_coin_selection(false, false)
519 .or_else(|_| do_coin_selection(false, true))
520 .or_else(|_| do_coin_selection(true, false))
521 .or_else(|_| do_coin_selection(true, true))
522 }
523
524 fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()> {
525 self.source.sign_psbt(psbt)
526 }
527}
528
529pub struct BumpTransactionEventHandler<B: Deref, C: Deref, SP: Deref, L: Deref>
535where
536 B::Target: BroadcasterInterface,
537 C::Target: CoinSelectionSource,
538 SP::Target: SignerProvider,
539 L::Target: Logger,
540{
541 broadcaster: B,
542 utxo_source: C,
543 signer_provider: SP,
544 logger: L,
545 secp: Secp256k1<secp256k1::All>,
546}
547
548impl<B: Deref, C: Deref, SP: Deref, L: Deref> BumpTransactionEventHandler<B, C, SP, L>
549where
550 B::Target: BroadcasterInterface,
551 C::Target: CoinSelectionSource,
552 SP::Target: SignerProvider,
553 L::Target: Logger,
554{
555 pub fn new(broadcaster: B, utxo_source: C, signer_provider: SP, logger: L) -> Self {
559 Self {
560 broadcaster,
561 utxo_source,
562 signer_provider,
563 logger,
564 secp: Secp256k1::new(),
565 }
566 }
567
568 fn process_coin_selection(&self, tx: &mut Transaction, coin_selection: &CoinSelection) {
570 for utxo in coin_selection.confirmed_utxos.iter() {
571 tx.input.push(TxIn {
572 previous_output: utxo.outpoint,
573 script_sig: ScriptBuf::new(),
574 sequence: Sequence::ZERO,
575 witness: Witness::new(),
576 });
577 }
578 if let Some(change_output) = coin_selection.change_output.clone() {
579 tx.output.push(change_output);
580 } else if tx.output.is_empty() {
581 if tx.input.len() <= 1 {
586 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");
589 debug_assert!(!tx.input.is_empty());
590 tx.output.push(TxOut {
591 value: Amount::ZERO,
592 script_pubkey: ScriptBuf::new_op_return(&[0, 0, 0]),
595 });
596 debug_assert_eq!(tx.base_size(), 65);
597 } else {
598 log_debug!(self.logger, "Including dummy OP_RETURN output since an output is needed and a change output was not provided");
599 tx.output.push(TxOut {
600 value: Amount::ZERO,
601 script_pubkey: ScriptBuf::new_op_return(&[]),
602 });
603 }
604 }
605 }
606
607 fn handle_channel_close(
611 &self, claim_id: ClaimId, package_target_feerate_sat_per_1000_weight: u32,
612 commitment_tx: &Transaction, commitment_tx_fee_sat: u64, anchor_descriptor: &AnchorDescriptor,
613 ) -> Result<(), ()> {
614 let mut anchor_utxo = anchor_descriptor.previous_utxo();
618 let commitment_tx_fee_sat = Amount::from_sat(commitment_tx_fee_sat);
619 anchor_utxo.value += commitment_tx_fee_sat;
620 let starting_package_and_fixed_input_satisfaction_weight =
621 commitment_tx.weight().to_wu() + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT;
622 let mut package_and_fixed_input_satisfaction_weight =
623 starting_package_and_fixed_input_satisfaction_weight;
624
625 loop {
626 let must_spend = vec![Input {
627 outpoint: anchor_descriptor.outpoint,
628 previous_utxo: anchor_utxo.clone(),
629 satisfaction_weight: package_and_fixed_input_satisfaction_weight,
630 }];
631 let must_spend_amount = must_spend.iter().map(|input| input.previous_utxo.value).sum::<Amount>();
632
633 log_debug!(self.logger, "Performing coin selection for commitment package (commitment and anchor transaction) targeting {} sat/kW",
634 package_target_feerate_sat_per_1000_weight);
635 let coin_selection: CoinSelection = self.utxo_source.select_confirmed_utxos(
636 claim_id, must_spend, &[], package_target_feerate_sat_per_1000_weight,
637 )?;
638
639 let mut anchor_tx = Transaction {
640 version: Version::TWO,
641 lock_time: LockTime::ZERO, input: vec![anchor_descriptor.unsigned_tx_input()],
643 output: vec![],
644 };
645
646 let total_satisfaction_weight = ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT +
647 coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum::<u64>();
648 let total_input_amount = must_spend_amount +
649 coin_selection.confirmed_utxos.iter().map(|utxo| utxo.output.value).sum();
650
651 self.process_coin_selection(&mut anchor_tx, &coin_selection);
652 let anchor_txid = anchor_tx.compute_txid();
653
654 let mut anchor_psbt = Psbt::from_unsigned_tx(anchor_tx).unwrap();
656 anchor_psbt.inputs[0].witness_utxo = Some(anchor_descriptor.previous_utxo());
658 for (idx, utxo) in coin_selection.confirmed_utxos.into_iter().enumerate() {
660 let index = idx + 1;
662 debug_assert_eq!(anchor_psbt.unsigned_tx.input[index].previous_output, utxo.outpoint);
663 if utxo.output.script_pubkey.is_witness_program() {
664 anchor_psbt.inputs[index].witness_utxo = Some(utxo.output);
665 }
666 }
667
668 debug_assert_eq!(anchor_psbt.unsigned_tx.output.len(), 1);
669 let unsigned_tx_weight = anchor_psbt.unsigned_tx.weight().to_wu() - (anchor_psbt.unsigned_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT);
670
671 let package_fee = total_input_amount -
672 anchor_psbt.unsigned_tx.output.iter().map(|output| output.value).sum();
673 let package_weight = unsigned_tx_weight + 2 + total_satisfaction_weight + commitment_tx.weight().to_wu();
674 if package_fee.to_sat() * 1000 / package_weight < package_target_feerate_sat_per_1000_weight.into() {
675 if package_and_fixed_input_satisfaction_weight == starting_package_and_fixed_input_satisfaction_weight {
680 debug_assert!(anchor_psbt.unsigned_tx.output[0].script_pubkey.is_op_return(),
681 "Coin selection failed to select sufficient coins for its change output");
682 package_and_fixed_input_satisfaction_weight += anchor_psbt.unsigned_tx.output[0].weight().to_wu();
683 continue;
684 } else {
685 debug_assert!(false, "Coin selection failed to select sufficient coins");
686 }
687 }
688
689 log_debug!(self.logger, "Signing anchor transaction {}", anchor_txid);
690 anchor_tx = self.utxo_source.sign_psbt(anchor_psbt)?;
691
692 let signer = anchor_descriptor.derive_channel_signer(&self.signer_provider);
693 let anchor_sig = signer.sign_holder_anchor_input(&anchor_tx, 0, &self.secp)?;
694 anchor_tx.input[0].witness = anchor_descriptor.tx_input_witness(&anchor_sig);
695
696 #[cfg(debug_assertions)] {
697 let signed_tx_weight = anchor_tx.weight().to_wu();
698 let expected_signed_tx_weight = unsigned_tx_weight + 2 + total_satisfaction_weight;
699 assert!(expected_signed_tx_weight >= signed_tx_weight &&
702 expected_signed_tx_weight - (expected_signed_tx_weight / 100) <= signed_tx_weight);
703
704 let expected_package_fee = Amount::from_sat(fee_for_weight(package_target_feerate_sat_per_1000_weight,
705 signed_tx_weight + commitment_tx.weight().to_wu()));
706 assert!(package_fee >= expected_package_fee);
709 }
710
711 log_info!(self.logger, "Broadcasting anchor transaction {} to bump channel close with txid {}",
712 anchor_txid, commitment_tx.compute_txid());
713 self.broadcaster.broadcast_transactions(&[&commitment_tx, &anchor_tx]);
714 return Ok(());
715 }
716 }
717
718 fn handle_htlc_resolution(
721 &self, claim_id: ClaimId, target_feerate_sat_per_1000_weight: u32,
722 htlc_descriptors: &[HTLCDescriptor], tx_lock_time: LockTime,
723 ) -> Result<(), ()> {
724 let mut htlc_tx = Transaction {
725 version: Version::TWO,
726 lock_time: tx_lock_time,
727 input: vec![],
728 output: vec![],
729 };
730 let mut must_spend = Vec::with_capacity(htlc_descriptors.len());
731 for htlc_descriptor in htlc_descriptors {
732 let htlc_input = htlc_descriptor.unsigned_tx_input();
733 must_spend.push(Input {
734 outpoint: htlc_input.previous_output.clone(),
735 previous_utxo: htlc_descriptor.previous_utxo(&self.secp),
736 satisfaction_weight: EMPTY_SCRIPT_SIG_WEIGHT + if htlc_descriptor.preimage.is_some() {
737 HTLC_SUCCESS_INPUT_ANCHOR_WITNESS_WEIGHT
738 } else {
739 HTLC_TIMEOUT_INPUT_ANCHOR_WITNESS_WEIGHT
740 },
741 });
742 htlc_tx.input.push(htlc_input);
743 let htlc_output = htlc_descriptor.tx_output(&self.secp);
744 htlc_tx.output.push(htlc_output);
745 }
746
747 log_debug!(self.logger, "Performing coin selection for HTLC transaction targeting {} sat/kW",
748 target_feerate_sat_per_1000_weight);
749
750 #[cfg(debug_assertions)]
751 let must_spend_satisfaction_weight =
752 must_spend.iter().map(|input| input.satisfaction_weight).sum::<u64>();
753 #[cfg(debug_assertions)]
754 let must_spend_amount = must_spend.iter().map(|input| input.previous_utxo.value.to_sat()).sum::<u64>();
755
756 let coin_selection: CoinSelection = self.utxo_source.select_confirmed_utxos(
757 claim_id, must_spend, &htlc_tx.output, target_feerate_sat_per_1000_weight,
758 )?;
759
760 #[cfg(debug_assertions)]
761 let total_satisfaction_weight = must_spend_satisfaction_weight +
762 coin_selection.confirmed_utxos.iter().map(|utxo| utxo.satisfaction_weight).sum::<u64>();
763 #[cfg(debug_assertions)]
764 let total_input_amount = must_spend_amount +
765 coin_selection.confirmed_utxos.iter().map(|utxo| utxo.output.value.to_sat()).sum::<u64>();
766
767 self.process_coin_selection(&mut htlc_tx, &coin_selection);
768
769 let mut htlc_psbt = Psbt::from_unsigned_tx(htlc_tx).unwrap();
771 for (i, htlc_descriptor) in htlc_descriptors.iter().enumerate() {
773 debug_assert_eq!(htlc_psbt.unsigned_tx.input[i].previous_output, htlc_descriptor.outpoint());
774 htlc_psbt.inputs[i].witness_utxo = Some(htlc_descriptor.previous_utxo(&self.secp));
775 }
776 for (idx, utxo) in coin_selection.confirmed_utxos.into_iter().enumerate() {
778 let index = idx + htlc_descriptors.len();
780 debug_assert_eq!(htlc_psbt.unsigned_tx.input[index].previous_output, utxo.outpoint);
781 if utxo.output.script_pubkey.is_witness_program() {
782 htlc_psbt.inputs[index].witness_utxo = Some(utxo.output);
783 }
784 }
785
786 #[cfg(debug_assertions)]
787 let unsigned_tx_weight = htlc_psbt.unsigned_tx.weight().to_wu() - (htlc_psbt.unsigned_tx.input.len() as u64 * EMPTY_SCRIPT_SIG_WEIGHT);
788
789 log_debug!(self.logger, "Signing HTLC transaction {}", htlc_psbt.unsigned_tx.compute_txid());
790 htlc_tx = self.utxo_source.sign_psbt(htlc_psbt)?;
791
792 let mut signers = BTreeMap::new();
793 for (idx, htlc_descriptor) in htlc_descriptors.iter().enumerate() {
794 let signer = signers.entry(htlc_descriptor.channel_derivation_parameters.keys_id)
795 .or_insert_with(|| htlc_descriptor.derive_channel_signer(&self.signer_provider));
796 let htlc_sig = signer.sign_holder_htlc_transaction(&htlc_tx, idx, htlc_descriptor, &self.secp)?;
797 let witness_script = htlc_descriptor.witness_script(&self.secp);
798 htlc_tx.input[idx].witness = htlc_descriptor.tx_input_witness(&htlc_sig, &witness_script);
799 }
800
801 #[cfg(debug_assertions)] {
802 let signed_tx_weight = htlc_tx.weight().to_wu();
803 let expected_signed_tx_weight = unsigned_tx_weight + total_satisfaction_weight;
804 assert!(expected_signed_tx_weight >= signed_tx_weight &&
807 expected_signed_tx_weight - (expected_signed_tx_weight / 100) <= signed_tx_weight);
808
809 let expected_signed_tx_fee = fee_for_weight(target_feerate_sat_per_1000_weight, signed_tx_weight);
810 let signed_tx_fee = total_input_amount -
811 htlc_tx.output.iter().map(|output| output.value.to_sat()).sum::<u64>();
812 assert!(signed_tx_fee >= expected_signed_tx_fee);
815 }
816
817 log_info!(self.logger, "Broadcasting {}", log_tx!(htlc_tx));
818 self.broadcaster.broadcast_transactions(&[&htlc_tx]);
819 Ok(())
820 }
821
822 pub fn handle_event(&self, event: &BumpTransactionEvent) {
824 match event {
825 BumpTransactionEvent::ChannelClose {
826 claim_id, package_target_feerate_sat_per_1000_weight, commitment_tx,
827 commitment_tx_fee_satoshis, anchor_descriptor, ..
828 } => {
829 log_info!(self.logger, "Handling channel close bump (claim_id = {}, commitment_txid = {})",
830 log_bytes!(claim_id.0), commitment_tx.compute_txid());
831 if let Err(_) = self.handle_channel_close(
832 *claim_id, *package_target_feerate_sat_per_1000_weight, commitment_tx,
833 *commitment_tx_fee_satoshis, anchor_descriptor,
834 ) {
835 log_error!(self.logger, "Failed bumping commitment transaction fee for {}",
836 commitment_tx.compute_txid());
837 }
838 }
839 BumpTransactionEvent::HTLCResolution {
840 claim_id, target_feerate_sat_per_1000_weight, htlc_descriptors, tx_lock_time, ..
841 } => {
842 log_info!(self.logger, "Handling HTLC bump (claim_id = {}, htlcs_to_claim = {})",
843 log_bytes!(claim_id.0), log_iter!(htlc_descriptors.iter().map(|d| d.outpoint())));
844 if let Err(_) = self.handle_htlc_resolution(
845 *claim_id, *target_feerate_sat_per_1000_weight, htlc_descriptors, *tx_lock_time,
846 ) {
847 log_error!(self.logger, "Failed bumping HTLC transaction fee for commitment {}",
848 htlc_descriptors[0].commitment_txid);
849 }
850 }
851 }
852 }
853}
854
855#[cfg(test)]
856mod tests {
857 use super::*;
858
859 use crate::io::Cursor;
860 use crate::ln::chan_utils::ChannelTransactionParameters;
861 use crate::util::ser::Readable;
862 use crate::util::test_utils::{TestBroadcaster, TestLogger};
863 use crate::sign::KeysManager;
864
865 use bitcoin::hashes::Hash;
866 use bitcoin::hex::FromHex;
867 use bitcoin::{Network, ScriptBuf, Transaction, Txid};
868
869 struct TestCoinSelectionSource {
870 expected_selects: Mutex<Vec<(u64, u64, u32, CoinSelection)>>,
872 }
873 impl CoinSelectionSource for TestCoinSelectionSource {
874 fn select_confirmed_utxos(
875 &self,
876 _claim_id: ClaimId,
877 must_spend: Vec<Input>,
878 _must_pay_to: &[TxOut],
879 target_feerate_sat_per_1000_weight: u32
880 ) -> Result<CoinSelection, ()> {
881 let mut expected_selects = self.expected_selects.lock().unwrap();
882 let (weight, value, feerate, res) = expected_selects.remove(0);
883 assert_eq!(must_spend.len(), 1);
884 assert_eq!(must_spend[0].satisfaction_weight, weight);
885 assert_eq!(must_spend[0].previous_utxo.value.to_sat(), value);
886 assert_eq!(target_feerate_sat_per_1000_weight, feerate);
887 Ok(res)
888 }
889 fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()> {
890 let mut tx = psbt.unsigned_tx;
891 for input in tx.input.iter_mut() {
892 if input.previous_output.txid != Txid::from_byte_array([44; 32]) {
893 input.witness = Witness::from_slice(&[vec![42; 162]]);
895 }
896 }
897 Ok(tx)
898 }
899 }
900
901 impl Drop for TestCoinSelectionSource {
902 fn drop(&mut self) {
903 assert!(self.expected_selects.lock().unwrap().is_empty());
904 }
905 }
906
907 #[test]
908 fn test_op_return_under_funds() {
909 let commitment_tx_bytes = Vec::<u8>::from_hex("02000000000101cc6b0a9dd84b52c07340fff6fab002fc37b4bdccfdce9f39c5ec8391a56b652907000000009b948b80044a01000000000000220020b4182433fdfdfbf894897c98f84d92cec815cee222755ffd000ae091c9dadc2d4a01000000000000220020f83f7dbf90e2de325b5bb6bab0ae370151278c6964739242b2e7ce0cb68a5d81cb4a02000000000022002024add256b3dccee772610caef82a601045ab6f98fd6d5df608cc756b891ccfe63ffa490000000000220020894bf32b37906a643625e87131897c3714c71b3ac9b161862c9aa6c8d468b4c70400473044022060abd347bff2cca0212b660e6addff792b3356bd4a1b5b26672dc2e694c3c5f002202b40b7e346b494a7b1d048b4ec33ba99c90a09ab48eb1df64ccdc768066c865c014730440220554d8361e04dc0ee178dcb23d2d23f53ec7a1ae4312a5be76bd9e83ab8981f3d0220501f23ffb18cb81ccea72d30252f88d5e69fd28ba4992803d03c00d06fa8899e0147522102817f6ce189ab7114f89e8d5df58cdbbaf272dc8e71b92982d47456a0b6a0ceee2102c9b4d2f24aca54f65e13f4c83e2a8d8e877e12d3c71a76e81f28a5cabc652aa352ae626c7620").unwrap();
922 let commitment_tx: Transaction = Readable::read(&mut Cursor::new(&commitment_tx_bytes)).unwrap();
923 let total_commitment_weight = commitment_tx.weight().to_wu() + ANCHOR_INPUT_WITNESS_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT;
924 let commitment_and_anchor_fee = 930 + 330;
925 let op_return_weight = TxOut {
926 value: Amount::ZERO,
927 script_pubkey: ScriptBuf::new_op_return(&[0; 3]),
928 }.weight().to_wu();
929
930 let broadcaster = TestBroadcaster::new(Network::Testnet);
931 let source = TestCoinSelectionSource {
932 expected_selects: Mutex::new(vec![
933 (total_commitment_weight, commitment_and_anchor_fee, 868, CoinSelection { confirmed_utxos: Vec::new(), change_output: None }),
934 (total_commitment_weight + op_return_weight, commitment_and_anchor_fee, 868, CoinSelection {
935 confirmed_utxos: vec![Utxo {
936 outpoint: OutPoint { txid: Txid::from_byte_array([44; 32]), vout: 0 },
937 output: TxOut { value: Amount::from_sat(200), script_pubkey: ScriptBuf::new() },
938 satisfaction_weight: 5, }],
940 change_output: None,
941 })
942 ]),
943 };
944 let signer = KeysManager::new(&[42; 32], 42, 42);
945 let logger = TestLogger::new();
946 let handler = BumpTransactionEventHandler::new(&broadcaster, &source, &signer, &logger);
947
948 handler.handle_event(&BumpTransactionEvent::ChannelClose {
949 channel_id: ChannelId([42; 32]),
950 counterparty_node_id: PublicKey::from_slice(&[2; 33]).unwrap(),
951 claim_id: ClaimId([42; 32]),
952 package_target_feerate_sat_per_1000_weight: 868,
953 commitment_tx_fee_satoshis: 930,
954 commitment_tx,
955 anchor_descriptor: AnchorDescriptor {
956 channel_derivation_parameters: ChannelDerivationParameters {
957 value_satoshis: 42_000_000,
958 keys_id: [42; 32],
959 transaction_parameters: ChannelTransactionParameters::test_dummy(),
960 },
961 outpoint: OutPoint { txid: Txid::from_byte_array([42; 32]), vout: 0 },
962 },
963 pending_htlcs: Vec::new(),
964 });
965 }
966}