use brk_types::{TxOut, Txid, Vin, Vout};
use crate::stores::MempoolState;
type Fills = Vec<(Vin, TxOut)>;
type Holes = Vec<(Vin, Txid, Vout)>;
pub struct Resolver;
impl Resolver {
pub fn resolve_in_mempool(state: &MempoolState) -> bool {
let filled: Vec<(Txid, Fills)> = {
let txs = state.txs.read();
if txs.unresolved().is_empty() {
return false;
}
txs.unresolved()
.iter()
.filter_map(|txid| {
let tx = txs.get(txid)?;
let fills: Fills = tx
.input
.iter()
.enumerate()
.filter(|(_, txin)| txin.prevout.is_none())
.filter_map(|(i, txin)| {
let parent = txs.get(&txin.txid)?;
let out = parent.output.get(usize::from(txin.vout))?;
Some((Vin::from(i), out.clone()))
})
.collect();
(!fills.is_empty()).then_some((txid.clone(), fills))
})
.collect()
};
Self::write_back(state, filled)
}
pub fn resolve_external<F>(state: &MempoolState, resolver: F) -> bool
where
F: Fn(&Txid, Vout) -> Option<TxOut>,
{
let holes: Vec<(Txid, Holes)> = {
let txs = state.txs.read();
if txs.unresolved().is_empty() {
return false;
}
txs.unresolved()
.iter()
.filter_map(|txid| {
let tx = txs.get(txid)?;
let holes: Holes = tx
.input
.iter()
.enumerate()
.filter(|(_, txin)| txin.prevout.is_none())
.map(|(i, txin)| (Vin::from(i), txin.txid.clone(), txin.vout))
.collect();
(!holes.is_empty()).then_some((txid.clone(), holes))
})
.collect()
};
let filled: Vec<(Txid, Fills)> = holes
.into_iter()
.filter_map(|(txid, holes)| {
let fills: Fills = holes
.into_iter()
.filter_map(|(vin, prev_txid, vout)| {
resolver(&prev_txid, vout).map(|o| (vin, o))
})
.collect();
(!fills.is_empty()).then_some((txid, fills))
})
.collect();
Self::write_back(state, filled)
}
fn write_back(state: &MempoolState, fills: Vec<(Txid, Fills)>) -> bool {
if fills.is_empty() {
return false;
}
let mut txs = state.txs.write();
let mut addrs = state.addrs.write();
for (txid, tx_fills) in fills {
for prevout in txs.apply_fills(&txid, tx_fills) {
addrs.add_input(&txid, &prevout);
}
}
true
}
}