//! ChannelMonitors to get out of the HSM and onto monitoring devices.
use bitcoin::blockdata::block::BlockHeader;
-use bitcoin::blockdata::transaction::{TxOut,Transaction};
-use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
+use bitcoin::blockdata::transaction::{OutPoint as BitcoinOutPoint, TxOut, Transaction};
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::opcodes;
use chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator};
use chain::transaction::{OutPoint, TransactionData};
use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface};
+#[cfg(anchors)]
+use chain::onchaintx::ClaimEvent;
use chain::onchaintx::OnchainTxHandler;
use chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput};
use chain::Filter;
use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48, OptionDeserWrapper};
use util::byte_utils;
use util::events::Event;
+#[cfg(anchors)]
+use util::events::{AnchorDescriptor, BumpTransactionEvent};
use prelude::*;
use core::{cmp, mem};
(14, htlc_outputs, vec_type)
});
+#[cfg(anchors)]
+impl HolderSignedTx {
+ fn non_dust_htlcs(&self) -> Vec<HTLCOutputInCommitment> {
+ self.htlc_outputs.iter().filter_map(|(htlc, _, _)| {
+ if let Some(_) = htlc.transaction_output_index {
+ Some(htlc.clone())
+ } else {
+ None
+ }
+ })
+ .collect()
+ }
+}
+
/// We use this to track static counterparty commitment transaction data and to generate any
/// justice or 2nd-stage preimage/timeout transactions.
#[derive(PartialEq, Eq)]
B::Target: BroadcasterInterface,
L::Target: Logger,
{
- self.inner.lock().unwrap().broadcast_latest_holder_commitment_txn(broadcaster, logger)
+ self.inner.lock().unwrap().broadcast_latest_holder_commitment_txn(broadcaster, logger);
}
/// Updates a ChannelMonitor on the basis of some new information provided by the Channel
panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
}
let mut ret = Ok(());
+ let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&*fee_estimator);
for update in updates.updates.iter() {
match update {
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs } => {
},
ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage } => {
log_trace!(logger, "Updating ChannelMonitor with payment preimage");
- let bounded_fee_estimator = LowerBoundedFeeEstimator::new(&*fee_estimator);
self.provide_payment_preimage(&PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()), &payment_preimage, broadcaster, &bounded_fee_estimator, logger)
},
ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } => {
self.lockdown_from_offchain = true;
if *should_broadcast {
self.broadcast_latest_holder_commitment_txn(broadcaster, logger);
+ // If the channel supports anchor outputs, we'll need to emit an external
+ // event to be consumed such that a child transaction is broadcast with a
+ // high enough feerate for the parent commitment transaction to confirm.
+ if self.onchain_tx_handler.opt_anchors() {
+ let funding_output = HolderFundingOutput::build(
+ self.funding_redeemscript.clone(), self.channel_value_satoshis,
+ self.onchain_tx_handler.opt_anchors(),
+ );
+ let best_block_height = self.best_block.height();
+ let commitment_package = PackageTemplate::build_package(
+ self.funding_info.0.txid.clone(), self.funding_info.0.index as u32,
+ PackageSolvingData::HolderFundingOutput(funding_output),
+ best_block_height, false, best_block_height,
+ );
+ self.onchain_tx_handler.update_claims_view(
+ &[], vec![commitment_package], best_block_height, best_block_height,
+ broadcaster, &bounded_fee_estimator, logger,
+ );
+ }
} else if !self.holder_tx_signed {
log_error!(logger, "WARNING: You have a potentially-unsafe holder commitment transaction available to broadcast");
log_error!(logger, " in channel monitor for channel {}!", log_bytes!(self.funding_info.0.to_channel_id()));
pub fn get_and_clear_pending_events(&mut self) -> Vec<Event> {
let mut ret = Vec::new();
mem::swap(&mut ret, &mut self.pending_events);
+ #[cfg(anchors)]
+ for claim_event in self.onchain_tx_handler.get_and_clear_pending_claim_events().drain(..) {
+ match claim_event {
+ ClaimEvent::BumpCommitment {
+ package_target_feerate_sat_per_1000_weight, commitment_tx, anchor_output_idx,
+ } => {
+ let commitment_txid = commitment_tx.txid();
+ debug_assert_eq!(self.current_holder_commitment_tx.txid, commitment_txid);
+ let pending_htlcs = self.current_holder_commitment_tx.non_dust_htlcs();
+ let commitment_tx_fee_satoshis = self.channel_value_satoshis -
+ commitment_tx.output.iter().fold(0u64, |sum, output| sum + output.value);
+ ret.push(Event::BumpTransaction(BumpTransactionEvent::ChannelClose {
+ package_target_feerate_sat_per_1000_weight,
+ commitment_tx,
+ commitment_tx_fee_satoshis,
+ anchor_descriptor: AnchorDescriptor {
+ channel_keys_id: self.channel_keys_id,
+ channel_value_satoshis: self.channel_value_satoshis,
+ outpoint: BitcoinOutPoint {
+ txid: commitment_txid,
+ vout: anchor_output_idx,
+ },
+ },
+ pending_htlcs,
+ }));
+ },
+ }
+ }
ret
}
self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
self.holder_tx_signed = true;
- // Because we're broadcasting a commitment transaction, we should construct the package
- // assuming it gets confirmed in the next block. Sadly, we have code which considers
- // "not yet confirmed" things as discardable, so we cannot do that here.
- let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
- let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
- if !new_outputs.is_empty() {
- watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
+ // We can't broadcast our HTLC transactions while the commitment transaction is
+ // unconfirmed. We'll delay doing so until we detect the confirmed commitment in
+ // `transactions_confirmed`.
+ if !self.onchain_tx_handler.opt_anchors() {
+ // Because we're broadcasting a commitment transaction, we should construct the package
+ // assuming it gets confirmed in the next block. Sadly, we have code which considers
+ // "not yet confirmed" things as discardable, so we cannot do that here.
+ let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
+ let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
+ if !new_outputs.is_empty() {
+ watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
+ }
+ claimable_outpoints.append(&mut new_outpoints);
}
- claimable_outpoints.append(&mut new_outpoints);
}
// Find which on-chain events have reached their confirmation threshold.
//! few other things.
use chain::keysinterface::SpendableOutputDescriptor;
+use ln::chan_utils::HTLCOutputInCommitment;
use ln::channelmanager::PaymentId;
use ln::channel::FUNDING_CONF_DEADLINE_BLOCKS;
use ln::features::ChannelTypeFeatures;
use util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper};
use routing::router::{RouteHop, RouteParameters};
-use bitcoin::{PackedLockTime, Transaction};
+use bitcoin::{PackedLockTime, Transaction, OutPoint};
use bitcoin::blockdata::script::Script;
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256::Hash as Sha256;
}
);
+/// A descriptor used to sign for a commitment transaction's anchor output.
+#[derive(Clone, Debug)]
+pub struct AnchorDescriptor {
+ /// A unique identifier used along with `channel_value_satoshis` to re-derive the
+ /// [`InMemorySigner`] required to sign `input`.
+ ///
+ /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
+ pub channel_keys_id: [u8; 32],
+ /// The value in satoshis of the channel we're attempting to spend the anchor output of. This is
+ /// used along with `channel_keys_id` to re-derive the [`InMemorySigner`] required to sign
+ /// `input`.
+ ///
+ /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
+ pub channel_value_satoshis: u64,
+ /// The transaction input's outpoint corresponding to the commitment transaction's anchor
+ /// output.
+ pub outpoint: OutPoint,
+}
+
+/// Represents the different types of transactions, originating from LDK, to be bumped.
+#[derive(Clone, Debug)]
+pub enum BumpTransactionEvent {
+ /// Indicates that a channel featuring anchor outputs is to be closed by broadcasting the local
+ /// commitment transaction. Since commitment transactions have a static feerate pre-agreed upon,
+ /// they may need additional fees to be attached through a child transaction using the popular
+ /// [Child-Pays-For-Parent](https://bitcoinops.org/en/topics/cpfp) fee bumping technique. This
+ /// child transaction must include the anchor input described within `anchor_descriptor` along
+ /// with additional inputs to meet the target feerate. Failure to meet the target feerate
+ /// decreases the confirmation odds of the transaction package (which includes the commitment
+ /// and child anchor transactions), possibly resulting in a loss of funds. Once the transaction
+ /// is constructed, it must be fully signed for and broadcasted by the consumer of the event
+ /// along with the `commitment_tx` enclosed. Note that the `commitment_tx` must always be
+ /// broadcast first, as the child anchor transaction depends on it.
+ ///
+ /// The consumer should be able to sign for any of the additional inputs included within the
+ /// child anchor transaction. To sign its anchor input, an [`InMemorySigner`] should be
+ /// re-derived through [`KeysManager::derive_channel_keys`] with the help of
+ /// [`AnchorDescriptor::channel_keys_id`] and [`AnchorDescriptor::channel_value_satoshis`].
+ ///
+ /// It is possible to receive more than one instance of this event if a valid child anchor
+ /// transaction is never broadcast or is but not with a sufficient fee to be mined. Care should
+ /// be taken by the consumer of the event to ensure any future iterations of the child anchor
+ /// transaction adhere to the [Replace-By-Fee
+ /// rules](https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md)
+ /// for fee bumps to be accepted into the mempool, and eventually the chain. As the frequency of
+ /// these events is not user-controlled, users may ignore/drop the event if they are no longer
+ /// able to commit external confirmed funds to the child anchor transaction.
+ ///
+ /// The set of `pending_htlcs` on the commitment transaction to be broadcast can be inspected to
+ /// determine whether a significant portion of the channel's funds are allocated to HTLCs,
+ /// enabling users to make their own decisions regarding the importance of the commitment
+ /// transaction's confirmation. Note that this is not required, but simply exists as an option
+ /// for users to override LDK's behavior. On commitments with no HTLCs (indicated by those with
+ /// an empty `pending_htlcs`), confirmation of the commitment transaction can be considered to
+ /// be not urgent.
+ ///
+ /// [`InMemorySigner`]: crate::chain::keysinterface::InMemorySigner
+ /// [`KeysManager::derive_channel_keys`]: crate::chain::keysinterface::KeysManager::derive_channel_keys
+ ChannelClose {
+ /// The target feerate that the transaction package, which consists of the commitment
+ /// transaction and the to-be-crafted child anchor transaction, must meet.
+ package_target_feerate_sat_per_1000_weight: u32,
+ /// The channel's commitment transaction to bump the fee of. This transaction should be
+ /// broadcast along with the anchor transaction constructed as a result of consuming this
+ /// event.
+ commitment_tx: Transaction,
+ /// The absolute fee in satoshis of the commitment transaction. This can be used along the
+ /// with weight of the commitment transaction to determine its feerate.
+ commitment_tx_fee_satoshis: u64,
+ /// The descriptor to sign the anchor input of the anchor transaction constructed as a
+ /// result of consuming this event.
+ anchor_descriptor: AnchorDescriptor,
+ /// The set of pending HTLCs on the commitment transaction that need to be resolved once the
+ /// commitment transaction confirms.
+ pending_htlcs: Vec<HTLCOutputInCommitment>,
+ },
+}
+
/// An Event which you should probably take some action in response to.
///
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use
/// Destination of the HTLC that failed to be processed.
failed_next_destination: HTLCDestination,
},
+ #[cfg(anchors)]
+ /// Indicates that a transaction originating from LDK needs to have its fee bumped. This event
+ /// requires confirmed external funds to be readily available to spend.
+ ///
+ /// LDK does not currently generate this event. It is limited to the scope of channels with
+ /// anchor outputs, which will be introduced in a future release.
+ BumpTransaction(BumpTransactionEvent),
}
impl Writeable for Event {
(2, failed_next_destination, required),
})
},
+ #[cfg(anchors)]
+ &Event::BumpTransaction(ref event)=> {
+ 27u8.write(writer)?;
+ match event {
+ // We never write the ChannelClose events as they'll be replayed upon restarting
+ // anyway if the commitment transaction remains unconfirmed.
+ BumpTransactionEvent::ChannelClose { .. } => {}
+ }
+ }
// Note that, going forward, all new events must only write data inside of
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
// data via `write_tlv_fields`.