From 52eb8a117eb35d840aada9aaa735970d9836c6ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Thu, 21 Jun 2018 14:38:13 +0100 Subject: [PATCH 1/9] rpc: return unordered transactions in pending transactions filter --- rpc/src/v1/helpers/poll_filter.rs | 2 +- rpc/src/v1/impls/eth_filter.rs | 21 ++++++++------------- rpc/src/v1/impls/light/eth.rs | 5 +++-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs index a7e42bb4068..3fb6a45e161 100644 --- a/rpc/src/v1/helpers/poll_filter.rs +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -28,7 +28,7 @@ pub enum PollFilter { /// Number of last block which client was notified about. Block(BlockNumber), /// Hashes of all transactions which client was notified about. - PendingTransaction(Vec), + PendingTransaction(HashSet), /// Number of From block number, last seen block hash, pending logs and log filter itself. Logs(BlockNumber, Option, HashSet, Filter) } diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index b79456cd8db..380df5f4631 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -41,8 +41,8 @@ pub trait Filterable { /// Get a block hash by block id. fn block_hash(&self, id: BlockId) -> Option; - /// pending transaction hashes at the given block. - fn pending_transactions_hashes(&self) -> Vec; + /// pending transaction hashes at the given block (unordered). + fn pending_transactions_hashes(&self) -> HashSet; /// Get logs that match the given filter. fn logs(&self, filter: EthcoreFilter) -> BoxFuture>; @@ -87,8 +87,8 @@ impl Filterable for EthFilterClient where self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> Vec { - self.miner.ready_transactions(&*self.client, usize::max_value(), miner::PendingOrdering::Priority) + fn pending_transactions_hashes(&self) -> HashSet { + self.miner.ready_transactions(&*self.client, usize::max_value(), miner::PendingOrdering::Unordered) .into_iter() .map(|tx| tx.signed().hash()) .collect() @@ -182,17 +182,12 @@ impl EthFilter for T { // get hashes of pending transactions let current_hashes = self.pending_transactions_hashes(); - let new_hashes = - { - let previous_hashes_set = previous_hashes.iter().collect::>(); - - // find all new hashes - current_hashes - .iter() - .filter(|hash| !previous_hashes_set.contains(hash)) + let new_hashes = { + // find all new hashes + current_hashes.difference(previous_hashes) .cloned() .map(Into::into) - .collect::>() + .collect() }; // save all hashes of pending transactions diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 7c47967b277..a488b9c93d8 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -16,6 +16,7 @@ //! Eth RPC interface for the light client. +use std::collections::HashSet; use std::sync::Arc; use jsonrpc_core::{Result, BoxFuture}; @@ -537,8 +538,8 @@ impl Filterable for EthClient { self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> Vec<::ethereum_types::H256> { - Vec::new() + fn pending_transactions_hashes(&self) -> HashSet<::ethereum_types::H256> { + HashSet::new() } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { From 473791d3179301aee5eabc435186575115e83fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Wed, 27 Jun 2018 12:21:40 +0100 Subject: [PATCH 2/9] ethcore: use LruCache for nonce cache Only clear the nonce cache when a block is retracted --- Cargo.lock | 1 + ethcore/private-tx/Cargo.toml | 1 + ethcore/private-tx/src/lib.rs | 10 +++++++--- ethcore/src/miner/miner.rs | 17 +++++++++++------ ethcore/src/miner/pool_client.rs | 24 +++++------------------- 5 files changed, 25 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 494f9c084a9..63909aceab3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -783,6 +783,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index e32c81bc26f..17db3dadd39 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -24,6 +24,7 @@ fetch = { path = "../../util/fetch" } futures = "0.1" keccak-hash = { path = "../../util/hash" } log = "0.3" +lru-cache = "0.1" parking_lot = "0.5" patricia-trie = { path = "../../util/patricia_trie" } rand = "0.3" diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 38285ed85b5..5b95ee10719 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -38,6 +38,7 @@ extern crate ethjson; extern crate fetch; extern crate futures; extern crate keccak_hash as hash; +extern crate lru_cache; extern crate parking_lot; extern crate patricia_trie as trie; extern crate rlp; @@ -69,6 +70,7 @@ use std::collections::{HashMap, HashSet}; use std::time::Duration; use ethereum_types::{H128, H256, U256, Address}; use hash::keccak; +use lru_cache::LruCache; use rlp::*; use parking_lot::{Mutex, RwLock}; use bytes::Bytes; @@ -95,6 +97,8 @@ use_contract!(private, "PrivateContract", "res/private.json"); /// Initialization vector length. const INIT_VEC_LEN: usize = 16; +const MAX_NONCE_CACHE_SIZE: usize = 4096; + /// Configurtion for private transaction provider #[derive(Default, PartialEq, Debug, Clone)] pub struct ProviderConfig { @@ -244,7 +248,7 @@ impl Provider where { Ok(original_transaction) } - fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { + fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { let engine = self.client.engine(); let refuse_service_transactions = true; miner::pool_client::PoolClient::new( @@ -263,7 +267,7 @@ impl Provider where { /// can be replaced with a single `drain()` method instead. /// Thanks to this we also don't really need to lock the entire verification for the time of execution. fn process_queue(&self) -> Result<(), Error> { - let nonce_cache = Default::default(); + let nonce_cache = RwLock::new(LruCache::new(MAX_NONCE_CACHE_SIZE)); let mut verification_queue = self.transactions_for_verification.lock(); let ready_transactions = verification_queue.ready_transactions(self.pool_client(&nonce_cache)); for transaction in ready_transactions { @@ -584,7 +588,7 @@ impl Importer for Arc { trace!("Validating transaction: {:?}", original_tx); // Verify with the first account available trace!("The following account will be used for verification: {:?}", validation_account); - let nonce_cache = Default::default(); + let nonce_cache = RwLock::new(LruCache::new(MAX_NONCE_CACHE_SIZE)); self.transactions_for_verification.lock().add_transaction( original_tx, contract, diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index db496e40dc0..d36581f6138 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::time::{Instant, Duration}; -use std::collections::{BTreeMap, HashSet, HashMap}; +use std::collections::{BTreeMap, HashSet}; use std::sync::Arc; use ansi_term::Colour; @@ -26,6 +26,7 @@ use ethcore_miner::gas_pricer::GasPricer; use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy}; use ethcore_miner::work_notify::NotifyWork; use ethereum_types::{H256, U256, Address}; +use lru_cache::LruCache; use parking_lot::{Mutex, RwLock}; use rayon::prelude::*; use transaction::{ @@ -96,6 +97,8 @@ const DEFAULT_MINIMAL_GAS_PRICE: u64 = 20_000_000_000; /// in case we have only a fraction of available block gas limit left. const MAX_SKIPPED_TRANSACTIONS: usize = 8; +const MAX_NONCE_CACHE_SIZE: usize = 4096; + /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] pub struct MinerOptions { @@ -201,7 +204,7 @@ pub struct Miner { sealing: Mutex, params: RwLock, listeners: RwLock>>, - nonce_cache: RwLock>, + nonce_cache: RwLock>, gas_pricer: Mutex, options: MinerOptions, // TODO [ToDr] Arc is only required because of price updater @@ -240,7 +243,7 @@ impl Miner { params: RwLock::new(AuthoringParams::default()), listeners: RwLock::new(vec![]), gas_pricer: Mutex::new(gas_pricer), - nonce_cache: RwLock::new(HashMap::with_capacity(1024)), + nonce_cache: RwLock::new(LruCache::new(MAX_NONCE_CACHE_SIZE)), options, transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)), accounts, @@ -1065,13 +1068,15 @@ impl miner::MinerService for Miner { // 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that // are in those blocks - // Clear nonce cache - self.nonce_cache.write().clear(); - // First update gas limit in transaction queue and minimal gas price. let gas_limit = *chain.best_block_header().gas_limit(); self.update_transaction_queue_limits(gas_limit); + if retracted.len() != 0 { + // Clear nonce cache + self.nonce_cache.write().clear(); + } + // Then import all transactions... let client = self.pool_client(chain); { diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs index bcf93d37532..de43eefa7be 100644 --- a/ethcore/src/miner/pool_client.rs +++ b/ethcore/src/miner/pool_client.rs @@ -17,11 +17,11 @@ //! Blockchain access for transaction pool. use std::fmt; -use std::collections::HashMap; -use ethereum_types::{H256, U256, Address}; -use ethcore_miner::pool; use ethcore_miner::pool::client::NonceClient; +use ethcore_miner::pool; +use ethereum_types::{H256, U256, Address}; +use lru_cache::LruCache; use transaction::{ self, UnverifiedTransaction, @@ -36,10 +36,7 @@ use header::Header; use miner; use miner::service_transaction_checker::ServiceTransactionChecker; -type NoncesCache = RwLock>; - -const MAX_NONCE_CACHE_SIZE: usize = 4096; -const EXPECTED_NONCE_CACHE_SIZE: usize = 2048; +type NoncesCache = RwLock>; /// Blockchain accesss for transaction pool. pub struct PoolClient<'a, C: 'a> { @@ -194,7 +191,7 @@ impl<'a, C: 'a> NonceClient for CachedNonceClient<'a, C> where C: Nonce + Sync, { fn account_nonce(&self, address: &Address) -> U256 { - if let Some(nonce) = self.cache.read().get(address) { + if let Some(nonce) = self.cache.write().get_mut(address) { return *nonce; } @@ -204,17 +201,6 @@ impl<'a, C: 'a> NonceClient for CachedNonceClient<'a, C> where let nonce = self.client.latest_nonce(address); cache.insert(*address, nonce); - if cache.len() < MAX_NONCE_CACHE_SIZE { - return nonce - } - - // Remove excessive amount of entries from the cache - while cache.len() > EXPECTED_NONCE_CACHE_SIZE { - // Just remove random entry - if let Some(key) = cache.keys().next().cloned() { - cache.remove(&key); - } - } nonce } } From d5fff50ace317ff085f24e640bcd65a6ab7eb160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 29 Jun 2018 11:44:39 +0200 Subject: [PATCH 3/9] Revert "ethcore: use LruCache for nonce cache" This reverts commit b382c19abdb9985be1724c3b8cde83906da07d68. --- Cargo.lock | 1 - ethcore/private-tx/Cargo.toml | 1 - ethcore/private-tx/src/lib.rs | 10 +++------- ethcore/src/miner/miner.rs | 17 ++++++----------- ethcore/src/miner/pool_client.rs | 24 +++++++++++++++++++----- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63909aceab3..494f9c084a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -783,7 +783,6 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index 17db3dadd39..e32c81bc26f 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -24,7 +24,6 @@ fetch = { path = "../../util/fetch" } futures = "0.1" keccak-hash = { path = "../../util/hash" } log = "0.3" -lru-cache = "0.1" parking_lot = "0.5" patricia-trie = { path = "../../util/patricia_trie" } rand = "0.3" diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 5b95ee10719..38285ed85b5 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -38,7 +38,6 @@ extern crate ethjson; extern crate fetch; extern crate futures; extern crate keccak_hash as hash; -extern crate lru_cache; extern crate parking_lot; extern crate patricia_trie as trie; extern crate rlp; @@ -70,7 +69,6 @@ use std::collections::{HashMap, HashSet}; use std::time::Duration; use ethereum_types::{H128, H256, U256, Address}; use hash::keccak; -use lru_cache::LruCache; use rlp::*; use parking_lot::{Mutex, RwLock}; use bytes::Bytes; @@ -97,8 +95,6 @@ use_contract!(private, "PrivateContract", "res/private.json"); /// Initialization vector length. const INIT_VEC_LEN: usize = 16; -const MAX_NONCE_CACHE_SIZE: usize = 4096; - /// Configurtion for private transaction provider #[derive(Default, PartialEq, Debug, Clone)] pub struct ProviderConfig { @@ -248,7 +244,7 @@ impl Provider where { Ok(original_transaction) } - fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { + fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { let engine = self.client.engine(); let refuse_service_transactions = true; miner::pool_client::PoolClient::new( @@ -267,7 +263,7 @@ impl Provider where { /// can be replaced with a single `drain()` method instead. /// Thanks to this we also don't really need to lock the entire verification for the time of execution. fn process_queue(&self) -> Result<(), Error> { - let nonce_cache = RwLock::new(LruCache::new(MAX_NONCE_CACHE_SIZE)); + let nonce_cache = Default::default(); let mut verification_queue = self.transactions_for_verification.lock(); let ready_transactions = verification_queue.ready_transactions(self.pool_client(&nonce_cache)); for transaction in ready_transactions { @@ -588,7 +584,7 @@ impl Importer for Arc { trace!("Validating transaction: {:?}", original_tx); // Verify with the first account available trace!("The following account will be used for verification: {:?}", validation_account); - let nonce_cache = RwLock::new(LruCache::new(MAX_NONCE_CACHE_SIZE)); + let nonce_cache = Default::default(); self.transactions_for_verification.lock().add_transaction( original_tx, contract, diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index d36581f6138..db496e40dc0 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::time::{Instant, Duration}; -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashSet, HashMap}; use std::sync::Arc; use ansi_term::Colour; @@ -26,7 +26,6 @@ use ethcore_miner::gas_pricer::GasPricer; use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy}; use ethcore_miner::work_notify::NotifyWork; use ethereum_types::{H256, U256, Address}; -use lru_cache::LruCache; use parking_lot::{Mutex, RwLock}; use rayon::prelude::*; use transaction::{ @@ -97,8 +96,6 @@ const DEFAULT_MINIMAL_GAS_PRICE: u64 = 20_000_000_000; /// in case we have only a fraction of available block gas limit left. const MAX_SKIPPED_TRANSACTIONS: usize = 8; -const MAX_NONCE_CACHE_SIZE: usize = 4096; - /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] pub struct MinerOptions { @@ -204,7 +201,7 @@ pub struct Miner { sealing: Mutex, params: RwLock, listeners: RwLock>>, - nonce_cache: RwLock>, + nonce_cache: RwLock>, gas_pricer: Mutex, options: MinerOptions, // TODO [ToDr] Arc is only required because of price updater @@ -243,7 +240,7 @@ impl Miner { params: RwLock::new(AuthoringParams::default()), listeners: RwLock::new(vec![]), gas_pricer: Mutex::new(gas_pricer), - nonce_cache: RwLock::new(LruCache::new(MAX_NONCE_CACHE_SIZE)), + nonce_cache: RwLock::new(HashMap::with_capacity(1024)), options, transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)), accounts, @@ -1068,15 +1065,13 @@ impl miner::MinerService for Miner { // 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that // are in those blocks + // Clear nonce cache + self.nonce_cache.write().clear(); + // First update gas limit in transaction queue and minimal gas price. let gas_limit = *chain.best_block_header().gas_limit(); self.update_transaction_queue_limits(gas_limit); - if retracted.len() != 0 { - // Clear nonce cache - self.nonce_cache.write().clear(); - } - // Then import all transactions... let client = self.pool_client(chain); { diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs index de43eefa7be..bcf93d37532 100644 --- a/ethcore/src/miner/pool_client.rs +++ b/ethcore/src/miner/pool_client.rs @@ -17,11 +17,11 @@ //! Blockchain access for transaction pool. use std::fmt; +use std::collections::HashMap; -use ethcore_miner::pool::client::NonceClient; -use ethcore_miner::pool; use ethereum_types::{H256, U256, Address}; -use lru_cache::LruCache; +use ethcore_miner::pool; +use ethcore_miner::pool::client::NonceClient; use transaction::{ self, UnverifiedTransaction, @@ -36,7 +36,10 @@ use header::Header; use miner; use miner::service_transaction_checker::ServiceTransactionChecker; -type NoncesCache = RwLock>; +type NoncesCache = RwLock>; + +const MAX_NONCE_CACHE_SIZE: usize = 4096; +const EXPECTED_NONCE_CACHE_SIZE: usize = 2048; /// Blockchain accesss for transaction pool. pub struct PoolClient<'a, C: 'a> { @@ -191,7 +194,7 @@ impl<'a, C: 'a> NonceClient for CachedNonceClient<'a, C> where C: Nonce + Sync, { fn account_nonce(&self, address: &Address) -> U256 { - if let Some(nonce) = self.cache.write().get_mut(address) { + if let Some(nonce) = self.cache.read().get(address) { return *nonce; } @@ -201,6 +204,17 @@ impl<'a, C: 'a> NonceClient for CachedNonceClient<'a, C> where let nonce = self.client.latest_nonce(address); cache.insert(*address, nonce); + if cache.len() < MAX_NONCE_CACHE_SIZE { + return nonce + } + + // Remove excessive amount of entries from the cache + while cache.len() > EXPECTED_NONCE_CACHE_SIZE { + // Just remove random entry + if let Some(key) = cache.keys().next().cloned() { + cache.remove(&key); + } + } nonce } } From a44c27103514ba6e5a0273f2b3213731151838d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 29 Jun 2018 12:21:20 +0200 Subject: [PATCH 4/9] Use only cached nonces when computing pending hashes. --- ethcore/src/miner/miner.rs | 33 ++++++++++++++++++++++++++++++- ethcore/src/miner/mod.rs | 8 +++++++- miner/src/pool/queue.rs | 15 +++++++++++++- miner/src/pool/ready.rs | 32 ++++++++++++++++++++++++++++++ rpc/src/v1/helpers/poll_filter.rs | 4 ++-- rpc/src/v1/impls/eth_filter.rs | 11 ++++------- rpc/src/v1/impls/light/eth.rs | 6 +++--- 7 files changed, 94 insertions(+), 15 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index db496e40dc0..571bce4a965 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::time::{Instant, Duration}; -use std::collections::{BTreeMap, HashSet, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashSet, HashMap}; use std::sync::Arc; use ansi_term::Colour; @@ -851,6 +851,37 @@ impl miner::MinerService for Miner { self.transaction_queue.all_transactions() } + fn pending_transactions_hashes(&self, chain: &C) -> BTreeSet where + C: ChainInfo + Sync, + { + let chain_info = chain.chain_info(); + + let from_queue = || self.transaction_queue.pending_hashes( + |sender| self.nonce_cache.read().get(sender).cloned(), + ); + + let from_pending = || { + self.map_existing_pending_block(|sealing| { + sealing.transactions() + .iter() + .map(|signed| signed.hash()) + .collect() + }, chain_info.best_block_number) + }; + + match self.options.pending_set { + PendingSet::AlwaysQueue => { + from_queue() + }, + PendingSet::AlwaysSealing => { + from_pending().unwrap_or_default() + }, + PendingSet::SealingOrElseQueue => { + from_pending().unwrap_or_else(from_queue) + }, + } + } + fn ready_transactions(&self, chain: &C, max_len: usize, ordering: miner::PendingOrdering) -> Vec> where diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 44d9ecf71af..37162c55941 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -29,7 +29,7 @@ pub use self::miner::{Miner, MinerOptions, Penalization, PendingSet, AuthoringPa pub use ethcore_miner::pool::PendingOrdering; use std::sync::Arc; -use std::collections::BTreeMap; +use std::collections::{BTreeSet, BTreeMap}; use bytes::Bytes; use ethereum_types::{H256, U256, Address}; @@ -164,6 +164,12 @@ pub trait MinerService : Send + Sync { fn next_nonce(&self, chain: &C, address: &Address) -> U256 where C: Nonce + Sync; + /// Get a set of all pending transactions hashes. + /// + /// Depending on the settings may look in transaction pool or only in pending block. + fn pending_transactions_hashes(&self, chain: &C) -> BTreeSet where + C: ChainInfo + Sync; + /// 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. diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index 4351087b29b..8b16eaa6483 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -19,7 +19,7 @@ use std::{cmp, fmt}; use std::sync::Arc; use std::sync::atomic::{self, AtomicUsize}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use ethereum_types::{H256, U256, Address}; use parking_lot::RwLock; @@ -220,6 +220,19 @@ impl TransactionQueue { self.pool.read().unordered_pending(ready).collect() } + /// Computes unordered set of pending hashes. + /// + /// Since strict nonce-checking is not required, you may get some false positive future transactions as well. + pub fn pending_hashes( + &self, + nonce: N, + ) -> BTreeSet where + N: Fn(&Address) -> Option, + { + let ready = ready::OptionalState::new(nonce); + self.pool.read().unordered_pending(ready).map(|tx| tx.hash).collect() + } + /// Returns current pending transactions ordered by priority. /// /// NOTE: This may return a cached version of pending transaction set. diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs index 0b4d27f7f2c..d0e33cae0e6 100644 --- a/miner/src/pool/ready.rs +++ b/miner/src/pool/ready.rs @@ -129,6 +129,38 @@ impl txpool::Ready for Condition { } } +pub struct OptionalState { + nonces: HashMap, + state: C, +} + +impl OptionalState { + pub fn new(state: C) -> Self { + OptionalState { + nonces: Default::default(), + state, + } + } +} + +impl Option> txpool::Ready for OptionalState { + fn is_ready(&mut self, tx: &VerifiedTransaction) -> txpool::Readiness { + let sender = tx.sender(); + let state = &self.state; + let nonce = self.nonces.entry(*sender).or_insert_with(|| { + state(sender).unwrap_or_else(|| tx.transaction.nonce) + }); + match tx.transaction.nonce.cmp(nonce) { + cmp::Ordering::Greater => txpool::Readiness::Future, + cmp::Ordering::Less => txpool::Readiness::Stale, + cmp::Ordering::Equal => { + *nonce = *nonce + 1.into(); + txpool::Readiness::Ready + }, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs index 3fb6a45e161..e616c47eedf 100644 --- a/rpc/src/v1/helpers/poll_filter.rs +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -16,7 +16,7 @@ //! Helper type with all filter state data. -use std::collections::HashSet; +use std::collections::{BTreeSet, HashSet}; use ethereum_types::H256; use v1::types::{Filter, Log}; @@ -28,7 +28,7 @@ pub enum PollFilter { /// Number of last block which client was notified about. Block(BlockNumber), /// Hashes of all transactions which client was notified about. - PendingTransaction(HashSet), + PendingTransaction(BTreeSet), /// Number of From block number, last seen block hash, pending logs and log filter itself. Logs(BlockNumber, Option, HashSet, Filter) } diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 380df5f4631..60bdd6fa879 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -17,7 +17,7 @@ //! Eth Filter RPC implementation use std::sync::Arc; -use std::collections::HashSet; +use std::collections::BTreeSet; use ethcore::miner::{self, MinerService}; use ethcore::filter::Filter as EthcoreFilter; @@ -42,7 +42,7 @@ pub trait Filterable { fn block_hash(&self, id: BlockId) -> Option; /// pending transaction hashes at the given block (unordered). - fn pending_transactions_hashes(&self) -> HashSet; + fn pending_transactions_hashes(&self) -> BTreeSet; /// Get logs that match the given filter. fn logs(&self, filter: EthcoreFilter) -> BoxFuture>; @@ -87,11 +87,8 @@ impl Filterable for EthFilterClient where self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> HashSet { - self.miner.ready_transactions(&*self.client, usize::max_value(), miner::PendingOrdering::Unordered) - .into_iter() - .map(|tx| tx.signed().hash()) - .collect() + fn pending_transactions_hashes(&self) -> BTreeSet { + self.miner.pending_transactions_hashes(&*self.client) } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index a488b9c93d8..fe240b51ded 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -16,7 +16,7 @@ //! Eth RPC interface for the light client. -use std::collections::HashSet; +use std::collections::BTreeSet; use std::sync::Arc; use jsonrpc_core::{Result, BoxFuture}; @@ -538,8 +538,8 @@ impl Filterable for EthClient { self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> HashSet<::ethereum_types::H256> { - HashSet::new() + fn pending_transactions_hashes(&self) -> BTreeSet<::ethereum_types::H256> { + BTreeSet::new() } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { From 30857cfdf27b43b0c8cd7f25c657aef243d8586f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 29 Jun 2018 12:50:22 +0200 Subject: [PATCH 5/9] Give filters their own locks, so that they don't block one another. --- rpc/src/v1/helpers/mod.rs | 2 +- rpc/src/v1/helpers/poll_filter.rs | 24 +++- rpc/src/v1/impls/eth_filter.rs | 196 +++++++++++++++--------------- rpc/src/v1/impls/light/eth.rs | 6 +- 4 files changed, 126 insertions(+), 102 deletions(-) diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index ce2babd0799..5b62087ab38 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -39,7 +39,7 @@ mod subscription_manager; pub use self::dispatch::{Dispatcher, FullDispatcher}; pub use self::network_settings::NetworkSettings; pub use self::poll_manager::PollManager; -pub use self::poll_filter::{PollFilter, limit_logs}; +pub use self::poll_filter::{PollFilter, SyncPollFilter, limit_logs}; pub use self::requests::{ TransactionRequest, FilledTransactionRequest, ConfirmationRequest, ConfirmationPayload, CallRequest, }; diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs index e616c47eedf..8c7bc7aaeb1 100644 --- a/rpc/src/v1/helpers/poll_filter.rs +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -16,12 +16,34 @@ //! Helper type with all filter state data. -use std::collections::{BTreeSet, HashSet}; +use std::{ + collections::{BTreeSet, HashSet}, + sync::Arc, +}; use ethereum_types::H256; +use parking_lot::Mutex; use v1::types::{Filter, Log}; pub type BlockNumber = u64; +/// Thread-safe filter state. +#[derive(Clone)] +pub struct SyncPollFilter(Arc>); + +impl SyncPollFilter { + /// New `SyncPollFilter` + pub fn new(f: PollFilter) -> Self { + SyncPollFilter(Arc::new(Mutex::new(f))) + } + + /// Modify underlying filter + pub fn modify(&self, f: F) -> R where + F: FnOnce(&mut PollFilter) -> R, + { + f(&mut self.0.lock()) + } +} + /// Filter state. #[derive(Clone)] pub enum PollFilter { diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 60bdd6fa879..eb0cd3655ca 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -30,7 +30,7 @@ use jsonrpc_core::futures::{future, Future}; use jsonrpc_core::futures::future::Either; use v1::traits::EthFilter; use v1::types::{BlockNumber, Index, Filter, FilterChanges, Log, H256 as RpcH256, U256 as RpcU256}; -use v1::helpers::{errors, PollFilter, PollManager, limit_logs}; +use v1::helpers::{errors, SyncPollFilter, PollFilter, PollManager, limit_logs}; use v1::impls::eth::pending_logs; /// Something which provides data that can be filtered over. @@ -51,7 +51,7 @@ pub trait Filterable { fn pending_logs(&self, block_number: u64, filter: &EthcoreFilter) -> Vec; /// Get a reference to the poll manager. - fn polls(&self) -> &Mutex>; + fn polls(&self) -> &Mutex>; /// Get removed logs within route from the given block to the nearest canon block, not including the canon block. Also returns how many logs have been traversed. fn removed_logs(&self, block_hash: H256, filter: &EthcoreFilter) -> (Vec, u64); @@ -61,7 +61,7 @@ pub trait Filterable { pub struct EthFilterClient { client: Arc, miner: Arc, - polls: Mutex>, + polls: Mutex>, } impl EthFilterClient { @@ -99,7 +99,7 @@ impl Filterable for EthFilterClient where pending_logs(&*self.miner, block_number, filter) } - fn polls(&self) -> &Mutex> { &self.polls } + fn polls(&self) -> &Mutex> { &self.polls } fn removed_logs(&self, block_hash: H256, filter: &EthcoreFilter) -> (Vec, u64) { let inner = || -> Option> { @@ -140,122 +140,124 @@ impl EthFilter for T { fn new_filter(&self, filter: Filter) -> Result { let mut polls = self.polls().lock(); let block_number = self.best_block_number(); - let id = polls.create_poll(PollFilter::Logs(block_number, None, Default::default(), filter)); + let id = polls.create_poll(SyncPollFilter::new(PollFilter::Logs(block_number, None, Default::default(), filter))); Ok(id.into()) } fn new_block_filter(&self) -> Result { let mut polls = self.polls().lock(); // +1, since we don't want to include the current block - let id = polls.create_poll(PollFilter::Block(self.best_block_number() + 1)); + let id = polls.create_poll(SyncPollFilter::new(PollFilter::Block(self.best_block_number() + 1))); Ok(id.into()) } fn new_pending_transaction_filter(&self) -> Result { let mut polls = self.polls().lock(); let pending_transactions = self.pending_transactions_hashes(); - let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); + let id = polls.create_poll(SyncPollFilter::new(PollFilter::PendingTransaction(pending_transactions))); Ok(id.into()) } fn filter_changes(&self, index: Index) -> BoxFuture { - let mut polls = self.polls().lock(); - Box::new(match polls.poll_mut(&index.value()) { - None => Either::A(future::err(errors::filter_not_found())), - Some(filter) => match *filter { - PollFilter::Block(ref mut block_number) => { - // +1, cause we want to return hashes including current block hash. - let current_number = self.best_block_number() + 1; - let hashes = (*block_number..current_number).into_iter() - .map(BlockId::Number) - .filter_map(|id| self.block_hash(id).map(Into::into)) - .collect::>(); - - *block_number = current_number; - - Either::A(future::ok(FilterChanges::Hashes(hashes))) - }, - PollFilter::PendingTransaction(ref mut previous_hashes) => { - // get hashes of pending transactions - let current_hashes = self.pending_transactions_hashes(); - - let new_hashes = { - // find all new hashes - current_hashes.difference(previous_hashes) - .cloned() - .map(Into::into) - .collect() - }; - - // save all hashes of pending transactions - *previous_hashes = current_hashes; - - // return new hashes - Either::A(future::ok(FilterChanges::Hashes(new_hashes))) - }, - PollFilter::Logs(ref mut block_number, ref mut last_block_hash, ref mut previous_logs, ref filter) => { - // retrive the current block number - let current_number = self.best_block_number(); - - // check if we need to check pending hashes - let include_pending = filter.to_block == Some(BlockNumber::Pending); - - // build appropriate filter - let mut filter: EthcoreFilter = filter.clone().into(); - - // retrieve reorg logs - let (mut reorg, reorg_len) = last_block_hash.map_or_else(|| (Vec::new(), 0), |h| self.removed_logs(h, &filter)); - *block_number -= reorg_len as u64; - - filter.from_block = BlockId::Number(*block_number); - filter.to_block = BlockId::Latest; - - // retrieve pending logs - let pending = if include_pending { - let pending_logs = self.pending_logs(current_number, &filter); - - // remove logs about which client was already notified about - let new_pending_logs: Vec<_> = pending_logs.iter() - .filter(|p| !previous_logs.contains(p)) - .cloned() - .collect(); - - // save all logs retrieved by client - *previous_logs = pending_logs.into_iter().collect(); - - new_pending_logs - } else { - Vec::new() - }; - - // save the number of the next block as a first block from which - // we want to get logs - *block_number = current_number + 1; - - // save the current block hash, which we used to get back to the - // canon chain in case of reorg. - *last_block_hash = self.block_hash(BlockId::Number(current_number)); - - // retrieve logs in range from_block..min(BlockId::Latest..to_block) - let limit = filter.limit; - Either::B(self.logs(filter) - .map(move |logs| { reorg.extend(logs); reorg }) // append reorg logs in the front - .map(move |mut logs| { logs.extend(pending); logs }) // append fetched pending logs - .map(move |logs| limit_logs(logs, limit)) // limit the logs - .map(FilterChanges::Logs)) - } + let filter = match self.polls().lock().poll_mut(&index.value()) { + Some(filter) => filter.clone(), + None => return Box::new(future::err(errors::filter_not_found())), + }; + + Box::new(filter.modify(|filter| match *filter { + PollFilter::Block(ref mut block_number) => { + // +1, cause we want to return hashes including current block hash. + let current_number = self.best_block_number() + 1; + let hashes = (*block_number..current_number).into_iter() + .map(BlockId::Number) + .filter_map(|id| self.block_hash(id).map(Into::into)) + .collect::>(); + + *block_number = current_number; + + Either::A(future::ok(FilterChanges::Hashes(hashes))) + }, + PollFilter::PendingTransaction(ref mut previous_hashes) => { + // get hashes of pending transactions + let current_hashes = self.pending_transactions_hashes(); + + let new_hashes = { + // find all new hashes + current_hashes.difference(previous_hashes) + .cloned() + .map(Into::into) + .collect() + }; + + // save all hashes of pending transactions + *previous_hashes = current_hashes; + + // return new hashes + Either::A(future::ok(FilterChanges::Hashes(new_hashes))) + }, + PollFilter::Logs(ref mut block_number, ref mut last_block_hash, ref mut previous_logs, ref filter) => { + // retrive the current block number + let current_number = self.best_block_number(); + + // check if we need to check pending hashes + let include_pending = filter.to_block == Some(BlockNumber::Pending); + + // build appropriate filter + let mut filter: EthcoreFilter = filter.clone().into(); + + // retrieve reorg logs + let (mut reorg, reorg_len) = last_block_hash.map_or_else(|| (Vec::new(), 0), |h| self.removed_logs(h, &filter)); + *block_number -= reorg_len as u64; + + filter.from_block = BlockId::Number(*block_number); + filter.to_block = BlockId::Latest; + + // retrieve pending logs + let pending = if include_pending { + let pending_logs = self.pending_logs(current_number, &filter); + + // remove logs about which client was already notified about + let new_pending_logs: Vec<_> = pending_logs.iter() + .filter(|p| !previous_logs.contains(p)) + .cloned() + .collect(); + + // save all logs retrieved by client + *previous_logs = pending_logs.into_iter().collect(); + + new_pending_logs + } else { + Vec::new() + }; + + // save the number of the next block as a first block from which + // we want to get logs + *block_number = current_number + 1; + + // save the current block hash, which we used to get back to the + // canon chain in case of reorg. + *last_block_hash = self.block_hash(BlockId::Number(current_number)); + + // retrieve logs in range from_block..min(BlockId::Latest..to_block) + let limit = filter.limit; + Either::B(self.logs(filter) + .map(move |logs| { reorg.extend(logs); reorg }) // append reorg logs in the front + .map(move |mut logs| { logs.extend(pending); logs }) // append fetched pending logs + .map(move |logs| limit_logs(logs, limit)) // limit the logs + .map(FilterChanges::Logs)) } - }) + })) } fn filter_logs(&self, index: Index) -> BoxFuture> { let filter = { let mut polls = self.polls().lock(); - match polls.poll(&index.value()) { - Some(&PollFilter::Logs(ref _block_number, ref _last_block_hash, ref _previous_log, ref filter)) => filter.clone(), - // just empty array - Some(_) => return Box::new(future::ok(Vec::new())), + match polls.poll(&index.value()).and_then(|f| f.modify(|filter| match *filter { + PollFilter::Logs(.., ref filter) => Some(filter.clone()), + _ => None, + })) { + Some(filter) => filter, None => return Box::new(future::err(errors::filter_not_found())), } }; diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index fe240b51ded..47882aa48c6 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -42,7 +42,7 @@ use transaction::SignedTransaction; use v1::impls::eth_filter::Filterable; use v1::helpers::{errors, limit_logs}; -use v1::helpers::{PollFilter, PollManager}; +use v1::helpers::{SyncPollFilter, PollManager}; use v1::helpers::light_fetch::{self, LightFetch}; use v1::traits::Eth; use v1::types::{ @@ -62,7 +62,7 @@ pub struct EthClient { transaction_queue: Arc>, accounts: Arc, cache: Arc>, - polls: Mutex>, + polls: Mutex>, poll_lifetime: u32, gas_price_percentile: usize, } @@ -550,7 +550,7 @@ impl Filterable for EthClient { Vec::new() // light clients don't mine. } - fn polls(&self) -> &Mutex> { + fn polls(&self) -> &Mutex> { &self.polls } From cd7a6c7509cae0f7d82051df02eddba7024c0a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 29 Jun 2018 13:41:03 +0200 Subject: [PATCH 6/9] Fix pending transaction count if not sealing. --- rpc/src/v1/impls/eth.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index d33d5e860a4..6709e409116 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -612,11 +612,9 @@ impl Eth for EthClient< } fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture> { - let block_number = self.client.chain_info().best_block_number; - Box::new(future::ok(match num { BlockNumber::Pending => - self.miner.pending_transactions(block_number).map(|x| x.len().into()), + Some(self.miner.pending_transactions_hashes(&*self.client).len().into()), _ => self.client.block(block_number_to_id(num)).map(|block| block.transactions_count().into()) })) From cad3a1e941fab4d7436e25fc3f6e90a32e25b23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 29 Jun 2018 14:30:58 +0200 Subject: [PATCH 7/9] Clear cache only when block is enacted. --- ethcore/src/miner/miner.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 571bce4a965..34b81fbd36d 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1096,13 +1096,18 @@ impl miner::MinerService for Miner { // 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that // are in those blocks - // Clear nonce cache - self.nonce_cache.write().clear(); + let has_new_best_block = enacted.len() > 0; + + if has_new_best_block { + // Clear nonce cache + self.nonce_cache.write().clear(); + } // First update gas limit in transaction queue and minimal gas price. let gas_limit = *chain.best_block_header().gas_limit(); self.update_transaction_queue_limits(gas_limit); + // Then import all transactions... let client = self.pool_client(chain); { @@ -1122,10 +1127,12 @@ impl miner::MinerService for Miner { }); } - // ...and at the end remove the old ones - self.transaction_queue.cull(client); + if has_new_best_block { + // ...and at the end remove the old ones + self.transaction_queue.cull(client); + } - if enacted.len() > 0 || (imported.len() > 0 && self.options.reseal_on_uncle) { + if has_new_best_block || (imported.len() > 0 && self.options.reseal_on_uncle) { // Reset `next_allowed_reseal` in case a block is imported. // Even if min_period is high, we will always attempt to create // new pending block. From bbf7997258d39d670550fc25619fa75d08ab0650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 2 Jul 2018 13:44:16 +0200 Subject: [PATCH 8/9] Fix RPC tests. --- rpc/src/v1/tests/helpers/miner_service.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index ce7ffc57a90..d8c93ee74f6 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -17,7 +17,7 @@ //! Test implementation of miner service. use std::sync::Arc; -use std::collections::{BTreeMap, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use bytes::Bytes; use ethcore::account_provider::SignError as AccountError; @@ -220,6 +220,10 @@ impl MinerService for TestMinerService { self.queued_transactions() } + fn pending_transactions_hashes(&self, _chain: &C) -> BTreeSet { + self.queued_transactions().into_iter().map(|tx| tx.signed().hash()).collect() + } + fn queued_transactions(&self) -> Vec> { self.pending_transactions.lock().values().cloned().map(|tx| { Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) From 7a504ab42669ce9e691138799aae9226daba6aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 3 Jul 2018 14:04:30 +0200 Subject: [PATCH 9/9] Address review comments. --- ethcore/src/miner/miner.rs | 3 +-- ethcore/src/miner/mod.rs | 4 ++-- miner/src/pool/ready.rs | 5 +++++ rpc/src/v1/helpers/poll_filter.rs | 2 +- rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/impls/eth_filter.rs | 10 +++++----- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/tests/helpers/miner_service.rs | 2 +- 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 34b81fbd36d..29b0f88501f 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -851,7 +851,7 @@ impl miner::MinerService for Miner { self.transaction_queue.all_transactions() } - fn pending_transactions_hashes(&self, chain: &C) -> BTreeSet where + fn pending_transaction_hashes(&self, chain: &C) -> BTreeSet where C: ChainInfo + Sync, { let chain_info = chain.chain_info(); @@ -1107,7 +1107,6 @@ impl miner::MinerService for Miner { let gas_limit = *chain.best_block_header().gas_limit(); self.update_transaction_queue_limits(gas_limit); - // Then import all transactions... let client = self.pool_client(chain); { diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 37162c55941..8886fff5421 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -164,10 +164,10 @@ pub trait MinerService : Send + Sync { fn next_nonce(&self, chain: &C, address: &Address) -> U256 where C: Nonce + Sync; - /// Get a set of all pending transactions hashes. + /// Get a set of all pending transaction hashes. /// /// Depending on the settings may look in transaction pool or only in pending block. - fn pending_transactions_hashes(&self, chain: &C) -> BTreeSet where + fn pending_transaction_hashes(&self, chain: &C) -> BTreeSet where C: ChainInfo + Sync; /// Get a list of all ready transactions either ordered by priority or unordered (cheaper). diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs index d0e33cae0e6..4ad7f05ee66 100644 --- a/miner/src/pool/ready.rs +++ b/miner/src/pool/ready.rs @@ -129,6 +129,11 @@ impl txpool::Ready for Condition { } } +/// Readiness checker that only relies on nonce cache (does actually go to state). +/// +/// Checks readiness of transactions by comparing the nonce to state nonce. If nonce +/// isn't found in provided state nonce store, defaults to the tx nonce and updates +/// the nonce store. Useful for using with a state nonce cache when false positives are allowed. pub struct OptionalState { nonces: HashMap, state: C, diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs index 8c7bc7aaeb1..19979c814b8 100644 --- a/rpc/src/v1/helpers/poll_filter.rs +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -49,7 +49,7 @@ impl SyncPollFilter { pub enum PollFilter { /// Number of last block which client was notified about. Block(BlockNumber), - /// Hashes of all transactions which client was notified about. + /// Hashes of all pending transactions the client knows about. PendingTransaction(BTreeSet), /// Number of From block number, last seen block hash, pending logs and log filter itself. Logs(BlockNumber, Option, HashSet, Filter) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 6709e409116..bf781d76525 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -614,7 +614,7 @@ impl Eth for EthClient< fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture> { Box::new(future::ok(match num { BlockNumber::Pending => - Some(self.miner.pending_transactions_hashes(&*self.client).len().into()), + Some(self.miner.pending_transaction_hashes(&*self.client).len().into()), _ => self.client.block(block_number_to_id(num)).map(|block| block.transactions_count().into()) })) diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index eb0cd3655ca..926439cfc91 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -42,7 +42,7 @@ pub trait Filterable { fn block_hash(&self, id: BlockId) -> Option; /// pending transaction hashes at the given block (unordered). - fn pending_transactions_hashes(&self) -> BTreeSet; + fn pending_transaction_hashes(&self) -> BTreeSet; /// Get logs that match the given filter. fn logs(&self, filter: EthcoreFilter) -> BoxFuture>; @@ -87,8 +87,8 @@ impl Filterable for EthFilterClient where self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> BTreeSet { - self.miner.pending_transactions_hashes(&*self.client) + fn pending_transaction_hashes(&self) -> BTreeSet { + self.miner.pending_transaction_hashes(&*self.client) } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { @@ -153,7 +153,7 @@ impl EthFilter for T { fn new_pending_transaction_filter(&self) -> Result { let mut polls = self.polls().lock(); - let pending_transactions = self.pending_transactions_hashes(); + let pending_transactions = self.pending_transaction_hashes(); let id = polls.create_poll(SyncPollFilter::new(PollFilter::PendingTransaction(pending_transactions))); Ok(id.into()) } @@ -179,7 +179,7 @@ impl EthFilter for T { }, PollFilter::PendingTransaction(ref mut previous_hashes) => { // get hashes of pending transactions - let current_hashes = self.pending_transactions_hashes(); + let current_hashes = self.pending_transaction_hashes(); let new_hashes = { // find all new hashes diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 47882aa48c6..e88ac2dab35 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -538,7 +538,7 @@ impl Filterable for EthClient { self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> BTreeSet<::ethereum_types::H256> { + fn pending_transaction_hashes(&self) -> BTreeSet<::ethereum_types::H256> { BTreeSet::new() } diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index d8c93ee74f6..fa9f22b2479 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -220,7 +220,7 @@ impl MinerService for TestMinerService { self.queued_transactions() } - fn pending_transactions_hashes(&self, _chain: &C) -> BTreeSet { + fn pending_transaction_hashes(&self, _chain: &C) -> BTreeSet { self.queued_transactions().into_iter().map(|tx| tx.signed().hash()).collect() }