use crate::prelude::*;
use anyhow::{anyhow, Result};
use std::collections::{HashMap, HashSet};
#[derive(Clone, Debug)]
pub struct MemoryPool<N: Network> {
transactions: HashMap<N::TransactionID, Transaction<N>>,
serial_numbers: HashSet<N::SerialNumber>,
commitments: HashSet<N::Commitment>,
#[allow(dead_code)]
requests: HashSet<Request<N>>,
}
impl<N: Network> MemoryPool<N> {
pub fn new() -> Self {
Self {
transactions: Default::default(),
serial_numbers: Default::default(),
commitments: Default::default(),
requests: Default::default(),
}
}
pub fn contains_transaction(&self, transaction: &Transaction<N>) -> bool {
self.transactions.contains_key(&transaction.transaction_id())
}
pub fn transactions(&self) -> Vec<Transaction<N>> {
self.transactions.values().cloned().collect()
}
pub fn add_transaction(&mut self, transaction: &Transaction<N>) -> Result<()> {
if !transaction.is_valid() {
return Err(anyhow!("The unconfirmed transaction is invalid"));
}
if transaction.value_balance().is_negative() {
return Err(anyhow!("The unconfirmed transaction is attempting to mint new value"));
}
let transaction_id = transaction.transaction_id();
if self.transactions.contains_key(&transaction_id) {
return Err(anyhow!("Transaction already exists in memory pool"));
}
for serial_number in transaction.serial_numbers() {
if self.serial_numbers.contains(serial_number) {
return Err(anyhow!("Serial number already used in memory pool"));
}
}
for commitment in transaction.commitments() {
if self.commitments.contains(commitment) {
return Err(anyhow!("Commitment already used in memory pool"));
}
}
{
let mut memory_pool = self.clone();
memory_pool.transactions.insert(transaction_id, transaction.clone());
for serial_number in transaction.serial_numbers() {
memory_pool.serial_numbers.insert(*serial_number);
}
for commitment in transaction.commitments() {
memory_pool.commitments.insert(*commitment);
}
*self = memory_pool;
}
Ok(())
}
pub fn remove_transaction(&mut self, transaction: &Transaction<N>) {
let mut memory_pool = self.clone();
memory_pool.transactions.remove(&transaction.transaction_id());
for serial_number in transaction.serial_numbers() {
memory_pool.serial_numbers.remove(serial_number);
}
for commitment in transaction.commitments() {
memory_pool.commitments.remove(commitment);
}
*self = memory_pool;
}
pub fn remove_transactions(&mut self, transactions: &[Transaction<N>]) {
let mut memory_pool = self.clone();
for transaction in transactions {
memory_pool.transactions.remove(&transaction.transaction_id());
for serial_number in transaction.serial_numbers() {
memory_pool.serial_numbers.remove(serial_number);
}
for commitment in transaction.commitments() {
memory_pool.commitments.remove(commitment);
}
}
*self = memory_pool;
}
pub fn clear_all_transactions(&mut self) {
self.transactions = Default::default();
self.serial_numbers = Default::default();
self.commitments = Default::default();
}
}
impl<N: Network> Default for MemoryPool<N> {
fn default() -> Self {
Self::new()
}
}