From 59db5e3bd18d60bd87656dff109a7a56af2e203f Mon Sep 17 00:00:00 2001 From: Quentin Le Sceller Date: Mon, 13 May 2019 18:03:47 -0400 Subject: [PATCH] Evict transaction from transaction pool (#2797) * Evict transaction from transaction pool * Remove Result from evict function --- pool/src/pool.rs | 2 +- pool/src/transaction_pool.rs | 44 +++++++++++++++++++++++++++++++----- pool/src/types.rs | 2 +- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/pool/src/pool.rs b/pool/src/pool.rs index e21b147023..036c4eff36 100644 --- a/pool/src/pool.rs +++ b/pool/src/pool.rs @@ -310,7 +310,7 @@ impl Pool { /// containing the tx it depends on. /// Sorting the buckets by fee_to_weight will therefore preserve dependency ordering, /// maximizing both cut-through and overall fees. - fn bucket_transactions(&self, weighting: Weighting) -> Vec { + pub fn bucket_transactions(&self, weighting: Weighting) -> Vec { let mut tx_buckets: Vec = Vec::new(); let mut output_commits = HashMap::new(); let mut rejected = HashSet::new(); diff --git a/pool/src/transaction_pool.rs b/pool/src/transaction_pool.rs index f0e0d81de4..3d92aa1da7 100644 --- a/pool/src/transaction_pool.rs +++ b/pool/src/transaction_pool.rs @@ -138,7 +138,13 @@ impl TransactionPool { } // Do we have the capacity to accept this transaction? - self.is_acceptable(&tx, stem)?; + let acceptability = self.is_acceptable(&tx, stem); + let mut evict = false; + if !stem && acceptability.as_ref().err() == Some(&PoolError::OverCapacity) { + evict = true; + } else if acceptability.is_err() { + return acceptability; + } // Make sure the transaction is valid before anything else. // Validate tx accounting for max tx weight. @@ -171,9 +177,36 @@ impl TransactionPool { self.adapter.tx_accepted(&entry.tx); } + // Transaction passed all the checks but we have to make space for it + if evict { + self.evict_from_txpool(); + } + Ok(()) } + // Remove the last transaction from the flattened bucket transactions. + // No other tx depends on it, it has low fee_to_weight and is unlikely to participate in any cut-through. + pub fn evict_from_txpool(&mut self) { + // Get bucket transactions + let bucket_transactions = self.txpool.bucket_transactions(Weighting::NoLimit); + + // Get last transaction and remove it + match bucket_transactions.last() { + Some(evictable_transaction) => { + // Remove transaction + self.txpool.entries = self + .txpool + .entries + .iter() + .filter(|x| x.tx != *evictable_transaction) + .map(|x| x.clone()) + .collect::>(); + } + None => (), + } + } + // Old txs will "age out" after 30 mins. pub fn truncate_reorg_cache(&mut self, cutoff: DateTime) { let mut cache = self.reorg_cache.write(); @@ -245,11 +278,10 @@ impl TransactionPool { } // Check that the stempool can accept this transaction - if stem { - if self.stempool.size() > self.config.max_stempool_size { - // TODO evict old/large transactions instead - return Err(PoolError::OverCapacity); - } + if stem && self.stempool.size() > self.config.max_stempool_size { + return Err(PoolError::OverCapacity); + } else if self.total_size() > self.config.max_pool_size { + return Err(PoolError::OverCapacity); } // for a basic transaction (1 input, 2 outputs) - diff --git a/pool/src/types.rs b/pool/src/types.rs index 20397a514e..3faee7e659 100644 --- a/pool/src/types.rs +++ b/pool/src/types.rs @@ -162,7 +162,7 @@ pub struct TxSource { } /// Possible errors when interacting with the transaction pool. -#[derive(Debug, Fail)] +#[derive(Debug, Fail, PartialEq)] pub enum PoolError { /// An invalid pool entry caused by underlying tx validation error #[fail(display = "Invalid Tx {}", _0)]