diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs index 359220405..dbe3c08f4 100644 --- a/miner/src/pool/scoring.rs +++ b/miner/src/pool/scoring.rs @@ -143,6 +143,10 @@ impl txpool::Scoring for NonceAndGasPrice { } } } + + fn should_ignore_sender_limit(&self, new: &VerifiedTransaction) -> bool { + new.priority().is_local() + } } #[cfg(test)] diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index b5cbaab63..1f6935589 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -116,12 +116,11 @@ fn should_never_drop_local_transactions_from_different_senders() { let r1 = txq.import(TestClient::new(), vec![tx1].local()); let r2 = txq.import(TestClient::new(), vec![tx2].local()); assert_eq!(r1, vec![Ok(())]); - // max-per-sender is reached, that's ok. - assert_eq!(r2, vec![Err(transaction::Error::LimitReached)]); - assert_eq!(txq.status().status.transaction_count, 1); + assert_eq!(r2, vec![Ok(())]); + assert_eq!(txq.status().status.transaction_count, 2); // then - assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 1.into())); + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 2.into())); // when let tx1 = Tx::gas_price(2).signed(); @@ -134,8 +133,8 @@ fn should_never_drop_local_transactions_from_different_senders() { // then assert_eq!(res, vec![Ok(()), Ok(())]); assert_eq!(res2, vec![Ok(()), Ok(())]); - assert_eq!(txq.status().status.transaction_count, 5); - assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 1.into())); + assert_eq!(txq.status().status.transaction_count, 6); + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 2.into())); } #[test] diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index e2fa36c0e..c94b736b8 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -613,3 +613,4 @@ impl<'a, T, R, S, L> Iterator for PendingIterator<'a, T, R, S, L> where None } } + diff --git a/transaction-pool/src/scoring.rs b/transaction-pool/src/scoring.rs index 390e016af..25189604c 100644 --- a/transaction-pool/src/scoring.rs +++ b/transaction-pool/src/scoring.rs @@ -102,6 +102,12 @@ pub trait Scoring: fmt::Debug { /// /// NOTE returning `InsertNew` here can lead to some transactions being accepted above pool limits. fn should_replace(&self, old: &T, new: &T) -> Choice; + + /// Decides if the transaction should ignore per-sender limit in the pool. + /// + /// If you return `true` for given transaction it's going to be accepted even though + /// the per-sender limit is exceeded. + fn should_ignore_sender_limit(&self, _new: &T) -> bool { false } } /// A score with a reference to the transaction. diff --git a/transaction-pool/src/tests/helpers.rs b/transaction-pool/src/tests/helpers.rs index 76a81eb9a..9918db91b 100644 --- a/transaction-pool/src/tests/helpers.rs +++ b/transaction-pool/src/tests/helpers.rs @@ -77,6 +77,10 @@ impl Scoring for DummyScoring { scoring::Choice::RejectNew } } + + fn should_ignore_sender_limit(&self, _new: &Transaction) -> bool { + self.always_insert + } } #[derive(Default)] diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index 0029d0622..85260133e 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -591,6 +591,33 @@ fn should_not_import_even_if_limit_is_reached_and_should_replace_returns_false() }); } +#[test] +fn should_import_even_if_sender_limit_is_reached() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::with_scoring(DummyScoring::always_insert(), Options { + max_count: 1, + max_per_sender: 1, + ..Default::default() + }); + txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + assert_eq!(txq.light_status(), LightStatus { + transaction_count: 1, + senders: 1, + mem_usage: 0, + }); + + // when + txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap(); + + // then + assert_eq!(txq.light_status(), LightStatus { + transaction_count: 2, + senders: 1, + mem_usage: 0, + }); +} + mod listener { use std::cell::RefCell; use std::rc::Rc; diff --git a/transaction-pool/src/transactions.rs b/transaction-pool/src/transactions.rs index edc26b69f..96fe2e91b 100644 --- a/transaction-pool/src/transactions.rs +++ b/transaction-pool/src/transactions.rs @@ -95,7 +95,7 @@ impl> Transactions { fn push_cheapest_transaction(&mut self, tx: Transaction, scoring: &S, max_count: usize) -> AddResult, S::Score> { let index = self.transactions.len(); - if index == max_count { + if index == max_count && !scoring.should_ignore_sender_limit(&tx) { let min_score = self.scores[index - 1].clone(); AddResult::TooCheapToEnter(tx, min_score) } else {