Removing old transactions from the queue (#4046)

* Removing old transactions from the queue

* Addressing grumbles
This commit is contained in:
Tomasz Drwięga 2017-01-05 21:16:52 +01:00 committed by Gav Wood
parent fbc9f0d7fb
commit eb0daea9b9
3 changed files with 255 additions and 179 deletions

View File

@ -23,6 +23,7 @@ use std::cell::Cell;
use transaction::{SignedTransaction, Action};
use transient_hashmap::TransientHashMap;
use miner::{TransactionQueue, TransactionImportResult, TransactionOrigin, AccountDetails};
use miner::transaction_queue::QueuingInstant;
use error::{Error, TransactionError};
use util::{Uint, U256, H256, Address, Hashable};
@ -78,6 +79,7 @@ impl BanningTransactionQueue {
pub fn add_with_banlist<F, G>(
&mut self,
transaction: SignedTransaction,
time: QueuingInstant,
account_details: &F,
gas_estimator: &G,
) -> Result<TransactionImportResult, Error> where
@ -115,7 +117,7 @@ impl BanningTransactionQueue {
}
}
}
self.queue.add(transaction, TransactionOrigin::External, None, account_details, gas_estimator)
self.queue.add(transaction, TransactionOrigin::External, time, None, account_details, gas_estimator)
}
/// Ban transaction with given hash.
@ -158,7 +160,7 @@ impl BanningTransactionQueue {
Threshold::BanAfter(threshold) if count > threshold => {
// Banlist the sender.
// Remove all transactions from the queue.
self.remove_all(address, !U256::zero());
self.cull(address, !U256::zero());
true
},
_ => false
@ -263,7 +265,7 @@ mod tests {
let mut txq = queue();
// when
txq.queue().add(tx, TransactionOrigin::External, None, &default_account_details, &gas_required).unwrap();
txq.queue().add(tx, TransactionOrigin::External, 0, None, &default_account_details, &gas_required).unwrap();
// then
// should also deref to queue
@ -279,12 +281,12 @@ mod tests {
let banlist1 = txq.ban_sender(tx.sender().unwrap());
assert!(!banlist1, "Threshold not reached yet.");
// Insert once
let import1 = txq.add_with_banlist(tx.clone(), &default_account_details, &gas_required).unwrap();
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
assert_eq!(import1, TransactionImportResult::Current);
// when
let banlist2 = txq.ban_sender(tx.sender().unwrap());
let import2 = txq.add_with_banlist(tx.clone(), &default_account_details, &gas_required);
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
// then
assert!(banlist2, "Threshold should be reached - banned.");
@ -303,12 +305,12 @@ mod tests {
let banlist1 = txq.ban_recipient(recipient);
assert!(!banlist1, "Threshold not reached yet.");
// Insert once
let import1 = txq.add_with_banlist(tx.clone(), &default_account_details, &gas_required).unwrap();
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
assert_eq!(import1, TransactionImportResult::Current);
// when
let banlist2 = txq.ban_recipient(recipient);
let import2 = txq.add_with_banlist(tx.clone(), &default_account_details, &gas_required);
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
// then
assert!(banlist2, "Threshold should be reached - banned.");
@ -325,12 +327,12 @@ mod tests {
let banlist1 = txq.ban_codehash(codehash);
assert!(!banlist1, "Threshold not reached yet.");
// Insert once
let import1 = txq.add_with_banlist(tx.clone(), &default_account_details, &gas_required).unwrap();
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
assert_eq!(import1, TransactionImportResult::Current);
// when
let banlist2 = txq.ban_codehash(codehash);
let import2 = txq.add_with_banlist(tx.clone(), &default_account_details, &gas_required);
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
// then
assert!(banlist2, "Threshold should be reached - banned.");

View File

@ -417,15 +417,12 @@ impl Miner {
let block = open_block.close();
let fetch_account = |a: &Address| AccountDetails {
nonce: chain.latest_nonce(a),
balance: chain.latest_balance(a),
};
let fetch_nonce = |a: &Address| chain.latest_nonce(a);
{
let mut queue = self.transaction_queue.lock();
for hash in invalid_transactions {
queue.remove_invalid(&hash, &fetch_account);
queue.remove_invalid(&hash, &fetch_nonce);
}
for hash in transactions_to_penalize {
queue.penalize(&hash);
@ -597,6 +594,8 @@ impl Miner {
let schedule = chain.latest_schedule();
let gas_required = |tx: &SignedTransaction| tx.gas_required(&schedule).into();
let best_block_header = chain.best_block_header().decode();
let insertion_time = chain.chain_info().best_block_number;
transactions.into_iter()
.map(|tx| {
if chain.transaction_block(TransactionId::Hash(tx.hash())).is_some() {
@ -618,10 +617,10 @@ impl Miner {
match origin {
TransactionOrigin::Local | TransactionOrigin::RetractedBlock => {
transaction_queue.add(tx, origin, min_block, &fetch_account, &gas_required)
transaction_queue.add(tx, origin, insertion_time, min_block, &fetch_account, &gas_required)
},
TransactionOrigin::External => {
transaction_queue.add_with_banlist(tx, &fetch_account, &gas_required)
transaction_queue.add_with_banlist(tx, insertion_time, &fetch_account, &gas_required)
}
}
},
@ -1141,8 +1140,13 @@ impl MinerService for Miner {
// ...and at the end remove the old ones
{
let fetch_account = |a: &Address| AccountDetails {
nonce: chain.latest_nonce(a),
balance: chain.latest_balance(a),
};
let time = chain.chain_info().best_block_number;
let mut transaction_queue = self.transaction_queue.lock();
transaction_queue.remove_old(|sender| chain.latest_nonce(sender));
transaction_queue.remove_old(&fetch_account, time);
}
if enacted.len() > 0 {

View File

@ -51,8 +51,8 @@
//! let gas_estimator = |_tx: &SignedTransaction| 2.into();
//!
//! let mut txq = TransactionQueue::default();
//! txq.add(st2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
//! txq.add(st1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
//! txq.add(st2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
//! txq.add(st1.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
//!
//! // Check status
//! assert_eq!(txq.status().pending, 2);
@ -64,7 +64,7 @@
//!
//! // And when transaction is removed (but nonce haven't changed)
//! // it will move subsequent transactions to future
//! txq.remove_invalid(&st1.hash(), &default_account_details);
//! txq.remove_invalid(&st1.hash(), &|_| 10.into());
//! assert_eq!(txq.status().pending, 0);
//! assert_eq!(txq.status().future, 1);
//! assert_eq!(txq.top_transactions().len(), 0);
@ -78,11 +78,11 @@
//! - When it's removed from `future` - all `future` transactions heights are recalculated and then
//! we check if the transactions should go to `current` (comparing state nonce)
//! - When it's removed from `current` - all transactions from this sender (`current` & `future`) are recalculated.
//! 3. `remove_all` is used to inform the queue about client (state) nonce changes.
//! 3. `cull` is used to inform the queue about client (state) nonce changes.
//! - It removes all transactions (either from `current` or `future`) with nonce < client nonce
//! - It moves matching `future` transactions to `current`
//! 4. `remove_old` is used as convenient method to update the state nonce for all senders in the queue.
//! - Invokes `remove_all` with latest state nonce for all senders.
//! - Invokes `cull` with latest state nonce for all senders.
use std::ops::Deref;
use std::cmp::Ordering;
@ -258,16 +258,19 @@ struct VerifiedTransaction {
transaction: SignedTransaction,
/// Transaction origin.
origin: TransactionOrigin,
/// Insertion time
insertion_time: QueuingInstant,
/// Delay until specifid block.
min_block: Option<BlockNumber>,
}
impl VerifiedTransaction {
fn new(transaction: SignedTransaction, origin: TransactionOrigin, min_block: Option<BlockNumber>) -> Result<Self, Error> {
fn new(transaction: SignedTransaction, origin: TransactionOrigin, time: QueuingInstant, min_block: Option<BlockNumber>) -> Result<Self, Error> {
transaction.sender()?;
Ok(VerifiedTransaction {
transaction: transaction,
origin: origin,
insertion_time: time,
min_block: min_block,
})
}
@ -283,6 +286,10 @@ impl VerifiedTransaction {
fn sender(&self) -> Address {
self.transaction.sender().expect("Sender is verified in new; qed")
}
fn cost(&self) -> U256 {
self.transaction.value + self.transaction.gas_price * self.transaction.gas
}
}
#[derive(Debug, Default)]
@ -488,6 +495,10 @@ pub enum PrioritizationStrategy {
GasFactorAndGasPrice,
}
/// Point in time when transaction was inserted.
pub type QueuingInstant = BlockNumber;
const DEFAULT_QUEUING_PERIOD: BlockNumber = 128;
/// `TransactionQueue` implementation
pub struct TransactionQueue {
/// Prioritization strategy for this queue
@ -498,6 +509,10 @@ pub struct TransactionQueue {
tx_gas_limit: U256,
/// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0)
gas_limit: U256,
/// Maximal time transaction may occupy the queue.
/// When we reach `max_time_in_queue / 2^3` we re-validate
/// account balance.
max_time_in_queue: QueuingInstant,
/// Priority queue for transactions that can go to block
current: TransactionSet,
/// Priority queue for transactions that has been received but are not yet valid to go to block
@ -545,6 +560,7 @@ impl TransactionQueue {
minimal_gas_price: U256::zero(),
tx_gas_limit: tx_gas_limit,
gas_limit: !U256::zero(),
max_time_in_queue: DEFAULT_QUEUING_PERIOD,
current: current,
future: future,
by_hash: HashMap::new(),
@ -624,6 +640,7 @@ impl TransactionQueue {
&mut self,
tx: SignedTransaction,
origin: TransactionOrigin,
time: QueuingInstant,
min_block: Option<BlockNumber>,
fetch_account: &F,
gas_estimator: &G,
@ -635,7 +652,7 @@ impl TransactionQueue {
let hash = tx.hash();
let cloned_tx = tx.clone();
let result = self.add_internal(tx, origin, min_block, fetch_account, gas_estimator);
let result = self.add_internal(tx, origin, time, min_block, fetch_account, gas_estimator);
match result {
Ok(TransactionImportResult::Current) => {
self.local_transactions.mark_pending(hash);
@ -656,7 +673,7 @@ impl TransactionQueue {
}
result
} else {
self.add_internal(tx, origin, min_block, fetch_account, gas_estimator)
self.add_internal(tx, origin, time, min_block, fetch_account, gas_estimator)
}
}
@ -665,6 +682,7 @@ impl TransactionQueue {
&mut self,
tx: SignedTransaction,
origin: TransactionOrigin,
time: QueuingInstant,
min_block: Option<BlockNumber>,
fetch_account: &F,
gas_estimator: &G,
@ -734,10 +752,10 @@ impl TransactionQueue {
// Verify signature
tx.check_low_s()?;
let vtx = VerifiedTransaction::new(tx, origin, min_block)?;
let vtx = VerifiedTransaction::new(tx, origin, time, min_block)?;
let client_account = fetch_account(&vtx.sender());
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
let cost = vtx.cost();
if client_account.balance < cost {
trace!(target: "txqueue",
"Dropping transaction without sufficient balance: {:?} ({} < {})",
@ -759,7 +777,7 @@ impl TransactionQueue {
/// Removes all transactions from particular sender up to (excluding) given client (state) nonce.
/// Client (State) Nonce = next valid nonce for this sender.
pub fn remove_all(&mut self, sender: Address, client_nonce: U256) {
pub fn cull(&mut self, sender: Address, client_nonce: U256) {
// Check if there is anything in current...
let should_check_in_current = self.current.by_address.row(&sender)
// If nonce == client_nonce nothing is changed
@ -775,11 +793,11 @@ impl TransactionQueue {
return;
}
self.remove_all_internal(sender, client_nonce);
self.cull_internal(sender, client_nonce);
}
/// Always updates future and moves transactions from current to future.
fn remove_all_internal(&mut self, sender: Address, client_nonce: U256) {
fn cull_internal(&mut self, sender: Address, client_nonce: U256) {
// We will either move transaction to future or remove it completely
// so there will be no transactions from this sender in current
self.last_nonces.remove(&sender);
@ -794,16 +812,45 @@ impl TransactionQueue {
}
/// Checks the current nonce for all transactions' senders in the queue and removes the old transactions.
pub fn remove_old<F>(&mut self, fetch_nonce: F) where
F: Fn(&Address) -> U256,
pub fn remove_old<F>(&mut self, fetch_account: &F, current_time: QueuingInstant) where
F: Fn(&Address) -> AccountDetails,
{
let senders = self.current.by_address.keys()
.chain(self.future.by_address.keys())
.cloned()
.collect::<HashSet<_>>();
.map(|sender| (*sender, fetch_account(sender)))
.collect::<HashMap<_, _>>();
for sender in senders {
self.remove_all(sender, fetch_nonce(&sender));
for (sender, details) in senders.iter() {
self.cull(*sender, details.nonce);
}
let max_time = self.max_time_in_queue;
let balance_check = max_time >> 3;
// Clear transactions occupying the queue too long
let invalid = self.by_hash.iter()
.map(|(hash, tx)| (hash, tx, current_time.saturating_sub(tx.insertion_time)))
.filter_map(|(hash, tx, time_diff)| {
if time_diff > max_time {
return Some(*hash);
}
if time_diff > balance_check {
return match senders.get(&tx.sender()) {
Some(details) if tx.cost() > details.balance => {
Some(*hash)
},
_ => None,
};
}
None
})
.collect::<Vec<_>>();
let fetch_nonce = |a: &Address| senders.get(a)
.expect("We fetch details for all senders from both current and future")
.nonce;
for hash in invalid {
self.remove_invalid(&hash, &fetch_nonce);
}
}
@ -851,8 +898,8 @@ impl TransactionQueue {
/// so transactions left in queue are processed according to client nonce.
///
/// If gap is introduced marks subsequent transactions as future
pub fn remove_invalid<T>(&mut self, transaction_hash: &H256, fetch_account: &T)
where T: Fn(&Address) -> AccountDetails {
pub fn remove_invalid<T>(&mut self, transaction_hash: &H256, fetch_nonce: &T)
where T: Fn(&Address) -> U256 {
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
let transaction = self.by_hash.remove(transaction_hash);
@ -864,7 +911,7 @@ impl TransactionQueue {
let transaction = transaction.expect("None is tested in early-exit condition above; qed");
let sender = transaction.sender();
let nonce = transaction.nonce();
let current_nonce = fetch_account(&sender).nonce;
let current_nonce = fetch_nonce(&sender);
trace!(target: "txqueue", "Removing invalid transaction: {:?}", transaction.hash());
@ -889,7 +936,7 @@ impl TransactionQueue {
if order.is_some() {
// This will keep consistency in queue
// Moves all to future and then promotes a batch from current:
self.remove_all_internal(sender, current_nonce);
self.cull_internal(sender, current_nonce);
assert_eq!(self.future.by_priority.len() + self.current.by_priority.len(), self.by_hash.len());
return;
}
@ -1039,7 +1086,7 @@ impl TransactionQueue {
/// Finds transaction in the queue by hash (if any)
pub fn find(&self, hash: &H256) -> Option<SignedTransaction> {
match self.by_hash.get(hash) { Some(transaction_ref) => Some(transaction_ref.transaction.clone()), None => None }
self.by_hash.get(hash).map(|tx| tx.transaction.clone())
}
/// Removes all elements (in any state) from the queue
@ -1388,14 +1435,14 @@ mod test {
let (tx1, tx2) = new_tx_pair(123.into(), 1.into(), 1.into(), 0.into());
let sender = tx1.sender().unwrap();
let nonce = tx1.nonce;
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2);
assert_eq!(txq.last_nonce(&sender), Some(nonce + 1.into()));
// when
let tx = new_tx(123.into(), 1.into());
let res = txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
// No longer the case as we don't even consider a transaction that isn't above a full
@ -1427,12 +1474,12 @@ mod test {
gas_limit: !U256::zero(),
};
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None).unwrap();
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, 0, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, 0, None).unwrap();
let mut by_hash = {
let mut x = HashMap::new();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None).unwrap();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, 0, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, 0, None).unwrap();
x.insert(tx1.hash(), tx1);
x.insert(tx2.hash(), tx2);
x
@ -1470,12 +1517,12 @@ mod test {
// Create two transactions with same nonce
// (same hash)
let (tx1, tx2) = new_tx_pair_default(0.into(), 0.into());
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, None).unwrap();
let tx1 = VerifiedTransaction::new(tx1, TransactionOrigin::External, 0, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2, TransactionOrigin::External, 0, None).unwrap();
let by_hash = {
let mut x = HashMap::new();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, None).unwrap();
let tx1 = VerifiedTransaction::new(tx1.transaction.clone(), TransactionOrigin::External, 0, None).unwrap();
let tx2 = VerifiedTransaction::new(tx2.transaction.clone(), TransactionOrigin::External, 0, None).unwrap();
x.insert(tx1.hash(), tx1);
x.insert(tx2.hash(), tx2);
x
@ -1517,10 +1564,10 @@ mod test {
gas_limit: !U256::zero(),
};
let tx = new_tx_default();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None).unwrap();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, 0, None).unwrap();
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx1.sender(), tx1.nonce(), order1).is_none());
let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External, None).unwrap();
let tx2 = VerifiedTransaction::new(tx, TransactionOrigin::External, 0, None).unwrap();
let order2 = TransactionOrder::for_transaction(&tx2, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx2.sender(), tx2.nonce(), order2).is_some());
}
@ -1537,7 +1584,7 @@ mod test {
assert_eq!(set.gas_price_entry_limit(), 0.into());
let tx = new_tx_default();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, None).unwrap();
let tx1 = VerifiedTransaction::new(tx.clone(), TransactionOrigin::External, 0, None).unwrap();
let order1 = TransactionOrder::for_transaction(&tx1, 0.into(), 1.into(), PrioritizationStrategy::GasPriceOnly);
assert!(set.insert(tx1.sender(), tx1.nonce(), order1.clone()).is_none());
assert_eq!(set.gas_price_entry_limit(), 2.into());
@ -1552,12 +1599,12 @@ mod test {
!U256::zero() };
// First insert one transaction to future
let res = txq.add(tx, TransactionOrigin::External, None, &prev_nonce, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator);
assert_eq!(res.unwrap(), TransactionImportResult::Future);
assert_eq!(txq.status().future, 1);
// now import second transaction to current
let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// and then there should be only one transaction in current (the one with higher gas_price)
assert_eq!(res.unwrap(), TransactionImportResult::Current);
@ -1577,12 +1624,12 @@ mod test {
!U256::zero() };
// First insert one transaction to future
let res = txq.add(tx.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator);
let res = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator);
assert_eq!(res.unwrap(), TransactionImportResult::Future);
assert_eq!(txq.status().future, 1);
// now import second transaction to current
let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
@ -1601,7 +1648,7 @@ mod test {
let tx = new_tx_default();
// when
let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
@ -1620,10 +1667,10 @@ mod test {
txq.set_minimal_gas_price(15.into());
// when
let res1 = txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res1 = txq.add(tx1, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@ -1654,10 +1701,10 @@ mod test {
txq.set_minimal_gas_price(15.into());
// when
let res1 = txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res1 = txq.add(tx1, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
let res3 = txq.add(tx3, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
let res4 = txq.add(tx4, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@ -1700,7 +1747,7 @@ mod test {
txq.set_gas_limit(limit);
// when
let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::GasLimitExceeded {
@ -1724,7 +1771,7 @@ mod test {
};
// when
let res = txq.add(tx, TransactionOrigin::External, None, &account, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, 0, None, &account, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientBalance {
@ -1744,7 +1791,7 @@ mod test {
txq.set_minimal_gas_price(tx.gas_price + U256::one());
// when
let res = txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::InsufficientGasPrice {
@ -1764,7 +1811,7 @@ mod test {
txq.set_minimal_gas_price(tx.gas_price + U256::one());
// when
let res = txq.add(tx, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator);
// then
assert_eq!(res.unwrap(), TransactionImportResult::Current);
@ -1794,7 +1841,7 @@ mod test {
rlp::decode(s.as_raw())
};
// when
let res = txq.add(stx, TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res = txq.add(stx, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
assert!(res.is_err());
@ -1808,8 +1855,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.top_transactions();
@ -1828,9 +1875,9 @@ mod test {
// when
// first insert the one with higher gas price
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then the one with lower gas price, but local
txq.add(tx.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.top_transactions();
@ -1847,15 +1894,15 @@ mod test {
// the second one has same nonce but higher `gas_price`
let (_, tx0) = new_similar_tx_pair();
txq.add(tx0.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx0.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// the one with higher gas price is first
assert_eq!(txq.top_transactions()[0], tx0);
assert_eq!(txq.top_transactions()[1], tx1);
// when
// insert second as local
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
// the order should be updated
@ -1874,9 +1921,9 @@ mod test {
// when
// first insert local one with higher gas price
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
// then the one with lower gas price, but from retracted block
txq.add(tx.clone(), TransactionOrigin::RetractedBlock, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::RetractedBlock, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.top_transactions();
@ -1892,8 +1939,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.top_transactions();
@ -1912,10 +1959,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything
txq.add(txa.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(txa.clone(), TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 4);
@ -1940,10 +1987,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything
txq.add(txa.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txa.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
let top = txq.top_transactions();
assert_eq!(top[0], tx1);
@ -1973,10 +2020,10 @@ mod test {
let (tx1, tx2) = new_tx_pair_with_gas_price_increment(3.into());
// insert everything
txq.add(txa.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txa.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(txb.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
let top = txq.top_transactions();
assert_eq!(top[0], tx1);
@ -2005,8 +2052,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let top = txq.pending_hashes();
@ -2023,8 +2070,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(2.into(), 0.into());
// when
let res1 = txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let res1 = txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
assert_eq!(res1, TransactionImportResult::Current);
@ -2045,8 +2092,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// when
let res1 = txq.add(tx.clone(), TransactionOrigin::External, Some(1), &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
let res1 = txq.add(tx.clone(), TransactionOrigin::External, 0, Some(1), &default_account_details, &gas_estimator).unwrap();
let res2 = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
assert_eq!(res1, TransactionImportResult::Current);
@ -2067,12 +2114,12 @@ mod test {
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 2);
// when
txq.remove_all(tx.sender().unwrap(), next2_nonce);
txq.cull(tx.sender().unwrap(), next2_nonce);
// should remove both transactions since they are not valid
// then
@ -2090,13 +2137,13 @@ mod test {
let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None);
let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret, None);
txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 1);
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
// when
txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let stats = txq.status();
@ -2112,14 +2159,14 @@ mod test {
// given
let mut txq2 = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(3.into(), 0.into());
txq2.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq2.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq2.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq2.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq2.status().pending, 1);
assert_eq!(txq2.status().future, 1);
// when
txq2.remove_all(tx.sender().unwrap(), tx.nonce + U256::one());
txq2.remove_all(tx2.sender().unwrap(), tx2.nonce + U256::one());
txq2.cull(tx.sender().unwrap(), tx.nonce + U256::one());
txq2.cull(tx2.sender().unwrap(), tx2.nonce + U256::one());
// then
@ -2134,14 +2181,14 @@ mod test {
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx3 = new_tx_default();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 3);
// when
txq.remove_invalid(&tx.hash(), &default_account_details);
txq.remove_invalid(&tx.hash(), &|_| default_nonce());
// then
let stats = txq.status();
@ -2156,8 +2203,8 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
// add
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
let stats = txq.status();
assert_eq!(stats.pending, 2);
@ -2176,11 +2223,11 @@ mod test {
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let sender = tx.sender().unwrap();
let nonce = tx.nonce;
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 1);
// when
let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator);
let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator);
// then
let t = txq.top_transactions();
@ -2197,14 +2244,14 @@ mod test {
txq.current.set_limit(10);
let (tx1, tx2) = new_tx_pair_default(4.into(), 1.into());
let (tx3, tx4) = new_tx_pair_default(4.into(), 2.into());
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2);
// when
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
txq.add(tx4.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
assert_eq!(txq.status().future, 1);
@ -2215,11 +2262,11 @@ mod test {
let mut txq = TransactionQueue::with_limits(PrioritizationStrategy::GasPriceOnly, 100, default_gas_val() * U256::from(2), !U256::zero());
let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// limited by gas
txq.add(tx4.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap_err();
txq.add(tx4.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap_err();
assert_eq!(txq.status().pending, 2);
}
@ -2229,12 +2276,12 @@ mod test {
let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
let (tx5, _) = new_tx_pair_default(U256::from(1), U256::from(2));
txq.add(tx1.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
// Not accepted because of limit
txq.add(tx5.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap_err();
txq.add(tx3.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4.clone(), TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx5.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap_err();
txq.add(tx3.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4.clone(), TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 4);
}
@ -2246,7 +2293,7 @@ mod test {
let fetch_last_nonce = |_a: &Address| AccountDetails { nonce: last_nonce, balance: !U256::zero() };
// when
let res = txq.add(tx, TransactionOrigin::External, None, &fetch_last_nonce, &gas_estimator);
let res = txq.add(tx, TransactionOrigin::External, 0, None, &fetch_last_nonce, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::Old);
@ -2262,12 +2309,12 @@ mod test {
balance: !U256::zero() };
let mut txq = TransactionQueue::default();
let (_tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
assert_eq!(txq.status().pending, 0);
// when
let res = txq.add(tx2.clone(), TransactionOrigin::External, None, &nonce, &gas_estimator);
let res = txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &nonce, &gas_estimator);
// then
assert_eq!(unwrap_tx_err(res), TransactionError::AlreadyImported);
@ -2281,15 +2328,15 @@ mod test {
// given
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 2);
// when
txq.remove_invalid(&tx1.hash(), &default_account_details);
txq.remove_invalid(&tx1.hash(), &|_| default_nonce());
assert_eq!(txq.status().pending, 0);
assert_eq!(txq.status().future, 1);
txq.add(tx1.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let stats = txq.status();
@ -2303,15 +2350,15 @@ mod test {
let mut txq = TransactionQueue::default();
let (tx, tx2) = new_tx_pair_default(1.into(), 0.into());
let tx3 = new_tx_default();
txq.add(tx2.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
txq.add(tx3.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx.clone(), TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 3);
// when
let sender = tx.sender().unwrap();
txq.remove_all(sender, default_nonce() + U256::one());
txq.cull(sender, default_nonce() + U256::one());
// then
let stats = txq.status();
@ -2333,8 +2380,8 @@ mod test {
};
// when
txq.add(tx, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let stats = txq.status();
@ -2361,10 +2408,10 @@ mod test {
};
// when
txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 1);
txq.add(tx0, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx0, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
// then
let stats = txq.status();
@ -2376,18 +2423,16 @@ mod test {
#[test]
fn should_recalculate_height_when_removing_from_future() {
// given
let previous_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce - U256::one(), balance:
!U256::zero() };
let next_nonce = |a: &Address| AccountDetails{ nonce: default_account_details(a).nonce + U256::one(), balance:
!U256::zero() };
let previous_nonce = |a: &Address|
AccountDetails { nonce: default_account_details(a).nonce - U256::one(), balance: !U256::zero() };
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
txq.add(tx1.clone(), TransactionOrigin::External, None, &previous_nonce, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &previous_nonce, &gas_estimator).unwrap();
txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &previous_nonce, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, 0, None, &previous_nonce, &gas_estimator).unwrap();
assert_eq!(txq.status().future, 2);
// when
txq.remove_invalid(&tx1.hash(), &next_nonce);
txq.remove_invalid(&tx1.hash(), &|_| default_nonce() + 1.into());
// then
let stats = txq.status();
@ -2414,7 +2459,7 @@ mod test {
let details = |_a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() };
// when
txq.add(tx, TransactionOrigin::External, None, &details, &gas_estimator).unwrap();
txq.add(tx, TransactionOrigin::External, 0, None, &details, &gas_estimator).unwrap();
// then
assert_eq!(txq.last_nonce(&from), Some(nonce));
@ -2429,17 +2474,17 @@ mod test {
let details1 = |_a: &Address| AccountDetails { nonce: nonce1, balance: !U256::zero() };
// Insert first transaction
txq.add(tx1, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::External, 0, None, &details1, &gas_estimator).unwrap();
// when
txq.remove_all(tx2.sender().unwrap(), nonce2 + U256::one());
txq.cull(tx2.sender().unwrap(), nonce2 + U256::one());
// then
assert!(txq.top_transactions().is_empty());
}
#[test]
fn should_return_valid_last_nonce_after_remove_all() {
fn should_return_valid_last_nonce_after_cull() {
// given
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(4.into(), 0.into());
@ -2449,11 +2494,11 @@ mod test {
// when
// Insert first transaction
assert_eq!(txq.add(tx1, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.add(tx1, TransactionOrigin::External, 0, None, &details1, &gas_estimator).unwrap(), TransactionImportResult::Current);
// Second should go to future
assert_eq!(txq.add(tx2, TransactionOrigin::External, None, &details1, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx2, TransactionOrigin::External, 0, None, &details1, &gas_estimator).unwrap(), TransactionImportResult::Future);
// Now block is imported
txq.remove_all(sender, nonce2 - U256::from(1));
txq.cull(sender, nonce2 - U256::from(1));
// tx2 should be not be promoted to current
assert_eq!(txq.status().pending, 0);
assert_eq!(txq.status().future, 1);
@ -2470,9 +2515,9 @@ mod test {
assert_eq!(txq.has_local_pending_transactions(), false);
// when
assert_eq!(txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.add(tx1, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.has_local_pending_transactions(), false);
assert_eq!(txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
assert_eq!(txq.add(tx2, TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap(), TransactionImportResult::Current);
// then
assert_eq!(txq.has_local_pending_transactions(), true);
@ -2487,8 +2532,8 @@ mod test {
default_account_details(a).balance };
// when
assert_eq!(txq.add(tx2, TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx2, TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
assert_eq!(txq.add(tx1.clone(), TransactionOrigin::External, 0, None, &prev_nonce, &gas_estimator).unwrap(), TransactionImportResult::Future);
// then
assert_eq!(txq.future.by_priority.len(), 1);
@ -2513,14 +2558,14 @@ mod test {
(tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None))
};
let sender = tx1.sender().unwrap();
txq.add(tx1, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::Local, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.future.by_priority.len(), 0);
assert_eq!(txq.current.by_priority.len(), 3);
// when
let res = txq.add(tx2_2, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
let res = txq.add(tx2_2, TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator);
// then
assert_eq!(txq.last_nonce(&sender).unwrap(), 125.into());
@ -2536,8 +2581,8 @@ mod test {
let high_gas = |_: &SignedTransaction| 100_001.into();
// when
let res1 = txq.add(tx1, TransactionOrigin::Local, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::Local, None, &default_account_details, &high_gas);
let res1 = txq.add(tx1, TransactionOrigin::Local, 0, None, &default_account_details, &gas_estimator);
let res2 = txq.add(tx2, TransactionOrigin::Local, 0, None, &default_account_details, &high_gas);
// then
assert_eq!(res1.unwrap(), TransactionImportResult::Current);
@ -2554,20 +2599,45 @@ mod test {
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
let (tx3, tx4) = new_tx_pair_default(1.into(), 0.into());
let nonce1 = tx1.nonce;
let next_nonce = |_: &Address|
AccountDetails { nonce: default_nonce() + U256::one(), balance: !U256::zero() };
// Insert all transactions
txq.add(tx1, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4, TransactionOrigin::External, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx1, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.top_transactions().len(), 4);
// when
txq.remove_old(|_| nonce1 + U256::one());
txq.remove_old(&next_nonce, 0);
// then
assert_eq!(txq.top_transactions().len(), 2);
}
#[test]
fn should_remove_out_of_date_transactions_occupying_queue() {
// given
let mut txq = TransactionQueue::default();
let (tx1, tx2) = new_tx_pair_default(1.into(), 0.into());
let (tx3, tx4) = new_tx_pair_default(2.into(), 0.into());
// Insert all transactions
txq.add(tx1, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx2, TransactionOrigin::External, 5, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx3.clone(), TransactionOrigin::External, 10, None, &default_account_details, &gas_estimator).unwrap();
txq.add(tx4, TransactionOrigin::External, 0, None, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.top_transactions().len(), 3);
assert_eq!(txq.future_transactions().len(), 1);
// when
txq.remove_old(&default_account_details, 9 + super::DEFAULT_QUEUING_PERIOD);
// then
assert_eq!(txq.top_transactions().len(), 1);
assert_eq!(txq.future_transactions().len(), 0);
assert_eq!(txq.top_transactions(), vec![tx3]);
}
}