use brk_types::{MempoolEntryInfo, SigOps, Transaction, TxIn, TxOut, TxStatus, Txid, Vout};
use crate::{
cycle::AddedKind,
state::TxEntry,
stores::{TxStore, TxTombstone},
};
pub enum TxAddition {
Fresh { tx: Transaction, entry: TxEntry },
Revived { entry: TxEntry },
}
impl TxAddition {
pub fn kind(&self) -> AddedKind {
match self {
Self::Fresh { .. } => AddedKind::Fresh,
Self::Revived { .. } => AddedKind::Revived,
}
}
pub(super) fn fresh(
info: &MempoolEntryInfo,
tx: bitcoin::Transaction,
mempool_txs: &TxStore,
) -> Self {
let total_size = tx.total_size();
let rbf = tx.input.iter().any(|i| i.sequence.is_rbf());
let built = Self::build_tx(info, tx, total_size, mempool_txs);
let entry = TxEntry::new(info, total_size as u64, rbf);
Self::Fresh { tx: built, entry }
}
fn build_tx(
info: &MempoolEntryInfo,
tx: bitcoin::Transaction,
total_size: usize,
mempool_txs: &TxStore,
) -> Transaction {
let input = tx
.input
.into_iter()
.map(|txin| Self::build_txin(txin, mempool_txs))
.collect();
let mut built = Transaction {
index: None,
txid: info.txid,
version: tx.version.into(),
total_sigop_cost: SigOps::ZERO,
weight: info.weight,
lock_time: tx.lock_time.into(),
total_size,
fee: info.fee,
input,
output: tx.output.into_iter().map(TxOut::from).collect(),
status: TxStatus::UNCONFIRMED,
};
built.refresh_sigops();
built
}
pub(super) fn revived(info: &MempoolEntryInfo, tomb: &TxTombstone) -> Self {
let mut entry = TxEntry::new(info, tomb.entry.size, tomb.entry.rbf);
entry.first_seen = tomb.entry.first_seen;
Self::Revived { entry }
}
fn build_txin(txin: bitcoin::TxIn, mempool_txs: &TxStore) -> TxIn {
let prev_txid: Txid = txin.previous_output.txid.into();
let prev_vout = Vout::from(txin.previous_output.vout);
let prevout = Self::resolve_prevout(&prev_txid, prev_vout, mempool_txs);
TxIn {
is_coinbase: false,
prevout,
txid: prev_txid,
vout: prev_vout,
script_sig: txin.script_sig,
script_sig_asm: (),
witness: txin.witness.into(),
sequence: txin.sequence.into(),
inner_redeem_script_asm: (),
inner_witness_script_asm: (),
}
}
fn resolve_prevout(prev_txid: &Txid, prev_vout: Vout, mempool_txs: &TxStore) -> Option<TxOut> {
let prev = mempool_txs.get(prev_txid)?;
prev.output
.get(usize::from(prev_vout))
.map(|o| TxOut::from((o.script_pubkey.clone(), o.value)))
}
}