//! security-domain-separated system design, you should consider having multiple paths for
//! ChannelMonitors to get out of the HSM and onto monitoring devices.
-use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::block::BlockHeader;
use bitcoin::blockdata::transaction::{TxOut,Transaction};
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::opcodes;
},
}
+impl ChannelMonitorUpdateStep {
+ fn variant_name(&self) -> &'static str {
+ match self {
+ ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { .. } => "LatestHolderCommitmentTXInfo",
+ ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. } => "LatestCounterpartyCommitmentTXInfo",
+ ChannelMonitorUpdateStep::PaymentPreimage { .. } => "PaymentPreimage",
+ ChannelMonitorUpdateStep::CommitmentSecret { .. } => "CommitmentSecret",
+ ChannelMonitorUpdateStep::ChannelForceClosed { .. } => "ChannelForceClosed",
+ ChannelMonitorUpdateStep::ShutdownScript { .. } => "ShutdownScript",
+ }
+ }
+}
+
impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
(0, LatestHolderCommitmentTXInfo) => {
(0, commitment_tx, required),
($holder_commitment: expr, $htlc_iter: expr) => {
for htlc in $htlc_iter {
if let Some(htlc_input_idx) = htlc.transaction_output_index {
- if us.htlcs_resolved_on_chain.iter().any(|v| v.input_idx == htlc_input_idx) {
- assert!(us.funding_spend_confirmed.is_some());
+ if let Some(conf_thresh) = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
+ if let OnchainEvent::MaturingOutput { descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) } = &event.event {
+ if descriptor.outpoint.index as u32 == htlc_input_idx { Some(event.confirmation_threshold()) } else { None }
+ } else { None }
+ }) {
+ debug_assert!($holder_commitment);
+ res.push(Balance::ClaimableAwaitingConfirmations {
+ claimable_amount_satoshis: htlc.amount_msat / 1000,
+ confirmation_height: conf_thresh,
+ });
+ } else if us.htlcs_resolved_on_chain.iter().any(|v| v.input_idx == htlc_input_idx) {
+ // Funding transaction spends should be fully confirmed by the time any
+ // HTLC transactions are resolved, unless we're talking about a holder
+ // commitment tx, whose resolution is delayed until the CSV timeout is
+ // reached, even though HTLCs may be resolved after only
+ // ANTI_REORG_DELAY confirmations.
+ debug_assert!($holder_commitment || us.funding_spend_confirmed.is_some());
} else if htlc.offered == $holder_commitment {
// If the payment was outbound, check if there's an HTLCUpdate
// indicating we have spent this HTLC with a timeout, claiming it back
F::Target: FeeEstimator,
L::Target: Logger,
{
+ log_info!(logger, "Applying update to monitor {}, bringing update_id from {} to {} with {} changes.",
+ log_funding_info!(self), self.latest_update_id, updates.update_id, updates.updates.len());
// ChannelMonitor updates may be applied after force close if we receive a
// preimage for a broadcasted commitment transaction HTLC output that we'd
// like to claim on-chain. If this is the case, we no longer have guaranteed
// access to the monitor's update ID, so we use a sentinel value instead.
if updates.update_id == CLOSED_CHANNEL_UPDATE_ID {
+ assert_eq!(updates.updates.len(), 1);
match updates.updates[0] {
ChannelMonitorUpdateStep::PaymentPreimage { .. } => {},
- _ => panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage"),
+ _ => {
+ log_error!(logger, "Attempted to apply post-force-close ChannelMonitorUpdate of type {}", updates.updates[0].variant_name());
+ panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage");
+ },
}
- assert_eq!(updates.updates.len(), 1);
} else if self.latest_update_id + 1 != updates.update_id {
panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
}
F::Target: FeeEstimator,
L::Target: Logger,
{
- fn block_connected(&self, block: &Block, height: u32) {
- let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
- self.0.block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3);
+ fn filtered_block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
+ self.0.block_connected(header, txdata, height, &*self.1, &*self.2, &*self.3);
}
fn block_disconnected(&self, header: &BlockHeader, height: u32) {