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
@@ -1956,8 +1956,8 @@ impl BlockChainClient for Client {
|
||||
(*self.build_last_hashes(&self.chain.read().best_block_hash())).clone()
|
||||
}
|
||||
|
||||
fn ready_transactions(&self) -> Vec<Arc<VerifiedTransaction>> {
|
||||
self.importer.miner.ready_transactions(self)
|
||||
fn ready_transactions(&self, max_len: usize) -> Vec<Arc<VerifiedTransaction>> {
|
||||
self.importer.miner.ready_transactions(self, max_len, ::miner::PendingOrdering::Priority)
|
||||
}
|
||||
|
||||
fn signing_chain_id(&self) -> Option<u64> {
|
||||
|
||||
@@ -48,7 +48,7 @@ use log_entry::LocalizedLogEntry;
|
||||
use receipt::{Receipt, LocalizedReceipt, TransactionOutcome};
|
||||
use error::ImportResult;
|
||||
use vm::Schedule;
|
||||
use miner::{Miner, MinerService};
|
||||
use miner::{self, Miner, MinerService};
|
||||
use spec::Spec;
|
||||
use types::basic_account::BasicAccount;
|
||||
use types::pruning_info::PruningInfo;
|
||||
@@ -806,8 +806,8 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
self.traces.read().clone()
|
||||
}
|
||||
|
||||
fn ready_transactions(&self) -> Vec<Arc<VerifiedTransaction>> {
|
||||
self.miner.ready_transactions(self)
|
||||
fn ready_transactions(&self, max_len: usize) -> Vec<Arc<VerifiedTransaction>> {
|
||||
self.miner.ready_transactions(self, max_len, miner::PendingOrdering::Priority)
|
||||
}
|
||||
|
||||
fn signing_chain_id(&self) -> Option<u64> { None }
|
||||
|
||||
@@ -321,7 +321,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra
|
||||
fn last_hashes(&self) -> LastHashes;
|
||||
|
||||
/// List all transactions that are allowed into the next block.
|
||||
fn ready_transactions(&self) -> Vec<Arc<VerifiedTransaction>>;
|
||||
fn ready_transactions(&self, max_len: usize) -> Vec<Arc<VerifiedTransaction>>;
|
||||
|
||||
/// Sorted list of transaction gas prices from at least last sample_size blocks.
|
||||
fn gas_price_corpus(&self, sample_size: usize) -> ::stats::Corpus<U256> {
|
||||
|
||||
@@ -364,18 +364,28 @@ impl Miner {
|
||||
|
||||
let client = self.pool_client(chain);
|
||||
let engine_params = self.engine.params();
|
||||
let min_tx_gas = self.engine.schedule(chain_info.best_block_number).tx_gas.into();
|
||||
let min_tx_gas: U256 = self.engine.schedule(chain_info.best_block_number).tx_gas.into();
|
||||
let nonce_cap: Option<U256> = if chain_info.best_block_number + 1 >= engine_params.dust_protection_transition {
|
||||
Some((engine_params.nonce_cap_increment * (chain_info.best_block_number + 1)).into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// we will never need more transactions than limit divided by min gas
|
||||
let max_transactions = if min_tx_gas.is_zero() {
|
||||
usize::max_value()
|
||||
} else {
|
||||
(*open_block.block().header().gas_limit() / min_tx_gas).as_u64() as usize
|
||||
};
|
||||
|
||||
let pending: Vec<Arc<_>> = self.transaction_queue.pending(
|
||||
client.clone(),
|
||||
chain_info.best_block_number,
|
||||
chain_info.best_block_timestamp,
|
||||
nonce_cap,
|
||||
pool::PendingSettings {
|
||||
block_number: chain_info.best_block_number,
|
||||
current_timestamp: chain_info.best_block_timestamp,
|
||||
nonce_cap,
|
||||
max_len: max_transactions,
|
||||
ordering: miner::PendingOrdering::Priority,
|
||||
}
|
||||
);
|
||||
|
||||
let took_ms = |elapsed: &Duration| {
|
||||
@@ -807,20 +817,28 @@ impl miner::MinerService for Miner {
|
||||
self.transaction_queue.all_transactions()
|
||||
}
|
||||
|
||||
fn ready_transactions<C>(&self, chain: &C) -> Vec<Arc<VerifiedTransaction>> where
|
||||
fn ready_transactions<C>(&self, chain: &C, max_len: usize, ordering: miner::PendingOrdering)
|
||||
-> Vec<Arc<VerifiedTransaction>>
|
||||
where
|
||||
C: ChainInfo + Nonce + Sync,
|
||||
{
|
||||
let chain_info = chain.chain_info();
|
||||
|
||||
let from_queue = || {
|
||||
// We propagate transactions over the nonce cap.
|
||||
// The mechanism is only to limit number of transactions in pending block
|
||||
// those transactions are valid and will just be ready to be included in next block.
|
||||
let nonce_cap = None;
|
||||
|
||||
self.transaction_queue.pending(
|
||||
CachedNonceClient::new(chain, &self.nonce_cache),
|
||||
chain_info.best_block_number,
|
||||
chain_info.best_block_timestamp,
|
||||
// We propagate transactions over the nonce cap.
|
||||
// The mechanism is only to limit number of transactions in pending block
|
||||
// those transactions are valid and will just be ready to be included in next block.
|
||||
None,
|
||||
pool::PendingSettings {
|
||||
block_number: chain_info.best_block_number,
|
||||
current_timestamp: chain_info.best_block_timestamp,
|
||||
nonce_cap,
|
||||
max_len,
|
||||
ordering,
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
@@ -830,6 +848,7 @@ impl miner::MinerService for Miner {
|
||||
.iter()
|
||||
.map(|signed| pool::VerifiedTransaction::from_pending_block_transaction(signed.clone()))
|
||||
.map(Arc::new)
|
||||
.take(max_len)
|
||||
.collect()
|
||||
}, chain_info.best_block_number)
|
||||
};
|
||||
@@ -1083,7 +1102,7 @@ mod tests {
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
use client::{TestBlockChainClient, EachBlockWith, ChainInfo, ImportSealedBlock};
|
||||
use miner::MinerService;
|
||||
use miner::{MinerService, PendingOrdering};
|
||||
use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts};
|
||||
use transaction::{Transaction};
|
||||
|
||||
@@ -1179,7 +1198,7 @@ mod tests {
|
||||
assert_eq!(res.unwrap(), ());
|
||||
assert_eq!(miner.pending_transactions(best_block).unwrap().len(), 1);
|
||||
assert_eq!(miner.pending_receipts(best_block).unwrap().len(), 1);
|
||||
assert_eq!(miner.ready_transactions(&client).len(), 1);
|
||||
assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1);
|
||||
// This method will let us know if pending block was created (before calling that method)
|
||||
assert!(!miner.prepare_pending_block(&client));
|
||||
}
|
||||
@@ -1198,7 +1217,7 @@ mod tests {
|
||||
assert_eq!(res.unwrap(), ());
|
||||
assert_eq!(miner.pending_transactions(best_block), None);
|
||||
assert_eq!(miner.pending_receipts(best_block), None);
|
||||
assert_eq!(miner.ready_transactions(&client).len(), 1);
|
||||
assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1217,11 +1236,11 @@ mod tests {
|
||||
assert_eq!(miner.pending_transactions(best_block), None);
|
||||
assert_eq!(miner.pending_receipts(best_block), None);
|
||||
// By default we use PendingSet::AlwaysSealing, so no transactions yet.
|
||||
assert_eq!(miner.ready_transactions(&client).len(), 0);
|
||||
assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 0);
|
||||
// This method will let us know if pending block was created (before calling that method)
|
||||
assert!(miner.prepare_pending_block(&client));
|
||||
// After pending block is created we should see a transaction.
|
||||
assert_eq!(miner.ready_transactions(&client).len(), 1);
|
||||
assert_eq!(miner.ready_transactions(&client, 10, PendingOrdering::Priority).len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -26,6 +26,7 @@ pub mod pool_client;
|
||||
pub mod stratum;
|
||||
|
||||
pub use self::miner::{Miner, MinerOptions, Penalization, PendingSet, AuthoringParams};
|
||||
pub use ethcore_miner::pool::PendingOrdering;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::BTreeMap;
|
||||
@@ -156,10 +157,12 @@ pub trait MinerService : Send + Sync {
|
||||
fn next_nonce<C>(&self, chain: &C, address: &Address) -> U256
|
||||
where C: Nonce + Sync;
|
||||
|
||||
/// Get a list of all ready transactions.
|
||||
/// Get a list of all ready transactions either ordered by priority or unordered (cheaper).
|
||||
///
|
||||
/// Depending on the settings may look in transaction pool or only in pending block.
|
||||
fn ready_transactions<C>(&self, chain: &C) -> Vec<Arc<VerifiedTransaction>>
|
||||
/// If you don't need a full set of transactions, you can add `max_len` and create only a limited set of
|
||||
/// transactions.
|
||||
fn ready_transactions<C>(&self, chain: &C, max_len: usize, ordering: PendingOrdering) -> Vec<Arc<VerifiedTransaction>>
|
||||
where C: ChainInfo + Nonce + Sync;
|
||||
|
||||
/// Get a list of all transactions in the pool (some of them might not be ready for inclusion yet).
|
||||
|
||||
@@ -30,7 +30,7 @@ use test_helpers::{
|
||||
use types::filter::Filter;
|
||||
use ethereum_types::{U256, Address};
|
||||
use kvdb_rocksdb::{Database, DatabaseConfig};
|
||||
use miner::Miner;
|
||||
use miner::{Miner, PendingOrdering};
|
||||
use spec::Spec;
|
||||
use views::BlockView;
|
||||
use ethkey::KeyPair;
|
||||
@@ -343,12 +343,12 @@ fn does_not_propagate_delayed_transactions() {
|
||||
|
||||
client.miner().import_own_transaction(&*client, tx0).unwrap();
|
||||
client.miner().import_own_transaction(&*client, tx1).unwrap();
|
||||
assert_eq!(0, client.ready_transactions().len());
|
||||
assert_eq!(0, client.miner().ready_transactions(&*client).len());
|
||||
assert_eq!(0, client.ready_transactions(10).len());
|
||||
assert_eq!(0, client.miner().ready_transactions(&*client, 10, PendingOrdering::Priority).len());
|
||||
push_blocks_to_client(&client, 53, 2, 2);
|
||||
client.flush_queue();
|
||||
assert_eq!(2, client.ready_transactions().len());
|
||||
assert_eq!(2, client.miner().ready_transactions(&*client).len());
|
||||
assert_eq!(2, client.ready_transactions(10).len());
|
||||
assert_eq!(2, client.miner().ready_transactions(&*client, 10, PendingOrdering::Priority).len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user