1use bitcoin::amount::Amount;
16use bitcoin::hash_types::{BlockHash, Txid};
17use bitcoin::hashes::Hash;
18use bitcoin::locktime::absolute::LockTime;
19use bitcoin::script::{Script, ScriptBuf};
20use bitcoin::secp256k1;
21use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
22use bitcoin::transaction::OutPoint as BitcoinOutPoint;
23use bitcoin::transaction::Transaction;
24
25use crate::chain::chaininterface::ConfirmationTarget;
26use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
27use crate::chain::channelmonitor::ANTI_REORG_DELAY;
28use crate::chain::package::{PackageSolvingData, PackageTemplate};
29use crate::chain::transaction::MaybeSignedTransaction;
30use crate::chain::ClaimId;
31use crate::ln::chan_utils::{
32 get_keyed_anchor_redeemscript, shared_anchor_script_pubkey, ChannelTransactionParameters,
33 HTLCOutputInCommitment, HolderCommitmentTransaction,
34};
35use crate::ln::msgs::DecodeError;
36use crate::sign::{ecdsa::EcdsaChannelSigner, EntropySource, HTLCDescriptor, SignerProvider};
37use crate::util::logger::Logger;
38use crate::util::ser::{
39 MaybeReadable, Readable, ReadableArgs, UpgradableRequired, Writeable, Writer,
40};
41
42use crate::io;
43use crate::prelude::*;
44use alloc::collections::BTreeMap;
45use core::cmp;
46use core::mem::replace;
47use core::mem::swap;
48use core::ops::Deref;
49
50const MAX_ALLOC_SIZE: usize = 64 * 1024;
51
52#[derive(Clone, PartialEq, Eq)]
57struct OnchainEventEntry {
58 txid: Txid,
59 height: u32,
60 block_hash: Option<BlockHash>, event: OnchainEvent,
62}
63
64impl OnchainEventEntry {
65 fn confirmation_threshold(&self) -> u32 {
66 self.height + ANTI_REORG_DELAY - 1
67 }
68
69 fn has_reached_confirmation_threshold(&self, height: u32) -> bool {
70 height >= self.confirmation_threshold()
71 }
72}
73
74#[derive(Clone, PartialEq, Eq)]
77enum OnchainEvent {
78 Claim { claim_id: ClaimId },
83 ContentiousOutpoint { package: PackageTemplate },
90}
91
92impl Writeable for OnchainEventEntry {
93 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
94 write_tlv_fields!(writer, {
95 (0, self.txid, required),
96 (1, self.block_hash, option),
97 (2, self.height, required),
98 (4, self.event, required),
99 });
100 Ok(())
101 }
102}
103
104impl MaybeReadable for OnchainEventEntry {
105 #[rustfmt::skip]
106 fn read<R: io::Read>(reader: &mut R) -> Result<Option<Self>, DecodeError> {
107 let mut txid = Txid::all_zeros();
108 let mut height = 0;
109 let mut block_hash = None;
110 let mut event = UpgradableRequired(None);
111 read_tlv_fields!(reader, {
112 (0, txid, required),
113 (1, block_hash, option),
114 (2, height, required),
115 (4, event, upgradable_required),
116 });
117 Ok(Some(Self { txid, height, block_hash, event: _init_tlv_based_struct_field!(event, upgradable_required) }))
118 }
119}
120
121impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
122 (0, Claim) => {
123 (0, claim_id, required),
124 },
125 (1, ContentiousOutpoint) => {
126 (0, package, required),
127 },
128);
129
130impl Readable for Option<Vec<Option<(usize, Signature)>>> {
131 #[rustfmt::skip]
132 fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
133 match Readable::read(reader)? {
134 0u8 => Ok(None),
135 1u8 => {
136 let vlen: u64 = Readable::read(reader)?;
137 let mut ret = Vec::with_capacity(cmp::min(vlen as usize, MAX_ALLOC_SIZE / ::core::mem::size_of::<Option<(usize, Signature)>>()));
138 for _ in 0..vlen {
139 ret.push(match Readable::read(reader)? {
140 0u8 => None,
141 1u8 => Some((<u64 as Readable>::read(reader)? as usize, Readable::read(reader)?)),
142 _ => return Err(DecodeError::InvalidValue)
143 });
144 }
145 Ok(Some(ret))
146 },
147 _ => Err(DecodeError::InvalidValue),
148 }
149 }
150}
151
152impl Writeable for Option<Vec<Option<(usize, Signature)>>> {
153 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
154 match self {
155 &Some(ref vec) => {
156 1u8.write(writer)?;
157 (vec.len() as u64).write(writer)?;
158 for opt in vec.iter() {
159 match opt {
160 &Some((ref idx, ref sig)) => {
161 1u8.write(writer)?;
162 (*idx as u64).write(writer)?;
163 sig.write(writer)?;
164 },
165 &None => 0u8.write(writer)?,
166 }
167 }
168 },
169 &None => 0u8.write(writer)?,
170 }
171 Ok(())
172 }
173}
174
175#[derive(Clone, PartialEq, Eq)]
178pub(crate) enum ClaimEvent {
179 BumpCommitment {
182 package_target_feerate_sat_per_1000_weight: u32,
183 commitment_tx: Transaction,
184 commitment_tx_fee_satoshis: u64,
185 pending_nondust_htlcs: Vec<HTLCOutputInCommitment>,
186 anchor_output_idx: u32,
187 channel_parameters: ChannelTransactionParameters,
188 },
189 BumpHTLC {
192 target_feerate_sat_per_1000_weight: u32,
193 htlcs: Vec<HTLCDescriptor>,
194 tx_lock_time: LockTime,
195 },
196}
197
198pub(crate) enum OnchainClaim {
201 Tx(MaybeSignedTransaction),
203 Event(ClaimEvent),
206}
207
208#[derive(Debug)]
210pub(crate) enum FeerateStrategy {
211 RetryPrevious,
213 HighestOfPreviousOrNew,
215 ForceBump,
218}
219
220#[derive(Clone)]
223pub struct OnchainTxHandler<ChannelSigner: EcdsaChannelSigner> {
224 channel_value_satoshis: u64, channel_keys_id: [u8; 32], destination_script: ScriptBuf, holder_commitment: HolderCommitmentTransaction,
228 prev_holder_commitment: Option<HolderCommitmentTransaction>,
229
230 pub(super) signer: ChannelSigner,
231 channel_transaction_parameters: ChannelTransactionParameters, #[cfg(any(test, feature = "_test_utils"))]
245 pub(crate) pending_claim_requests: HashMap<ClaimId, PackageTemplate>,
246 #[cfg(not(any(test, feature = "_test_utils")))]
247 pending_claim_requests: HashMap<ClaimId, PackageTemplate>,
248
249 pending_claim_events: Vec<(ClaimId, ClaimEvent)>,
260
261 #[cfg(any(test, feature = "_test_utils"))]
268 pub(crate) claimable_outpoints: HashMap<BitcoinOutPoint, (ClaimId, u32)>,
269 #[cfg(not(any(test, feature = "_test_utils")))]
270 claimable_outpoints: HashMap<BitcoinOutPoint, (ClaimId, u32)>,
271
272 #[cfg(any(test, feature = "_test_utils"))]
273 pub(crate) locktimed_packages: BTreeMap<u32, Vec<PackageTemplate>>,
274 #[cfg(not(any(test, feature = "_test_utils")))]
275 locktimed_packages: BTreeMap<u32, Vec<PackageTemplate>>,
276
277 onchain_events_awaiting_threshold_conf: Vec<OnchainEventEntry>,
278
279 pub(super) secp_ctx: Secp256k1<secp256k1::All>,
280}
281
282impl<ChannelSigner: EcdsaChannelSigner> PartialEq for OnchainTxHandler<ChannelSigner> {
283 #[rustfmt::skip]
284 fn eq(&self, other: &Self) -> bool {
285 self.channel_value_satoshis == other.channel_value_satoshis &&
287 self.channel_keys_id == other.channel_keys_id &&
288 self.destination_script == other.destination_script &&
289 self.holder_commitment == other.holder_commitment &&
290 self.prev_holder_commitment == other.prev_holder_commitment &&
291 self.channel_transaction_parameters == other.channel_transaction_parameters &&
292 self.pending_claim_requests == other.pending_claim_requests &&
293 self.claimable_outpoints == other.claimable_outpoints &&
294 self.locktimed_packages == other.locktimed_packages &&
295 self.onchain_events_awaiting_threshold_conf == other.onchain_events_awaiting_threshold_conf
296 }
297}
298
299const SERIALIZATION_VERSION: u8 = 1;
300const MIN_SERIALIZATION_VERSION: u8 = 1;
301
302impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
303 #[rustfmt::skip]
304 pub(crate) fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
305 write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
306
307 self.destination_script.write(writer)?;
308 self.holder_commitment.write(writer)?;
309 None::<Option<Vec<Option<(usize, Signature)>>>>.write(writer)?; self.prev_holder_commitment.write(writer)?;
311 None::<Option<Vec<Option<(usize, Signature)>>>>.write(writer)?; self.channel_transaction_parameters.write(writer)?;
314
315 0u32.write(writer)?;
318
319 writer.write_all(&(self.pending_claim_requests.len() as u64).to_be_bytes())?;
320 for (ref ancestor_claim_txid, request) in self.pending_claim_requests.iter() {
321 ancestor_claim_txid.write(writer)?;
322 request.write(writer)?;
323 }
324
325 writer.write_all(&(self.claimable_outpoints.len() as u64).to_be_bytes())?;
326 for (ref outp, ref claim_and_height) in self.claimable_outpoints.iter() {
327 outp.write(writer)?;
328 claim_and_height.0.write(writer)?;
329 claim_and_height.1.write(writer)?;
330 }
331
332 writer.write_all(&(self.locktimed_packages.len() as u64).to_be_bytes())?;
333 for (ref locktime, ref packages) in self.locktimed_packages.iter() {
334 locktime.write(writer)?;
335 writer.write_all(&(packages.len() as u64).to_be_bytes())?;
336 for ref package in packages.iter() {
337 package.write(writer)?;
338 }
339 }
340
341 writer.write_all(&(self.onchain_events_awaiting_threshold_conf.len() as u64).to_be_bytes())?;
342 for ref entry in self.onchain_events_awaiting_threshold_conf.iter() {
343 entry.write(writer)?;
344 }
345
346 write_tlv_fields!(writer, {});
347 Ok(())
348 }
349}
350
351impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP, u64, [u8; 32])>
352 for OnchainTxHandler<SP::EcdsaSigner>
353{
354 #[rustfmt::skip]
355 fn read<R: io::Read>(reader: &mut R, args: (&'a ES, &'b SP, u64, [u8; 32])) -> Result<Self, DecodeError> {
356 let entropy_source = args.0;
357 let signer_provider = args.1;
358 let channel_value_satoshis = args.2;
359 let channel_keys_id = args.3;
360
361 let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
362
363 let destination_script = Readable::read(reader)?;
364
365 let holder_commitment = Readable::read(reader)?;
366 let _holder_htlc_sigs: Option<Vec<Option<(usize, Signature)>>> = Readable::read(reader)?;
367 let prev_holder_commitment = Readable::read(reader)?;
368 let _prev_holder_htlc_sigs: Option<Vec<Option<(usize, Signature)>>> = Readable::read(reader)?;
369
370 let channel_parameters = ReadableArgs::<Option<u64>>::read(reader, Some(channel_value_satoshis))?;
371
372 let keys_len: u32 = Readable::read(reader)?;
375 let mut bytes_read = 0;
376 while bytes_read != keys_len as usize {
377 let mut data = [0; 1024];
379 let bytes_to_read = cmp::min(1024, keys_len as usize - bytes_read);
380 let read_slice = &mut data[0..bytes_to_read];
381 reader.read_exact(read_slice)?;
382 bytes_read += bytes_to_read;
383 }
384
385 let signer = signer_provider.derive_channel_signer(channel_keys_id);
386
387 let pending_claim_requests_len: u64 = Readable::read(reader)?;
388 let mut pending_claim_requests = hash_map_with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128));
389 for _ in 0..pending_claim_requests_len {
390 pending_claim_requests.insert(Readable::read(reader)?, Readable::read(reader)?);
391 }
392
393 let claimable_outpoints_len: u64 = Readable::read(reader)?;
394 let mut claimable_outpoints = hash_map_with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128));
395 for _ in 0..claimable_outpoints_len {
396 let outpoint = Readable::read(reader)?;
397 let ancestor_claim_txid = Readable::read(reader)?;
398 let height = Readable::read(reader)?;
399 claimable_outpoints.insert(outpoint, (ancestor_claim_txid, height));
400 }
401
402 let locktimed_packages_len: u64 = Readable::read(reader)?;
403 let mut locktimed_packages = BTreeMap::new();
404 for _ in 0..locktimed_packages_len {
405 let locktime = Readable::read(reader)?;
406 let packages_len: u64 = Readable::read(reader)?;
407 let mut packages = Vec::with_capacity(cmp::min(packages_len as usize, MAX_ALLOC_SIZE / core::mem::size_of::<PackageTemplate>()));
408 for _ in 0..packages_len {
409 packages.push(Readable::read(reader)?);
410 }
411 locktimed_packages.insert(locktime, packages);
412 }
413
414 let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
415 let mut onchain_events_awaiting_threshold_conf = Vec::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
416 for _ in 0..waiting_threshold_conf_len {
417 if let Some(val) = MaybeReadable::read(reader)? {
418 onchain_events_awaiting_threshold_conf.push(val);
419 }
420 }
421
422 read_tlv_fields!(reader, {});
423
424 let mut secp_ctx = Secp256k1::new();
425 secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
426
427 Ok(OnchainTxHandler {
428 channel_value_satoshis,
429 channel_keys_id,
430 destination_script,
431 holder_commitment,
432 prev_holder_commitment,
433 signer,
434 channel_transaction_parameters: channel_parameters,
435 claimable_outpoints,
436 locktimed_packages,
437 pending_claim_requests,
438 onchain_events_awaiting_threshold_conf,
439 pending_claim_events: Vec::new(),
440 secp_ctx,
441 })
442 }
443}
444
445impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
446 pub(crate) fn new(
447 channel_value_satoshis: u64, channel_keys_id: [u8; 32], destination_script: ScriptBuf,
448 signer: ChannelSigner, channel_parameters: ChannelTransactionParameters,
449 holder_commitment: HolderCommitmentTransaction, secp_ctx: Secp256k1<secp256k1::All>,
450 ) -> Self {
451 OnchainTxHandler {
452 channel_value_satoshis,
453 channel_keys_id,
454 destination_script,
455 holder_commitment,
456 prev_holder_commitment: None,
457 signer,
458 channel_transaction_parameters: channel_parameters,
459 pending_claim_requests: new_hash_map(),
460 claimable_outpoints: new_hash_map(),
461 locktimed_packages: BTreeMap::new(),
462 onchain_events_awaiting_threshold_conf: Vec::new(),
463 pending_claim_events: Vec::new(),
464 secp_ctx,
465 }
466 }
467
468 pub(crate) fn prev_holder_commitment_tx(&self) -> Option<&HolderCommitmentTransaction> {
469 self.prev_holder_commitment.as_ref()
470 }
471
472 pub(crate) fn current_holder_commitment_tx(&self) -> &HolderCommitmentTransaction {
473 &self.holder_commitment
474 }
475
476 pub(crate) fn get_and_clear_pending_claim_events(&mut self) -> Vec<(ClaimId, ClaimEvent)> {
477 let mut events = Vec::new();
478 swap(&mut events, &mut self.pending_claim_events);
479 events
480 }
481
482 #[rustfmt::skip]
488 pub(super) fn rebroadcast_pending_claims<B: Deref, F: Deref, L: Logger>(
489 &mut self, current_height: u32, feerate_strategy: FeerateStrategy, broadcaster: &B,
490 conf_target: ConfirmationTarget, destination_script: &Script,
491 fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
492 )
493 where
494 B::Target: BroadcasterInterface,
495 F::Target: FeeEstimator,
496 {
497 let mut bump_requests = Vec::with_capacity(self.pending_claim_requests.len());
498 for (claim_id, request) in self.pending_claim_requests.iter() {
499 let inputs = request.outpoints();
500 log_info!(logger, "Triggering rebroadcast/fee-bump for request with inputs {:?}", inputs);
501 bump_requests.push((*claim_id, request.clone()));
502 }
503 for (claim_id, request) in bump_requests {
504 self.generate_claim(
505 current_height, &request, &feerate_strategy, conf_target, destination_script,
506 fee_estimator, logger,
507 )
508 .map(|(_, new_feerate, claim)| {
509 let mut feerate_was_bumped = false;
510 if let Some(mut_request) = self.pending_claim_requests.get_mut(&claim_id) {
511 feerate_was_bumped = new_feerate > request.previous_feerate();
512 mut_request.set_feerate(new_feerate);
513 }
514 match claim {
515 OnchainClaim::Tx(tx) => {
516 if tx.is_fully_signed() {
517 let log_start = if feerate_was_bumped { "Broadcasting RBF-bumped" } else { "Rebroadcasting" };
518 log_info!(logger, "{} onchain {}", log_start, log_tx!(tx.0));
519 broadcaster.broadcast_transactions(&[&tx.0]);
520 } else {
521 log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", tx.0.compute_txid());
522 }
523 },
524 OnchainClaim::Event(event) => {
525 let log_start = if feerate_was_bumped { "Yielding fee-bumped" } else { "Replaying" };
526 log_info!(logger, "{} onchain event to spend inputs {:?}", log_start,
527 request.outpoints());
528 #[cfg(debug_assertions)] {
529 debug_assert!(request.requires_external_funding());
530 let num_existing = self.pending_claim_events.iter()
531 .filter(|entry| entry.0 == claim_id).count();
532 assert!(num_existing == 0 || num_existing == 1);
533 }
534 self.pending_claim_events.retain(|event| event.0 != claim_id);
535 self.pending_claim_events.push((claim_id, event));
536 }
537 }
538 });
539 }
540 }
541
542 pub(super) fn has_pending_claims(&self) -> bool {
545 self.pending_claim_requests.len() != 0
546 }
547
548 #[rustfmt::skip]
557 fn generate_claim<F: Deref, L: Logger>(
558 &mut self, cur_height: u32, cached_request: &PackageTemplate,
559 feerate_strategy: &FeerateStrategy, conf_target: ConfirmationTarget,
560 destination_script: &Script, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
561 ) -> Option<(u32, u64, OnchainClaim)>
562 where F::Target: FeeEstimator,
563 {
564 let request_outpoints = cached_request.outpoints();
565 if request_outpoints.is_empty() {
566 debug_assert!(cached_request.is_malleable());
570 return None;
571 }
572 let mut all_inputs_have_confirmed_spend = true;
577 for outpoint in request_outpoints.iter() {
578 if let Some((request_claim_id, _)) = self.claimable_outpoints.get(*outpoint) {
579 if !self.onchain_events_awaiting_threshold_conf.iter()
582 .any(|event_entry| if let OnchainEvent::Claim { claim_id } = event_entry.event {
583 *request_claim_id == claim_id
584 } else {
585 false
587 })
588 {
589 all_inputs_have_confirmed_spend = false;
592 }
593 } else {
594 all_inputs_have_confirmed_spend = false;
596 }
597 }
598 if all_inputs_have_confirmed_spend {
599 return None;
600 }
601
602 let new_timer = cached_request.get_height_timer(cur_height);
605 if cached_request.is_malleable() {
606 if cached_request.requires_external_funding() {
607 let target_feerate_sat_per_1000_weight = cached_request.compute_package_feerate(
608 fee_estimator, conf_target, feerate_strategy,
609 );
610 let htlcs = cached_request.construct_malleable_package_with_external_funding(self)?;
611 return Some((
612 new_timer,
613 target_feerate_sat_per_1000_weight as u64,
614 OnchainClaim::Event(ClaimEvent::BumpHTLC {
615 target_feerate_sat_per_1000_weight,
616 htlcs,
617 tx_lock_time: LockTime::from_consensus(cached_request.package_locktime(cur_height)),
618 }),
619 ));
620 }
621
622 let predicted_weight = cached_request.package_weight(destination_script);
623 if let Some((output_value, new_feerate)) = cached_request.compute_package_output(
624 predicted_weight, destination_script.minimal_non_dust().to_sat(),
625 feerate_strategy, conf_target, fee_estimator, logger,
626 ) {
627 assert!(new_feerate != 0);
628
629 let transaction = cached_request.maybe_finalize_malleable_package(
630 cur_height, self, Amount::from_sat(output_value), destination_script.into(), logger
631 ).unwrap();
632 assert!(predicted_weight >= transaction.0.weight().to_wu());
633 return Some((new_timer, new_feerate, OnchainClaim::Tx(transaction)));
634 }
635 } else {
636 let mut inputs = cached_request.inputs();
640 debug_assert_eq!(inputs.len(), 1);
641
642 if !cached_request.requires_external_funding() {
643 return cached_request.maybe_finalize_untractable_package(self, logger)
644 .map(|tx| (new_timer, 0, OnchainClaim::Tx(tx)))
645 }
646
647 return inputs.find_map(|input| match input {
648 PackageSolvingData::HolderFundingOutput(output) => {
651 let maybe_signed_commitment_tx = output.get_maybe_signed_commitment_tx(self);
652 let tx = if maybe_signed_commitment_tx.is_fully_signed() {
653 maybe_signed_commitment_tx.0
654 } else {
655 return Some((new_timer, 0, OnchainClaim::Tx(maybe_signed_commitment_tx)));
659 };
660
661 let holder_commitment = output.commitment_tx.as_ref()
662 .unwrap_or(self.current_holder_commitment_tx());
663
664 let input_amount_sats = if let Some(funding_amount_sats) = output.funding_amount_sats {
665 funding_amount_sats
666 } else {
667 debug_assert!(false, "Funding amount should always exist for anchor-based claims");
668 self.channel_value_satoshis
669 };
670
671 let fee_sat = input_amount_sats - tx.output.iter()
672 .map(|output| output.value.to_sat()).sum::<u64>();
673 let package_target_feerate_sat_per_1000_weight = cached_request
674 .compute_package_feerate(fee_estimator, conf_target, feerate_strategy);
675
676 let channel_parameters = output.channel_parameters.as_ref()
678 .unwrap_or(self.channel_parameters());
679 let funding_pubkey = &channel_parameters.holder_pubkeys.funding_pubkey;
680 let script_pubkey = if channel_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx() {
681 get_keyed_anchor_redeemscript(funding_pubkey).to_p2wsh()
682 } else {
683 debug_assert!(channel_parameters.channel_type_features.supports_anchor_zero_fee_commitments());
684 shared_anchor_script_pubkey()
685 };
686 let anchor_output = tx.output.iter().enumerate()
687 .find(|(_, txout)| txout.script_pubkey == script_pubkey)
688 .map(|(idx, txout)| (idx as u32, txout));
689 match anchor_output {
690 Some((idx, _)) => {
692 Some((
695 new_timer,
696 package_target_feerate_sat_per_1000_weight as u64,
697 OnchainClaim::Event(ClaimEvent::BumpCommitment {
698 package_target_feerate_sat_per_1000_weight,
699 commitment_tx: tx,
700 pending_nondust_htlcs: holder_commitment.nondust_htlcs().to_vec(),
701 commitment_tx_fee_satoshis: fee_sat,
702 anchor_output_idx: idx,
703 channel_parameters: channel_parameters.clone(),
704 }),
705 ))
706 },
707 None => Some((new_timer, 0, OnchainClaim::Tx(MaybeSignedTransaction(tx)))),
712 }
713 },
714 _ => {
715 debug_assert!(false, "Only HolderFundingOutput inputs should be untractable and require external funding");
716 None
717 },
718 })
719 }
720 None
721 }
722
723 #[rustfmt::skip]
724 pub fn abandon_claim(&mut self, outpoint: &BitcoinOutPoint) -> bool {
725 let mut found_claim = false;
726 let claim_id = self.claimable_outpoints.get(outpoint).map(|(claim_id, _)| *claim_id)
727 .or_else(|| {
728 self.pending_claim_requests.iter()
729 .find(|(_, claim)| claim.outpoints().contains(&outpoint))
730 .map(|(claim_id, _)| *claim_id)
731 });
732 if let Some(claim_id) = claim_id {
733 if let Some(claim) = self.pending_claim_requests.remove(&claim_id) {
734 for outpoint in claim.outpoints() {
735 if self.claimable_outpoints.remove(outpoint).is_some() {
736 found_claim = true;
737 }
738 }
739 }
740 } else {
741 self.locktimed_packages.values_mut().for_each(|claims| {
742 claims.retain(|claim| {
743 let includes_outpoint = claim.outpoints().contains(&outpoint);
744 if includes_outpoint {
745 found_claim = true;
746 }
747 !includes_outpoint
748 })
749 });
750 }
751 found_claim
752 }
753
754 #[rustfmt::skip]
764 pub(super) fn update_claims_view_from_requests<B: Deref, F: Deref, L: Logger>(
765 &mut self, mut requests: Vec<PackageTemplate>, conf_height: u32, cur_height: u32,
766 broadcaster: &B, conf_target: ConfirmationTarget, destination_script: &Script,
767 fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
768 ) where
769 B::Target: BroadcasterInterface,
770 F::Target: FeeEstimator,
771 {
772 if !requests.is_empty() {
773 log_debug!(logger, "Updating claims view at height {} with {} claim requests", cur_height, requests.len());
774 }
775
776 requests.retain(|req| {
778 debug_assert_eq!(
779 req.outpoints().len(),
780 1,
781 "Claims passed to `update_claims_view_from_requests` should not be aggregated"
782 );
783 let mut all_outpoints_claiming = true;
784 for outpoint in req.outpoints() {
785 if self.claimable_outpoints.get(outpoint).is_none() {
786 all_outpoints_claiming = false;
787 }
788 }
789 if all_outpoints_claiming {
790 log_info!(logger, "Ignoring second claim for outpoint {}:{}, already registered its claiming request",
791 req.outpoints()[0].txid, req.outpoints()[0].vout);
792 false
793 } else {
794 let timelocked_equivalent_package = self.locktimed_packages.iter().map(|v| v.1.iter()).flatten()
795 .find(|locked_package| locked_package.outpoints() == req.outpoints());
796 if let Some(package) = timelocked_equivalent_package {
797 log_info!(logger, "Ignoring second claim for outpoint {}:{}, we already have one which we're waiting on a timelock at {} for.",
798 req.outpoints()[0].txid, req.outpoints()[0].vout, package.package_locktime(cur_height));
799 false
800 } else {
801 true
802 }
803 }
804 });
805
806 for i in (1..requests.len()).rev() {
808 for j in 0..i {
809 if requests[i].can_merge_with(&requests[j], cur_height) {
810 let merge = requests.remove(i);
811 if let Err(rejected) = requests[j].merge_package(merge, cur_height) {
812 debug_assert!(false, "Merging package should not be rejected after verifying can_merge_with.");
813 requests.insert(i, rejected);
814 } else {
815 break;
816 }
817 }
818 }
819 }
820
821 let mut preprocessed_requests = Vec::with_capacity(requests.len());
823 for req in requests {
824 let package_locktime = req.package_locktime(cur_height);
825 if package_locktime > cur_height {
826 log_info!(logger, "Delaying claim of package until its timelock at {} (current height {}), the following outpoints are spent:", package_locktime, cur_height);
827 for outpoint in req.outpoints() {
828 log_info!(logger, " Outpoint {}", outpoint);
829 }
830 self.locktimed_packages.entry(package_locktime).or_default().push(req);
831 } else {
832 preprocessed_requests.push(req);
833 }
834 }
835
836 let remaining_locked_packages = self.locktimed_packages.split_off(&(cur_height + 1));
838 if !self.locktimed_packages.is_empty() {
839 log_debug!(logger,
840 "Updating claims view at height {} with {} locked packages available for claim",
841 cur_height,
842 self.locktimed_packages.len());
843 }
844 for (pop_height, mut entry) in self.locktimed_packages.iter_mut() {
845 log_trace!(logger, "Restoring delayed claim of package(s) at their timelock at {}.", pop_height);
846 preprocessed_requests.append(&mut entry);
847 }
848 self.locktimed_packages = remaining_locked_packages;
849
850 for mut req in preprocessed_requests {
853 if let Some((new_timer, new_feerate, claim)) = self.generate_claim(
854 cur_height, &req, &FeerateStrategy::ForceBump, conf_target, destination_script,
855 &*fee_estimator, &*logger,
856 ) {
857 req.set_timer(new_timer);
858 req.set_feerate(new_feerate);
859 let claim_id = match claim {
863 OnchainClaim::Tx(tx) => {
864 if tx.is_fully_signed() {
865 log_info!(logger, "Broadcasting onchain {}", log_tx!(tx.0));
866 broadcaster.broadcast_transactions(&[&tx.0]);
867 } else {
868 log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", tx.0.compute_txid());
869 }
870 ClaimId(tx.0.compute_txid().to_byte_array())
871 },
872 OnchainClaim::Event(claim_event) => {
873 log_info!(logger, "Yielding onchain event to spend inputs {:?}", req.outpoints());
874 let claim_id = match claim_event {
875 ClaimEvent::BumpCommitment { ref commitment_tx, .. } =>
876 ClaimId(commitment_tx.compute_txid().to_byte_array()),
879 ClaimEvent::BumpHTLC { ref htlcs, .. } => {
880 ClaimId::from_htlcs(htlcs)
885 },
886 };
887 debug_assert!(self.pending_claim_requests.get(&claim_id).is_none());
888 debug_assert_eq!(self.pending_claim_events.iter().filter(|entry| entry.0 == claim_id).count(), 0);
889 self.pending_claim_events.push((claim_id, claim_event));
890 claim_id
891 },
892 };
893 debug_assert!(cfg!(fuzzing) || self.pending_claim_requests.get(&claim_id).is_none());
896 for (k, outpoint_confirmation_height) in req.outpoints_and_creation_heights() {
897 let creation_height = outpoint_confirmation_height.unwrap_or(conf_height);
898 log_info!(logger, "Registering claiming request for {}:{}, which exists as of height {creation_height}", k.txid, k.vout);
899 self.claimable_outpoints.insert(k.clone(), (claim_id, creation_height));
900 }
901 self.pending_claim_requests.insert(claim_id, req);
902 }
903 }
904 }
905
906 #[rustfmt::skip]
915 pub(super) fn update_claims_view_from_matched_txn<B: Deref, F: Deref, L: Logger>(
916 &mut self, txn_matched: &[&Transaction], conf_height: u32, conf_hash: BlockHash,
917 cur_height: u32, broadcaster: &B, conf_target: ConfirmationTarget,
918 destination_script: &Script, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
919 ) where
920 B::Target: BroadcasterInterface,
921 F::Target: FeeEstimator,
922 {
923 let mut have_logged_intro = false;
924 let mut maybe_log_intro = || {
925 if !have_logged_intro {
926 log_debug!(logger, "Updating claims view at height {} with {} matched transactions in block {}", cur_height, txn_matched.len(), conf_height);
927 have_logged_intro = true;
928 }
929 };
930 let mut bump_candidates = new_hash_map();
931 if !txn_matched.is_empty() { maybe_log_intro(); }
932 for tx in txn_matched {
933 let mut claimed_outputs_material = Vec::new();
935 for inp in &tx.input {
936 if let Some((claim_id, _)) = self.claimable_outpoints.get(&inp.previous_output) {
937 if let Some(request) = self.pending_claim_requests.get_mut(claim_id) {
939 let mut is_claim_subset_of_tx = true;
944 let mut tx_inputs = tx.input.iter().map(|input| &input.previous_output).collect::<Vec<_>>();
945 tx_inputs.sort_unstable();
946 for request_input in request.outpoints() {
947 if tx_inputs.binary_search(&request_input).is_err() {
948 is_claim_subset_of_tx = false;
949 break;
950 }
951 }
952
953 macro_rules! clean_claim_request_after_safety_delay {
954 () => {
955 let entry = OnchainEventEntry {
956 txid: tx.compute_txid(),
957 height: conf_height,
958 block_hash: Some(conf_hash),
959 event: OnchainEvent::Claim { claim_id: *claim_id }
960 };
961 if !self.onchain_events_awaiting_threshold_conf.contains(&entry) {
962 self.onchain_events_awaiting_threshold_conf.push(entry);
963 }
964 }
965 }
966
967 if is_claim_subset_of_tx {
971 clean_claim_request_after_safety_delay!();
972 } else { let mut at_least_one_drop = false;
974 for input in tx.input.iter() {
975 if let Some(package) = request.split_package(&input.previous_output) {
976 claimed_outputs_material.push(package);
977 at_least_one_drop = true;
978 }
979 if request.outpoints().is_empty() {
981 clean_claim_request_after_safety_delay!();
982 }
983 }
984 if at_least_one_drop {
986 bump_candidates.insert(*claim_id, request.clone());
987 #[cfg(debug_assertions)] {
994 let existing = self.pending_claim_events.iter()
995 .filter(|entry| entry.0 == *claim_id).count();
996 assert!(existing == 0 || existing == 1);
997 }
998 self.pending_claim_events.retain(|entry| entry.0 != *claim_id);
999 }
1000 }
1001 } else {
1002 panic!("Inconsistencies between pending_claim_requests map and claimable_outpoints map");
1003 }
1004 }
1005
1006 self.locktimed_packages.retain(|_locktime, packages|{
1008 packages.retain_mut(|package| {
1009 if let Some(p) = package.split_package(&inp.previous_output) {
1010 claimed_outputs_material.push(p);
1011 }
1012 !package.outpoints().is_empty()
1013 });
1014 !packages.is_empty()
1015 });
1016 }
1017 for package in claimed_outputs_material.drain(..) {
1018 let entry = OnchainEventEntry {
1019 txid: tx.compute_txid(),
1020 height: conf_height,
1021 block_hash: Some(conf_hash),
1022 event: OnchainEvent::ContentiousOutpoint { package },
1023 };
1024 if !self.onchain_events_awaiting_threshold_conf.contains(&entry) {
1025 self.onchain_events_awaiting_threshold_conf.push(entry);
1026 }
1027 }
1028 }
1029
1030 let onchain_events_awaiting_threshold_conf =
1032 self.onchain_events_awaiting_threshold_conf.drain(..).collect::<Vec<_>>();
1033 for entry in onchain_events_awaiting_threshold_conf {
1034 if entry.has_reached_confirmation_threshold(cur_height) {
1035 maybe_log_intro();
1036 match entry.event {
1037 OnchainEvent::Claim { claim_id } => {
1038 if let Some(request) = self.pending_claim_requests.remove(&claim_id) {
1041 for outpoint in request.outpoints() {
1042 log_debug!(logger, "Removing claim tracking for {} due to maturation of claim package {}.",
1043 outpoint, log_bytes!(claim_id.0));
1044 self.claimable_outpoints.remove(outpoint);
1045 }
1046 #[cfg(debug_assertions)] {
1047 let num_existing = self.pending_claim_events.iter()
1048 .filter(|entry| entry.0 == claim_id).count();
1049 assert!(num_existing == 0 || num_existing == 1);
1050 }
1051 self.pending_claim_events.retain(|(id, _)| *id != claim_id);
1052 }
1053 },
1054 OnchainEvent::ContentiousOutpoint { package } => {
1055 log_debug!(logger, "Removing claim tracking due to maturation of claim tx for outpoints:");
1056 log_debug!(logger, " {:?}", package.outpoints());
1057 self.claimable_outpoints.remove(package.outpoints()[0]);
1058 }
1059 }
1060 } else {
1061 self.onchain_events_awaiting_threshold_conf.push(entry);
1062 }
1063 }
1064
1065 for (claim_id, request) in self.pending_claim_requests.iter() {
1067 if cur_height >= request.timer() {
1068 bump_candidates.insert(*claim_id, request.clone());
1069 }
1070 }
1071
1072 if !bump_candidates.is_empty() {
1074 maybe_log_intro();
1075 log_trace!(logger, "Bumping {} candidates", bump_candidates.len());
1076 }
1077
1078 for (claim_id, request) in bump_candidates.iter() {
1079 if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(
1080 cur_height, &request, &FeerateStrategy::ForceBump, conf_target, destination_script,
1081 &*fee_estimator, &*logger,
1082 ) {
1083 match bump_claim {
1084 OnchainClaim::Tx(bump_tx) => {
1085 if bump_tx.is_fully_signed() {
1086 log_info!(logger, "Broadcasting RBF-bumped onchain {}", log_tx!(bump_tx.0));
1087 broadcaster.broadcast_transactions(&[&bump_tx.0]);
1088 } else {
1089 log_info!(logger, "Waiting for signature of RBF-bumped unsigned onchain transaction {}",
1090 bump_tx.0.compute_txid());
1091 }
1092 },
1093 OnchainClaim::Event(claim_event) => {
1094 log_info!(logger, "Yielding RBF-bumped onchain event to spend inputs {:?}", request.outpoints());
1095 #[cfg(debug_assertions)] {
1096 let num_existing = self.pending_claim_events.iter().
1097 filter(|entry| entry.0 == *claim_id).count();
1098 assert!(num_existing == 0 || num_existing == 1);
1099 }
1100 self.pending_claim_events.retain(|event| event.0 != *claim_id);
1101 self.pending_claim_events.push((*claim_id, claim_event));
1102 },
1103 }
1104 if let Some(request) = self.pending_claim_requests.get_mut(claim_id) {
1105 request.set_timer(new_timer);
1106 request.set_feerate(new_feerate);
1107 }
1108 }
1109 }
1110 }
1111
1112 #[rustfmt::skip]
1113 pub(super) fn transaction_unconfirmed<B: Deref, F: Deref, L: Logger>(
1114 &mut self,
1115 txid: &Txid,
1116 broadcaster: &B,
1117 conf_target: ConfirmationTarget,
1118 destination_script: &Script,
1119 fee_estimator: &LowerBoundedFeeEstimator<F>,
1120 logger: &L,
1121 ) where
1122 B::Target: BroadcasterInterface,
1123 F::Target: FeeEstimator,
1124 {
1125 let mut height = None;
1126 for entry in self.onchain_events_awaiting_threshold_conf.iter() {
1127 if entry.txid == *txid {
1128 height = Some(entry.height);
1129 break;
1130 }
1131 }
1132
1133 if let Some(height) = height {
1134 self.blocks_disconnected(
1135 height - 1, broadcaster, conf_target, destination_script, fee_estimator, logger,
1136 );
1137 }
1138 }
1139
1140 #[rustfmt::skip]
1141 pub(super) fn blocks_disconnected<B: Deref, F: Deref, L: Logger>(
1142 &mut self, new_best_height: u32, broadcaster: &B, conf_target: ConfirmationTarget,
1143 destination_script: &Script, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
1144 )
1145 where B::Target: BroadcasterInterface,
1146 F::Target: FeeEstimator,
1147 {
1148 let mut bump_candidates = new_hash_map();
1149 let onchain_events_awaiting_threshold_conf =
1150 self.onchain_events_awaiting_threshold_conf.drain(..).collect::<Vec<_>>();
1151 for entry in onchain_events_awaiting_threshold_conf {
1152 if entry.height > new_best_height {
1153 match entry.event {
1156 OnchainEvent::ContentiousOutpoint { package } => {
1157 let package_locktime = package.package_locktime(0);
1159 if package_locktime > new_best_height {
1160 self.locktimed_packages.entry(package_locktime).or_default().push(package);
1161 continue;
1162 }
1163
1164 if let Some(pending_claim) = self.claimable_outpoints.get(package.outpoints()[0]) {
1165 if let Some(request) = self.pending_claim_requests.get_mut(&pending_claim.0) {
1166 assert!(request.merge_package(package, new_best_height + 1).is_ok());
1167 bump_candidates.insert(pending_claim.clone(), request.clone());
1170 }
1171 }
1172 },
1173 _ => {},
1174 }
1175 } else {
1176 self.onchain_events_awaiting_threshold_conf.push(entry);
1177 }
1178 }
1179 for ((_claim_id, _), ref mut request) in bump_candidates.iter_mut() {
1180 if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(
1181 new_best_height, &request, &FeerateStrategy::ForceBump, conf_target,
1182 destination_script, fee_estimator, logger
1183 ) {
1184 request.set_timer(new_timer);
1185 request.set_feerate(new_feerate);
1186 match bump_claim {
1187 OnchainClaim::Tx(bump_tx) => {
1188 if bump_tx.is_fully_signed() {
1189 log_info!(logger, "Broadcasting onchain {}", log_tx!(bump_tx.0));
1190 broadcaster.broadcast_transactions(&[&bump_tx.0]);
1191 } else {
1192 log_info!(logger, "Waiting for signature of unsigned onchain transaction {}", bump_tx.0.compute_txid());
1193 }
1194 },
1195 OnchainClaim::Event(claim_event) => {
1196 log_info!(logger, "Yielding onchain event after reorg to spend inputs {:?}", request.outpoints());
1197 #[cfg(debug_assertions)] {
1198 let num_existing = self.pending_claim_events.iter()
1199 .filter(|entry| entry.0 == *_claim_id).count();
1200 assert!(num_existing == 0 || num_existing == 1);
1201 }
1202 self.pending_claim_events.retain(|event| event.0 != *_claim_id);
1203 self.pending_claim_events.push((*_claim_id, claim_event));
1204 },
1205 }
1206 }
1207 }
1208 for (ancestor_claim_txid, request) in bump_candidates.drain() {
1209 self.pending_claim_requests.insert(ancestor_claim_txid.0, request);
1210 }
1211 let mut remove_request = Vec::new();
1214 self.claimable_outpoints.retain(|_, ref v|
1215 if v.1 > new_best_height {
1216 remove_request.push(v.0.clone());
1217 false
1218 } else { true });
1219 for req in remove_request {
1220 self.pending_claim_requests.remove(&req);
1221 }
1222 }
1223
1224 pub(crate) fn is_output_spend_pending(&self, outpoint: &BitcoinOutPoint) -> bool {
1225 self.claimable_outpoints.get(outpoint).is_some()
1226 }
1227
1228 #[rustfmt::skip]
1229 pub(crate) fn get_relevant_txids(&self) -> Vec<(Txid, u32, Option<BlockHash>)> {
1230 let mut txids: Vec<(Txid, u32, Option<BlockHash>)> = self.onchain_events_awaiting_threshold_conf
1231 .iter()
1232 .map(|entry| (entry.txid, entry.height, entry.block_hash))
1233 .collect();
1234 txids.sort_unstable_by(|a, b| a.0.cmp(&b.0).then(b.1.cmp(&a.1)));
1235 txids.dedup_by_key(|(txid, _, _)| *txid);
1236 txids
1237 }
1238
1239 pub(crate) fn provide_latest_holder_tx(&mut self, tx: HolderCommitmentTransaction) {
1240 self.prev_holder_commitment = Some(replace(&mut self.holder_commitment, tx));
1241 }
1242
1243 pub(crate) fn update_after_renegotiated_funding_locked(
1246 &mut self, channel_parameters: ChannelTransactionParameters,
1247 current: HolderCommitmentTransaction, prev: Option<HolderCommitmentTransaction>,
1248 ) {
1249 self.channel_value_satoshis = channel_parameters.channel_value_satoshis;
1250 self.channel_transaction_parameters = channel_parameters;
1251 self.holder_commitment = current;
1252 self.prev_holder_commitment = prev;
1253 }
1254
1255 pub(crate) fn channel_parameters(&self) -> &ChannelTransactionParameters {
1257 &self.channel_transaction_parameters
1258 }
1259
1260 pub(crate) fn channel_keys_id(&self) -> [u8; 32] {
1262 self.channel_keys_id
1263 }
1264}
1265
1266#[cfg(test)]
1267mod tests {
1268 use bitcoin::hash_types::Txid;
1269 use bitcoin::hashes::sha256::Hash as Sha256;
1270 use bitcoin::hashes::Hash;
1271 use bitcoin::Network;
1272 use bitcoin::{key::Secp256k1, secp256k1::PublicKey, secp256k1::SecretKey, ScriptBuf};
1273 use types::features::ChannelTypeFeatures;
1274
1275 use crate::chain::chaininterface::{ConfirmationTarget, LowerBoundedFeeEstimator};
1276 use crate::chain::package::{HolderHTLCOutput, PackageSolvingData, PackageTemplate};
1277 use crate::chain::transaction::OutPoint;
1278 use crate::ln::chan_utils::{
1279 ChannelPublicKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters,
1280 HTLCOutputInCommitment, HolderCommitmentTransaction,
1281 };
1282 use crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint};
1283 use crate::ln::functional_test_utils::create_dummy_block;
1284 use crate::sign::{ChannelDerivationParameters, ChannelSigner, HTLCDescriptor, InMemorySigner};
1285 use crate::types::payment::{PaymentHash, PaymentPreimage};
1286 use crate::util::test_utils::{TestBroadcaster, TestFeeEstimator, TestLogger};
1287
1288 use super::OnchainTxHandler;
1289
1290 #[test]
1294 #[rustfmt::skip]
1295 fn test_broadcast_height() {
1296 let secp_ctx = Secp256k1::new();
1297 let signer = InMemorySigner::new(
1298 SecretKey::from_slice(&[41; 32]).unwrap(),
1299 SecretKey::from_slice(&[41; 32]).unwrap(),
1300 SecretKey::from_slice(&[41; 32]).unwrap(),
1301 SecretKey::from_slice(&[41; 32]).unwrap(),
1302 true,
1303 SecretKey::from_slice(&[41; 32]).unwrap(),
1304 SecretKey::from_slice(&[41; 32]).unwrap(),
1305 [41; 32],
1306 [0; 32],
1307 [0; 32],
1308 );
1309 let counterparty_pubkeys = ChannelPublicKeys {
1310 funding_pubkey: PublicKey::from_secret_key(
1311 &secp_ctx,
1312 &SecretKey::from_slice(&[44; 32]).unwrap(),
1313 ),
1314 revocation_basepoint: RevocationBasepoint::from(PublicKey::from_secret_key(
1315 &secp_ctx,
1316 &SecretKey::from_slice(&[45; 32]).unwrap(),
1317 )),
1318 payment_point: PublicKey::from_secret_key(
1319 &secp_ctx,
1320 &SecretKey::from_slice(&[46; 32]).unwrap(),
1321 ),
1322 delayed_payment_basepoint: DelayedPaymentBasepoint::from(PublicKey::from_secret_key(
1323 &secp_ctx,
1324 &SecretKey::from_slice(&[47; 32]).unwrap(),
1325 )),
1326 htlc_basepoint: HtlcBasepoint::from(PublicKey::from_secret_key(
1327 &secp_ctx,
1328 &SecretKey::from_slice(&[48; 32]).unwrap(),
1329 )),
1330 };
1331 let funding_outpoint = OutPoint { txid: Txid::all_zeros(), index: u16::MAX };
1332
1333 let chan_params = ChannelTransactionParameters {
1336 holder_pubkeys: signer.pubkeys(&secp_ctx),
1337 holder_selected_contest_delay: 66,
1338 is_outbound_from_holder: true,
1339 counterparty_parameters: Some(CounterpartyChannelTransactionParameters {
1340 pubkeys: counterparty_pubkeys,
1341 selected_contest_delay: 67,
1342 }),
1343 funding_outpoint: Some(funding_outpoint),
1344 splice_parent_funding_txid: None,
1345 channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
1346 channel_value_satoshis: 0,
1347 };
1348
1349 let mut nondust_htlcs = Vec::new();
1352 for i in 0..3 {
1353 let preimage = PaymentPreimage([i; 32]);
1354 let hash = PaymentHash(Sha256::hash(&preimage.0[..]).to_byte_array());
1355 nondust_htlcs.push(
1356 HTLCOutputInCommitment {
1357 offered: true,
1358 amount_msat: 10000,
1359 cltv_expiry: i as u32,
1360 payment_hash: hash,
1361 transaction_output_index: Some(i as u32),
1362 }
1363 );
1364 }
1365 let holder_commit = HolderCommitmentTransaction::dummy(1000000, funding_outpoint, nondust_htlcs);
1366 let destination_script = ScriptBuf::new();
1367 let mut tx_handler = OnchainTxHandler::new(
1368 1000000,
1369 [0; 32],
1370 destination_script.clone(),
1371 signer,
1372 chan_params,
1373 holder_commit,
1374 secp_ctx,
1375 );
1376
1377 let broadcaster = TestBroadcaster::new(Network::Testnet);
1379 {
1380 let mut blocks = broadcaster.blocks.lock().unwrap();
1381 let genesis_hash = blocks[0].0.block_hash();
1382 blocks.push((create_dummy_block(genesis_hash, 0, Vec::new()), 1));
1383 }
1384
1385 let fee_estimator = TestFeeEstimator::new(253);
1386 let fee_estimator = LowerBoundedFeeEstimator::new(&fee_estimator);
1387 let logger = TestLogger::new();
1388
1389 let holder_commit = tx_handler.current_holder_commitment_tx();
1391 let holder_commit_txid = holder_commit.trust().txid();
1392 let mut requests = Vec::new();
1393 for (htlc, counterparty_sig) in holder_commit.nondust_htlcs().iter().zip(holder_commit.counterparty_htlc_sigs.iter()) {
1394 requests.push(PackageTemplate::build_package(
1395 holder_commit_txid,
1396 htlc.transaction_output_index.unwrap(),
1397 PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build(HTLCDescriptor {
1398 channel_derivation_parameters: ChannelDerivationParameters {
1399 value_satoshis: tx_handler.channel_value_satoshis,
1400 keys_id: tx_handler.channel_keys_id,
1401 transaction_parameters: tx_handler.channel_transaction_parameters.clone(),
1402 },
1403 commitment_txid: holder_commit_txid,
1404 per_commitment_number: holder_commit.commitment_number(),
1405 per_commitment_point: holder_commit.per_commitment_point(),
1406 feerate_per_kw: holder_commit.negotiated_feerate_per_kw(),
1407 htlc: htlc.clone(),
1408 preimage: None,
1409 counterparty_sig: *counterparty_sig,
1410 },
1411 0
1412 )),
1413 0,
1414 ));
1415 }
1416 tx_handler.update_claims_view_from_requests(
1417 requests,
1418 1,
1419 1,
1420 &&broadcaster,
1421 ConfirmationTarget::UrgentOnChainSweep,
1422 &destination_script,
1423 &fee_estimator,
1424 &logger,
1425 );
1426
1427 let txs_broadcasted = broadcaster.txn_broadcast();
1430 assert_eq!(txs_broadcasted.len(), 2);
1431 assert!(txs_broadcasted[0].lock_time.to_consensus_u32() <= 1);
1432 assert!(txs_broadcasted[1].lock_time.to_consensus_u32() <= 1);
1433
1434 {
1436 let mut blocks = broadcaster.blocks.lock().unwrap();
1437 let block1_hash = blocks[1].0.block_hash();
1438 blocks.push((create_dummy_block(block1_hash, 0, Vec::new()), 2));
1439 }
1440 tx_handler.update_claims_view_from_requests(
1441 Vec::new(),
1442 2,
1443 2,
1444 &&broadcaster,
1445 ConfirmationTarget::UrgentOnChainSweep,
1446 &destination_script,
1447 &fee_estimator,
1448 &logger,
1449 );
1450
1451 let txs_broadcasted = broadcaster.txn_broadcast();
1453 assert_eq!(txs_broadcasted.len(), 1);
1454 assert_eq!(txs_broadcasted[0].lock_time.to_consensus_u32(), 2);
1455 }
1456}