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:
committed by
Afri Schoedon
parent
8fa56add47
commit
d5c19f8719
@@ -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
244
parity/account_utils.rs
Normal 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,
|
||||
};
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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")),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
132
parity/run.rs
132
parity/run.rs
@@ -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.");
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user