diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 8e77a414f..3e1d1058c 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -269,7 +269,7 @@ impl AccountProvider { /// Checks whether an account with a given address is present. pub fn has_account(&self, address: Address) -> Result { - Ok(self.accounts()?.iter().any(|&a| a == address)) + Ok(self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address)) } /// Returns addresses of all accounts. diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index a8f18b73a..324619273 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -647,10 +647,6 @@ impl Miner { condition: Option, transaction_queue: &mut BanningTransactionQueue, ) -> Vec> { - let accounts = self.accounts.as_ref() - .and_then(|provider| provider.accounts().ok()) - .map(|accounts| accounts.into_iter().collect::>()); - let best_block_header = client.best_block_header().decode(); let insertion_time = client.chain_info().best_block_number; @@ -669,8 +665,8 @@ impl Miner { Err(e) }, Ok(transaction) => { - let origin = accounts.as_ref().and_then(|accounts| { - match accounts.contains(&transaction.sender()) { + let origin = self.accounts.as_ref().and_then(|accounts| { + match accounts.has_account(transaction.sender()).unwrap_or(false) { true => Some(TransactionOrigin::Local), false => None, } diff --git a/ethstore/src/dir/disk.rs b/ethstore/src/dir/disk.rs index 3f56ebe40..ebd67de2e 100755 --- a/ethstore/src/dir/disk.rs +++ b/ethstore/src/dir/disk.rs @@ -122,6 +122,13 @@ impl DiskDirectory where T: KeyFileManager { Ok(hasher.finish()) } + fn last_modification_date(&self) -> Result { + use std::time::{Duration, UNIX_EPOCH}; + let duration = fs::metadata(&self.path)?.modified()?.duration_since(UNIX_EPOCH).unwrap_or(Duration::default()); + let timestamp = duration.as_secs() ^ (duration.subsec_nanos() as u64); + Ok(timestamp) + } + /// all accounts found in keys directory fn files_content(&self) -> Result, Error> { // it's not done using one iterator cause @@ -226,7 +233,7 @@ impl KeyDirectory for DiskDirectory where T: KeyFileManager { } fn unique_repr(&self) -> Result { - self.files_hash() + self.last_modification_date() } } diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 7588cc9fb..1b8cf7ac2 100755 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -18,6 +18,7 @@ use std::collections::{BTreeMap, HashMap}; use std::mem; use std::path::PathBuf; use parking_lot::{Mutex, RwLock}; +use std::time::{Instant, Duration}; use crypto::KEY_ITERATIONS; use random::Random; @@ -28,6 +29,8 @@ use presale::PresaleWallet; use json::{self, Uuid, OpaqueKeyFile}; use {import, Error, SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation, OpaqueSecret}; +const REFRESH_TIME_SEC: u64 = 5; + /// Accounts store. pub struct EthStore { store: EthMultiStore, @@ -245,7 +248,12 @@ pub struct EthMultiStore { // order lock: cache, then vaults cache: RwLock>>, vaults: Mutex>>, - dir_hash: Mutex>, + timestamp: Mutex, +} + +struct Timestamp { + dir_hash: Option, + last_checked: Instant, } impl EthMultiStore { @@ -261,20 +269,27 @@ impl EthMultiStore { vaults: Mutex::new(HashMap::new()), iterations: iterations, cache: Default::default(), - dir_hash: Default::default(), + timestamp: Mutex::new(Timestamp { + dir_hash: None, + last_checked: Instant::now(), + }), }; store.reload_accounts()?; Ok(store) } fn reload_if_changed(&self) -> Result<(), Error> { - let mut last_dir_hash = self.dir_hash.lock(); - let dir_hash = Some(self.dir.unique_repr()?); - if *last_dir_hash == dir_hash { - return Ok(()) + let mut last_timestamp = self.timestamp.lock(); + let now = Instant::now(); + if (now - last_timestamp.last_checked) > Duration::from_secs(REFRESH_TIME_SEC) { + let dir_hash = Some(self.dir.unique_repr()?); + last_timestamp.last_checked = now; + if last_timestamp.dir_hash == dir_hash { + return Ok(()) + } + self.reload_accounts()?; + last_timestamp.dir_hash = dir_hash; } - self.reload_accounts()?; - *last_dir_hash = dir_hash; Ok(()) } @@ -455,11 +470,11 @@ impl SimpleSecretStore for EthMultiStore { } fn account_ref(&self, address: &Address) -> Result { + use std::collections::Bound; self.reload_if_changed()?; - self.cache.read().keys() - .find(|r| &r.address == address) - .cloned() - .ok_or(Error::InvalidAccount) + let cache = self.cache.read(); + let mut r = cache.range((Bound::Included(*address), Bound::Included(*address))); + r.next().ok_or(Error::InvalidAccount).map(|(k, _)| k.clone()) } fn accounts(&self) -> Result, Error> { diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs index e364245b7..c71db3fe2 100755 --- a/ethstore/src/secret_store.rs +++ b/ethstore/src/secret_store.rs @@ -16,6 +16,7 @@ use std::hash::{Hash, Hasher}; use std::path::PathBuf; +use std::cmp::Ordering; use ethkey::{Address, Message, Signature, Secret, Public}; use Error; use json::{Uuid, OpaqueKeyFile}; @@ -32,12 +33,24 @@ pub enum SecretVaultRef { } /// Stored account reference -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, Ord)] pub struct StoreAccountRef { - /// Vault reference - pub vault: SecretVaultRef, /// Account address pub address: Address, + /// Vault reference + pub vault: SecretVaultRef, +} + +impl PartialOrd for StoreAccountRef { + fn partial_cmp(&self, other: &StoreAccountRef) -> Option { + Some(self.address.cmp(&other.address).then_with(|| self.vault.cmp(&other.vault))) + } +} + +impl ::std::borrow::Borrow
for StoreAccountRef { + fn borrow(&self) -> &Address { + &self.address + } } /// Simple Secret Store API