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::{HashMap, HashSet};
use std::ops::Deref;
pub(crate) struct SyncState {
pub watched_transactions: HashSet<Txid>,
pub watched_outputs: HashMap<OutPoint, WatchedOutput>,
pub outputs_spends_pending_threshold_conf: Vec<(Txid, u32, OutPoint, WatchedOutput)>,
pub last_sync_hash: Option<BlockHash>,
pub pending_sync: bool,
}
impl SyncState {
pub fn new() -> Self {
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<C: Deref>(
&mut self, confirmables: &Vec<C>, unconfirmed_txs: Vec<Txid>,
) where
C::Target: Confirm,
{
for txid in unconfirmed_txs {
for c in confirmables {
c.transaction_unconfirmed(&txid);
}
self.watched_transactions.insert(txid);
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<C: Deref>(
&mut self, confirmables: &Vec<C>, confirmed_txs: Vec<ConfirmedTx>,
) where
C::Target: Confirm,
{
for ctx in confirmed_txs {
for c in confirmables {
c.transactions_confirmed(
&ctx.block_header,
&[(ctx.pos, &ctx.tx)],
ctx.block_height,
);
}
self.watched_transactions.remove(&ctx.tx.compute_txid());
for input in &ctx.tx.input {
if let Some(output) = self.watched_outputs.remove(&input.previous_output) {
let spent =
(ctx.tx.compute_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);
}
}
pub(crate) struct FilterQueue {
pub transactions: HashSet<Txid>,
pub outputs: HashMap<OutPoint, WatchedOutput>,
}
impl FilterQueue {
pub fn new() -> Self {
Self { transactions: HashSet::new(), outputs: HashMap::new() }
}
pub fn process_queues(&mut self, sync_state: &mut SyncState) -> bool {
let mut pending_registrations = false;
if !self.transactions.is_empty() {
pending_registrations = true;
sync_state.watched_transactions.extend(self.transactions.drain());
}
if !self.outputs.is_empty() {
pending_registrations = true;
sync_state.watched_outputs.extend(self.outputs.drain());
}
pending_registrations
}
}
#[derive(Debug)]
pub(crate) struct ConfirmedTx {
pub tx: Transaction,
pub txid: Txid,
pub block_header: Header,
pub block_height: u32,
pub pos: usize,
}