//! 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};
/// much smaller than a full [`ChannelMonitor`]. However, for large single commitment transaction
/// updates (e.g. ones during which there are hundreds of HTLCs pending on the commitment
/// transaction), a single update may reach upwards of 1 MiB in serialized size.
-#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq))]
+#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq, Eq))]
#[derive(Clone)]
#[must_use]
pub struct ChannelMonitorUpdate {
/// increasing and increase by one for each new update, with one exception specified below.
///
/// This sequence number is also used to track up to which points updates which returned
- /// ChannelMonitorUpdateErr::TemporaryFailure have been applied to all copies of a given
+ /// [`ChannelMonitorUpdateStatus::InProgress`] have been applied to all copies of a given
/// ChannelMonitor when ChannelManager::channel_monitor_updated is called.
///
/// The only instance where update_id values are not strictly increasing is the case where we
/// allow post-force-close updates with a special update ID of [`CLOSED_CHANNEL_UPDATE_ID`]. See
/// its docs for more details.
+ ///
+ /// [`ChannelMonitorUpdateStatus::InProgress`]: super::ChannelMonitorUpdateStatus::InProgress
pub update_id: u64,
}
}
/// An event to be processed by the ChannelManager.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub enum MonitorEvent {
/// A monitor event containing an HTLCUpdate.
HTLCEvent(HTLCUpdate),
CommitmentTxConfirmed(OutPoint),
/// Indicates a [`ChannelMonitor`] update has completed. See
- /// [`ChannelMonitorUpdateErr::TemporaryFailure`] for more information on how this is used.
+ /// [`ChannelMonitorUpdateStatus::InProgress`] for more information on how this is used.
///
- /// [`ChannelMonitorUpdateErr::TemporaryFailure`]: super::ChannelMonitorUpdateErr::TemporaryFailure
- UpdateCompleted {
+ /// [`ChannelMonitorUpdateStatus::InProgress`]: super::ChannelMonitorUpdateStatus::InProgress
+ Completed {
/// The funding outpoint of the [`ChannelMonitor`] that was updated
funding_txo: OutPoint,
/// The Update ID from [`ChannelMonitorUpdate::update_id`] which was applied or
},
/// Indicates a [`ChannelMonitor`] update has failed. See
- /// [`ChannelMonitorUpdateErr::PermanentFailure`] for more information on how this is used.
+ /// [`ChannelMonitorUpdateStatus::PermanentFailure`] for more information on how this is used.
///
- /// [`ChannelMonitorUpdateErr::PermanentFailure`]: super::ChannelMonitorUpdateErr::PermanentFailure
+ /// [`ChannelMonitorUpdateStatus::PermanentFailure`]: super::ChannelMonitorUpdateStatus::PermanentFailure
UpdateFailed(OutPoint),
}
impl_writeable_tlv_based_enum_upgradable!(MonitorEvent,
- // Note that UpdateCompleted and UpdateFailed are currently never serialized to disk as they are
+ // Note that Completed and UpdateFailed are currently never serialized to disk as they are
// generated only in ChainMonitor
- (0, UpdateCompleted) => {
+ (0, Completed) => {
(0, funding_txo, required),
(2, monitor_update_id, required),
},
/// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on
/// chain. Used to update the corresponding HTLC in the backward channel. Failing to pass the
/// preimage claim backward will lead to loss of funds.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
pub struct HTLCUpdate {
pub(crate) payment_hash: PaymentHash,
pub(crate) payment_preimage: Option<PaymentPreimage>,
pub(crate) const HTLC_FAIL_BACK_BUFFER: u32 = CLTV_CLAIM_BUFFER + LATENCY_GRACE_PERIOD_BLOCKS;
// TODO(devrandom) replace this with HolderCommitmentTransaction
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, Eq)]
struct HolderSignedTx {
/// txid of the transaction in tx, just used to make comparison faster
txid: Txid,
(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)]
+#[derive(PartialEq, Eq)]
struct CounterpartyCommitmentParameters {
counterparty_delayed_payment_base_key: PublicKey,
counterparty_htlc_base_key: PublicKey,
/// transaction causing it.
///
/// Used to determine when the on-chain event can be considered safe from a chain reorganization.
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
struct OnchainEventEntry {
txid: Txid,
height: u32,
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
/// once they mature to enough confirmations (ANTI_REORG_DELAY)
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
enum OnchainEvent {
/// An outbound HTLC failing after a transaction is confirmed. Used
/// * when an outbound HTLC output is spent by us after the HTLC timed out
);
-#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq))]
+#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq, Eq))]
#[derive(Clone)]
pub(crate) enum ChannelMonitorUpdateStep {
LatestHolderCommitmentTXInfo {
}
/// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY.
-#[derive(PartialEq)]
+#[derive(PartialEq, Eq)]
struct IrrevocablyResolvedHTLC {
commitment_tx_output_idx: Option<u32>,
/// The txid of the transaction which resolved the HTLC, this may be a commitment (if the HTLC
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
}
/// Used by ChannelManager deserialization to broadcast the latest holder state if its copy of
- /// the Channel was out-of-date. You may use it to get a broadcastable holder toxic tx in case of
- /// fallen-behind, i.e when receiving a channel_reestablish with a proof that our counterparty side knows
- /// a higher revocation secret than the holder commitment number we are aware of. Broadcasting these
- /// transactions are UNSAFE, as they allow counterparty side to punish you. Nevertheless you may want to
- /// broadcast them if counterparty don't close channel with his higher commitment transaction after a
- /// substantial amount of time (a month or even a year) to get back funds. Best may be to contact
- /// out-of-band the other node operator to coordinate with him if option is available to you.
- /// In any-case, choice is up to the user.
+ /// the Channel was out-of-date.
+ ///
+ /// You may also use this to broadcast the latest local commitment transaction, either because
+ /// a monitor update failed with [`ChannelMonitorUpdateStatus::PermanentFailure`] or because we've
+ /// fallen behind (i.e. we've received proof that our counterparty side knows a revocation
+ /// secret we gave them that they shouldn't know).
+ ///
+ /// Broadcasting these transactions in the second case is UNSAFE, as they allow counterparty
+ /// side to punish you. Nevertheless you may want to broadcast them if counterparty doesn't
+ /// close channel with their commitment transaction after a substantial amount of time. Best
+ /// may be to contact the other node operator out-of-band to coordinate other options available
+ /// to you. In any-case, the choice is up to you.
+ ///
+ /// [`ChannelMonitorUpdateStatus::PermanentFailure`]: super::ChannelMonitorUpdateStatus::PermanentFailure
pub fn get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
where L::Target: Logger {
self.inner.lock().unwrap().get_latest_holder_commitment_txn(logger)
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, "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");
+ 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()));
+ log_error!(logger, " Read the docs for ChannelMonitor::get_latest_holder_commitment_txn and take manual action!");
} else {
// If we generated a MonitorEvent::CommitmentTxConfirmed, the ChannelManager
// will still give us a ChannelForceClosed event with !should_broadcast, but we
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
}
CounterpartyOfferedHTLCOutput::build(*per_commitment_point,
self.counterparty_commitment_params.counterparty_delayed_payment_base_key,
self.counterparty_commitment_params.counterparty_htlc_base_key,
- preimage.unwrap(), htlc.clone()))
+ preimage.unwrap(), htlc.clone(), self.onchain_tx_handler.opt_anchors()))
} else {
PackageSolvingData::CounterpartyReceivedHTLCOutput(
CounterpartyReceivedHTLCOutput::build(*per_commitment_point,
self.counterparty_commitment_params.counterparty_delayed_payment_base_key,
self.counterparty_commitment_params.counterparty_htlc_base_key,
- htlc.clone()))
+ htlc.clone(), self.onchain_tx_handler.opt_anchors()))
};
let aggregation = if !htlc.offered { false } else { true };
let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry,aggregation, 0);
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
txid,
transaction: Some((*tx).clone()),
- height: height,
+ height,
event: OnchainEvent::FundingSpendConfirmation {
on_local_output_csv: balance_spendable_csv,
commitment_tx_to_counterparty_output,
let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
if should_broadcast {
- let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone());
+ let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone(), self.channel_value_satoshis, self.onchain_tx_handler.opt_anchors());
let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), self.best_block.height(), false, self.best_block.height());
claimable_outpoints.push(commitment_package);
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.
let entry = OnchainEventEntry {
txid: tx.txid(),
transaction: Some(tx.clone()),
- height: height,
+ height,
event: OnchainEvent::MaturingOutput { descriptor: spendable_output.clone() },
};
log_info!(logger, "Received spendable output {}, spendable at height {}", log_spendable!(spendable_output), entry.confirmation_threshold());
use ln::{PaymentPreimage, PaymentHash};
use ln::chan_utils;
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
- use ln::channelmanager::PaymentSendFailure;
- use ln::features::InitFeatures;
+ use ln::channelmanager::{self, PaymentSendFailure};
use ln::functional_test_utils::*;
use ln::script::ShutdownScript;
use util::errors::APIError;
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
let channel = create_announced_chan_between_nodes(
- &nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
+ &nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
create_announced_chan_between_nodes(
- &nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
+ &nodes, 1, 2, channelmanager::provided_init_features(), channelmanager::provided_init_features());
// Rebalance somewhat
send_payment(&nodes[0], &[&nodes[1]], 10_000_000);