X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=bee2bfd012e0ff3efc628b4954883804f5d6a0c7;hb=21804de70c3ff37970ead98e5e72c4fccd14b1fb;hp=0bfd944456ab6851749505350c781e8ec267d27e;hpb=593d8c4610f082441563d4906d64175a354b1cfc;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 0bfd9444..bee2bfd0 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -826,6 +826,13 @@ pub(crate) struct ChannelMonitorImpl { /// spending CSV for revocable outputs). htlcs_resolved_on_chain: Vec, + /// The set of `SpendableOutput` events which we have already passed upstream to be claimed. + /// These are tracked explicitly to ensure that we don't generate the same events redundantly + /// if users duplicatively confirm old transactions. Specifically for transactions claiming a + /// revoked remote outpoint we otherwise have no tracking at all once they've reached + /// [`ANTI_REORG_DELAY`], so we have to track them here. + spendable_txids_confirmed: Vec, + // We simply modify best_block in Channel's block_connected so that serialization is // consistent but hopefully the users' copy handles block_connected in a consistent way. // (we do *not*, however, update them in update_monitor to ensure any local user copies keep @@ -1071,6 +1078,7 @@ impl Writeable for ChannelMonitorImpl { (7, self.funding_spend_seen, required), (9, self.counterparty_node_id, option), (11, self.confirmed_commitment_tx_counterparty_output, option), + (13, self.spendable_txids_confirmed, vec_type), }); Ok(()) @@ -1179,6 +1187,7 @@ impl ChannelMonitor { funding_spend_confirmed: None, confirmed_commitment_tx_counterparty_output: None, htlcs_resolved_on_chain: Vec::new(), + spendable_txids_confirmed: Vec::new(), best_block, counterparty_node_id: Some(counterparty_node_id), @@ -2860,7 +2869,37 @@ impl ChannelMonitorImpl { let mut watch_outputs = Vec::new(); let mut claimable_outpoints = Vec::new(); - for tx in &txn_matched { + 'tx_iter: for tx in &txn_matched { + let txid = tx.txid(); + // If a transaction has already been confirmed, ensure we don't bother processing it duplicatively. + if Some(txid) == self.funding_spend_confirmed { + log_debug!(logger, "Skipping redundant processing of funding-spend tx {} as it was previously confirmed", txid); + continue 'tx_iter; + } + for ev in self.onchain_events_awaiting_threshold_conf.iter() { + if ev.txid == txid { + if let Some(conf_hash) = ev.block_hash { + assert_eq!(header.block_hash(), conf_hash, + "Transaction {} was already confirmed and is being re-confirmed in a different block.\n\ + This indicates a severe bug in the transaction connection logic - a reorg should have been processed first!", ev.txid); + } + log_debug!(logger, "Skipping redundant processing of confirming tx {} as it was previously confirmed", txid); + continue 'tx_iter; + } + } + for htlc in self.htlcs_resolved_on_chain.iter() { + if Some(txid) == htlc.resolving_txid { + log_debug!(logger, "Skipping redundant processing of HTLC resolution tx {} as it was previously confirmed", txid); + continue 'tx_iter; + } + } + for spendable_txid in self.spendable_txids_confirmed.iter() { + if txid == *spendable_txid { + log_debug!(logger, "Skipping redundant processing of spendable tx {} as it was previously confirmed", txid); + continue 'tx_iter; + } + } + if tx.input.len() == 1 { // Assuming our keys were not leaked (in which case we're screwed no matter what), // commitment transactions and HTLC transactions will all only ever have one input, @@ -2870,7 +2909,7 @@ impl ChannelMonitorImpl { if prevout.txid == self.funding_info.0.txid && prevout.vout == self.funding_info.0.index as u32 { let mut balance_spendable_csv = None; log_info!(logger, "Channel {} closed by funding output spend in txid {}.", - log_bytes!(self.funding_info.0.to_channel_id()), tx.txid()); + log_bytes!(self.funding_info.0.to_channel_id()), txid); self.funding_spend_seen = true; let mut commitment_tx_to_counterparty_output = None; if (tx.input[0].sequence.0 >> 8*3) as u8 == 0x80 && (tx.lock_time.0 >> 8*3) as u8 == 0x20 { @@ -2893,7 +2932,6 @@ impl ChannelMonitorImpl { } } } - let txid = tx.txid(); self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry { txid, transaction: Some((*tx).clone()), @@ -3042,6 +3080,7 @@ impl ChannelMonitorImpl { self.pending_events.push(Event::SpendableOutputs { outputs: vec![descriptor] }); + self.spendable_txids_confirmed.push(entry.txid); }, OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. } => { self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC { @@ -3551,8 +3590,8 @@ where const MAX_ALLOC_SIZE: usize = 64*1024; -impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> - for (BlockHash, ChannelMonitor) { +impl<'a, K: KeysInterface> ReadableArgs<&'a K> + for (BlockHash, ChannelMonitor) { fn read(reader: &mut R, keys_manager: &'a K) -> Result { macro_rules! unwrap_obj { ($key: expr) => { @@ -3736,7 +3775,7 @@ impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> return Err(DecodeError::InvalidValue); } } - let onchain_tx_handler: OnchainTxHandler = ReadableArgs::read(reader, keys_manager)?; + let onchain_tx_handler: OnchainTxHandler = ReadableArgs::read(reader, keys_manager)?; let lockdown_from_offchain = Readable::read(reader)?; let holder_tx_signed = Readable::read(reader)?; @@ -3763,6 +3802,7 @@ impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> let mut funding_spend_seen = Some(false); let mut counterparty_node_id = None; let mut confirmed_commitment_tx_counterparty_output = None; + let mut spendable_txids_confirmed = Some(Vec::new()); read_tlv_fields!(reader, { (1, funding_spend_confirmed, option), (3, htlcs_resolved_on_chain, vec_type), @@ -3770,6 +3810,7 @@ impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> (7, funding_spend_seen, option), (9, counterparty_node_id, option), (11, confirmed_commitment_tx_counterparty_output, option), + (13, spendable_txids_confirmed, vec_type), }); let mut secp_ctx = Secp256k1::new(); @@ -3822,6 +3863,7 @@ impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> funding_spend_confirmed, confirmed_commitment_tx_counterparty_output, htlcs_resolved_on_chain: htlcs_resolved_on_chain.unwrap(), + spendable_txids_confirmed: spendable_txids_confirmed.unwrap(), best_block, counterparty_node_id,