X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning-transaction-sync%2Fsrc%2Fcommon.rs;h=420d7d8a9575f8672ce3111a52d000270c141a4e;hb=c5cd801f8781dd459b01e0221fd499f62922eb34;hp=be49fbe96ff017aa73d0c8e87265bb442b50fffc;hpb=c2bbfffb1eb249c2c422cf2e9ccac97a34275f7a;p=rust-lightning diff --git a/lightning-transaction-sync/src/common.rs b/lightning-transaction-sync/src/common.rs index be49fbe9..420d7d8a 100644 --- a/lightning-transaction-sync/src/common.rs +++ b/lightning-transaction-sync/src/common.rs @@ -1,9 +1,10 @@ -use lightning::chain::{Confirm, WatchedOutput}; -use bitcoin::{Txid, BlockHash, Transaction, OutPoint}; use bitcoin::block::Header; +use bitcoin::{BlockHash, OutPoint, Transaction, Txid}; +use lightning::chain::channelmonitor::ANTI_REORG_DELAY; +use lightning::chain::{Confirm, WatchedOutput}; -use std::collections::{HashSet, HashMap}; - +use std::collections::{HashMap, HashSet}; +use std::ops::Deref; // Represents the current state. pub(crate) struct SyncState { @@ -13,6 +14,9 @@ pub(crate) struct SyncState { // Outputs that were previously processed, but must not be forgotten yet as // as we still need to monitor any spends on-chain. pub watched_outputs: HashMap, + // Outputs for which we previously saw a spend on-chain but kept around until the spends reach + // sufficient depth. + pub outputs_spends_pending_threshold_conf: Vec<(Txid, u32, OutPoint, WatchedOutput)>, // The tip hash observed during our last sync. pub last_sync_hash: Option, // Indicates whether we need to resync, e.g., after encountering an error. @@ -24,27 +28,43 @@ impl SyncState { Self { watched_transactions: HashSet::new(), watched_outputs: HashMap::new(), + outputs_spends_pending_threshold_conf: Vec::new(), last_sync_hash: None, pending_sync: false, } } - pub fn sync_unconfirmed_transactions( - &mut self, confirmables: &Vec<&(dyn Confirm + Sync + Send)>, - unconfirmed_txs: Vec, - ) { + pub fn sync_unconfirmed_transactions( + &mut self, confirmables: &Vec, unconfirmed_txs: Vec, + ) where + C::Target: Confirm, + { for txid in unconfirmed_txs { for c in confirmables { c.transaction_unconfirmed(&txid); } self.watched_transactions.insert(txid); + + // If a previously-confirmed output spend is unconfirmed, re-add the watched output to + // the tracking map. + self.outputs_spends_pending_threshold_conf.retain( + |(conf_txid, _, prev_outpoint, output)| { + if txid == *conf_txid { + self.watched_outputs.insert(*prev_outpoint, output.clone()); + false + } else { + true + } + }, + ) } } - pub fn sync_confirmed_transactions( - &mut self, confirmables: &Vec<&(dyn Confirm + Sync + Send)>, - confirmed_txs: Vec - ) { + pub fn sync_confirmed_transactions( + &mut self, confirmables: &Vec, confirmed_txs: Vec, + ) where + C::Target: Confirm, + { for ctx in confirmed_txs { for c in confirmables { c.transactions_confirmed( @@ -57,12 +77,19 @@ impl SyncState { self.watched_transactions.remove(&ctx.tx.txid()); for input in &ctx.tx.input { - self.watched_outputs.remove(&input.previous_output); + if let Some(output) = self.watched_outputs.remove(&input.previous_output) { + let spent = (ctx.tx.txid(), ctx.block_height, input.previous_output, output); + self.outputs_spends_pending_threshold_conf.push(spent); + } } } } -} + pub fn prune_output_spends(&mut self, cur_height: u32) { + self.outputs_spends_pending_threshold_conf + .retain(|(_, conf_height, _, _)| cur_height < conf_height + ANTI_REORG_DELAY - 1); + } +} // A queue that is to be filled by `Filter` and drained during the next syncing round. pub(crate) struct FilterQueue { @@ -74,10 +101,7 @@ pub(crate) struct FilterQueue { impl FilterQueue { pub fn new() -> Self { - Self { - transactions: HashSet::new(), - outputs: HashMap::new(), - } + Self { transactions: HashSet::new(), outputs: HashMap::new() } } // Processes the transaction and output queues and adds them to the given [`SyncState`]. @@ -104,6 +128,7 @@ impl FilterQueue { #[derive(Debug)] pub(crate) struct ConfirmedTx { pub tx: Transaction, + pub txid: Txid, pub block_header: Header, pub block_height: u32, pub pos: usize,