Skip to content

Commit 626a612

Browse files
committed
Yield channel close bump events
1 parent 94d4e3a commit 626a612

File tree

4 files changed

+175
-14
lines changed

4 files changed

+175
-14
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
//! ChannelMonitors to get out of the HSM and onto monitoring devices.
2222
2323
use bitcoin::blockdata::block::BlockHeader;
24-
use bitcoin::blockdata::transaction::{TxOut,Transaction};
25-
use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
24+
use bitcoin::blockdata::transaction::{OutPoint as BitcoinOutPoint, TxOut, Transaction};
2625
use bitcoin::blockdata::script::{Script, Builder};
2726
use bitcoin::blockdata::opcodes;
2827

@@ -44,13 +43,17 @@ use chain::{BestBlock, WatchedOutput};
4443
use chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
4544
use chain::transaction::{OutPoint, TransactionData};
4645
use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface};
46+
#[cfg(test)] // TODO: remove-on-anchors-release
47+
use chain::onchaintx::ClaimEvent;
4748
use chain::onchaintx::OnchainTxHandler;
4849
use chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput};
4950
use chain::Filter;
5051
use util::logger::Logger;
5152
use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48, OptionDeserWrapper};
5253
use util::byte_utils;
5354
use util::events::Event;
55+
#[cfg(test)] // TODO: remove-on-anchors-release
56+
use util::events::{AnchorDescriptor, BumpTransactionEvent};
5457

5558
use prelude::*;
5659
use core::{cmp, mem};
@@ -1219,7 +1222,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
12191222
B::Target: BroadcasterInterface,
12201223
L::Target: Logger,
12211224
{
1222-
self.inner.lock().unwrap().broadcast_latest_holder_commitment_txn(broadcaster, logger)
1225+
self.inner.lock().unwrap().broadcast_latest_holder_commitment_txn(broadcaster, logger);
12231226
}
12241227

12251228
/// Updates a ChannelMonitor on the basis of some new information provided by the Channel
@@ -2214,6 +2217,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
22142217
panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
22152218
}
22162219
let mut ret = Ok(());
2220+
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&*fee_estimator);
22172221
for update in updates.updates.iter() {
22182222
match update {
22192223
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs } => {
@@ -2231,7 +2235,6 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
22312235
},
22322236
ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage } => {
22332237
log_trace!(logger, "Updating ChannelMonitor with payment preimage");
2234-
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&*fee_estimator);
22352238
self.provide_payment_preimage(&PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()), &payment_preimage, broadcaster, &bounded_fee_estimator, logger)
22362239
},
22372240
ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } => {
@@ -2247,6 +2250,25 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
22472250
self.lockdown_from_offchain = true;
22482251
if *should_broadcast {
22492252
self.broadcast_latest_holder_commitment_txn(broadcaster, logger);
2253+
// If the channel supports anchor outputs, we'll need to emit an external
2254+
// event to be consumed such that a child transaction is broadcast with a
2255+
// high enough feerate for the parent commitment transaction to confirm.
2256+
if self.onchain_tx_handler.opt_anchors() {
2257+
let funding_output = HolderFundingOutput::build(
2258+
self.funding_redeemscript.clone(), self.channel_value_satoshis,
2259+
self.onchain_tx_handler.opt_anchors(),
2260+
);
2261+
let best_block_height = self.best_block.height();
2262+
let commitment_package = PackageTemplate::build_package(
2263+
self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
2264+
PackageSolvingData::HolderFundingOutput(funding_output),
2265+
best_block_height, false, best_block_height,
2266+
);
2267+
self.onchain_tx_handler.update_claims_view(
2268+
&[], vec![commitment_package], best_block_height, best_block_height,
2269+
broadcaster, &bounded_fee_estimator, logger,
2270+
);
2271+
}
22502272
} else if !self.holder_tx_signed {
22512273
log_error!(logger, "You have a toxic holder commitment transaction avaible in channel monitor, read comment in ChannelMonitor::get_latest_holder_commitment_txn to be informed of manual action to take");
22522274
} else {
@@ -2299,6 +2321,39 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
22992321
pub fn get_and_clear_pending_events(&mut self) -> Vec<Event> {
23002322
let mut ret = Vec::new();
23012323
mem::swap(&mut ret, &mut self.pending_events);
2324+
#[cfg(test)] // TODO: remove-on-anchors-release
2325+
for claim_event in self.onchain_tx_handler.get_and_clear_pending_claim_events().drain(..) {
2326+
match claim_event {
2327+
ClaimEvent::BumpCommitment {
2328+
package_target_feerate_sat_per_1000_weight, commitment_tx, anchor_output_idx,
2329+
} => {
2330+
let commitment_txid = commitment_tx.txid();
2331+
debug_assert_eq!(self.current_holder_commitment_tx.txid, commitment_txid);
2332+
let pending_htlcs = self.current_holder_commitment_tx.htlc_outputs.iter()
2333+
.filter_map(|(htlc, _, _)| {
2334+
if let Some(_) = htlc.transaction_output_index {
2335+
Some(htlc.clone())
2336+
} else {
2337+
None
2338+
}
2339+
})
2340+
.collect();
2341+
ret.push(Event::BumpTransaction(BumpTransactionEvent::ChannelClose {
2342+
package_target_feerate_sat_per_1000_weight,
2343+
commitment_tx,
2344+
anchor_descriptor: AnchorDescriptor {
2345+
channel_keys_id: self.channel_keys_id,
2346+
channel_value_satoshis: self.channel_value_satoshis,
2347+
outpoint: BitcoinOutPoint {
2348+
txid: commitment_txid,
2349+
vout: anchor_output_idx,
2350+
},
2351+
},
2352+
pending_htlcs,
2353+
}));
2354+
},
2355+
}
2356+
}
23022357
ret
23032358
}
23042359

@@ -2880,15 +2935,20 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
28802935
self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
28812936
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
28822937
self.holder_tx_signed = true;
2883-
// Because we're broadcasting a commitment transaction, we should construct the package
2884-
// assuming it gets confirmed in the next block. Sadly, we have code which considers
2885-
// "not yet confirmed" things as discardable, so we cannot do that here.
2886-
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
2887-
let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
2888-
if !new_outputs.is_empty() {
2889-
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
2938+
// We can't broadcast our HTLC transactions while the commitment transaction is
2939+
// unconfirmed. We'll delay doing so until we detect the confirmed commitment in
2940+
// `transactions_confirmed`.
2941+
if !self.onchain_tx_handler.opt_anchors() {
2942+
// Because we're broadcasting a commitment transaction, we should construct the package
2943+
// assuming it gets confirmed in the next block. Sadly, we have code which considers
2944+
// "not yet confirmed" things as discardable, so we cannot do that here.
2945+
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
2946+
let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
2947+
if !new_outputs.is_empty() {
2948+
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
2949+
}
2950+
claimable_outpoints.append(&mut new_outpoints);
28902951
}
2891-
claimable_outpoints.append(&mut new_outpoints);
28922952
}
28932953

28942954
// Find which on-chain events have reached their confirmation threshold.

lightning/src/chain/onchaintx.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ use alloc::collections::BTreeMap;
3939
use core::cmp;
4040
use core::ops::Deref;
4141
use core::mem::replace;
42+
#[cfg(test)] // TODO: remove-on-anchors-release
43+
use core::mem::swap;
4244
use bitcoin::hashes::Hash;
4345

4446
const MAX_ALLOC_SIZE: usize = 64*1024;
@@ -400,6 +402,13 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
400402
self.holder_commitment.to_broadcaster_value_sat()
401403
}
402404

405+
#[cfg(test)] // TODO: remove-on-anchors-release
406+
pub(crate) fn get_and_clear_pending_claim_events(&mut self) -> Vec<ClaimEvent> {
407+
let mut ret = HashMap::new();
408+
swap(&mut ret, &mut self.pending_claim_events);
409+
ret.into_iter().map(|(_, event)| event).collect::<Vec<_>>()
410+
}
411+
403412
/// Lightning security model (i.e being able to redeem/timeout HTLC or penalize counterparty
404413
/// onchain) lays on the assumption of claim transactions getting confirmed before timelock
405414
/// expiration (CSV or CLTV following cases). In case of high-fee spikes, claim tx may get stuck

lightning/src/ln/chan_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, contest_delay: u1
525525
res
526526
}
527527

528-
#[derive(Clone, PartialEq)]
528+
#[derive(Clone, Debug, PartialEq)]
529529
/// Information about an HTLC as it appears in a commitment transaction
530530
pub struct HTLCOutputInCommitment {
531531
/// Whether the HTLC was "offered" (ie outbound in relation to this commitment transaction).

lightning/src/util/events.rs

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//! few other things.
1616
1717
use chain::keysinterface::SpendableOutputDescriptor;
18+
use ln::chan_utils::HTLCOutputInCommitment;
1819
use ln::channelmanager::PaymentId;
1920
use ln::channel::FUNDING_CONF_DEADLINE_BLOCKS;
2021
use ln::features::ChannelTypeFeatures;
@@ -25,7 +26,7 @@ use routing::gossip::NetworkUpdate;
2526
use util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper};
2627
use routing::router::{RouteHop, RouteParameters};
2728

28-
use bitcoin::{PackedLockTime, Transaction};
29+
use bitcoin::{PackedLockTime, Transaction, OutPoint};
2930
use bitcoin::blockdata::script::Script;
3031
use bitcoin::hashes::Hash;
3132
use bitcoin::hashes::sha256::Hash as Sha256;
@@ -196,6 +197,81 @@ impl_writeable_tlv_based_enum_upgradable!(HTLCDestination,
196197
}
197198
);
198199

200+
/// A descriptor used to sign for a commitment transaction's anchor output.
201+
#[derive(Clone, Debug)]
202+
pub struct AnchorDescriptor {
203+
/// A unique identifier used along with `channel_value_satoshis` to re-derive the
204+
/// [`InMemorySigner`] required to sign `input`.
205+
///
206+
/// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
207+
pub channel_keys_id: [u8; 32],
208+
/// The value in satoshis of the channel we're attempting to spend the anchor output of. This is
209+
/// used along with `channel_keys_id` to re-derive the [`InMemorySigner`] required to sign
210+
/// `input`.
211+
///
212+
/// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
213+
pub channel_value_satoshis: u64,
214+
/// The transaction input's outpoint corresponding to the commitment transaction's anchor
215+
/// output.
216+
pub outpoint: OutPoint,
217+
}
218+
219+
/// Represents the different types of transactions, originating from LDK, to be bumped.
220+
#[derive(Clone, Debug)]
221+
pub enum BumpTransactionEvent {
222+
/// Indicates that a channel featuring anchor outputs is to be closed by broadcasting the local
223+
/// commitment transaction. Since commitment transactions have a static feerate pre-agreed upon,
224+
/// they may need additional fees to be attached through a child transaction using the popular
225+
/// [Child-Pays-For-Parent](https://bitcoinops.org/en/topics/cpfp) fee bumping technique. This
226+
/// child transaction must include the anchor input described within `anchor_descriptor` along
227+
/// with additional inputs to meet the target feerate. Failure to meet the target feerate
228+
/// decreases the confirmation odds of the transaction package (which includes the commitment
229+
/// and child anchor transactions), possibly resulting in a loss of funds. Once the transaction
230+
/// is constructed, it must be fully signed for and broadcasted by the consumer of the event
231+
/// along with the `commitment_tx` enclosed. Note that the `commitment_tx` must always be
232+
/// broadcast first, as the child anchor transaction depends on it.
233+
///
234+
/// The consumer should be able to sign for any of the additional inputs included within the
235+
/// child anchor transaction. To sign its anchor input, an [`InMemorySigner`] should be
236+
/// re-derived through [`KeysManager::derive_channel_keys`] with the help of
237+
/// [`AnchorDescriptor::channel_keys_id`] and [`AnchorDescriptor::channel_value_satoshis`].
238+
///
239+
/// It is possible to receive more than one instance of this event if a valid child anchor
240+
/// transaction is never broadcast or is but not with a sufficient fee to be mined. Care should
241+
/// be taken by the consumer of the event to ensure any future iterations of the child anchor
242+
/// transaction adhere to the [Replace-By-Fee
243+
/// rules](https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md)
244+
/// for fee bumps to be accepted into the mempool, and eventually the chain. As the frequency of
245+
/// these events is not user-controlled, users may ignore/drop the event if they are no longer
246+
/// able to commit external confirmed funds to the child anchor transaction.
247+
///
248+
/// The set of `pending_htlcs` on the commitment transaction to be broadcast can be inspected to
249+
/// determine whether a significant portion of the channel's funds are allocated to HTLCs,
250+
/// enabling users to make their own decisions regarding the importance of the commitment
251+
/// transaction's confirmation. Note that this is not required, but simply exists as an option
252+
/// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
253+
/// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
254+
/// be not urgent.
255+
///
256+
/// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
257+
/// [`KeysManager::derive_channel_keys`]: crate::chain::keysinterface::KeysManager::derive_channel_keys
258+
ChannelClose {
259+
/// The target feerate that the transaction package, which consists of the commitment
260+
/// transaction and the to-be-crafted child anchor transaction, must meet.
261+
package_target_feerate_sat_per_1000_weight: u32,
262+
/// The channel's commitment transaction to bump the fee of. This transaction should be
263+
/// broadcast along with the anchor transaction constructed as a result of consuming this
264+
/// event.
265+
commitment_tx: Transaction,
266+
/// The descriptor to sign the anchor input of the anchor transaction constructed as a
267+
/// result of consuming this event.
268+
anchor_descriptor: AnchorDescriptor,
269+
/// The set of pending HTLCs on the commitment transaction that need to be resolved once the
270+
/// commitment transaction confirms.
271+
pending_htlcs: Vec<HTLCOutputInCommitment>,
272+
},
273+
}
274+
199275
/// An Event which you should probably take some action in response to.
200276
///
201277
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use
@@ -602,6 +678,13 @@ pub enum Event {
602678
/// Destination of the HTLC that failed to be processed.
603679
failed_next_destination: HTLCDestination,
604680
},
681+
/// Indicates that a transaction originating from LDK needs to have its fee bumped. This event
682+
/// requires confirmed external funds to be readily available to spend.
683+
///
684+
/// LDK does not currently generate this event. It is limited to the scope of channels with
685+
/// anchor outputs, which will be introduced in a future release.
686+
#[cfg(test)] // TODO: remove-on-anchors-release
687+
BumpTransaction(BumpTransactionEvent),
605688
}
606689

607690
impl Writeable for Event {
@@ -753,6 +836,15 @@ impl Writeable for Event {
753836
(2, failed_next_destination, required),
754837
})
755838
},
839+
#[cfg(test)] // TODO: remove-on-anchors-release
840+
&Event::BumpTransaction(ref event)=> {
841+
27u8.write(writer)?;
842+
match event {
843+
// We never write the ChannelClose events as they'll be replayed upon restarting
844+
// anyway if the commitment transaction remains unconfirmed.
845+
BumpTransactionEvent::ChannelClose { .. } => {}
846+
}
847+
}
756848
// Note that, going forward, all new events must only write data inside of
757849
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
758850
// data via `write_tlv_fields`.

0 commit comments

Comments
 (0)