dynamic keys pickup

This commit is contained in:
debris 2016-07-31 10:44:17 +02:00
parent 9e5e57fdcd
commit 489722b83f
7 changed files with 88 additions and 64 deletions

View File

@ -107,18 +107,23 @@ impl_bridge_type!(Message, 32, H256, SSMessage);
impl_bridge_type!(Address, 20, H160, SSAddress); impl_bridge_type!(Address, 20, H160, SSAddress);
struct NullDir; #[derive(Default)]
struct NullDir {
accounts: RwLock<HashMap<SSAddress, SafeAccount>>,
}
impl KeyDirectory for NullDir { impl KeyDirectory for NullDir {
fn load(&self) -> Result<Vec<SafeAccount>, SSError> { fn load(&self) -> Result<Vec<SafeAccount>, SSError> {
Ok(vec![]) Ok(self.accounts.read().values().cloned().collect())
} }
fn insert(&self, account: SafeAccount) -> Result<SafeAccount, SSError> { fn insert(&self, account: SafeAccount) -> Result<SafeAccount, SSError> {
self.accounts.write().insert(account.address.clone(), account.clone());
Ok(account) Ok(account)
} }
fn remove(&self, _address: &SSAddress) -> Result<(), SSError> { fn remove(&self, address: &SSAddress) -> Result<(), SSError> {
self.accounts.write().remove(address);
Ok(()) Ok(())
} }
} }
@ -164,7 +169,7 @@ impl AccountProvider {
pub fn transient_provider() -> Self { pub fn transient_provider() -> Self {
AccountProvider { AccountProvider {
unlocked: RwLock::new(HashMap::new()), unlocked: RwLock::new(HashMap::new()),
sstore: Box::new(EthStore::open(Box::new(NullDir)).unwrap()) sstore: Box::new(EthStore::open(Box::new(NullDir::default())).unwrap())
} }
} }
@ -184,13 +189,14 @@ impl AccountProvider {
} }
/// Returns addresses of all accounts. /// Returns addresses of all accounts.
pub fn accounts(&self) -> Vec<H160> { pub fn accounts(&self) -> Result<Vec<H160>, Error> {
self.sstore.accounts().into_iter().map(|a| H160(a.into())).collect() let accounts = try!(self.sstore.accounts()).into_iter().map(|a| H160(a.into())).collect();
Ok(accounts)
} }
/// Returns each account along with name and meta. /// Returns each account along with name and meta.
pub fn accounts_info(&self) -> Result<HashMap<H160, AccountMeta>, Error> { pub fn accounts_info(&self) -> Result<HashMap<H160, AccountMeta>, Error> {
let r: HashMap<H160, AccountMeta> = self.sstore.accounts() let r: HashMap<H160, AccountMeta> = try!(self.sstore.accounts())
.into_iter() .into_iter()
.map(|a| (H160(a.clone().into()), self.account_meta(a).unwrap_or_else(|_| Default::default()))) .map(|a| (H160(a.clone().into()), self.account_meta(a).unwrap_or_else(|_| Default::default())))
.collect(); .collect();

View File

@ -16,6 +16,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::RwLock; use std::sync::RwLock;
use std::mem;
use ethkey::KeyPair; use ethkey::KeyPair;
use crypto::KEY_ITERATIONS; use crypto::KEY_ITERATIONS;
use random::Random; use random::Random;
@ -56,6 +57,26 @@ impl EthStore {
cache.insert(account.address.clone(), account); cache.insert(account.address.clone(), account);
Ok(()) Ok(())
} }
fn reload_accounts(&self) -> Result<(), Error> {
let mut cache = self.cache.write().unwrap();
let accounts = try!(self.dir.load());
let new_accounts: BTreeMap<_, _> = accounts.into_iter().map(|account| (account.address.clone(), account)).collect();
mem::replace(&mut *cache, new_accounts);
Ok(())
}
fn get(&self, address: &Address) -> Result<SafeAccount, Error> {
{
let cache = self.cache.read().unwrap();
if let Some(account) = cache.get(address) {
return Ok(account.clone())
}
}
try!(self.reload_accounts());
let cache = self.cache.read().unwrap();
cache.get(address).cloned().ok_or(Error::InvalidAccount)
}
} }
impl SecretStore for EthStore { impl SecretStore for EthStore {
@ -68,17 +89,15 @@ impl SecretStore for EthStore {
Ok(address) Ok(address)
} }
fn accounts(&self) -> Vec<Address> { fn accounts(&self) -> Result<Vec<Address>, Error> {
self.cache.read().unwrap().keys().cloned().collect() try!(self.reload_accounts());
Ok(self.cache.read().unwrap().keys().cloned().collect())
} }
fn change_password(&self, address: &Address, old_password: &str, new_password: &str) -> Result<(), Error> { fn change_password(&self, address: &Address, old_password: &str, new_password: &str) -> Result<(), Error> {
// change password // change password
let account = { let account = try!(self.get(address));
let cache = self.cache.read().unwrap(); let account = try!(account.change_password(old_password, new_password, self.iterations));
let account = try!(cache.get(address).ok_or(Error::InvalidAccount));
try!(account.change_password(old_password, new_password, self.iterations))
};
// save to file // save to file
self.save(account) self.save(account)
@ -86,8 +105,7 @@ impl SecretStore for EthStore {
fn remove_account(&self, address: &Address, password: &str) -> Result<(), Error> { fn remove_account(&self, address: &Address, password: &str) -> Result<(), Error> {
let can_remove = { let can_remove = {
let cache = self.cache.read().unwrap(); let account = try!(self.get(address));
let account = try!(cache.get(address).ok_or(Error::InvalidAccount));
account.check_password(password) account.check_password(password)
}; };
@ -101,50 +119,38 @@ impl SecretStore for EthStore {
} }
} }
fn sign(&self, account: &Address, password: &str, message: &Message) -> Result<Signature, Error> { fn sign(&self, address: &Address, password: &str, message: &Message) -> Result<Signature, Error> {
let cache = self.cache.read().unwrap(); let account = try!(self.get(address));
let account = try!(cache.get(account).ok_or(Error::InvalidAccount));
account.sign(password, message) account.sign(password, message)
} }
fn uuid(&self, addr: &Address) -> Result<UUID, Error> { fn uuid(&self, address: &Address) -> Result<UUID, Error> {
let cache = self.cache.read().unwrap(); let account = try!(self.get(address));
let account = try!(cache.get(addr).ok_or(Error::InvalidAccount));
Ok(account.id.into()) Ok(account.id.into())
} }
fn name(&self, addr: &Address) -> Result<String, Error> { fn name(&self, address: &Address) -> Result<String, Error> {
let cache = self.cache.read().unwrap(); let account = try!(self.get(address));
let account = try!(cache.get(addr).ok_or(Error::InvalidAccount));
Ok(account.name.clone()) Ok(account.name.clone())
} }
fn meta(&self, addr: &Address) -> Result<String, Error> { fn meta(&self, address: &Address) -> Result<String, Error> {
let cache = self.cache.read().unwrap(); let account = try!(self.get(address));
let account = try!(cache.get(addr).ok_or(Error::InvalidAccount));
Ok(account.meta.clone()) Ok(account.meta.clone())
} }
fn set_name(&self, addr: &Address, name: String) -> Result<(), Error> { fn set_name(&self, address: &Address, name: String) -> Result<(), Error> {
let account = { let mut account = try!(self.get(address));
let cache = self.cache.read().unwrap(); account.name = name;
let mut account = try!(cache.get(addr).ok_or(Error::InvalidAccount)).clone();
account.name = name;
account
};
// save to file // save to file
self.save(account) self.save(account)
} }
fn set_meta(&self, addr: &Address, meta: String) -> Result<(), Error> { fn set_meta(&self, address: &Address, meta: String) -> Result<(), Error> {
let account = { let mut account = try!(self.get(address));
let cache = self.cache.read().unwrap(); account.meta = meta;
let mut account = try!(cache.get(addr).ok_or(Error::InvalidAccount)).clone();
account.meta = meta;
account
};
// save to file // save to file
self.save(account) self.save(account)
} }

View File

@ -21,7 +21,7 @@ use json::UUID;
pub trait SecretStore: Send + Sync { pub trait SecretStore: Send + Sync {
fn insert_account(&self, secret: Secret, password: &str) -> Result<Address, Error>; fn insert_account(&self, secret: Secret, password: &str) -> Result<Address, Error>;
fn accounts(&self) -> Vec<Address>; fn accounts(&self) -> Result<Vec<Address>, Error>;
fn change_password(&self, account: &Address, old_password: &str, new_password: &str) -> Result<(), Error>; fn change_password(&self, account: &Address, old_password: &str, new_password: &str) -> Result<(), Error>;

View File

@ -46,11 +46,11 @@ fn random_secret() -> Secret {
fn secret_store_create_account() { fn secret_store_create_account() {
let dir = TransientDir::create().unwrap(); let dir = TransientDir::create().unwrap();
let store = EthStore::open(Box::new(dir)).unwrap(); let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts().len(), 0); assert_eq!(store.accounts().unwrap().len(), 0);
assert!(store.insert_account(random_secret(), "").is_ok()); assert!(store.insert_account(random_secret(), "").is_ok());
assert_eq!(store.accounts().len(), 1); assert_eq!(store.accounts().unwrap().len(), 1);
assert!(store.insert_account(random_secret(), "").is_ok()); assert!(store.insert_account(random_secret(), "").is_ok());
assert_eq!(store.accounts().len(), 2); assert_eq!(store.accounts().unwrap().len(), 2);
} }
#[test] #[test]
@ -58,7 +58,7 @@ fn secret_store_sign() {
let dir = TransientDir::create().unwrap(); let dir = TransientDir::create().unwrap();
let store = EthStore::open(Box::new(dir)).unwrap(); let store = EthStore::open(Box::new(dir)).unwrap();
assert!(store.insert_account(random_secret(), "").is_ok()); assert!(store.insert_account(random_secret(), "").is_ok());
let accounts = store.accounts(); let accounts = store.accounts().unwrap();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
assert!(store.sign(&accounts[0], "", &Default::default()).is_ok()); assert!(store.sign(&accounts[0], "", &Default::default()).is_ok());
assert!(store.sign(&accounts[0], "1", &Default::default()).is_err()); assert!(store.sign(&accounts[0], "1", &Default::default()).is_err());
@ -69,7 +69,7 @@ fn secret_store_change_password() {
let dir = TransientDir::create().unwrap(); let dir = TransientDir::create().unwrap();
let store = EthStore::open(Box::new(dir)).unwrap(); let store = EthStore::open(Box::new(dir)).unwrap();
assert!(store.insert_account(random_secret(), "").is_ok()); assert!(store.insert_account(random_secret(), "").is_ok());
let accounts = store.accounts(); let accounts = store.accounts().unwrap();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
assert!(store.sign(&accounts[0], "", &Default::default()).is_ok()); assert!(store.sign(&accounts[0], "", &Default::default()).is_ok());
assert!(store.change_password(&accounts[0], "", "1").is_ok()); assert!(store.change_password(&accounts[0], "", "1").is_ok());
@ -82,10 +82,10 @@ fn secret_store_remove_account() {
let dir = TransientDir::create().unwrap(); let dir = TransientDir::create().unwrap();
let store = EthStore::open(Box::new(dir)).unwrap(); let store = EthStore::open(Box::new(dir)).unwrap();
assert!(store.insert_account(random_secret(), "").is_ok()); assert!(store.insert_account(random_secret(), "").is_ok());
let accounts = store.accounts(); let accounts = store.accounts().unwrap();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
assert!(store.remove_account(&accounts[0], "").is_ok()); assert!(store.remove_account(&accounts[0], "").is_ok());
assert_eq!(store.accounts().len(), 0); assert_eq!(store.accounts().unwrap().len(), 0);
assert!(store.remove_account(&accounts[0], "").is_err()); assert!(store.remove_account(&accounts[0], "").is_err());
} }
@ -107,7 +107,7 @@ fn pat_path() -> &'static str {
fn secret_store_laod_geth_files() { fn secret_store_laod_geth_files() {
let dir = DiskDirectory::at(test_path()); let dir = DiskDirectory::at(test_path());
let store = EthStore::open(Box::new(dir)).unwrap(); let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts(), vec![ assert_eq!(store.accounts().unwrap(), vec![
Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap(), Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap(),
Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap(), Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap(),
Address::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap(), Address::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap(),
@ -118,7 +118,7 @@ fn secret_store_laod_geth_files() {
fn secret_store_load_pat_files() { fn secret_store_load_pat_files() {
let dir = DiskDirectory::at(pat_path()); let dir = DiskDirectory::at(pat_path());
let store = EthStore::open(Box::new(dir)).unwrap(); let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts(), vec![ assert_eq!(store.accounts().unwrap(), vec![
Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap(), Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap(),
Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap(), Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap(),
]); ]);

View File

@ -340,10 +340,16 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
} }
} }
fn accounts(&self, _: Params) -> Result<Value, Error> { fn accounts(&self, params: Params) -> Result<Value, Error> {
try!(self.active()); try!(self.active());
let store = take_weak!(self.accounts); match params {
to_value(&store.accounts().into_iter().map(Into::into).collect::<Vec<RpcH160>>()) Params::None => {
let store = take_weak!(self.accounts);
let accounts = try!(store.accounts().map_err(|_| Error::internal_error()));
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
},
_ => Err(Error::invalid_params())
}
} }
fn block_number(&self, params: Params) -> Result<Value, Error> { fn block_number(&self, params: Params) -> Result<Value, Error> {

View File

@ -62,10 +62,16 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
.unwrap_or_else(|| to_value(&false)) .unwrap_or_else(|| to_value(&false))
} }
fn accounts(&self, _: Params) -> Result<Value, Error> { fn accounts(&self, params: Params) -> Result<Value, Error> {
try!(self.active()); try!(self.active());
let store = take_weak!(self.accounts); match params {
to_value(&store.accounts().into_iter().map(Into::into).collect::<Vec<RpcH160>>()) Params::None => {
let store = take_weak!(self.accounts);
let accounts = try!(store.accounts().map_err(|_| Error::internal_error()));
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
},
_ => Err(Error::invalid_params())
}
} }
fn new_account(&self, params: Params) -> Result<Value, Error> { fn new_account(&self, params: Params) -> Result<Value, Error> {

View File

@ -110,7 +110,7 @@ fn new_account() {
let res = tester.io.handle_request(request); let res = tester.io.handle_request(request);
let accounts = tester.accounts.accounts(); let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
let address = accounts[0]; let address = accounts[0];
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"","id":1}"#; let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"","id":1}"#;
@ -122,7 +122,7 @@ fn new_account() {
fn should_be_able_to_get_account_info() { fn should_be_able_to_get_account_info() {
let tester = setup(None); let tester = setup(None);
tester.accounts.new_account("").unwrap(); tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts(); let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
let address = accounts[0]; let address = accounts[0];
@ -140,7 +140,7 @@ fn should_be_able_to_get_account_info() {
fn should_be_able_to_set_name() { fn should_be_able_to_set_name() {
let tester = setup(None); let tester = setup(None);
tester.accounts.new_account("").unwrap(); tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts(); let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
let address = accounts[0]; let address = accounts[0];
@ -161,7 +161,7 @@ fn should_be_able_to_set_name() {
fn should_be_able_to_set_meta() { fn should_be_able_to_set_meta() {
let tester = setup(None); let tester = setup(None);
tester.accounts.new_account("").unwrap(); tester.accounts.new_account("").unwrap();
let accounts = tester.accounts.accounts(); let accounts = tester.accounts.accounts().unwrap();
assert_eq!(accounts.len(), 1); assert_eq!(accounts.len(), 1);
let address = accounts[0]; let address = accounts[0];