Limit the number of transactions in pending set (#8777)
* Unordered iterator. * Use unordered and limited set if full not required. * Split timeout work into smaller timers. * Avoid collecting all pending transactions when mining * Remove println. * Use priority ordering in eth-filter. * Fix ethcore-miner tests and tx propagation. * Review grumbles addressed. * Add test for unordered not populating the cache. * Fix ethcore tests. * Fix light tests. * Fix ethcore-sync tests. * Fix RPC tests.
This commit is contained in:
committed by
Marek Kotewicz
parent
4817b94d0b
commit
4938d5dde5
@@ -18,7 +18,7 @@ use ethereum_types::U256;
|
||||
use transaction::{self, PendingTransaction};
|
||||
use txpool;
|
||||
|
||||
use pool::{verifier, TransactionQueue, PrioritizationStrategy};
|
||||
use pool::{verifier, TransactionQueue, PrioritizationStrategy, PendingSettings, PendingOrdering};
|
||||
|
||||
pub mod tx;
|
||||
pub mod client;
|
||||
@@ -108,7 +108,7 @@ fn should_handle_same_transaction_imported_twice_with_different_state_nonces() {
|
||||
// and then there should be only one transaction in current (the one with higher gas_price)
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 1);
|
||||
let top = txq.pending(TestClient::new(), 0, 0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(top[0].hash, hash);
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ fn should_move_all_transactions_from_future() {
|
||||
// then
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 2);
|
||||
let top = txq.pending(TestClient::new(), 0, 0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(top[0].hash, hash);
|
||||
assert_eq!(top[1].hash, hash2);
|
||||
}
|
||||
@@ -207,7 +207,7 @@ fn should_import_txs_from_same_sender() {
|
||||
txq.import(TestClient::new(), txs.local().into_vec());
|
||||
|
||||
// then
|
||||
let top = txq.pending(TestClient::new(), 0 ,0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0 ,0));
|
||||
assert_eq!(top[0].hash, hash);
|
||||
assert_eq!(top[1].hash, hash2);
|
||||
assert_eq!(top.len(), 2);
|
||||
@@ -229,7 +229,7 @@ fn should_prioritize_local_transactions_within_same_nonce_height() {
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
|
||||
// then
|
||||
let top = txq.pending(client, 0, 0, None);
|
||||
let top = txq.pending(client, PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(top[0].hash, hash); // local should be first
|
||||
assert_eq!(top[1].hash, hash2);
|
||||
assert_eq!(top.len(), 2);
|
||||
@@ -251,7 +251,7 @@ fn should_prioritize_reimported_transactions_within_same_nonce_height() {
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
|
||||
// then
|
||||
let top = txq.pending(TestClient::new(), 0, 0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(top[0].hash, hash); // retracted should be first
|
||||
assert_eq!(top[1].hash, hash2);
|
||||
assert_eq!(top.len(), 2);
|
||||
@@ -270,7 +270,7 @@ fn should_not_prioritize_local_transactions_with_different_nonce_height() {
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
|
||||
// then
|
||||
let top = txq.pending(TestClient::new(), 0, 0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(top[0].hash, hash);
|
||||
assert_eq!(top[1].hash, hash2);
|
||||
assert_eq!(top.len(), 2);
|
||||
@@ -288,7 +288,7 @@ fn should_put_transaction_to_futures_if_gap_detected() {
|
||||
|
||||
// then
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
let top = txq.pending(TestClient::new(), 0, 0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(top.len(), 1);
|
||||
assert_eq!(top[0].hash, hash);
|
||||
}
|
||||
@@ -308,9 +308,9 @@ fn should_handle_min_block() {
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
|
||||
// then
|
||||
let top = txq.pending(TestClient::new(), 0, 0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(top.len(), 0);
|
||||
let top = txq.pending(TestClient::new(), 1, 0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(1, 0));
|
||||
assert_eq!(top.len(), 2);
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ fn should_move_transactions_if_gap_filled() {
|
||||
let res = txq.import(TestClient::new(), vec![tx, tx2].local());
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1);
|
||||
|
||||
// when
|
||||
let res = txq.import(TestClient::new(), vec![tx1.local()]);
|
||||
@@ -349,7 +349,7 @@ fn should_move_transactions_if_gap_filled() {
|
||||
|
||||
// then
|
||||
assert_eq!(txq.status().status.transaction_count, 3);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -361,12 +361,12 @@ fn should_remove_transaction() {
|
||||
let res = txq.import(TestClient::default(), vec![tx, tx2].local());
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1);
|
||||
|
||||
// when
|
||||
txq.cull(TestClient::new().with_nonce(124));
|
||||
assert_eq!(txq.status().status.transaction_count, 1);
|
||||
assert_eq!(txq.pending(TestClient::new().with_nonce(125), 0, 0, None).len(), 1);
|
||||
assert_eq!(txq.pending(TestClient::new().with_nonce(125), PendingSettings::all_prioritized(0, 0)).len(), 1);
|
||||
txq.cull(TestClient::new().with_nonce(126));
|
||||
|
||||
// then
|
||||
@@ -384,19 +384,19 @@ fn should_move_transactions_to_future_if_gap_introduced() {
|
||||
let res = txq.import(TestClient::new(), vec![tx3, tx2].local());
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1);
|
||||
|
||||
let res = txq.import(TestClient::new(), vec![tx].local());
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 3);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 3);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 3);
|
||||
|
||||
// when
|
||||
txq.remove(vec![&hash], true);
|
||||
|
||||
// then
|
||||
assert_eq!(txq.status().status.transaction_count, 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -447,7 +447,7 @@ fn should_prefer_current_transactions_when_hitting_the_limit() {
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 1);
|
||||
|
||||
let top = txq.pending(TestClient::new(), 0, 0, None);
|
||||
let top = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(top.len(), 1);
|
||||
assert_eq!(top[0].hash, hash);
|
||||
assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(124.into()));
|
||||
@@ -494,19 +494,19 @@ fn should_accept_same_transaction_twice_if_removed() {
|
||||
let res = txq.import(TestClient::new(), txs.local().into_vec());
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 2);
|
||||
|
||||
// when
|
||||
txq.remove(vec![&hash], true);
|
||||
assert_eq!(txq.status().status.transaction_count, 1);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 0);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 0);
|
||||
|
||||
let res = txq.import(TestClient::new(), vec![tx1].local());
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
|
||||
// then
|
||||
assert_eq!(txq.status().status.transaction_count, 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -526,8 +526,8 @@ fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() {
|
||||
// then
|
||||
assert_eq!(res, vec![Err(transaction::Error::TooCheapToReplace), Ok(())]);
|
||||
assert_eq!(txq.status().status.transaction_count, 2);
|
||||
assert_eq!(txq.pending(client.clone(), 0, 0, None)[0].signed().gas_price, U256::from(20));
|
||||
assert_eq!(txq.pending(client.clone(), 0, 0, None)[1].signed().gas_price, U256::from(2));
|
||||
assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[0].signed().gas_price, U256::from(20));
|
||||
assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[1].signed().gas_price, U256::from(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -569,7 +569,7 @@ fn should_return_valid_last_nonce_after_cull() {
|
||||
let client = TestClient::new().with_nonce(124);
|
||||
txq.cull(client.clone());
|
||||
// tx2 should be not be promoted to current
|
||||
assert_eq!(txq.pending(client.clone(), 0, 0, None).len(), 0);
|
||||
assert_eq!(txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0)).len(), 0);
|
||||
|
||||
// then
|
||||
assert_eq!(txq.next_nonce(client.clone(), &sender), None);
|
||||
@@ -667,7 +667,7 @@ fn should_accept_local_transactions_below_min_gas_price() {
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
|
||||
// then
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -685,7 +685,7 @@ fn should_accept_local_service_transaction() {
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
|
||||
// then
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 0, None).len(), 1);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0)).len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -726,15 +726,77 @@ fn should_not_return_transactions_over_nonce_cap() {
|
||||
assert_eq!(res, vec![Ok(()), Ok(()), Ok(())]);
|
||||
|
||||
// when
|
||||
let all = txq.pending(TestClient::new(), 0, 0, None);
|
||||
let all = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
// This should invalidate the cache!
|
||||
let limited = txq.pending(TestClient::new(), 0, 0, Some(123.into()));
|
||||
let limited = txq.pending(TestClient::new(), PendingSettings {
|
||||
block_number: 0,
|
||||
current_timestamp: 0,
|
||||
nonce_cap: Some(123.into()),
|
||||
max_len: usize::max_value(),
|
||||
ordering: PendingOrdering::Priority,
|
||||
});
|
||||
|
||||
// then
|
||||
assert_eq!(all.len(), 3);
|
||||
assert_eq!(limited.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_cached_pending_even_if_unordered_is_requested() {
|
||||
// given
|
||||
let txq = new_queue();
|
||||
let tx1 = Tx::default().signed();
|
||||
let (tx2_1, tx2_2)= Tx::default().signed_pair();
|
||||
let tx2_1_hash = tx2_1.hash();
|
||||
let res = txq.import(TestClient::new(), vec![tx1].unverified());
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
let res = txq.import(TestClient::new(), vec![tx2_1, tx2_2].local());
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
|
||||
// when
|
||||
let all = txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 0));
|
||||
assert_eq!(all[0].hash, tx2_1_hash);
|
||||
assert_eq!(all.len(), 3);
|
||||
|
||||
// This should not invalidate the cache!
|
||||
let limited = txq.pending(TestClient::new(), PendingSettings {
|
||||
block_number: 0,
|
||||
current_timestamp: 0,
|
||||
nonce_cap: None,
|
||||
max_len: 3,
|
||||
ordering: PendingOrdering::Unordered,
|
||||
});
|
||||
|
||||
// then
|
||||
assert_eq!(all, limited);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_unordered_and_not_populate_the_cache() {
|
||||
// given
|
||||
let txq = new_queue();
|
||||
let tx1 = Tx::default().signed();
|
||||
let (tx2_1, tx2_2)= Tx::default().signed_pair();
|
||||
let res = txq.import(TestClient::new(), vec![tx1].unverified());
|
||||
assert_eq!(res, vec![Ok(())]);
|
||||
let res = txq.import(TestClient::new(), vec![tx2_1, tx2_2].local());
|
||||
assert_eq!(res, vec![Ok(()), Ok(())]);
|
||||
|
||||
// when
|
||||
// This should not invalidate the cache!
|
||||
let limited = txq.pending(TestClient::new(), PendingSettings {
|
||||
block_number: 0,
|
||||
current_timestamp: 0,
|
||||
nonce_cap: None,
|
||||
max_len: usize::max_value(),
|
||||
ordering: PendingOrdering::Unordered,
|
||||
});
|
||||
|
||||
// then
|
||||
assert_eq!(limited.len(), 3);
|
||||
assert!(!txq.is_pending_cached());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_clear_cache_after_timeout_for_local() {
|
||||
// given
|
||||
@@ -748,12 +810,12 @@ fn should_clear_cache_after_timeout_for_local() {
|
||||
|
||||
// This should populate cache and set timestamp to 1
|
||||
// when
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 1, None).len(), 0);
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 1000, None).len(), 0);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1)).len(), 0);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1000)).len(), 0);
|
||||
|
||||
// This should invalidate the cache and trigger transaction ready.
|
||||
// then
|
||||
assert_eq!(txq.pending(TestClient::new(), 0, 1002, None).len(), 2);
|
||||
assert_eq!(txq.pending(TestClient::new(), PendingSettings::all_prioritized(0, 1002)).len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user