use crate::{
mempool::{
model::{map::MempoolTransactionCollection, tx::MempoolTransaction},
tx::Priority,
},
model::{
owner_txs::{GroupedOwnerTransactions, ScriptPublicKeySet},
topological_index::TopologicalIndex,
TransactionIdSet,
},
};
use kaspa_consensus_core::tx::{MutableTransaction, TransactionId};
use std::collections::{hash_set::Iter, HashMap, HashSet, VecDeque};
pub(crate) type TransactionsEdges = HashMap<TransactionId, TransactionIdSet>;
pub(crate) trait Pool {
fn all(&self) -> &MempoolTransactionCollection;
fn chained(&self) -> &TransactionsEdges;
fn has(&self, transaction_id: &TransactionId) -> bool {
self.all().contains_key(transaction_id)
}
fn get(&self, transaction_id: &TransactionId) -> Option<&MempoolTransaction> {
self.all().get(transaction_id)
}
fn len(&self) -> usize {
self.all().len()
}
#[allow(dead_code)]
fn index(&self, priority: Priority) -> PoolIndex {
let transactions: TransactionIdSet =
self.all().iter().filter_map(|(id, tx)| if tx.priority == priority { Some(*id) } else { None }).collect();
let chained_transactions = transactions
.iter()
.filter_map(|id| {
self.chained()
.get(id)
.map(|chains| (*id, chains.iter().filter_map(|chain| transactions.get(chain).copied()).collect()))
})
.collect();
PoolIndex::new(transactions, chained_transactions)
}
fn get_parent_transaction_ids_in_pool(&self, transaction: &MutableTransaction) -> TransactionIdSet {
let mut parents = HashSet::with_capacity(transaction.tx.inputs.len());
for input in transaction.tx.inputs.iter() {
if self.has(&input.previous_outpoint.transaction_id) {
parents.insert(input.previous_outpoint.transaction_id);
}
}
parents
}
fn get_redeemer_ids_in_pool(&self, transaction_id: &TransactionId) -> Vec<TransactionId> {
let mut visited = TransactionIdSet::new();
let mut descendants = vec![];
if let Some(transaction) = self.get(transaction_id) {
let mut queue = VecDeque::new();
queue.push_back(transaction);
while let Some(transaction) = queue.pop_front() {
if let Some(chains) = self.chained().get(&transaction.id()) {
chains.iter().for_each(|redeemer_id| {
if let Some(redeemer) = self.get(redeemer_id) {
if visited.insert(*redeemer_id) {
descendants.push(*redeemer_id);
queue.push_back(redeemer);
}
}
})
}
}
}
descendants
}
fn get_all_transactions(&self) -> Vec<MutableTransaction> {
self.all().values().map(|x| x.mtx.clone()).collect()
}
fn get_all_transaction_ids(&self) -> Vec<TransactionId> {
self.all().keys().cloned().collect()
}
fn fill_owner_set_transactions(&self, script_public_keys: &ScriptPublicKeySet, owner_set: &mut GroupedOwnerTransactions) {
script_public_keys.iter().for_each(|script_public_key| {
let owner = owner_set.owners.entry(script_public_key.clone()).or_default();
self.all().iter().for_each(|(id, transaction)| {
if transaction.mtx.entries.iter().any(|x| x.is_some() && x.as_ref().unwrap().script_public_key == *script_public_key) {
owner_set.transactions.entry(*id).or_insert_with(|| transaction.mtx.clone());
owner.sending_txs.insert(*id);
}
if transaction.mtx.tx.outputs.iter().any(|x| x.script_public_key == *script_public_key) {
owner_set.transactions.entry(*id).or_insert_with(|| transaction.mtx.clone());
owner.receiving_txs.insert(*id);
}
});
});
}
}
pub(crate) struct PoolIndex {
transactions: TransactionIdSet,
chained_transactions: TransactionsEdges,
}
impl PoolIndex {
#[allow(dead_code)]
pub(crate) fn new(transactions: TransactionIdSet, chained_transactions: TransactionsEdges) -> Self {
Self { transactions, chained_transactions }
}
}
type IterTxId<'a> = Iter<'a, TransactionId>;
impl<'a> TopologicalIndex<'a, IterTxId<'a>, IterTxId<'a>, TransactionId> for PoolIndex {
fn topology_nodes(&'a self) -> IterTxId<'a> {
self.transactions.iter()
}
fn topology_node_edges(&'a self, key: &TransactionId) -> Option<IterTxId<'a>> {
self.chained_transactions.get(key).map(|x| x.iter())
}
}