-
Notifications
You must be signed in to change notification settings - Fork 411
Expose new BumpChannelClose event for channels with anchor outputs #1689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
519ec90
492b240
ccf318e
40b1d4f
bac1b79
e9ac2b1
892f8fe
843b826
2fa45ae
abe85a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,8 +21,7 @@ | |
//! 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; | ||
|
||
|
@@ -44,13 +43,17 @@ use chain::{BestBlock, WatchedOutput}; | |
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::logger::Logger; | ||
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}; | ||
|
@@ -263,6 +266,20 @@ impl_writeable_tlv_based!(HolderSignedTx, { | |
(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)] | ||
|
@@ -1221,7 +1238,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> { | |
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 | ||
|
@@ -2222,6 +2239,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> { | |
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 } => { | ||
|
@@ -2239,7 +2257,6 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> { | |
}, | ||
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 } => { | ||
|
@@ -2255,6 +2272,25 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> { | |
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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For builders/helpers in safety-critical parts, we could start to document the boolean argument at the caller call-site, i.e "/* aggregable */ false". It sounds a code style sophistication, though we already do that on the Core-side. As the codebase keeps growing I think this could be a good practice as a argument misusage could introduce a logical bug. E.g, aggregating a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will address this as a separate PR. |
||
); | ||
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())); | ||
|
@@ -2309,6 +2345,34 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> { | |
pub fn get_and_clear_pending_events(&mut self) -> Vec<Event> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. I wonder if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah we can do in a follow-up. |
||
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 | ||
} | ||
|
||
|
@@ -2521,13 +2585,13 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> { | |
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); | ||
|
@@ -2884,21 +2948,26 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> { | |
|
||
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. | ||
|
Uh oh!
There was an error while loading. Please reload this page.