Deprecate account management (#10213)

* Extract accounts from ethcore.

* Fix ethcore.

* Get rid of AccountProvider in test_helpers

* Fix rest of the code.

* Re-use EngineSigner, fix tests.

* Simplify EngineSigner to always have an Address.

* Fix RPC tests.

* Add deprecation notice to RPCs.

* Feature to disable accounts.

* extract accounts in RPC

* Run with accounts in tests.

* Fix RPC compilation and tests.

* Fix compilation of the binary.

* Fix compilation of the binary.

* Fix compilation with accounts enabled.

* Fix tests.

* Update submodule.

* Remove android.

* Use derive for Default

* Don't build secretstore by default.

* Add link to issue.

* Refresh Cargo.lock.

* Fix miner tests.

* Update rpc/Cargo.toml

Co-Authored-By: tomusdrw <tomusdrw@users.noreply.github.com>

* Fix private tests.
This commit is contained in:
Tomasz Drwięga
2019-02-07 14:34:24 +01:00
committed by Afri Schoedon
parent 8fa56add47
commit d5c19f8719
102 changed files with 3222 additions and 2393 deletions

View File

@@ -15,12 +15,6 @@
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::num::NonZeroU32;
use std::path::PathBuf;
use ethstore::{EthStore, SecretStore, import_account, import_accounts, read_geth_accounts};
use ethstore::accounts_dir::RootDiskDirectory;
use ethstore::SecretVaultRef;
use ethcore::account_provider::{AccountProvider, AccountProviderSettings};
use helpers::{password_prompt, password_from_file};
use params::SpecType;
#[derive(Debug, PartialEq)]
@@ -62,83 +56,102 @@ pub struct ImportFromGethAccounts {
pub spec: SpecType,
}
#[cfg(not(feature = "accounts"))]
pub fn execute(cmd: AccountCmd) -> Result<String, String> {
match cmd {
AccountCmd::New(new_cmd) => new(new_cmd),
AccountCmd::List(list_cmd) => list(list_cmd),
AccountCmd::Import(import_cmd) => import(import_cmd),
AccountCmd::ImportFromGeth(import_geth_cmd) => import_geth(import_geth_cmd)
}
Err("Account management is deprecated. Please see #9997 for alternatives:\nhttps://github.com/paritytech/parity-ethereum/issues/9997".into())
}
fn keys_dir(path: String, spec: SpecType) -> Result<RootDiskDirectory, String> {
let spec = spec.spec(&::std::env::temp_dir())?;
let mut path = PathBuf::from(&path);
path.push(spec.data_dir);
RootDiskDirectory::create(path).map_err(|e| format!("Could not open keys directory: {}", e))
}
#[cfg(feature = "accounts")]
mod command {
use super::*;
use std::path::PathBuf;
use accounts::{AccountProvider, AccountProviderSettings};
use ethstore::{EthStore, SecretStore, SecretVaultRef, import_account, import_accounts, read_geth_accounts};
use ethstore::accounts_dir::RootDiskDirectory;
use helpers::{password_prompt, password_from_file};
fn secret_store(dir: Box<RootDiskDirectory>, iterations: Option<NonZeroU32>) -> Result<EthStore, String> {
match iterations {
Some(i) => EthStore::open_with_iterations(dir, i),
_ => EthStore::open(dir)
}.map_err(|e| format!("Could not open keys store: {}", e))
}
fn new(n: NewAccount) -> Result<String, String> {
let password = match n.password_file {
Some(file) => password_from_file(file)?,
None => password_prompt()?,
};
let dir = Box::new(keys_dir(n.path, n.spec)?);
let secret_store = Box::new(secret_store(dir, Some(n.iterations))?);
let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default());
let new_account = acc_provider.new_account(&password).map_err(|e| format!("Could not create new account: {}", e))?;
Ok(format!("0x{:x}", new_account))
}
fn list(list_cmd: ListAccounts) -> Result<String, String> {
let dir = Box::new(keys_dir(list_cmd.path, list_cmd.spec)?);
let secret_store = Box::new(secret_store(dir, None)?);
let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default());
let accounts = acc_provider.accounts().map_err(|e| format!("{}", e))?;
let result = accounts.into_iter()
.map(|a| format!("0x{:x}", a))
.collect::<Vec<String>>()
.join("\n");
Ok(result)
}
fn import(i: ImportAccounts) -> Result<String, String> {
let to = keys_dir(i.to, i.spec)?;
let mut imported = 0;
for path in &i.from {
let path = PathBuf::from(path);
if path.is_dir() {
let from = RootDiskDirectory::at(&path);
imported += import_accounts(&from, &to).map_err(|e| format!("Importing accounts from {:?} failed: {}", path, e))?.len();
} else if path.is_file() {
import_account(&path, &to).map_err(|e| format!("Importing account from {:?} failed: {}", path, e))?;
imported += 1;
pub fn execute(cmd: AccountCmd) -> Result<String, String> {
match cmd {
AccountCmd::New(new_cmd) => new(new_cmd),
AccountCmd::List(list_cmd) => list(list_cmd),
AccountCmd::Import(import_cmd) => import(import_cmd),
AccountCmd::ImportFromGeth(import_geth_cmd) => import_geth(import_geth_cmd)
}
}
Ok(format!("{} account(s) imported", imported))
}
fn keys_dir(path: String, spec: SpecType) -> Result<RootDiskDirectory, String> {
let spec = spec.spec(&::std::env::temp_dir())?;
let mut path = PathBuf::from(&path);
path.push(spec.data_dir);
RootDiskDirectory::create(path).map_err(|e| format!("Could not open keys directory: {}", e))
}
fn import_geth(i: ImportFromGethAccounts) -> Result<String, String> {
use std::io::ErrorKind;
use ethstore::Error;
fn secret_store(dir: Box<RootDiskDirectory>, iterations: Option<NonZeroU32>) -> Result<EthStore, String> {
match iterations {
Some(i) => EthStore::open_with_iterations(dir, i),
_ => EthStore::open(dir)
}.map_err(|e| format!("Could not open keys store: {}", e))
}
let dir = Box::new(keys_dir(i.to, i.spec)?);
let secret_store = Box::new(secret_store(dir, None)?);
let geth_accounts = read_geth_accounts(i.testnet);
match secret_store.import_geth_accounts(SecretVaultRef::Root, geth_accounts, i.testnet) {
Ok(v) => Ok(format!("Successfully imported {} account(s) from geth.", v.len())),
Err(Error::Io(ref io_err)) if io_err.kind() == ErrorKind::NotFound => Err("Failed to find geth keys folder.".into()),
Err(err) => Err(format!("Import geth accounts failed. {}", err))
fn new(n: NewAccount) -> Result<String, String> {
let password = match n.password_file {
Some(file) => password_from_file(file)?,
None => password_prompt()?,
};
let dir = Box::new(keys_dir(n.path, n.spec)?);
let secret_store = Box::new(secret_store(dir, Some(n.iterations))?);
let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default());
let new_account = acc_provider.new_account(&password).map_err(|e| format!("Could not create new account: {}", e))?;
Ok(format!("0x{:x}", new_account))
}
fn list(list_cmd: ListAccounts) -> Result<String, String> {
let dir = Box::new(keys_dir(list_cmd.path, list_cmd.spec)?);
let secret_store = Box::new(secret_store(dir, None)?);
let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default());
let accounts = acc_provider.accounts().map_err(|e| format!("{}", e))?;
let result = accounts.into_iter()
.map(|a| format!("0x{:x}", a))
.collect::<Vec<String>>()
.join("\n");
Ok(result)
}
fn import(i: ImportAccounts) -> Result<String, String> {
let to = keys_dir(i.to, i.spec)?;
let mut imported = 0;
for path in &i.from {
let path = PathBuf::from(path);
if path.is_dir() {
let from = RootDiskDirectory::at(&path);
imported += import_accounts(&from, &to).map_err(|e| format!("Importing accounts from {:?} failed: {}", path, e))?.len();
} else if path.is_file() {
import_account(&path, &to).map_err(|e| format!("Importing account from {:?} failed: {}", path, e))?;
imported += 1;
}
}
Ok(format!("{} account(s) imported", imported))
}
fn import_geth(i: ImportFromGethAccounts) -> Result<String, String> {
use std::io::ErrorKind;
use ethstore::Error;
let dir = Box::new(keys_dir(i.to, i.spec)?);
let secret_store = Box::new(secret_store(dir, None)?);
let geth_accounts = read_geth_accounts(i.testnet);
match secret_store.import_geth_accounts(SecretVaultRef::Root, geth_accounts, i.testnet) {
Ok(v) => Ok(format!("Successfully imported {} account(s) from geth.", v.len())),
Err(Error::Io(ref io_err)) if io_err.kind() == ErrorKind::NotFound => Err("Failed to find geth keys folder.".into()),
Err(err) => Err(format!("Import geth accounts failed. {}", err))
}
}
}
#[cfg(feature = "accounts")]
pub use self::command::execute;

244
parity/account_utils.rs Normal file
View File

@@ -0,0 +1,244 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use dir::Directories;
use ethereum_types::Address;
use ethkey::Password;
use params::{SpecType, AccountsConfig};
#[cfg(not(feature = "accounts"))]
mod accounts {
use super::*;
/// Dummy AccountProvider
pub struct AccountProvider;
impl ::ethcore::miner::LocalAccounts for AccountProvider {
fn is_local(&self, address: &Address) -> bool {
false
}
}
pub fn prepare_account_provider(_spec: &SpecType, _dirs: &Directories, _data_dir: &str, cfg: AccountsConfig, _passwords: &[Password]) -> Result<AccountProvider, String> {
warn!("Note: Your instance of Parity Ethereum is running without account support. Some CLI options are ignored.");
Ok(AccountProvider)
}
pub fn miner_local_accounts(_: Arc<AccountProvider>) -> AccountProvider {
AccountProvider
}
pub fn miner_author(_spec: &SpecType, _dirs: &Directories, _account_provider: &Arc<AccountProvider>, _engine_signer: Address, _passwords: &[Password]) -> Result<Option<::ethcore::miner::Author>, String> {
Ok(None)
}
pub fn private_tx_signer(_account_provider: Arc<AccountProvider>, _passwords: &[Password]) -> Result<Arc<::ethcore_private_tx::Signer>, String> {
Ok(Arc::new(::ethcore_private_tx::DummySigner))
}
pub fn accounts_list(_account_provider: Arc<AccountProvider>) -> Arc<Fn() -> Vec<Address> + Send + Sync> {
Arc::new(|| vec![])
}
}
#[cfg(feature = "accounts")]
mod accounts {
use super::*;
use upgrade::upgrade_key_location;
pub use accounts::AccountProvider;
/// Pops along with error messages when a password is missing or invalid.
const VERIFY_PASSWORD_HINT: &str = "Make sure valid password is present in files passed using `--password` or in the configuration file.";
/// Initialize account provider
pub fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[Password]) -> Result<AccountProvider, String> {
use ethstore::EthStore;
use ethstore::accounts_dir::RootDiskDirectory;
use accounts::AccountProviderSettings;
let path = dirs.keys_path(data_dir);
upgrade_key_location(&dirs.legacy_keys_path(cfg.testnet), &path);
let dir = Box::new(RootDiskDirectory::create(&path).map_err(|e| format!("Could not open keys directory: {}", e))?);
let account_settings = AccountProviderSettings {
enable_hardware_wallets: cfg.enable_hardware_wallets,
hardware_wallet_classic_key: spec == &SpecType::Classic,
unlock_keep_secret: cfg.enable_fast_unlock,
blacklisted_accounts: match *spec {
SpecType::Morden | SpecType::Ropsten | SpecType::Kovan | SpecType::Sokol | SpecType::Dev => vec![],
_ => vec![
"00a329c0648769a73afac7f9381e08fb43dbea72".into()
],
},
};
let ethstore = EthStore::open_with_iterations(dir, cfg.iterations).map_err(|e| format!("Could not open keys directory: {}", e))?;
if cfg.refresh_time > 0 {
ethstore.set_refresh_time(::std::time::Duration::from_secs(cfg.refresh_time));
}
let account_provider = AccountProvider::new(
Box::new(ethstore),
account_settings,
);
// Add development account if running dev chain:
if let SpecType::Dev = *spec {
insert_dev_account(&account_provider);
}
for a in cfg.unlocked_accounts {
// Check if the account exists
if !account_provider.has_account(a) {
return Err(format!("Account {} not found for the current chain. {}", a, build_create_account_hint(spec, &dirs.keys)));
}
// Check if any passwords have been read from the password file(s)
if passwords.is_empty() {
return Err(format!("No password found to unlock account {}. {}", a, VERIFY_PASSWORD_HINT));
}
if !passwords.iter().any(|p| account_provider.unlock_account_permanently(a, (*p).clone()).is_ok()) {
return Err(format!("No valid password to unlock account {}. {}", a, VERIFY_PASSWORD_HINT));
}
}
Ok(account_provider)
}
pub struct LocalAccounts(Arc<AccountProvider>);
impl ::ethcore::miner::LocalAccounts for LocalAccounts {
fn is_local(&self, address: &Address) -> bool {
self.0.has_account(*address)
}
}
pub fn miner_local_accounts(account_provider: Arc<AccountProvider>) -> LocalAccounts {
LocalAccounts(account_provider)
}
pub fn miner_author(spec: &SpecType, dirs: &Directories, account_provider: &Arc<AccountProvider>, engine_signer: Address, passwords: &[Password]) -> Result<Option<::ethcore::miner::Author>, String> {
use ethcore::engines::EngineSigner;
// Check if engine signer exists
if !account_provider.has_account(engine_signer) {
return Err(format!("Consensus signer account not found for the current chain. {}", build_create_account_hint(spec, &dirs.keys)));
}
// Check if any passwords have been read from the password file(s)
if passwords.is_empty() {
return Err(format!("No password found for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT));
}
let mut author = None;
for password in passwords {
let signer = parity_rpc::signer::EngineSigner::new(
account_provider.clone(),
engine_signer,
password.clone(),
);
if signer.sign(Default::default()).is_ok() {
author = Some(::ethcore::miner::Author::Sealer(Box::new(signer)));
}
}
if author.is_none() {
return Err(format!("No valid password for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT));
}
Ok(author)
}
mod private_tx {
use super::*;
use ethkey::{Signature, Message};
use ethcore_private_tx::{Error};
pub struct AccountSigner {
pub accounts: Arc<AccountProvider>,
pub passwords: Vec<Password>,
}
impl ::ethcore_private_tx::Signer for AccountSigner {
fn decrypt(&self, account: Address, shared_mac: &[u8], payload: &[u8]) -> Result<Vec<u8>, Error> {
let password = self.find_account_password(&account);
Ok(self.accounts.decrypt(account, password, shared_mac, payload).map_err(|e| e.to_string())?)
}
fn sign(&self, account: Address, hash: Message) -> Result<Signature, Error> {
let password = self.find_account_password(&account);
Ok(self.accounts.sign(account, password, hash).map_err(|e| e.to_string())?)
}
}
impl AccountSigner {
/// Try to unlock account using stored password, return found password if any
fn find_account_password(&self, account: &Address) -> Option<Password> {
for password in &self.passwords {
if let Ok(true) = self.accounts.test_password(account, password) {
return Some(password.clone());
}
}
None
}
}
}
pub fn private_tx_signer(accounts: Arc<AccountProvider>, passwords: &[Password]) -> Result<Arc<::ethcore_private_tx::Signer>, String> {
Ok(Arc::new(self::private_tx::AccountSigner {
accounts,
passwords: passwords.to_vec(),
}))
}
pub fn accounts_list(account_provider: Arc<AccountProvider>) -> Arc<Fn() -> Vec<Address> + Send + Sync> {
Arc::new(move || account_provider.accounts().unwrap_or_default())
}
fn insert_dev_account(account_provider: &AccountProvider) {
let secret: ethkey::Secret = "4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into();
let dev_account = ethkey::KeyPair::from_secret(secret.clone()).expect("Valid secret produces valid key;qed");
if !account_provider.has_account(dev_account.address()) {
match account_provider.insert_account(secret, &Password::from(String::new())) {
Err(e) => warn!("Unable to add development account: {}", e),
Ok(address) => {
let _ = account_provider.set_account_name(address.clone(), "Development Account".into());
let _ = account_provider.set_account_meta(address, ::serde_json::to_string(&(vec![
("description", "Never use this account outside of development chain!"),
("passwordHint","Password is empty string"),
].into_iter().collect::<::std::collections::HashMap<_,_>>())).expect("Serialization of hashmap does not fail."));
},
}
}
}
// Construct an error `String` with an adaptive hint on how to create an account.
fn build_create_account_hint(spec: &SpecType, keys: &str) -> String {
format!("You can create an account via RPC, UI or `parity account new --chain {} --keys-path {}`.", spec, keys)
}
}
pub use self::accounts::{
AccountProvider,
prepare_account_provider,
miner_local_accounts,
miner_author,
private_tx_signer,
accounts_list,
};

View File

@@ -25,9 +25,9 @@ use hash::{keccak, KECCAK_NULL_RLP};
use ethereum_types::{U256, H256, Address};
use bytes::ToPretty;
use rlp::PayloadInfo;
use ethcore::account_provider::AccountProvider;
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, Nonce, Balance, BlockChainClient, BlockId, BlockInfo,
ImportBlock, BlockChainReset};
use ethcore::client::{
Mode, DatabaseCompactionProfile, VMType, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock, BlockChainReset
};
use ethcore::error::{ImportErrorKind, ErrorKind as EthcoreErrorKind, Error as EthcoreError};
use ethcore::miner::Miner;
use ethcore::verification::queue::VerifierSettings;
@@ -395,7 +395,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
// TODO [ToDr] don't use test miner here
// (actually don't require miner at all)
Arc::new(Miner::new_for_tests(&spec, None)),
Arc::new(AccountProvider::transient_provider()),
Arc::new(ethcore_private_tx::DummySigner),
Box::new(ethcore_private_tx::NoopEncryptor),
Default::default(),
Default::default(),
@@ -587,7 +587,7 @@ fn start_client(
// It's fine to use test version here,
// since we don't care about miner parameters at all
Arc::new(Miner::new_for_tests(&spec, None)),
Arc::new(AccountProvider::transient_provider()),
Arc::new(ethcore_private_tx::DummySigner),
Box::new(ethcore_private_tx::NoopEncryptor),
Default::default(),
Default::default(),

View File

@@ -29,7 +29,7 @@ use parity_version::{version_data, version};
use bytes::Bytes;
use ansi_term::Colour;
use sync::{NetworkConfiguration, validate_node_url, self};
use ethstore::ethkey::{Secret, Public};
use ethkey::{Secret, Public};
use ethcore::client::{VMType};
use ethcore::miner::{stratum, MinerOptions};
use ethcore::snapshot::SnapshotConfiguration;
@@ -40,7 +40,7 @@ use num_cpus;
use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration};
use parity_rpc::NetworkSettings;
use cache::CacheConfig;
use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization, passwords_from_files};
use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization};
use dir::helpers::{replace_home, replace_home_and_local};
use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType};
use ethcore_logger::Config as LogConfig;
@@ -442,6 +442,7 @@ impl Configuration {
gas_range_target: (floor, ceil),
engine_signer: self.engine_signer()?,
work_notify: self.work_notify(),
local_accounts: HashSet::from_iter(to_addresses(&self.args.arg_tx_queue_locals)?.into_iter()),
};
Ok(extras)
@@ -579,7 +580,6 @@ impl Configuration {
infinite_pending_block: self.args.flag_infinite_pending_block,
tx_queue_penalization: to_queue_penalization(self.args.arg_tx_time_limit)?,
tx_queue_locals: HashSet::from_iter(to_addresses(&self.args.arg_tx_queue_locals)?.into_iter()),
tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?,
tx_queue_no_unfamiliar_locals: self.args.flag_tx_queue_no_unfamiliar_locals,
refuse_service_transactions: self.args.flag_refuse_service_transactions,
@@ -916,20 +916,12 @@ impl Configuration {
let provider_conf = ProviderConfig {
validator_accounts: to_addresses(&self.args.arg_private_validators)?,
signer_account: self.args.arg_private_signer.clone().and_then(|account| to_address(Some(account)).ok()),
passwords: match self.args.arg_private_passwords.clone() {
Some(file) => passwords_from_files(&vec![file].as_slice())?,
None => Vec::new(),
},
};
let encryptor_conf = EncryptorConfig {
base_url: self.args.arg_private_sstore_url.clone(),
threshold: self.args.arg_private_sstore_threshold.unwrap_or(0),
key_server_account: self.args.arg_private_account.clone().and_then(|account| to_address(Some(account)).ok()),
passwords: match self.args.arg_private_passwords.clone() {
Some(file) => passwords_from_files(&vec![file].as_slice())?,
None => Vec::new(),
},
};
Ok((provider_conf, encryptor_conf, self.args.flag_private_enabled))
@@ -1070,6 +1062,7 @@ impl Configuration {
match self.args.arg_secretstore_secret {
Some(ref s) if s.len() == 64 => Ok(Some(NodeSecretKey::Plain(s.parse()
.map_err(|e| format!("Invalid secret store secret: {}. Error: {:?}", s, e))?))),
#[cfg(feature = "accounts")]
Some(ref s) if s.len() == 40 => Ok(Some(NodeSecretKey::KeyStore(s.parse()
.map_err(|e| format!("Invalid secret store secret address: {}. Error: {:?}", s, e))?))),
Some(_) => Err(format!("Invalid secret store secret. Must be either existing account address, or hex-encoded private key")),

View File

@@ -43,7 +43,6 @@ extern crate toml;
extern crate blooms_db;
extern crate cli_signer;
extern crate common_types as types;
extern crate parity_bytes as bytes;
extern crate ethcore;
extern crate ethcore_call_contract as call_contract;
extern crate ethcore_db;
@@ -56,26 +55,30 @@ extern crate ethcore_private_tx;
extern crate ethcore_service;
extern crate ethcore_sync as sync;
extern crate ethereum_types;
extern crate ethstore;
extern crate ethkey;
extern crate ethstore;
extern crate journaldb;
extern crate keccak_hash as hash;
extern crate kvdb;
extern crate node_filter;
extern crate parity_bytes as bytes;
extern crate parity_hash_fetch as hash_fetch;
extern crate parity_ipfs_api;
extern crate parity_local_store as local_store;
extern crate parity_runtime;
extern crate parity_path as path;
extern crate parity_rpc;
extern crate parity_runtime;
extern crate parity_updater as updater;
extern crate parity_version;
extern crate parity_whisper;
extern crate parity_path as path;
extern crate node_filter;
extern crate keccak_hash as hash;
extern crate journaldb;
extern crate registrar;
#[macro_use]
extern crate log as rlog;
#[cfg(feature = "ethcore-accounts")]
extern crate ethcore_accounts as accounts;
#[cfg(feature = "secretstore")]
extern crate ethcore_secretstore;
@@ -91,6 +94,7 @@ extern crate tempdir;
extern crate lazy_static;
mod account;
mod account_utils;
mod blockchain;
mod cache;
mod cli;

View File

@@ -14,9 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::collections::HashSet;
use std::time::Duration;
use std::{str, fs, fmt};
use std::num::NonZeroU32;
use std::time::Duration;
use ethcore::client::Mode;
use ethcore::ethereum;
@@ -283,6 +284,7 @@ pub struct MinerExtras {
pub extra_data: Vec<u8>,
pub gas_range_target: (U256, U256),
pub work_notify: Vec<String>,
pub local_accounts: HashSet<Address>,
}
impl Default for MinerExtras {
@@ -293,6 +295,7 @@ impl Default for MinerExtras {
extra_data: version_data(),
gas_range_target: (8_000_000.into(), 10_000_000.into()),
work_notify: Default::default(),
local_accounts: Default::default(),
}
}
}

View File

@@ -14,9 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use ethstore::{PresaleWallet, EthStore};
use ethstore::accounts_dir::RootDiskDirectory;
use ethcore::account_provider::{AccountProvider, AccountProviderSettings};
use ethkey::Password;
use ethstore::PresaleWallet;
use helpers::{password_prompt, password_from_file};
use params::SpecType;
use std::num::NonZeroU32;
@@ -31,16 +31,29 @@ pub struct ImportWallet {
}
pub fn execute(cmd: ImportWallet) -> Result<String, String> {
let password = match cmd.password_file {
let password = match cmd.password_file.clone() {
Some(file) => password_from_file(file)?,
None => password_prompt()?,
};
let dir = Box::new(RootDiskDirectory::create(cmd.path).unwrap());
let secret_store = Box::new(EthStore::open_with_iterations(dir, cmd.iterations).unwrap());
let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default());
let wallet = PresaleWallet::open(cmd.wallet_path).map_err(|_| "Unable to open presale wallet.")?;
let wallet = PresaleWallet::open(cmd.wallet_path.clone()).map_err(|_| "Unable to open presale wallet.")?;
let kp = wallet.decrypt(&password).map_err(|_| "Invalid password.")?;
let address = acc_provider.insert_account(kp.secret().clone(), &password).unwrap();
let address = kp.address();
import_account(&cmd, kp, password);
Ok(format!("{:?}", address))
}
#[cfg(feature = "accounts")]
pub fn import_account(cmd: &ImportWallet, kp: ethkey::KeyPair, password: Password) {
use accounts::{AccountProvider, AccountProviderSettings};
use ethstore::EthStore;
use ethstore::accounts_dir::RootDiskDirectory;
let dir = Box::new(RootDiskDirectory::create(cmd.path.clone()).unwrap());
let secret_store = Box::new(EthStore::open_with_iterations(dir, cmd.iterations).unwrap());
let acc_provider = AccountProvider::new(secret_store, AccountProviderSettings::default());
acc_provider.insert_account(kp.secret().clone(), &password).unwrap();
}
#[cfg(not(feature = "accounts"))]
pub fn import_account(_cmd: &ImportWallet, _kp: ethkey::KeyPair, _password: Password) {}

View File

@@ -21,7 +21,7 @@ use std::sync::{Arc, Weak};
pub use parity_rpc::signer::SignerService;
use ethcore::account_provider::AccountProvider;
use account_utils::{self, AccountProvider};
use ethcore::client::Client;
use ethcore::miner::Miner;
use ethcore::snapshot::SnapshotService;
@@ -197,6 +197,26 @@ fn to_modules(apis: &HashSet<Api>) -> BTreeMap<String, String> {
modules
}
macro_rules! add_signing_methods {
($namespace:ident, $handler:expr, $deps:expr, $dispatch:expr) => {{
let deps = &$deps;
let (dispatcher, accounts) = $dispatch;
if deps.signer_service.is_enabled() {
$handler.extend_with($namespace::to_delegate(SigningQueueClient::new(
&deps.signer_service,
dispatcher.clone(),
deps.executor.clone(),
accounts,
)))
} else {
$handler.extend_with($namespace::to_delegate(SigningUnsafeClient::new(
accounts,
dispatcher.clone(),
)))
}
}};
}
/// RPC dependencies can be used to initialize RPC endpoints from APIs.
pub trait Dependencies {
type Notifier: ActivityNotifier;
@@ -217,7 +237,7 @@ pub struct FullDependencies {
pub snapshot: Arc<SnapshotService>,
pub sync: Arc<SyncProvider>,
pub net: Arc<ManageNetwork>,
pub secret_store: Arc<AccountProvider>,
pub accounts: Arc<AccountProvider>,
pub private_tx_service: Option<Arc<PrivateTxService>>,
pub miner: Arc<Miner>,
pub external_miner: Arc<ExternalMiner>,
@@ -247,31 +267,6 @@ impl FullDependencies {
{
use parity_rpc::v1::*;
macro_rules! add_signing_methods {
($namespace:ident, $handler:expr, $deps:expr, $nonces:expr) => {{
let deps = &$deps;
let dispatcher = FullDispatcher::new(
deps.client.clone(),
deps.miner.clone(),
$nonces,
deps.gas_price_percentile,
);
if deps.signer_service.is_enabled() {
$handler.extend_with($namespace::to_delegate(SigningQueueClient::new(
&deps.signer_service,
dispatcher,
deps.executor.clone(),
&deps.secret_store,
)))
} else {
$handler.extend_with($namespace::to_delegate(SigningUnsafeClient::new(
&deps.secret_store,
dispatcher,
)))
}
}};
}
let nonces = Arc::new(Mutex::new(dispatch::Reservations::new(
self.executor.clone(),
)));
@@ -281,6 +276,9 @@ impl FullDependencies {
nonces.clone(),
self.gas_price_percentile,
);
let account_signer = Arc::new(dispatch::Signer::new(self.accounts.clone())) as _;
let accounts = account_utils::accounts_list(self.accounts.clone());
for api in apis {
match *api {
Api::Debug => {
@@ -297,7 +295,7 @@ impl FullDependencies {
&self.client,
&self.snapshot,
&self.sync,
&self.secret_store,
&accounts,
&self.miner,
&self.external_miner,
EthClientOptions {
@@ -319,7 +317,7 @@ impl FullDependencies {
);
handler.extend_with(filter_client.to_delegate());
add_signing_methods!(EthSigning, handler, self, nonces.clone());
add_signing_methods!(EthSigning, handler, self, (&dispatcher, &account_signer));
}
}
Api::EthPubSub => {
@@ -341,9 +339,10 @@ impl FullDependencies {
}
}
Api::Personal => {
#[cfg(feature = "accounts")]
handler.extend_with(
PersonalClient::new(
&self.secret_store,
&self.accounts,
dispatcher.clone(),
self.geth_compatibility,
self.experimental_rpcs,
@@ -353,7 +352,7 @@ impl FullDependencies {
Api::Signer => {
handler.extend_with(
SignerClient::new(
&self.secret_store,
account_signer.clone(),
dispatcher.clone(),
&self.signer_service,
self.executor.clone(),
@@ -372,7 +371,6 @@ impl FullDependencies {
self.sync.clone(),
self.updater.clone(),
self.net_service.clone(),
self.secret_store.clone(),
self.logger.clone(),
self.settings.clone(),
signer,
@@ -380,9 +378,11 @@ impl FullDependencies {
self.snapshot.clone().into(),
).to_delegate(),
);
#[cfg(feature = "accounts")]
handler.extend_with(ParityAccountsInfo::to_delegate(ParityAccountsClient::new(&self.accounts)));
if !for_generic_pubsub {
add_signing_methods!(ParitySigning, handler, self, nonces.clone());
add_signing_methods!(ParitySigning, handler, self, (&dispatcher, &account_signer));
}
}
Api::ParityPubSub => {
@@ -398,25 +398,35 @@ impl FullDependencies {
}
}
Api::ParityAccounts => {
handler
.extend_with(ParityAccountsClient::new(&self.secret_store).to_delegate());
#[cfg(feature = "accounts")]
handler.extend_with(ParityAccounts::to_delegate(ParityAccountsClient::new(&self.accounts)));
}
Api::ParitySet => {
handler.extend_with(
ParitySetClient::new(
&self.client,
&self.miner,
&self.updater,
&self.net_service,
self.fetch.clone(),
).to_delegate(),
);
#[cfg(feature = "accounts")]
handler.extend_with(
ParitySetAccountsClient::new(
&self.accounts,
&self.miner,
).to_delegate(),
);
}
Api::ParitySet => handler.extend_with(
ParitySetClient::new(
&self.client,
&self.miner,
&self.updater,
&self.net_service,
self.fetch.clone(),
).to_delegate(),
),
Api::Traces => handler.extend_with(TracesClient::new(&self.client).to_delegate()),
Api::Rpc => {
let modules = to_modules(&apis);
handler.extend_with(RpcClient::new(modules).to_delegate());
}
Api::SecretStore => {
handler.extend_with(SecretStoreClient::new(&self.secret_store).to_delegate());
#[cfg(feature = "accounts")]
handler.extend_with(SecretStoreClient::new(&self.accounts).to_delegate());
}
Api::Whisper => {
if let Some(ref whisper_rpc) = self.whisper_rpc {
@@ -475,7 +485,7 @@ pub struct LightDependencies<T> {
pub client: Arc<T>,
pub sync: Arc<LightSync>,
pub net: Arc<ManageNetwork>,
pub secret_store: Arc<AccountProvider>,
pub accounts: Arc<AccountProvider>,
pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>,
pub on_demand: Arc<::light::on_demand::OnDemand>,
@@ -512,27 +522,8 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
))),
self.gas_price_percentile,
);
macro_rules! add_signing_methods {
($namespace:ident, $handler:expr, $deps:expr) => {{
let deps = &$deps;
let dispatcher = dispatcher.clone();
let secret_store = deps.secret_store.clone();
if deps.signer_service.is_enabled() {
$handler.extend_with($namespace::to_delegate(SigningQueueClient::new(
&deps.signer_service,
dispatcher,
deps.executor.clone(),
&secret_store,
)))
} else {
$handler.extend_with($namespace::to_delegate(SigningUnsafeClient::new(
&secret_store,
dispatcher,
)))
}
}};
}
let account_signer = Arc::new(dispatch::Signer::new(self.accounts.clone())) as _;
let accounts = account_utils::accounts_list(self.accounts.clone());
for api in apis {
match *api {
@@ -551,7 +542,7 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
self.client.clone(),
self.on_demand.clone(),
self.transaction_queue.clone(),
self.secret_store.clone(),
accounts.clone(),
self.cache.clone(),
self.gas_price_percentile,
self.poll_lifetime,
@@ -560,7 +551,7 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
if !for_generic_pubsub {
handler.extend_with(EthFilter::to_delegate(client));
add_signing_methods!(EthSigning, handler, self);
add_signing_methods!(EthSigning, handler, self, (&dispatcher, &account_signer));
}
}
Api::EthPubSub => {
@@ -584,9 +575,10 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
handler.extend_with(EthPubSub::to_delegate(client));
}
Api::Personal => {
#[cfg(feature = "accounts")]
handler.extend_with(
PersonalClient::new(
&self.secret_store,
&self.accounts,
dispatcher.clone(),
self.geth_compatibility,
self.experimental_rpcs,
@@ -596,7 +588,7 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
Api::Signer => {
handler.extend_with(
SignerClient::new(
&self.secret_store,
account_signer.clone(),
dispatcher.clone(),
&self.signer_service,
self.executor.clone(),
@@ -611,7 +603,6 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
handler.extend_with(
light::ParityClient::new(
Arc::new(dispatcher.clone()),
self.secret_store.clone(),
self.logger.clone(),
self.settings.clone(),
signer,
@@ -619,9 +610,13 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
self.gas_price_percentile,
).to_delegate(),
);
#[cfg(feature = "accounts")]
handler.extend_with(
ParityAccountsInfo::to_delegate(ParityAccountsClient::new(&self.accounts))
);
if !for_generic_pubsub {
add_signing_methods!(ParitySigning, handler, self);
add_signing_methods!(ParitySigning, handler, self, (&dispatcher, &account_signer));
}
}
Api::ParityPubSub => {
@@ -637,8 +632,8 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
}
}
Api::ParityAccounts => {
handler
.extend_with(ParityAccountsClient::new(&self.secret_store).to_delegate());
#[cfg(feature = "accounts")]
handler.extend_with(ParityAccounts::to_delegate(ParityAccountsClient::new(&self.accounts)));
}
Api::ParitySet => handler.extend_with(
light::ParitySetClient::new(self.sync.clone(), self.fetch.clone())
@@ -650,7 +645,8 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
handler.extend_with(RpcClient::new(modules).to_delegate());
}
Api::SecretStore => {
handler.extend_with(SecretStoreClient::new(&self.secret_store).to_delegate());
#[cfg(feature = "accounts")]
handler.extend_with(SecretStoreClient::new(&self.accounts).to_delegate());
}
Api::Whisper => {
if let Some(ref whisper_rpc) = self.whisper_rpc {

View File

@@ -22,28 +22,27 @@ use std::thread;
use ansi_term::Colour;
use bytes::Bytes;
use call_contract::CallContract;
use ethcore::account_provider::{AccountProvider, AccountProviderSettings};
use ethcore::client::{BlockId, Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo};
use ethstore::ethkey;
use ethcore::miner::{stratum, Miner, MinerService, MinerOptions};
use ethcore::miner::{self, stratum, Miner, MinerService, MinerOptions};
use ethcore::snapshot::{self, SnapshotConfiguration};
use ethcore::spec::{SpecParams, OptimizeFor};
use ethcore::verification::queue::VerifierSettings;
use ethcore_logger::{Config as LogConfig, RotatingLogger};
use ethcore_service::ClientService;
use ethereum_types::Address;
use sync::{self, SyncConfig, PrivateTxHandler};
use miner::work_notify::WorkPoster;
use futures::IntoFuture;
use hash_fetch::{self, fetch};
use informant::{Informant, LightNodeInformantData, FullNodeInformantData};
use journaldb::Algorithm;
use light::Cache as LightDataCache;
use miner::external::ExternalMiner;
use miner::work_notify::WorkPoster;
use node_filter::NodeFilter;
use parity_runtime::Runtime;
use parity_rpc::{Origin, Metadata, NetworkSettings, informant, is_major_importing, PubSubSession, FutureResult,
FutureResponse, FutureOutput};
use sync::{self, SyncConfig, PrivateTxHandler};
use parity_rpc::{
Origin, Metadata, NetworkSettings, informant, is_major_importing, PubSubSession, FutureResult, FutureResponse, FutureOutput
};
use updater::{UpdatePolicy, Updater};
use parity_version::version;
use ethcore_private_tx::{ProviderConfig, EncryptorConfig, SecretStoreEncryptor};
@@ -51,8 +50,8 @@ use params::{
SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch,
tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool
};
use account_utils;
use helpers::{to_client_config, execute_upgrades, passwords_from_files};
use upgrade::upgrade_key_location;
use dir::{Directories, DatabaseDirectories};
use cache::CacheConfig;
use user_defaults::UserDefaults;
@@ -65,7 +64,6 @@ use rpc_apis;
use secretstore;
use signer;
use db;
use ethkey::Password;
// how often to take periodic snapshots.
const SNAPSHOT_PERIOD: u64 = 5000;
@@ -77,9 +75,6 @@ const SNAPSHOT_HISTORY: u64 = 100;
// Light client only.
const GAS_CORPUS_EXPIRATION_MINUTES: u64 = 60 * 6;
// Pops along with error messages when a password is missing or invalid.
const VERIFY_PASSWORD_HINT: &str = "Make sure valid password is present in files passed using `--password` or in the configuration file.";
// Full client number of DNS threads
const FETCH_FULL_NUM_DNS_THREADS: usize = 4;
@@ -317,7 +312,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
// prepare account provider
let account_provider = Arc::new(prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
let account_provider = Arc::new(account_utils::prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
let rpc_stats = Arc::new(informant::RpcStats::default());
// the dapps server
@@ -329,7 +324,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
client: client.clone(),
sync: light_sync.clone(),
net: light_sync.clone(),
secret_store: account_provider,
accounts: account_provider,
logger: logger,
settings: Arc::new(cmd.net_settings),
on_demand: on_demand,
@@ -489,7 +484,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
// prepare account provider
let account_provider = Arc::new(prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
let account_provider = Arc::new(account_utils::prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
// spin up event loop
let runtime = Runtime::with_default_thread_count();
@@ -503,9 +498,12 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
cmd.miner_options,
cmd.gas_pricer_conf.to_gas_pricer(fetch.clone(), runtime.executor()),
&spec,
Some(account_provider.clone()),
(
cmd.miner_extras.local_accounts,
account_utils::miner_local_accounts(account_provider.clone()),
)
));
miner.set_author(cmd.miner_extras.author, None).expect("Fails only if password is Some; password is None; qed");
miner.set_author(miner::Author::External(cmd.miner_extras.author));
miner.set_gas_range_target(cmd.miner_extras.gas_range_target);
miner.set_extra_data(cmd.miner_extras.extra_data);
@@ -517,19 +515,8 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
let engine_signer = cmd.miner_extras.engine_signer;
if engine_signer != Default::default() {
// Check if engine signer exists
if !account_provider.has_account(engine_signer) {
return Err(format!("Consensus signer account not found for the current chain. {}", build_create_account_hint(&cmd.spec, &cmd.dirs.keys)));
}
// Check if any passwords have been read from the password file(s)
if passwords.is_empty() {
return Err(format!("No password found for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT));
}
// Attempt to sign in the engine signer.
if !passwords.iter().any(|p| miner.set_author(engine_signer, Some(p.to_owned())).is_ok()) {
return Err(format!("No valid password for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT));
if let Some(author) = account_utils::miner_author(&cmd.spec, &cmd.dirs, &account_provider, engine_signer, &passwords)? {
miner.set_author(author);
}
}
@@ -572,6 +559,8 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
let client_db = restoration_db_handler.open(&client_path)
.map_err(|e| format!("Failed to open database {:?}", e))?;
let private_tx_signer = account_utils::private_tx_signer(account_provider.clone(), &passwords)?;
// create client service.
let service = ClientService::start(
client_config,
@@ -581,8 +570,8 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
restoration_db_handler,
&cmd.dirs.ipc_path(),
miner.clone(),
account_provider.clone(),
Box::new(SecretStoreEncryptor::new(cmd.private_encryptor_conf.clone(), fetch.clone()).map_err(|e| e.to_string())?),
private_tx_signer.clone(),
Box::new(SecretStoreEncryptor::new(cmd.private_encryptor_conf.clone(), fetch.clone(), private_tx_signer).map_err(|e| e.to_string())?),
cmd.private_provider_conf,
cmd.private_encryptor_conf,
).map_err(|e| format!("Client service error: {:?}", e))?;
@@ -743,7 +732,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
client: client.clone(),
sync: sync_provider.clone(),
net: manage_network.clone(),
secret_store: secret_store,
accounts: secret_store,
miner: miner.clone(),
external_miner: external_miner.clone(),
logger: logger.clone(),
@@ -779,7 +768,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
client: client.clone(),
sync: sync_provider.clone(),
miner: miner.clone(),
account_provider: account_provider,
account_provider,
accounts_passwords: &passwords,
};
let secretstore_key_server = secretstore::start(cmd.secretstore_conf.clone(), secretstore_deps, runtime.executor())?;
@@ -953,80 +942,6 @@ fn print_running_environment(data_dir: &str, dirs: &Directories, db_dirs: &Datab
info!("DB path {}", Colour::White.bold().paint(db_dirs.db_root_path().to_string_lossy().into_owned()));
}
fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[Password]) -> Result<AccountProvider, String> {
use ethstore::EthStore;
use ethstore::accounts_dir::RootDiskDirectory;
let path = dirs.keys_path(data_dir);
upgrade_key_location(&dirs.legacy_keys_path(cfg.testnet), &path);
let dir = Box::new(RootDiskDirectory::create(&path).map_err(|e| format!("Could not open keys directory: {}", e))?);
let account_settings = AccountProviderSettings {
enable_hardware_wallets: cfg.enable_hardware_wallets,
hardware_wallet_classic_key: spec == &SpecType::Classic,
unlock_keep_secret: cfg.enable_fast_unlock,
blacklisted_accounts: match *spec {
SpecType::Morden | SpecType::Ropsten | SpecType::Kovan | SpecType::Sokol | SpecType::Dev => vec![],
_ => vec![
"00a329c0648769a73afac7f9381e08fb43dbea72".into()
],
},
};
let ethstore = EthStore::open_with_iterations(dir, cfg.iterations).map_err(|e| format!("Could not open keys directory: {}", e))?;
if cfg.refresh_time > 0 {
ethstore.set_refresh_time(::std::time::Duration::from_secs(cfg.refresh_time));
}
let account_provider = AccountProvider::new(
Box::new(ethstore),
account_settings,
);
// Add development account if running dev chain:
if let SpecType::Dev = *spec {
insert_dev_account(&account_provider);
}
for a in cfg.unlocked_accounts {
// Check if the account exists
if !account_provider.has_account(a) {
return Err(format!("Account {} not found for the current chain. {}", a, build_create_account_hint(spec, &dirs.keys)));
}
// Check if any passwords have been read from the password file(s)
if passwords.is_empty() {
return Err(format!("No password found to unlock account {}. {}", a, VERIFY_PASSWORD_HINT));
}
if !passwords.iter().any(|p| account_provider.unlock_account_permanently(a, (*p).clone()).is_ok()) {
return Err(format!("No valid password to unlock account {}. {}", a, VERIFY_PASSWORD_HINT));
}
}
Ok(account_provider)
}
fn insert_dev_account(account_provider: &AccountProvider) {
let secret: ethkey::Secret = "4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into();
let dev_account = ethkey::KeyPair::from_secret(secret.clone()).expect("Valid secret produces valid key;qed");
if !account_provider.has_account(dev_account.address()) {
match account_provider.insert_account(secret, &Password::from(String::new())) {
Err(e) => warn!("Unable to add development account: {}", e),
Ok(address) => {
let _ = account_provider.set_account_name(address.clone(), "Development Account".into());
let _ = account_provider.set_account_meta(address, ::serde_json::to_string(&(vec![
("description", "Never use this account outside of development chain!"),
("passwordHint","Password is empty string"),
].into_iter().collect::<::std::collections::HashMap<_,_>>())).expect("Serialization of hashmap does not fail."));
},
}
}
}
// Construct an error `String` with an adaptive hint on how to create an account.
fn build_create_account_hint(spec: &SpecType, keys: &str) -> String {
format!("You can create an account via RPC, UI or `parity account new --chain {} --keys-path {}`.", spec, keys)
}
fn wait_for_drop<T>(w: Weak<T>) {
let sleep_duration = Duration::from_secs(1);
let warn_timeout = Duration::from_secs(60);
@@ -1050,3 +965,4 @@ fn wait_for_drop<T>(w: Weak<T>) {
warn!("Shutdown timeout reached, exiting uncleanly.");
}

View File

@@ -16,12 +16,12 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use account_utils::AccountProvider;
use dir::default_data_path;
use dir::helpers::replace_home;
use ethcore::account_provider::AccountProvider;
use ethcore::client::Client;
use ethcore::miner::Miner;
use ethkey::{Secret, Public};
use ethkey::{Secret, Public, Password};
use sync::SyncProvider;
use ethereum_types::Address;
use parity_runtime::Executor;
@@ -32,6 +32,7 @@ pub enum NodeSecretKey {
/// Stored as plain text in configuration file.
Plain(Secret),
/// Stored as account in key store.
#[cfg(feature = "accounts")]
KeyStore(Address),
}
@@ -141,6 +142,7 @@ mod server {
let self_secret: Arc<ethcore_secretstore::NodeKeyPair> = match conf.self_secret.take() {
Some(NodeSecretKey::Plain(secret)) => Arc::new(ethcore_secretstore::PlainNodeKeyPair::new(
KeyPair::from_secret(secret).map_err(|e| format!("invalid secret: {}", e))?)),
#[cfg(feature = "accounts")]
Some(NodeSecretKey::KeyStore(account)) => {
// Check if account exists
if !deps.account_provider.has_account(account.clone()) {
@@ -209,7 +211,6 @@ mod server {
}
pub use self::server::KeyServer;
use ethkey::Password;
impl Default for Configuration {
fn default() -> Self {

View File

@@ -21,7 +21,6 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use hash::keccak;
use ethcore::account_provider::AccountProvider;
use ethcore::snapshot::{Progress, RestorationStatus, SnapshotConfiguration, SnapshotService as SS};
use ethcore::snapshot::io::{SnapshotReader, PackedReader, PackedWriter};
use ethcore::snapshot::service::Service as SnapshotService;
@@ -199,7 +198,7 @@ impl SnapshotCommand {
// TODO [ToDr] don't use test miner here
// (actually don't require miner at all)
Arc::new(Miner::new_for_tests(&spec, None)),
Arc::new(AccountProvider::transient_provider()),
Arc::new(ethcore_private_tx::DummySigner),
Box::new(ethcore_private_tx::NoopEncryptor),
Default::default(),
Default::default(),