Merge pull request #4034 from maciejhirsz/mh-pwmsg
Better error messages for PoA chains, closes #4030
This commit is contained in:
commit
881066243b
@ -150,6 +150,11 @@ impl AccountProvider {
|
|||||||
Ok(Address::from(address).into())
|
Ok(Address::from(address).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether an account with a given address is present.
|
||||||
|
pub fn has_account(&self, address: Address) -> Result<bool, Error> {
|
||||||
|
Ok(self.accounts()?.iter().any(|&a| a == address))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns addresses of all accounts.
|
/// Returns addresses of all accounts.
|
||||||
pub fn accounts(&self) -> Result<Vec<Address>, Error> {
|
pub fn accounts(&self) -> Result<Vec<Address>, Error> {
|
||||||
let accounts = self.sstore.accounts()?;
|
let accounts = self.sstore.accounts()?;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{str, fs};
|
use std::{str, fs, fmt};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use util::{Address, U256, version_data};
|
use util::{Address, U256, version_data};
|
||||||
use util::journaldb::Algorithm;
|
use util::journaldb::Algorithm;
|
||||||
@ -60,6 +60,21 @@ impl str::FromStr for SpecType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SpecType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.write_str(match *self {
|
||||||
|
SpecType::Mainnet => "homestead",
|
||||||
|
SpecType::Morden => "morden",
|
||||||
|
SpecType::Ropsten => "ropsten",
|
||||||
|
SpecType::Olympic => "olympic",
|
||||||
|
SpecType::Classic => "classic",
|
||||||
|
SpecType::Expanse => "expanse",
|
||||||
|
SpecType::Dev => "dev",
|
||||||
|
SpecType::Custom(ref custom) => custom,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SpecType {
|
impl SpecType {
|
||||||
pub fn spec(&self) -> Result<Spec, String> {
|
pub fn spec(&self) -> Result<Spec, String> {
|
||||||
match *self {
|
match *self {
|
||||||
@ -305,6 +320,18 @@ mod tests {
|
|||||||
assert_eq!(SpecType::Mainnet, SpecType::default());
|
assert_eq!(SpecType::Mainnet, SpecType::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_spec_type_display() {
|
||||||
|
assert_eq!(format!("{}", SpecType::Mainnet), "homestead");
|
||||||
|
assert_eq!(format!("{}", SpecType::Ropsten), "ropsten");
|
||||||
|
assert_eq!(format!("{}", SpecType::Morden), "morden");
|
||||||
|
assert_eq!(format!("{}", SpecType::Olympic), "olympic");
|
||||||
|
assert_eq!(format!("{}", SpecType::Classic), "classic");
|
||||||
|
assert_eq!(format!("{}", SpecType::Expanse), "expanse");
|
||||||
|
assert_eq!(format!("{}", SpecType::Dev), "dev");
|
||||||
|
assert_eq!(format!("{}", SpecType::Custom("foo/bar".into())), "foo/bar");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pruning_parsing() {
|
fn test_pruning_parsing() {
|
||||||
assert_eq!(Pruning::Auto, "auto".parse().unwrap());
|
assert_eq!(Pruning::Auto, "auto".parse().unwrap());
|
||||||
|
@ -60,6 +60,9 @@ const SNAPSHOT_PERIOD: u64 = 10000;
|
|||||||
// how many blocks to wait before starting a periodic snapshot.
|
// how many blocks to wait before starting a periodic snapshot.
|
||||||
const SNAPSHOT_HISTORY: u64 = 100;
|
const SNAPSHOT_HISTORY: u64 = 100;
|
||||||
|
|
||||||
|
// Pops along with error messages when a password is missing or invalid.
|
||||||
|
const VERIFY_PASSWORD_HINT: &'static str = "Make sure valid password is present in files passed using `--password` or in the configuration file.";
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct RunCmd {
|
pub struct RunCmd {
|
||||||
pub cache_config: CacheConfig,
|
pub cache_config: CacheConfig,
|
||||||
@ -217,7 +220,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
|||||||
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
|
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
|
||||||
|
|
||||||
// prepare account provider
|
// prepare account provider
|
||||||
let account_provider = Arc::new(prepare_account_provider(&cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
|
let account_provider = Arc::new(prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
|
||||||
|
|
||||||
// let the Engine access the accounts
|
// let the Engine access the accounts
|
||||||
spec.engine.register_account_provider(account_provider.clone());
|
spec.engine.register_account_provider(account_provider.clone());
|
||||||
@ -230,9 +233,21 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
|||||||
miner.set_extra_data(cmd.miner_extras.extra_data);
|
miner.set_extra_data(cmd.miner_extras.extra_data);
|
||||||
miner.set_transactions_limit(cmd.miner_extras.transactions_limit);
|
miner.set_transactions_limit(cmd.miner_extras.transactions_limit);
|
||||||
let engine_signer = cmd.miner_extras.engine_signer;
|
let engine_signer = cmd.miner_extras.engine_signer;
|
||||||
|
|
||||||
if engine_signer != Default::default() {
|
if engine_signer != Default::default() {
|
||||||
|
// Check if engine signer exists
|
||||||
|
if !account_provider.has_account(engine_signer).unwrap_or(false) {
|
||||||
|
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.into_iter().any(|p| miner.set_engine_signer(engine_signer, p).is_ok()) {
|
if !passwords.into_iter().any(|p| miner.set_engine_signer(engine_signer, p).is_ok()) {
|
||||||
return Err(format!("No password found for the consensus signer {}. Make sure valid password is present in files passed using `--password`.", engine_signer));
|
return Err(format!("No valid password for the consensus signer {}. {}", engine_signer, VERIFY_PASSWORD_HINT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,24 +486,39 @@ fn daemonize(_pid_file: String) -> Result<(), String> {
|
|||||||
Err("daemon is no supported on windows".into())
|
Err("daemon is no supported on windows".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_account_provider(dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[String]) -> Result<AccountProvider, String> {
|
fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[String]) -> Result<AccountProvider, String> {
|
||||||
use ethcore::ethstore::EthStore;
|
use ethcore::ethstore::EthStore;
|
||||||
use ethcore::ethstore::dir::DiskDirectory;
|
use ethcore::ethstore::dir::DiskDirectory;
|
||||||
|
|
||||||
let path = dirs.keys_path(data_dir);
|
let path = dirs.keys_path(data_dir);
|
||||||
upgrade_key_location(&dirs.legacy_keys_path(cfg.testnet), &path);
|
upgrade_key_location(&dirs.legacy_keys_path(cfg.testnet), &path);
|
||||||
let dir = Box::new(DiskDirectory::create(&path).map_err(|e| format!("Could not open keys directory: {}", e))?);
|
let dir = Box::new(DiskDirectory::create(&path).map_err(|e| format!("Could not open keys directory: {}", e))?);
|
||||||
let account_service = AccountProvider::new(Box::new(
|
let account_provider = AccountProvider::new(Box::new(
|
||||||
EthStore::open_with_iterations(dir, cfg.iterations).map_err(|e| format!("Could not open keys directory: {}", e))?
|
EthStore::open_with_iterations(dir, cfg.iterations).map_err(|e| format!("Could not open keys directory: {}", e))?
|
||||||
));
|
));
|
||||||
|
|
||||||
for a in cfg.unlocked_accounts {
|
for a in cfg.unlocked_accounts {
|
||||||
if !passwords.iter().any(|p| account_service.unlock_account_permanently(a, (*p).clone()).is_ok()) {
|
// Check if the account exists
|
||||||
return Err(format!("No password found to unlock account {}. Make sure valid password is present in files passed using `--password`.", a));
|
if !account_provider.has_account(a).unwrap_or(false) {
|
||||||
|
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_service)
|
Ok(account_provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_exit(
|
fn wait_for_exit(
|
||||||
|
Loading…
Reference in New Issue
Block a user