Recalculating heights in future when removing transaction

This commit is contained in:
Tomasz Drwięga 2016-03-05 16:42:34 +01:00
parent 6afa1c85b7
commit 0a7fc4af73

View File

@ -238,26 +238,50 @@ impl TransactionQueue {
// We don't know this transaction // We don't know this transaction
return; return;
} }
let transaction = transaction.unwrap(); let transaction = transaction.unwrap();
let sender = transaction.sender(); let sender = transaction.sender();
let nonce = transaction.nonce(); let nonce = transaction.nonce();
let current_nonce = fetch_nonce(&sender);
// Remove from future // Remove from future
self.future.drop(&sender, &nonce); let order = self.future.drop(&sender, &nonce);
if order.is_some() {
// Remove from current self.recalculate_future_for_sender(&sender, current_nonce);
let order = self.current.drop(&sender, &nonce); // And now lets check if there is some chain of transactions in future
if order.is_none() { // that should be placed in current
self.move_future_txs(sender.clone(), current_nonce, current_nonce);
return; return;
} }
// Let's remove transactions where tx.nonce < current_nonce // Remove from current
// and if there are any future transactions matching current_nonce+1 - move to current let order = self.current.drop(&sender, &nonce);
let current_nonce = fetch_nonce(&sender); if order.is_some() {
// We will either move transaction to future or remove it completely // We will either move transaction to future or remove it completely
// so there will be no transactions from this sender in current // so there will be no transactions from this sender in current
self.last_nonces.remove(&sender); self.last_nonces.remove(&sender);
// This should move all current transactions to future and remove old transactions
self.move_all_to_future(&sender, current_nonce);
// And now lets check if there is some chain of transactions in future
// that should be placed in current. It should also update last_nonces.
self.move_future_txs(sender.clone(), current_nonce, current_nonce);
return;
}
}
fn recalculate_future_for_sender(&mut self, sender: &Address, current_nonce: U256) {
// We need to drain all transactions for current sender from future and reinsert them with updated height
let all_nonces_from_sender = match self.future.by_address.row(&sender) {
Some(row_map) => row_map.keys().cloned().collect::<Vec<U256>>(),
None => vec![],
};
for k in all_nonces_from_sender {
let order = self.future.drop(&sender, &k).unwrap();
self.future.insert(sender.clone(), k, order.update_height(k, current_nonce));
}
}
fn move_all_to_future(&mut self, sender: &Address, current_nonce: U256) {
let all_nonces_from_sender = match self.current.by_address.row(&sender) { let all_nonces_from_sender = match self.current.by_address.row(&sender) {
Some(row_map) => row_map.keys().cloned().collect::<Vec<U256>>(), Some(row_map) => row_map.keys().cloned().collect::<Vec<U256>>(),
None => vec![], None => vec![],
@ -273,14 +297,9 @@ impl TransactionQueue {
} }
} }
self.future.enforce_limit(&mut self.by_hash); self.future.enforce_limit(&mut self.by_hash);
// And now lets check if there is some chain of transactions in future
// that should be placed in current
if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce, current_nonce) {
self.last_nonces.insert(sender, new_current_top);
}
} }
/// Returns top transactions from the queue /// Returns top transactions from the queue
pub fn top_transactions(&self, size: usize) -> Vec<SignedTransaction> { pub fn top_transactions(&self, size: usize) -> Vec<SignedTransaction> {
self.current.by_priority self.current.by_priority
@ -299,11 +318,11 @@ impl TransactionQueue {
self.last_nonces.clear(); self.last_nonces.clear();
} }
fn move_future_txs(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) -> Option<U256> { fn move_future_txs(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) {
{ {
let by_nonce = self.future.by_address.row_mut(&address); let by_nonce = self.future.by_address.row_mut(&address);
if let None = by_nonce { if let None = by_nonce {
return None; return;
} }
let mut by_nonce = by_nonce.unwrap(); let mut by_nonce = by_nonce.unwrap();
while let Some(order) = by_nonce.remove(&current_nonce) { while let Some(order) = by_nonce.remove(&current_nonce) {
@ -316,8 +335,8 @@ impl TransactionQueue {
} }
} }
self.future.by_address.clear_if_empty(&address); self.future.by_address.clear_if_empty(&address);
// Returns last inserted nonce // Update last inserted nonce
Some(current_nonce - U256::one()) self.last_nonces.insert(address, current_nonce - U256::one());
} }
fn import_tx<T>(&mut self, tx: VerifiedTransaction, fetch_nonce: &T) fn import_tx<T>(&mut self, tx: VerifiedTransaction, fetch_nonce: &T)
@ -353,9 +372,9 @@ impl TransactionQueue {
let base_nonce = fetch_nonce(&address); let base_nonce = fetch_nonce(&address);
Self::replace_transaction(tx, base_nonce.clone(), &mut self.current, &mut self.by_hash); Self::replace_transaction(tx, base_nonce.clone(), &mut self.current, &mut self.by_hash);
self.last_nonces.insert(address.clone(), nonce);
// But maybe there are some more items waiting in future? // But maybe there are some more items waiting in future?
let new_last_nonce = self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce); self.move_future_txs(address.clone(), nonce + U256::one(), base_nonce);
self.last_nonces.insert(address.clone(), new_last_nonce.unwrap_or(nonce));
self.current.enforce_limit(&mut self.by_hash); self.current.enforce_limit(&mut self.by_hash);
} }
@ -777,6 +796,7 @@ mod test {
fn should_recalculate_height_when_removing_from_future() { fn should_recalculate_height_when_removing_from_future() {
// given // given
let previous_nonce = |a: &Address| default_nonce(a) - U256::one(); let previous_nonce = |a: &Address| default_nonce(a) - U256::one();
let next_nonce = |a: &Address| default_nonce(a) + U256::one();
let mut txq = TransactionQueue::new(); let mut txq = TransactionQueue::new();
let (tx1, tx2) = new_txs(U256::one()); let (tx1, tx2) = new_txs(U256::one());
txq.add(tx1.clone(), &previous_nonce); txq.add(tx1.clone(), &previous_nonce);
@ -784,7 +804,7 @@ mod test {
assert_eq!(txq.status().future, 2); assert_eq!(txq.status().future, 2);
// when // when
txq.remove(&tx1.hash(), &default_nonce); txq.remove(&tx1.hash(), &next_nonce);
// then // then
let stats = txq.status(); let stats = txq.status();