use std::mem;
use brk_rpc::RawTx;
use brk_types::{
MempoolEntryInfo, Timestamp, Transaction, TxIn, TxOut, TxStatus, Txid, TxidPrefix, VSize, Vout,
};
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
use crate::stores::{Entry, Tombstone, TxStore};
pub enum Addition {
Fresh { tx: Transaction, entry: Entry },
Revived { entry: Entry },
}
pub(super) fn fresh(
info: &MempoolEntryInfo,
mut raw: RawTx,
parent_raws: &FxHashMap<Txid, RawTx>,
mempool_txs: &TxStore,
) -> Addition {
let total_size = raw.hex.len() / 2;
let rbf = raw.tx.input.iter().any(|i| i.sequence.is_rbf());
let input = mem::take(&mut raw.tx.input)
.into_iter()
.map(|txin| {
let prev_txid: Txid = txin.previous_output.txid.into();
let prev_vout = usize::from(Vout::from(txin.previous_output.vout));
let prevout = if let Some(prev) = mempool_txs.get(&prev_txid) {
prev.output
.get(prev_vout)
.map(|o| TxOut::from((o.script_pubkey.clone(), o.value)))
} else if let Some(parent) = parent_raws.get(&prev_txid) {
parent
.tx
.output
.get(prev_vout)
.map(|o| TxOut::from((o.script_pubkey.clone(), o.value.into())))
} else {
None
};
TxIn {
is_coinbase: false,
prevout,
txid: prev_txid,
vout: txin.previous_output.vout.into(),
script_sig: txin.script_sig,
script_sig_asm: (),
witness: txin.witness.into(),
sequence: txin.sequence.into(),
inner_redeem_script_asm: (),
inner_witness_script_asm: (),
}
})
.collect();
let mut tx = Transaction {
index: None,
txid: info.txid.clone(),
version: raw.tx.version.into(),
total_sigop_cost: 0,
weight: info.weight.into(),
lock_time: raw.tx.lock_time.into(),
total_size,
fee: info.fee,
input,
output: raw.tx.output.into_iter().map(TxOut::from).collect(),
status: TxStatus::UNCONFIRMED,
};
tx.total_sigop_cost = tx.total_sigop_cost();
let entry = build_entry(info, tx.total_size as u64, rbf, Timestamp::now());
Addition::Fresh { tx, entry }
}
pub(super) fn revived(info: &MempoolEntryInfo, tomb: &Tombstone) -> Addition {
let entry = build_entry(info, tomb.entry.size, tomb.entry.rbf, tomb.entry.first_seen);
Addition::Revived { entry }
}
fn build_entry(info: &MempoolEntryInfo, size: u64, rbf: bool, first_seen: Timestamp) -> Entry {
let depends: SmallVec<[TxidPrefix; 2]> = info.depends.iter().map(TxidPrefix::from).collect();
Entry {
txid: info.txid.clone(),
fee: info.fee,
vsize: VSize::from(info.vsize),
size,
depends,
first_seen,
rbf,
}
}