Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
ethcore: use LruCache for nonce cache
Browse files Browse the repository at this point in the history
Only clear the nonce cache when a block is retracted
  • Loading branch information
andresilva committed Jun 27, 2018
1 parent a397b76 commit b382c19
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 28 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ethcore/private-tx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
10 changes: 7 additions & 3 deletions ethcore/private-tx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -94,6 +96,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 {
Expand Down Expand Up @@ -243,7 +247,7 @@ impl Provider where {
Ok(original_transaction)
}

fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock<HashMap<Address, U256>>) -> miner::pool_client::PoolClient<'a, Client> {
fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock<LruCache<Address, U256>>) -> miner::pool_client::PoolClient<'a, Client> {
let engine = self.client.engine();
let refuse_service_transactions = true;
miner::pool_client::PoolClient::new(
Expand All @@ -262,7 +266,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 {
Expand Down Expand Up @@ -583,7 +587,7 @@ impl Importer for Arc<Provider> {
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,
Expand Down
17 changes: 11 additions & 6 deletions ethcore/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

use std::time::{Instant, Duration};
use std::collections::{BTreeMap, HashSet, HashMap};
use std::collections::{BTreeMap, HashSet};
use std::sync::Arc;

use ansi_term::Colour;
Expand All @@ -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::{
Expand Down Expand Up @@ -95,6 +96,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 {
Expand Down Expand Up @@ -200,7 +203,7 @@ pub struct Miner {
sealing: Mutex<SealingWork>,
params: RwLock<AuthoringParams>,
listeners: RwLock<Vec<Box<NotifyWork>>>,
nonce_cache: RwLock<HashMap<Address, U256>>,
nonce_cache: RwLock<LruCache<Address, U256>>,
gas_pricer: Mutex<GasPricer>,
options: MinerOptions,
// TODO [ToDr] Arc is only required because of price updater
Expand Down Expand Up @@ -239,7 +242,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,
Expand Down Expand Up @@ -1064,13 +1067,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);
{
Expand Down
24 changes: 5 additions & 19 deletions ethcore/src/miner/pool_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -36,10 +36,7 @@ use header::Header;
use miner;
use miner::service_transaction_checker::ServiceTransactionChecker;

type NoncesCache = RwLock<HashMap<Address, U256>>;

const MAX_NONCE_CACHE_SIZE: usize = 4096;
const EXPECTED_NONCE_CACHE_SIZE: usize = 2048;
type NoncesCache = RwLock<LruCache<Address, U256>>;

/// Blockchain accesss for transaction pool.
pub struct PoolClient<'a, C: 'a> {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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
}
}

0 comments on commit b382c19

Please sign in to comment.