use std::{
collections::{HashMap, HashSet},
iter,
};
use elements::{OutPoint, Transaction, Txid};
use crate::{
store::{AnyStore, Store},
ScriptHash,
};
pub struct Mempool {
txid_hashes: HashMap<Txid, HashSet<ScriptHash>>,
hash_txids: HashMap<ScriptHash, Vec<Txid>>,
outpoints_created: HashMap<OutPoint, ScriptHash>,
}
impl Mempool {
pub fn new() -> Mempool {
Mempool {
txid_hashes: HashMap::new(),
hash_txids: HashMap::new(),
outpoints_created: HashMap::new(),
}
}
pub fn remove(&mut self, txids: &[Txid]) {
for txid in txids {
if let Some(hashes) = self.txid_hashes.remove(txid) {
for hash in hashes {
self.hash_txids.remove(&hash);
}
}
}
self.outpoints_created
.retain(|k, _| !txids.contains(&k.txid));
}
pub fn add(&mut self, db: &AnyStore, txs: &[Transaction]) {
let txs_map: HashMap<Txid, &Transaction> = txs.iter().map(|tx| (tx.txid(), tx)).collect();
let outputs_created = txs_map
.iter()
.flat_map(|(txid, tx)| tx.output.iter().enumerate().zip(iter::repeat(txid)))
.map(|((vout, txout), txid)| {
(
OutPoint::new(*txid, vout as u32),
db.hash(&txout.script_pubkey),
)
});
self.outpoints_created.extend(outputs_created);
let mut txid_hashes: HashMap<Txid, HashSet<ScriptHash>> = HashMap::new();
let prevouts: Vec<OutPoint> = txs
.iter()
.flat_map(|e| e.input.iter())
.map(|i| i.previous_output)
.collect();
let spending_script_hashes = db.get_utxos(&prevouts).unwrap();
let mut prevouts_index = 0usize;
for (txid, tx) in txs_map {
for input in tx.input.iter() {
let e = match spending_script_hashes[prevouts_index] {
Some(e) => e,
None => {
match self.outpoints_created.get(&input.previous_output) {
Some(e) => *e,
None => {
prevouts_index += 1;
continue;
}
}
}
};
txid_hashes.entry(txid).or_insert(HashSet::new()).insert(e);
prevouts_index += 1;
}
for output in tx.output.iter() {
let e = db.hash(&output.script_pubkey);
txid_hashes.entry(txid).or_insert(HashSet::new()).insert(e);
}
}
for (k, v) in txid_hashes {
self.txid_hashes
.entry(k)
.or_insert(HashSet::new())
.extend(&v);
for e in v {
self.hash_txids.entry(e).or_insert(vec![]).push(k);
}
}
}
pub fn seen(&self, script_hashes: &[ScriptHash]) -> Vec<Vec<Txid>> {
let mut result = vec![];
for h in script_hashes {
let r = self.hash_txids.get(h).cloned().unwrap_or(vec![]);
result.push(r)
}
result
}
pub(crate) fn txids(&self) -> HashSet<Txid> {
self.txid_hashes.keys().cloned().collect()
}
}
#[cfg(test)]
mod test {
#[test]
fn test_mempool() {}
}