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

[beta] Ethstore optimizations (#6827) #6844

Merged
merged 1 commit into from
Oct 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ethcore/src/account_provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ impl AccountProvider {

/// Checks whether an account with a given address is present.
pub fn has_account(&self, address: Address) -> Result<bool, Error> {
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.
Expand Down
8 changes: 2 additions & 6 deletions ethcore/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,10 +647,6 @@ impl Miner {
condition: Option<TransactionCondition>,
transaction_queue: &mut BanningTransactionQueue,
) -> Vec<Result<TransactionImportResult, Error>> {
let accounts = self.accounts.as_ref()
.and_then(|provider| provider.accounts().ok())
.map(|accounts| accounts.into_iter().collect::<HashSet<_>>());

let best_block_header = client.best_block_header().decode();
let insertion_time = client.chain_info().best_block_number;

Expand All @@ -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,
}
Expand Down
9 changes: 8 additions & 1 deletion ethstore/src/dir/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
Ok(hasher.finish())
}

fn last_modification_date(&self) -> Result<u64, Error> {
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<HashMap<PathBuf, SafeAccount>, Error> {
// it's not done using one iterator cause
Expand Down Expand Up @@ -226,7 +233,7 @@ impl<T> KeyDirectory for DiskDirectory<T> where T: KeyFileManager {
}

fn unique_repr(&self) -> Result<u64, Error> {
self.files_hash()
self.last_modification_date()
}
}

Expand Down
39 changes: 27 additions & 12 deletions ethstore/src/ethstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -245,7 +248,12 @@ pub struct EthMultiStore {
// order lock: cache, then vaults
cache: RwLock<BTreeMap<StoreAccountRef, Vec<SafeAccount>>>,
vaults: Mutex<HashMap<String, Box<VaultKeyDirectory>>>,
dir_hash: Mutex<Option<u64>>,
timestamp: Mutex<Timestamp>,
}

struct Timestamp {
dir_hash: Option<u64>,
last_checked: Instant,
}

impl EthMultiStore {
Expand All @@ -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(())
}

Expand Down Expand Up @@ -455,11 +470,11 @@ impl SimpleSecretStore for EthMultiStore {
}

fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error> {
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<Vec<StoreAccountRef>, Error> {
Expand Down
19 changes: 16 additions & 3 deletions ethstore/src/secret_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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<Ordering> {
Some(self.address.cmp(&other.address).then_with(|| self.vault.cmp(&other.vault)))
}
}

impl ::std::borrow::Borrow<Address> for StoreAccountRef {
fn borrow(&self) -> &Address {
&self.address
}
}

/// Simple Secret Store API
Expand Down