use crate::{
feerate::{FeerateEstimator, FeerateEstimatorArgs},
model::{
owner_txs::{GroupedOwnerTransactions, ScriptPublicKeySet},
tx_query::TransactionQuery,
},
MiningCounters,
};
use self::{
config::Config,
model::{accepted_transactions::AcceptedTransactions, orphan_pool::OrphanPool, pool::Pool, transactions_pool::TransactionsPool},
tx::Priority,
};
use kaspa_consensus_core::{
block::TemplateTransactionSelector,
tx::{MutableTransaction, TransactionId},
};
use kaspa_core::time::Stopwatch;
use std::sync::Arc;
pub(crate) mod check_transaction_standard;
pub mod config;
pub mod errors;
pub(crate) mod handle_new_block_transactions;
pub(crate) mod model;
pub(crate) mod populate_entries_and_try_validate;
pub(crate) mod remove_transaction;
pub(crate) mod replace_by_fee;
pub(crate) mod validate_and_insert_transaction;
pub(crate) struct Mempool {
config: Arc<Config>,
transaction_pool: TransactionsPool,
orphan_pool: OrphanPool,
accepted_transactions: AcceptedTransactions,
counters: Arc<MiningCounters>,
}
impl Mempool {
pub(crate) fn new(config: Arc<Config>, counters: Arc<MiningCounters>) -> Self {
let transaction_pool = TransactionsPool::new(config.clone());
let orphan_pool = OrphanPool::new(config.clone());
let accepted_transactions = AcceptedTransactions::new(config.clone());
Self { config, transaction_pool, orphan_pool, accepted_transactions, counters }
}
pub(crate) fn get_transaction(&self, transaction_id: &TransactionId, query: TransactionQuery) -> Option<MutableTransaction> {
let mut transaction = None;
if query.include_transaction_pool() {
transaction = self.transaction_pool.get(transaction_id);
}
if transaction.is_none() && query.include_orphan_pool() {
transaction = self.orphan_pool.get(transaction_id);
}
transaction.map(|x| x.mtx.clone())
}
pub(crate) fn has_transaction(&self, transaction_id: &TransactionId, query: TransactionQuery) -> bool {
(query.include_transaction_pool() && self.transaction_pool.has(transaction_id))
|| (query.include_orphan_pool() && self.orphan_pool.has(transaction_id))
}
pub(crate) fn get_all_transactions(&self, query: TransactionQuery) -> (Vec<MutableTransaction>, Vec<MutableTransaction>) {
let transactions = if query.include_transaction_pool() { self.transaction_pool.get_all_transactions() } else { vec![] };
let orphans = if query.include_orphan_pool() { self.orphan_pool.get_all_transactions() } else { vec![] };
(transactions, orphans)
}
pub(crate) fn get_all_transaction_ids(&self, query: TransactionQuery) -> (Vec<TransactionId>, Vec<TransactionId>) {
let transactions = if query.include_transaction_pool() { self.transaction_pool.get_all_transaction_ids() } else { vec![] };
let orphans = if query.include_orphan_pool() { self.orphan_pool.get_all_transaction_ids() } else { vec![] };
(transactions, orphans)
}
pub(crate) fn get_transactions_by_addresses(
&self,
script_public_keys: &ScriptPublicKeySet,
query: TransactionQuery,
) -> GroupedOwnerTransactions {
let mut owner_set = GroupedOwnerTransactions::default();
if query.include_transaction_pool() {
self.transaction_pool.fill_owner_set_transactions(script_public_keys, &mut owner_set);
}
if query.include_orphan_pool() {
self.orphan_pool.fill_owner_set_transactions(script_public_keys, &mut owner_set);
}
owner_set
}
pub(crate) fn transaction_count(&self, query: TransactionQuery) -> usize {
let mut count = 0;
if query.include_transaction_pool() {
count += self.transaction_pool.len()
}
if query.include_orphan_pool() {
count += self.orphan_pool.len()
}
count
}
pub(crate) fn ready_transaction_count(&self) -> usize {
self.transaction_pool.ready_transaction_count()
}
pub(crate) fn ready_transaction_total_mass(&self) -> u64 {
self.transaction_pool.ready_transaction_total_mass()
}
pub(crate) fn build_selector(&self) -> Box<dyn TemplateTransactionSelector> {
let _sw = Stopwatch::<10>::with_threshold("build_selector op");
self.transaction_pool.build_selector()
}
pub(crate) fn build_feerate_estimator(&self, args: FeerateEstimatorArgs) -> FeerateEstimator {
self.transaction_pool.build_feerate_estimator(args)
}
pub(crate) fn all_transaction_ids_with_priority(&self, priority: Priority) -> Vec<TransactionId> {
let _sw = Stopwatch::<15>::with_threshold("all_transaction_ids_with_priority op");
self.transaction_pool.all_transaction_ids_with_priority(priority)
}
pub(crate) fn update_revalidated_transaction(&mut self, transaction: MutableTransaction) -> bool {
self.transaction_pool.update_revalidated_transaction(transaction)
}
pub(crate) fn has_accepted_transaction(&self, transaction_id: &TransactionId) -> bool {
self.accepted_transactions.has(transaction_id)
}
pub(crate) fn unaccepted_transactions(&self, transactions: Vec<TransactionId>) -> Vec<TransactionId> {
self.accepted_transactions.unaccepted(&mut transactions.into_iter())
}
pub(crate) fn unknown_transactions(&self, transactions: Vec<TransactionId>) -> Vec<TransactionId> {
let mut not_in_pools_txs = transactions
.into_iter()
.filter(|transaction_id| !(self.transaction_pool.has(transaction_id) || self.orphan_pool.has(transaction_id)));
self.accepted_transactions.unaccepted(&mut not_in_pools_txs)
}
#[cfg(test)]
pub(crate) fn get_estimated_size(&self) -> usize {
self.transaction_pool.get_estimated_size()
}
}
pub mod tx {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Priority {
Low,
High,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Orphan {
Forbidden,
Allowed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RbfPolicy {
Forbidden,
Allowed,
Mandatory,
}
}