[ethcore]: apply filter when PendingSet::AlwaysQueue in ready_transactions_filtered (#11227)

* [ethcore]: apply filter when `from_queue`

In `ready_transactions_filtered` the filter were never applied when
the options PendingSet::AlwaysQueue` was configured which this fixes

It also adds a two tests for it

* [ethcore test-helpers]: stray printlns

* docs(ethcore filter options): more generic desc

* tests(ethcore miner): simply filter tests

* [ethcore filter_options]: fix nits

* doc: nit

Co-Authored-By: David <dvdplm@gmail.com>

* doc: nit

Co-Authored-By: David <dvdplm@gmail.com>

* doc: nit

Co-Authored-By: David <dvdplm@gmail.com>

* doc: nit

Co-Authored-By: David <dvdplm@gmail.com>

* doc: nit

Co-Authored-By: David <dvdplm@gmail.com>

* doc(miner filter): simplify documentation

* [rpc]: make tests compile
This commit is contained in:
Niklas Adolfsson 2019-11-25 12:03:50 +01:00 committed by Andronik Ordian
parent 1b0948d9d1
commit dcb69ba353
3 changed files with 922 additions and 820 deletions

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ use ethcore_miner::work_notify::NotifyWork;
use ethereum_types::{H256, U256, Address}; use ethereum_types::{H256, U256, Address};
use futures::sync::mpsc; use futures::sync::mpsc;
use io::IoChannel; use io::IoChannel;
use miner::filter_options::{FilterOptions, FilterOperator}; use miner::filter_options::FilterOptions;
use miner::pool_client::{PoolClient, CachedNonceClient, NonceCache}; use miner::pool_client::{PoolClient, CachedNonceClient, NonceCache};
use miner::{self, MinerService}; use miner::{self, MinerService};
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
@ -1095,7 +1095,8 @@ impl miner::MinerService for Miner {
max_len: usize, max_len: usize,
filter: Option<FilterOptions>, filter: Option<FilterOptions>,
ordering: miner::PendingOrdering, ordering: miner::PendingOrdering,
) -> Vec<Arc<VerifiedTransaction>> where ) -> Vec<Arc<VerifiedTransaction>>
where
C: ChainInfo + Nonce + Sync, C: ChainInfo + Nonce + Sync,
{ {
let chain_info = chain.chain_info(); let chain_info = chain.chain_info();
@ -1106,7 +1107,7 @@ impl miner::MinerService for Miner {
// those transactions are valid and will just be ready to be included in next block. // those transactions are valid and will just be ready to be included in next block.
let nonce_cap = None; let nonce_cap = None;
self.transaction_queue.pending( let mut pending = self.transaction_queue.pending(
CachedNonceClient::new(chain, &self.nonce_cache), CachedNonceClient::new(chain, &self.nonce_cache),
pool::PendingSettings { pool::PendingSettings {
block_number: chain_info.best_block_number, block_number: chain_info.best_block_number,
@ -1115,77 +1116,26 @@ impl miner::MinerService for Miner {
max_len, max_len,
ordering, ordering,
}, },
) );
pending.retain(|tx| {
filter.as_ref().map_or(true, |filter| {
filter.matches(tx.signed())
})
});
pending
}; };
use miner::filter_options::FilterOperator::*;
let from_pending = || { let from_pending = || {
self.map_existing_pending_block(|sealing| { self.map_existing_pending_block(|sealing| {
// This filter is used for gas, gas price, value and nonce.
// Sender and receiver have their custom matches, since those
// allow/disallow different operators.
fn match_common_filter(operator: &FilterOperator<U256>, tx_value: &U256) -> bool {
match operator {
Eq(value) => tx_value == value,
GreaterThan(value) => tx_value > value,
LessThan(value) => tx_value < value,
// Will always occur on `Any`, other operators
// get handled during deserialization
_ => true,
}
}
sealing.transactions sealing.transactions
.iter() .iter()
.map(|signed| pool::VerifiedTransaction::from_pending_block_transaction(signed.clone())) .map(|signed| pool::VerifiedTransaction::from_pending_block_transaction(signed.clone()))
.map(Arc::new) .map(Arc::new)
// Filter by sender
.filter(|tx| { .filter(|tx| {
filter.as_ref().map_or(true, |filter| { filter.as_ref().map_or(true, |filter| {
let sender = tx.signed().sender(); filter.matches(tx.signed())
match filter.from {
Eq(value) => sender == value,
// Will always occur on `Any`, other operators
// get handled during deserialization
_ => true,
}
})
})
// Filter by receiver
.filter(|tx| {
filter.as_ref().map_or(true, |filter| {
let receiver = (*tx.signed()).receiver();
match filter.to {
// Could apply to `Some(Address)` or `None` (for contract creation)
Eq(value) => receiver == value,
// Will always occur on `Any`, other operators
// get handled during deserialization
_ => true,
}
})
})
// Filter by gas
.filter(|tx| {
filter.as_ref().map_or(true, |filter| {
match_common_filter(&filter.gas, &(*tx.signed()).gas)
})
})
// Filter by gas price
.filter(|tx| {
filter.as_ref().map_or(true, |filter| {
match_common_filter(&filter.gas_price, &(*tx.signed()).gas_price)
})
})
// Filter by tx value
.filter(|tx| {
filter.as_ref().map_or(true, |filter| {
match_common_filter(&filter.value, &(*tx.signed()).value)
})
})
// Filter by nonce
.filter(|tx| {
filter.as_ref().map_or(true, |filter| {
match_common_filter(&filter.nonce, &(*tx.signed()).nonce)
}) })
}) })
.take(max_len) .take(max_len)
@ -1520,7 +1470,7 @@ mod tests {
use client_traits::ChainInfo; use client_traits::ChainInfo;
use client::ImportSealedBlock; use client::ImportSealedBlock;
use miner::{MinerService, PendingOrdering}; use miner::{MinerService, PendingOrdering, filter_options::FilterOperator};
use test_helpers::{ use test_helpers::{
generate_dummy_client, generate_dummy_client_with_spec, TestBlockChainClient, EachBlockWith generate_dummy_client, generate_dummy_client_with_spec, TestBlockChainClient, EachBlockWith
}; };
@ -1937,4 +1887,93 @@ mod tests {
assert!(received_error_msg == expected_error_msg); assert!(received_error_msg == expected_error_msg);
} }
fn filter_tester(option: PendingSet) {
let client = TestBlockChainClient::default();
let mut miner = miner();
miner.options.pending_set = option;
let transaction = transaction();
let best_block = 10;
let mut sender = transaction.sender();
miner.import_own_transaction(&client, PendingTransaction::new(transaction, None)).unwrap();
assert_eq!(miner.pending_transactions(best_block), None);
assert_eq!(miner.pending_receipts(best_block), None);
assert_eq!(
miner.ready_transactions_filtered(&client, 10, Some(FilterOptions::default()), PendingOrdering::Priority).len(),
1
);
// sender filter
{
// reverse address for false match
for byte in sender.as_bytes_mut() {
*byte = !*byte;
}
let mut filter = FilterOptions::default();
filter.from = FilterOperator::Eq(sender);
assert_eq!(
miner.ready_transactions_filtered(&client, 10, Some(filter), PendingOrdering::Priority).len(),
0
);
}
// receiver filter
{
let mut filter = FilterOptions::default();
filter.to = FilterOperator::Eq(Some(sender));
assert_eq!(
miner.ready_transactions_filtered(&client, 10, Some(filter), PendingOrdering::Priority).len(),
0
);
}
// gas filter
{
let mut filter = FilterOptions::default();
filter.gas = FilterOperator::LessThan(U256::from(100_000));
assert_eq!(
miner.ready_transactions_filtered(&client, 10, Some(filter), PendingOrdering::Priority).len(),
0
);
}
// gas_price filter
{
let mut filter = FilterOptions::default();
filter.gas_price = FilterOperator::GreaterThan(U256::from(10));
assert_eq!(
miner.ready_transactions_filtered(&client, 10, Some(filter), PendingOrdering::Priority).len(),
0
);
}
// value filter
{
let mut filter = FilterOptions::default();
filter.value = FilterOperator::Eq(U256::from(19));
assert_eq!(
miner.ready_transactions_filtered(&client, 10, Some(filter), PendingOrdering::Priority).len(),
0
);
}
// nonce filter
{
let mut filter = FilterOptions::default();
filter.nonce = FilterOperator::GreaterThan(U256::from(10));
assert_eq!(
miner.ready_transactions_filtered(&client, 10, Some(filter), PendingOrdering::Priority).len(),
0
);
}
}
#[test]
fn transaction_filtering() {
filter_tester(PendingSet::AlwaysQueue);
filter_tester(PendingSet::AlwaysSealing);
filter_tester(PendingSet::SealingOrElseQueue);
}
} }

View File

@ -229,8 +229,23 @@ impl MinerService for TestMinerService {
self.queued_transactions() self.queued_transactions()
} }
fn ready_transactions_filtered<C>(&self, _chain: &C, _max_len: usize, _filter: Option<FilterOptions>, _ordering: miner::PendingOrdering) -> Vec<Arc<VerifiedTransaction>> { fn ready_transactions_filtered<C>(
&self,
_chain: &C,
max_len: usize,
filter: Option<FilterOptions>,
_ordering: miner::PendingOrdering
) -> Vec<Arc<VerifiedTransaction>> {
self.queued_transactions() self.queued_transactions()
.iter()
.cloned()
.filter(|tx| {
filter.as_ref().map_or(true, |filter| {
filter.matches(tx.signed())
})
})
.take(max_len)
.collect()
} }
fn pending_transaction_hashes<C>(&self, _chain: &C) -> BTreeSet<H256> { fn pending_transaction_hashes<C>(&self, _chain: &C) -> BTreeSet<H256> {