// Copyright 2015, 2016 Ethcore (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 .
use std::time::Duration;
use std::io::Read;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::cmp::max;
use cli::{USAGE, Args};
use docopt::{Docopt, Error as DocoptError};
use util::{Hashable, U256, Uint, Bytes, version_data, Secret, Address};
use util::log::Colour;
use ethsync::{NetworkConfiguration, is_valid_node_url};
use ethcore::client::{VMType, Mode};
use ethcore::miner::MinerOptions;
use rpc::{IpcConfiguration, HttpConfiguration};
use ethcore_rpc::NetworkSettings;
use cache::CacheConfig;
use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home,
geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address};
use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType};
use ethcore_logger::Config as LogConfig;
use dir::Directories;
use dapps::Configuration as DappsConfiguration;
use signer::Configuration as SignerConfiguration;
use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
use presale::ImportWallet;
use account::{AccountCmd, NewAccount, ImportAccounts};
use snapshot::{self, SnapshotCommand};
#[derive(Debug, PartialEq)]
pub enum Cmd {
Run(RunCmd),
Version,
Account(AccountCmd),
ImportPresaleWallet(ImportWallet),
Blockchain(BlockchainCmd),
SignerToken(String),
Snapshot(SnapshotCommand),
}
#[derive(Debug, PartialEq)]
pub struct Configuration {
pub args: Args,
}
impl Configuration {
pub fn parse(command: I) -> Result where I: IntoIterator, S: AsRef {
let args = try!(Docopt::new(USAGE).and_then(|d| d.argv(command).decode()));
let config = Configuration {
args: args,
};
Ok(config)
}
pub fn into_command(self) -> Result {
let dirs = self.directories();
let pruning = try!(self.args.flag_pruning.parse());
let vm_type = try!(self.vm_type());
let mode = try!(to_mode(&self.args.flag_mode, self.args.flag_mode_timeout, self.args.flag_mode_alarm));
let miner_options = try!(self.miner_options());
let logger_config = self.logger_config();
let http_conf = try!(self.http_config());
let ipc_conf = try!(self.ipc_config());
let net_conf = try!(self.net_config());
let network_id = try!(self.network_id());
let cache_config = self.cache_config();
let spec = try!(self.chain().parse());
let tracing = try!(self.args.flag_tracing.parse());
let compaction = try!(self.args.flag_db_compaction.parse());
let wal = !self.args.flag_fast_and_loose;
let enable_network = self.enable_network(&mode);
let geth_compatibility = self.args.flag_geth;
let signer_port = self.signer_port();
let dapps_conf = self.dapps_config();
let signer_conf = self.signer_config();
let format = try!(self.format());
let cmd = if self.args.flag_version {
Cmd::Version
} else if self.args.cmd_signer {
Cmd::SignerToken(dirs.signer)
} else if self.args.cmd_account {
let account_cmd = if self.args.cmd_new {
let new_acc = NewAccount {
iterations: self.args.flag_keys_iterations,
path: dirs.keys,
password_file: self.args.flag_password.first().cloned(),
};
AccountCmd::New(new_acc)
} else if self.args.cmd_list {
AccountCmd::List(dirs.keys)
} else if self.args.cmd_import {
let import_acc = ImportAccounts {
from: self.args.arg_path.clone(),
to: dirs.keys,
};
AccountCmd::Import(import_acc)
} else {
unreachable!();
};
Cmd::Account(account_cmd)
} else if self.args.cmd_wallet {
let presale_cmd = ImportWallet {
iterations: self.args.flag_keys_iterations,
path: dirs.keys,
wallet_path: self.args.arg_path.first().unwrap().clone(),
password_file: self.args.flag_password.first().cloned(),
};
Cmd::ImportPresaleWallet(presale_cmd)
} else if self.args.cmd_import {
let import_cmd = ImportBlockchain {
spec: spec,
logger_config: logger_config,
cache_config: cache_config,
dirs: dirs,
file_path: self.args.arg_file.clone(),
format: format,
pruning: pruning,
compaction: compaction,
wal: wal,
mode: mode,
tracing: tracing,
vm_type: vm_type,
};
Cmd::Blockchain(BlockchainCmd::Import(import_cmd))
} else if self.args.cmd_export {
let export_cmd = ExportBlockchain {
spec: spec,
logger_config: logger_config,
cache_config: cache_config,
dirs: dirs,
file_path: self.args.arg_file.clone(),
format: format,
pruning: pruning,
compaction: compaction,
wal: wal,
mode: mode,
tracing: tracing,
from_block: try!(to_block_id(&self.args.flag_from)),
to_block: try!(to_block_id(&self.args.flag_to)),
};
Cmd::Blockchain(BlockchainCmd::Export(export_cmd))
} else if self.args.cmd_snapshot {
let snapshot_cmd = SnapshotCommand {
cache_config: cache_config,
dirs: dirs,
spec: spec,
pruning: pruning,
logger_config: logger_config,
mode: mode,
tracing: tracing,
compaction: compaction,
file_path: self.args.arg_file.clone(),
wal: wal,
kind: snapshot::Kind::Take,
block_at: try!(to_block_id(&self.args.flag_at)),
};
Cmd::Snapshot(snapshot_cmd)
} else if self.args.cmd_restore {
let restore_cmd = SnapshotCommand {
cache_config: cache_config,
dirs: dirs,
spec: spec,
pruning: pruning,
logger_config: logger_config,
mode: mode,
tracing: tracing,
compaction: compaction,
file_path: self.args.arg_file.clone(),
wal: wal,
kind: snapshot::Kind::Restore,
block_at: try!(to_block_id("latest")), // unimportant.
};
Cmd::Snapshot(restore_cmd)
} else {
let daemon = if self.args.cmd_daemon {
Some(self.args.arg_pid_file.clone())
} else {
None
};
let run_cmd = RunCmd {
cache_config: cache_config,
dirs: dirs,
spec: spec,
pruning: pruning,
daemon: daemon,
logger_config: logger_config,
miner_options: miner_options,
http_conf: http_conf,
ipc_conf: ipc_conf,
net_conf: net_conf,
network_id: network_id,
acc_conf: try!(self.accounts_config()),
gas_pricer: try!(self.gas_pricer_config()),
miner_extras: try!(self.miner_extras()),
mode: mode,
tracing: tracing,
compaction: compaction,
wal: wal,
vm_type: vm_type,
enable_network: enable_network,
geth_compatibility: geth_compatibility,
signer_port: signer_port,
net_settings: self.network_settings(),
dapps_conf: dapps_conf,
signer_conf: signer_conf,
ui: self.args.cmd_ui,
name: self.args.flag_identity,
custom_bootnodes: self.args.flag_bootnodes.is_some(),
};
Cmd::Run(run_cmd)
};
Ok(cmd)
}
fn enable_network(&self, mode: &Mode) -> bool {
match *mode {
Mode::Dark(_) => false,
_ => !self.args.flag_no_network,
}
}
fn vm_type(&self) -> Result {
if self.args.flag_jitvm {
VMType::jit().ok_or("Parity is built without the JIT EVM.".into())
} else {
Ok(VMType::Interpreter)
}
}
fn miner_extras(&self) -> Result {
let extras = MinerExtras {
author: try!(self.author()),
extra_data: try!(self.extra_data()),
gas_floor_target: try!(to_u256(&self.args.flag_gas_floor_target)),
gas_ceil_target: try!(to_u256(&self.args.flag_gas_cap)),
transactions_limit: self.args.flag_tx_queue_size,
};
Ok(extras)
}
fn author(&self) -> Result {
to_address(self.args.flag_etherbase.clone().or(self.args.flag_author.clone()))
}
fn format(&self) -> Result