Merge with master
This commit is contained in:
110
parity/cli.rs
110
parity/cli.rs
@@ -25,10 +25,12 @@ Usage:
|
||||
parity daemon <pid-file> [options]
|
||||
parity account (new | list ) [options]
|
||||
parity account import <path>... [options]
|
||||
parity wallet import <path> --password FILE [options]
|
||||
parity import [ <file> ] [options]
|
||||
parity export [ <file> ] [options]
|
||||
parity signer new-token [options]
|
||||
parity [options]
|
||||
parity ui [options]
|
||||
|
||||
Protocol Options:
|
||||
--chain CHAIN Specify the blockchain type. CHAIN may be either a
|
||||
@@ -40,6 +42,12 @@ Protocol Options:
|
||||
--keys-path PATH Specify the path for JSON key files to be found
|
||||
[default: $HOME/.parity/keys].
|
||||
--identity NAME Specify your node's name.
|
||||
--fork POLICY Specifies the client's fork policy. POLICY must be
|
||||
one of:
|
||||
dogmatic - sticks rigidly to the standard chain.
|
||||
dao-soft - votes for the DAO-rescue soft-fork.
|
||||
normal - goes with whatever fork is decided but
|
||||
votes for none. [default: normal].
|
||||
|
||||
Account Options:
|
||||
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
|
||||
@@ -52,6 +60,7 @@ Account Options:
|
||||
--no-import-keys Do not import keys from legacy clients.
|
||||
|
||||
Networking Options:
|
||||
--no-network Disable p2p networking.
|
||||
--port PORT Override the port on which the node should listen
|
||||
[default: 30303].
|
||||
--peers NUM Try to maintain that many peers [default: 25].
|
||||
@@ -65,9 +74,13 @@ Networking Options:
|
||||
--no-discovery Disable new peer discovery.
|
||||
--node-key KEY Specify node secret key, either as 64-character hex
|
||||
string or input to SHA3 operation.
|
||||
--reserved-peers FILE Provide a file containing enodes, one per line.
|
||||
These nodes will always have a reserved slot on top
|
||||
of the normal maximum peers.
|
||||
--reserved-only Connect only to reserved nodes.
|
||||
|
||||
API and Console Options:
|
||||
--jsonrpc-off Disable the JSON-RPC API server.
|
||||
--no-jsonrpc Disable the JSON-RPC API server.
|
||||
--jsonrpc-port PORT Specify the port portion of the JSONRPC API server
|
||||
[default: 8545].
|
||||
--jsonrpc-interface IP Specify the hostname portion of the JSONRPC API
|
||||
@@ -80,13 +93,13 @@ API and Console Options:
|
||||
ethcore, ethcore_set, traces.
|
||||
[default: web3,eth,net,ethcore,personal,traces].
|
||||
|
||||
--ipc-off Disable JSON-RPC over IPC service.
|
||||
--no-ipc Disable JSON-RPC over IPC service.
|
||||
--ipc-path PATH Specify custom path for JSON-RPC over IPC service
|
||||
[default: $HOME/.parity/jsonrpc.ipc].
|
||||
--ipc-apis APIS Specify custom API set available via JSON-RPC over
|
||||
IPC [default: web3,eth,net,ethcore,personal,traces].
|
||||
IPC [default: web3,eth,net,ethcore,personal,traces,rpc].
|
||||
|
||||
--dapps-off Disable the Dapps server (e.g. status page).
|
||||
--no-dapps Disable the Dapps server (e.g. status page).
|
||||
--dapps-port PORT Specify the port portion of the Dapps server
|
||||
[default: 8080].
|
||||
--dapps-interface IP Specify the hostname portion of the Dapps
|
||||
@@ -102,15 +115,38 @@ API and Console Options:
|
||||
[default: $HOME/.parity/dapps]
|
||||
|
||||
--signer Enable Trusted Signer WebSocket endpoint used by
|
||||
Signer UIs.
|
||||
Signer UIs. Default if run with ui command.
|
||||
--no-signer Disable Trusted Signer WebSocket endpoint used by
|
||||
Signer UIs. Default if no command is specified.
|
||||
--signer-port PORT Specify the port of Trusted Signer server
|
||||
[default: 8180].
|
||||
--signer-path PATH Specify directory where Signer UIs tokens should
|
||||
be stored. [default: $HOME/.parity/signer]
|
||||
--no-token By default a new system UI security token will be
|
||||
output on start up. This will prevent it.
|
||||
|
||||
Sealing/Mining Options:
|
||||
--author ADDRESS Specify the block author (aka "coinbase") address
|
||||
for sending block rewards from sealed blocks.
|
||||
NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION.
|
||||
--force-sealing Force the node to author new blocks as if it were
|
||||
always sealing/mining.
|
||||
--reseal-on-txs SET Specify which transactions should force the node
|
||||
to reseal a block. SET is one of:
|
||||
none - never reseal on new transactions;
|
||||
own - reseal only on a new local transaction;
|
||||
ext - reseal only on a new external transaction;
|
||||
all - reseal on all new transactions [default: all].
|
||||
--tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas
|
||||
a single transaction may have for it to be mined.
|
||||
--relay-set SET Set of transactions to relay. SET may be:
|
||||
cheap - Relay any transaction in the queue (this
|
||||
may include invalid transactions);
|
||||
strict - Relay only executed transactions (this
|
||||
guarantees we don't relay invalid transactions, but
|
||||
means we relay nothing if not mining);
|
||||
lenient - Same as strict when mining, and cheap
|
||||
when not [default: cheap].
|
||||
--usd-per-tx USD Amount of USD to be paid for a basic transaction
|
||||
[default: 0.005]. The minimum gas price is set
|
||||
accordingly.
|
||||
@@ -119,14 +155,13 @@ Sealing/Mining Options:
|
||||
web service in turn and fallback on the last known
|
||||
good value [default: auto].
|
||||
--gas-floor-target GAS Amount of gas per block to target when sealing a new
|
||||
block [default: 4712388].
|
||||
--author ADDRESS Specify the block author (aka "coinbase") address
|
||||
for sending block rewards from sealed blocks
|
||||
[default: 0037a6b811ffeb6e072da21179d11b1406371c63].
|
||||
block [default: 4700000].
|
||||
--gas-cap GAS A cap on how large we will raise the gas limit per
|
||||
block due to transaction volume [default: 6283184].
|
||||
--extra-data STRING Specify a custom extra-data for authored blocks, no
|
||||
more than 32 characters.
|
||||
--tx-limit LIMIT Limit of transactions kept in the queue (waiting to
|
||||
be included in next block) [default: 1024].
|
||||
--tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting
|
||||
to be included in next block) [default: 1024].
|
||||
|
||||
Footprint Options:
|
||||
--tracing BOOL Indicates if full transaction tracing should be
|
||||
@@ -135,15 +170,11 @@ Footprint Options:
|
||||
off. auto uses last used value of this option (off
|
||||
if it does not exist) [default: auto].
|
||||
--pruning METHOD Configure pruning of the state/storage trie. METHOD
|
||||
may be one of auto, archive, fast, basic, light:
|
||||
may be one of auto, archive, fast:
|
||||
archive - keep all state trie data. No pruning.
|
||||
fast - maintain journal overlay. Fast but 50MB used.
|
||||
basic - reference count in disk DB. Slow, light, and
|
||||
experimental!
|
||||
light - early merges with partial tracking. Fast,
|
||||
light, and experimental!
|
||||
auto - use the method most recently synced or
|
||||
default to archive if none synced [default: auto].
|
||||
default to fast if none synced [default: auto].
|
||||
--cache-pref-size BYTES Specify the prefered size of the blockchain cache in
|
||||
bytes [default: 16384].
|
||||
--cache-max-size BYTES Specify the maximum size of the blockchain cache in
|
||||
@@ -154,6 +185,12 @@ Footprint Options:
|
||||
the entire system, overrides other cache and queue
|
||||
options.
|
||||
|
||||
Database Options:
|
||||
--db-cache-size MB Override RocksDB database cache size.
|
||||
--db-compaction TYPE Database compaction type. TYPE may be one of:
|
||||
ssd - suitable for SSDs and fast HDDs;
|
||||
hdd - suitable for slow HDDs [default: ssd].
|
||||
|
||||
Import/Export Options:
|
||||
--from BLOCK Export from block BLOCK, which may be an index or
|
||||
hash [default: 1].
|
||||
@@ -166,9 +203,10 @@ Virtual Machine Options:
|
||||
--jitvm Enable the JIT VM.
|
||||
|
||||
Legacy Options:
|
||||
--geth Run in Geth-compatibility mode. Currently just sets
|
||||
the IPC path to be the same as Geth's. Overrides
|
||||
the --ipc-path/--ipcpath options.
|
||||
--geth Run in Geth-compatibility mode. Sets the IPC path
|
||||
to be the same as Geth's. Overrides the --ipc-path
|
||||
and --ipcpath options. Alters RPCs to reflect Geth
|
||||
bugs.
|
||||
--testnet Geth-compatible testnet mode. Equivalent to --chain
|
||||
testnet --keys-path $HOME/parity/testnet-keys.
|
||||
Overrides the --keys-path option.
|
||||
@@ -178,13 +216,16 @@ Legacy Options:
|
||||
--nodekey KEY Equivalent to --node-key KEY.
|
||||
--nodiscover Equivalent to --no-discovery.
|
||||
-j --jsonrpc Does nothing; JSON-RPC is on by default now.
|
||||
--jsonrpc-off Equivalent to --no-jsonrpc.
|
||||
-w --webapp Does nothing; dapps server is on by default now.
|
||||
--dapps-off Equivalent to --no-dapps.
|
||||
--rpc Does nothing; JSON-RPC is on by default now.
|
||||
--rpcaddr IP Equivalent to --jsonrpc-interface IP.
|
||||
--rpcport PORT Equivalent to --jsonrpc-port PORT.
|
||||
--rpcapi APIS Equivalent to --jsonrpc-apis APIS.
|
||||
--rpccorsdomain URL Equivalent to --jsonrpc-cors URL.
|
||||
--ipcdisable Equivalent to --ipc-off.
|
||||
--ipcdisable Equivalent to --no-ipc.
|
||||
--ipc-off Equivalent to --no-ipc.
|
||||
--ipcapi APIS Equivalent to --ipc-apis APIS.
|
||||
--ipcpath PATH Equivalent to --ipc-path PATH.
|
||||
--gasprice WEI Minimum amount of Wei per GAS to be paid for a
|
||||
@@ -205,18 +246,21 @@ Miscellaneous Options:
|
||||
pub struct Args {
|
||||
pub cmd_daemon: bool,
|
||||
pub cmd_account: bool,
|
||||
pub cmd_wallet: bool,
|
||||
pub cmd_new: bool,
|
||||
pub cmd_list: bool,
|
||||
pub cmd_export: bool,
|
||||
pub cmd_import: bool,
|
||||
pub cmd_signer: bool,
|
||||
pub cmd_new_token: bool,
|
||||
pub cmd_ui: bool,
|
||||
pub arg_pid_file: String,
|
||||
pub arg_file: Option<String>,
|
||||
pub arg_path: Vec<String>,
|
||||
pub flag_chain: String,
|
||||
pub flag_db_path: String,
|
||||
pub flag_identity: String,
|
||||
pub flag_fork: String,
|
||||
pub flag_unlock: Option<String>,
|
||||
pub flag_password: Vec<String>,
|
||||
pub flag_cache: Option<usize>,
|
||||
@@ -232,33 +276,41 @@ pub struct Args {
|
||||
pub flag_no_discovery: bool,
|
||||
pub flag_nat: String,
|
||||
pub flag_node_key: Option<String>,
|
||||
pub flag_reserved_peers: Option<String>,
|
||||
pub flag_reserved_only: bool,
|
||||
pub flag_cache_pref_size: usize,
|
||||
pub flag_cache_max_size: usize,
|
||||
pub flag_queue_max_size: usize,
|
||||
pub flag_jsonrpc_off: bool,
|
||||
pub flag_no_jsonrpc: bool,
|
||||
pub flag_jsonrpc_interface: String,
|
||||
pub flag_jsonrpc_port: u16,
|
||||
pub flag_jsonrpc_cors: Option<String>,
|
||||
pub flag_jsonrpc_apis: String,
|
||||
pub flag_ipc_off: bool,
|
||||
pub flag_no_ipc: bool,
|
||||
pub flag_ipc_path: String,
|
||||
pub flag_ipc_apis: String,
|
||||
pub flag_dapps_off: bool,
|
||||
pub flag_no_dapps: bool,
|
||||
pub flag_dapps_port: u16,
|
||||
pub flag_dapps_interface: String,
|
||||
pub flag_dapps_user: Option<String>,
|
||||
pub flag_dapps_pass: Option<String>,
|
||||
pub flag_dapps_path: String,
|
||||
pub flag_signer: bool,
|
||||
pub flag_no_signer: bool,
|
||||
pub flag_signer_port: u16,
|
||||
pub flag_signer_path: String,
|
||||
pub flag_no_token: bool,
|
||||
pub flag_force_sealing: bool,
|
||||
pub flag_author: String,
|
||||
pub flag_reseal_on_txs: String,
|
||||
pub flag_tx_gas_limit: Option<String>,
|
||||
pub flag_relay_set: String,
|
||||
pub flag_author: Option<String>,
|
||||
pub flag_usd_per_tx: String,
|
||||
pub flag_usd_per_eth: String,
|
||||
pub flag_gas_floor_target: String,
|
||||
pub flag_gas_cap: String,
|
||||
pub flag_extra_data: Option<String>,
|
||||
pub flag_tx_limit: usize,
|
||||
pub flag_tx_queue_size: usize,
|
||||
pub flag_logging: Option<String>,
|
||||
pub flag_version: bool,
|
||||
pub flag_from: String,
|
||||
@@ -266,6 +318,7 @@ pub struct Args {
|
||||
pub flag_format: Option<String>,
|
||||
pub flag_jitvm: bool,
|
||||
pub flag_no_color: bool,
|
||||
pub flag_no_network: bool,
|
||||
// legacy...
|
||||
pub flag_geth: bool,
|
||||
pub flag_nodekey: Option<String>,
|
||||
@@ -285,8 +338,13 @@ pub struct Args {
|
||||
pub flag_testnet: bool,
|
||||
pub flag_networkid: Option<String>,
|
||||
pub flag_ipcdisable: bool,
|
||||
pub flag_ipc_off: bool,
|
||||
pub flag_jsonrpc_off: bool,
|
||||
pub flag_dapps_off: bool,
|
||||
pub flag_ipcpath: Option<String>,
|
||||
pub flag_ipcapi: Option<String>,
|
||||
pub flag_db_cache_size: Option<usize>,
|
||||
pub flag_db_compaction: String,
|
||||
}
|
||||
|
||||
pub fn print_version() {
|
||||
|
||||
@@ -24,9 +24,10 @@ use docopt::Docopt;
|
||||
|
||||
use die::*;
|
||||
use util::*;
|
||||
use util::keys::store::{ImportKeySet, AccountService};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use util::network_settings::NetworkSettings;
|
||||
use ethcore::client::{append_path, get_db_path, ClientConfig, Switch, VMType};
|
||||
use ethcore::client::{append_path, get_db_path, ClientConfig, DatabaseCompactionProfile, Switch, VMType};
|
||||
use ethcore::miner::{MinerOptions, PendingSet};
|
||||
use ethcore::ethereum;
|
||||
use ethcore::spec::Spec;
|
||||
use ethsync::SyncConfig;
|
||||
@@ -44,6 +45,13 @@ pub struct Directories {
|
||||
pub signer: String,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub enum Policy {
|
||||
DaoSoft,
|
||||
Normal,
|
||||
Dogmatic,
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
pub fn parse() -> Self {
|
||||
Configuration {
|
||||
@@ -67,18 +75,74 @@ impl Configuration {
|
||||
self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32
|
||||
}
|
||||
|
||||
pub fn author(&self) -> Address {
|
||||
let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author);
|
||||
Address::from_str(clean_0x(d)).unwrap_or_else(|_| {
|
||||
die!("{}: Invalid address for --author. Must be 40 hex characters, with or without the 0x at the beginning.", d)
|
||||
})
|
||||
fn decode_u256(d: &str, argument: &str) -> U256 {
|
||||
U256::from_dec_str(d).unwrap_or_else(|_|
|
||||
U256::from_str(clean_0x(d)).unwrap_or_else(|_|
|
||||
die!("{}: Invalid numeric value for {}. Must be either a decimal or a hex number.", d, argument)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn miner_options(&self) -> MinerOptions {
|
||||
let (own, ext) = match self.args.flag_reseal_on_txs.as_str() {
|
||||
"none" => (false, false),
|
||||
"own" => (true, false),
|
||||
"ext" => (false, true),
|
||||
"all" => (true, true),
|
||||
x => die!("{}: Invalid value for --reseal option. Use --help for more information.", x)
|
||||
};
|
||||
MinerOptions {
|
||||
force_sealing: self.args.flag_force_sealing,
|
||||
reseal_on_external_tx: ext,
|
||||
reseal_on_own_tx: own,
|
||||
tx_gas_limit: self.args.flag_tx_gas_limit.as_ref().map_or(!U256::zero(), |d| Self::decode_u256(d, "--tx-gas-limit")),
|
||||
tx_queue_size: self.args.flag_tx_queue_size,
|
||||
pending_set: match self.args.flag_relay_set.as_str() {
|
||||
"cheap" => PendingSet::AlwaysQueue,
|
||||
"strict" => PendingSet::AlwaysSealing,
|
||||
"lenient" => PendingSet::SealingOrElseQueue,
|
||||
x => die!("{}: Invalid value for --relay-set option. Use --help for more information.", x)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn author(&self) -> Option<Address> {
|
||||
self.args.flag_etherbase.as_ref()
|
||||
.or(self.args.flag_author.as_ref())
|
||||
.map(|d| Address::from_str(clean_0x(d)).unwrap_or_else(|_| {
|
||||
die!("{}: Invalid address for --author. Must be 40 hex characters, with or without the 0x at the beginning.", d)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn policy(&self) -> Policy {
|
||||
match self.args.flag_fork.as_str() {
|
||||
"dao-soft" => Policy::DaoSoft,
|
||||
"normal" => Policy::Normal,
|
||||
"dogmatic" => Policy::Dogmatic,
|
||||
x => die!("{}: Invalid value given for --policy option. Use --help for more info.", x)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gas_floor_target(&self) -> U256 {
|
||||
let d = &self.args.flag_gas_floor_target;
|
||||
U256::from_dec_str(d).unwrap_or_else(|_| {
|
||||
die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d)
|
||||
})
|
||||
if self.policy() == Policy::DaoSoft {
|
||||
3_141_592.into()
|
||||
} else {
|
||||
let d = &self.args.flag_gas_floor_target;
|
||||
U256::from_dec_str(d).unwrap_or_else(|_| {
|
||||
die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gas_ceil_target(&self) -> U256 {
|
||||
if self.policy() == Policy::DaoSoft {
|
||||
3_141_592.into()
|
||||
} else {
|
||||
let d = &self.args.flag_gas_cap;
|
||||
U256::from_dec_str(d).unwrap_or_else(|_| {
|
||||
die!("{}: Invalid target gas ceiling given. Must be a decimal unsigned 256-bit number.", d)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gas_price(&self) -> U256 {
|
||||
@@ -124,7 +188,7 @@ impl Configuration {
|
||||
|
||||
pub fn spec(&self) -> Spec {
|
||||
match self.chain().as_str() {
|
||||
"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(),
|
||||
"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(self.policy() != Policy::Dogmatic),
|
||||
"morden" | "testnet" => ethereum::new_morden(),
|
||||
"olympic" => ethereum::new_olympic(),
|
||||
f => Spec::load(contents(f).unwrap_or_else(|_| {
|
||||
@@ -153,6 +217,25 @@ impl Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_reserved_nodes(&self) -> Vec<String> {
|
||||
use std::fs::File;
|
||||
|
||||
if let Some(ref path) = self.args.flag_reserved_peers {
|
||||
let mut buffer = String::new();
|
||||
let mut node_file = File::open(path).unwrap_or_else(|e| {
|
||||
die!("Error opening reserved nodes file: {}", e);
|
||||
});
|
||||
node_file.read_to_string(&mut buffer).expect("Error reading reserved node file");
|
||||
buffer.lines().map(|s| {
|
||||
Self::normalize_enode(s).unwrap_or_else(|| {
|
||||
die!("{}: Invalid node address format given for a reserved node.", s);
|
||||
})
|
||||
}).collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn net_addresses(&self) -> (Option<SocketAddr>, Option<SocketAddr>) {
|
||||
let port = self.net_port();
|
||||
let listen_address = Some(SocketAddr::new(IpAddr::from_str("0.0.0.0").unwrap(), port));
|
||||
@@ -179,6 +262,11 @@ impl Configuration {
|
||||
let mut net_path = PathBuf::from(&self.path());
|
||||
net_path.push("network");
|
||||
ret.config_path = Some(net_path.to_str().unwrap().to_owned());
|
||||
ret.reserved_nodes = self.init_reserved_nodes();
|
||||
|
||||
if self.args.flag_reserved_only {
|
||||
ret.non_reserved_mode = ::util::network::NonReservedPeerMode::Deny;
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
@@ -187,7 +275,7 @@ impl Configuration {
|
||||
let mut latest_era = None;
|
||||
let jdb_types = [journaldb::Algorithm::Archive, journaldb::Algorithm::EarlyMerge, journaldb::Algorithm::OverlayRecent, journaldb::Algorithm::RefCounted];
|
||||
for i in jdb_types.into_iter() {
|
||||
let db = journaldb::new(&append_path(&get_db_path(Path::new(&self.path()), *i, spec.genesis_header().hash()), "state"), *i);
|
||||
let db = journaldb::new(&append_path(&get_db_path(Path::new(&self.path()), *i, spec.genesis_header().hash()), "state"), *i, kvdb::DatabaseConfig::default());
|
||||
trace!(target: "parity", "Looking for best DB: {} at {:?}", i, db.latest_era());
|
||||
match (latest_era, db.latest_era()) {
|
||||
(Some(best), Some(this)) if best >= this => {}
|
||||
@@ -214,6 +302,8 @@ impl Configuration {
|
||||
client_config.blockchain.max_cache_size = self.args.flag_cache_max_size;
|
||||
}
|
||||
}
|
||||
// forced blockchain (blocks + extras) db cache size if provided
|
||||
client_config.blockchain.db_cache_size = self.args.flag_db_cache_size.and_then(|cs| Some(cs / 2));
|
||||
|
||||
client_config.tracing.enabled = match self.args.flag_tracing.as_str() {
|
||||
"auto" => Switch::Auto,
|
||||
@@ -221,16 +311,28 @@ impl Configuration {
|
||||
"off" => Switch::Off,
|
||||
_ => { die!("Invalid tracing method given!") }
|
||||
};
|
||||
// forced trace db cache size if provided
|
||||
client_config.tracing.db_cache_size = self.args.flag_db_cache_size.and_then(|cs| Some(cs / 4));
|
||||
|
||||
client_config.pruning = match self.args.flag_pruning.as_str() {
|
||||
"archive" => journaldb::Algorithm::Archive,
|
||||
"light" => journaldb::Algorithm::EarlyMerge,
|
||||
"fast" => journaldb::Algorithm::OverlayRecent,
|
||||
"basic" => journaldb::Algorithm::RefCounted,
|
||||
"auto" => self.find_best_db(spec).unwrap_or(journaldb::Algorithm::Archive),
|
||||
"auto" => self.find_best_db(spec).unwrap_or(journaldb::Algorithm::OverlayRecent),
|
||||
_ => { die!("Invalid pruning method given."); }
|
||||
};
|
||||
|
||||
// forced state db cache size if provided
|
||||
client_config.db_cache_size = self.args.flag_db_cache_size.and_then(|cs| Some(cs / 4));
|
||||
|
||||
// compaction profile
|
||||
client_config.db_compaction = match self.args.flag_db_compaction.as_str() {
|
||||
"ssd" => DatabaseCompactionProfile::Default,
|
||||
"hdd" => DatabaseCompactionProfile::HDD,
|
||||
_ => { die!("Invalid compaction profile given (--db-compaction argument), expected hdd/default."); }
|
||||
};
|
||||
|
||||
if self.args.flag_jitvm {
|
||||
client_config.vm_type = VMType::jit().unwrap_or_else(|| die!("Parity built without jit vm."))
|
||||
}
|
||||
@@ -249,7 +351,10 @@ impl Configuration {
|
||||
sync_config
|
||||
}
|
||||
|
||||
pub fn account_service(&self) -> AccountService {
|
||||
pub fn account_service(&self) -> AccountProvider {
|
||||
use ethcore::ethstore::{import_accounts, EthStore};
|
||||
use ethcore::ethstore::dir::{GethDirectory, DirectoryType, DiskDirectory};
|
||||
|
||||
// Secret Store
|
||||
let passwords = self.args.flag_password.iter().flat_map(|filename| {
|
||||
BufReader::new(&File::open(filename).unwrap_or_else(|_| die!("{} Unable to read password file. Ensure it exists and permissions are correct.", filename)))
|
||||
@@ -258,18 +363,30 @@ impl Configuration {
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
}).collect::<Vec<_>>();
|
||||
let import_keys = match (self.args.flag_no_import_keys, self.args.flag_testnet) {
|
||||
(true, _) => ImportKeySet::None,
|
||||
(false, false) => ImportKeySet::Legacy,
|
||||
(false, true) => ImportKeySet::LegacyTestnet,
|
||||
};
|
||||
let account_service = AccountService::with_security(Path::new(&self.keys_path()), self.keys_iterations(), import_keys);
|
||||
|
||||
if !self.args.flag_no_import_keys {
|
||||
let dir_type = if self.args.flag_testnet {
|
||||
DirectoryType::Testnet
|
||||
} else {
|
||||
DirectoryType::Main
|
||||
};
|
||||
|
||||
let from = GethDirectory::open(dir_type);
|
||||
let to = DiskDirectory::create(self.keys_path()).unwrap();
|
||||
// ignore error, cause geth may not exist
|
||||
let _ = import_accounts(&from, &to);
|
||||
}
|
||||
|
||||
let dir = Box::new(DiskDirectory::create(self.keys_path()).unwrap());
|
||||
let iterations = self.keys_iterations();
|
||||
let account_service = AccountProvider::new(Box::new(EthStore::open_with_iterations(dir, iterations).unwrap()));
|
||||
|
||||
if let Some(ref unlocks) = self.args.flag_unlock {
|
||||
for d in unlocks.split(',') {
|
||||
let a = Address::from_str(clean_0x(d)).unwrap_or_else(|_| {
|
||||
die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d)
|
||||
});
|
||||
if passwords.iter().find(|p| account_service.unlock_account_no_expire(&a, p).is_ok()).is_none() {
|
||||
if passwords.iter().find(|p| account_service.unlock_account_permanently(a, (*p).clone()).is_ok()).is_none() {
|
||||
die!("No password given to unlock account {}. Pass the password using `--password`.", a);
|
||||
}
|
||||
}
|
||||
@@ -287,9 +404,14 @@ impl Configuration {
|
||||
}
|
||||
|
||||
fn geth_ipc_path(&self) -> String {
|
||||
if self.args.flag_testnet { path::ethereum::with_testnet("geth.ipc") }
|
||||
else { path::ethereum::with_default("geth.ipc") }
|
||||
.to_str().unwrap().to_owned()
|
||||
if cfg!(windows) {
|
||||
r"\\.\pipe\geth.ipc".to_owned()
|
||||
}
|
||||
else {
|
||||
if self.args.flag_testnet { path::ethereum::with_testnet("geth.ipc") }
|
||||
else { path::ethereum::with_default("geth.ipc") }
|
||||
.to_str().unwrap().to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keys_iterations(&self) -> u32 {
|
||||
@@ -298,7 +420,7 @@ impl Configuration {
|
||||
|
||||
pub fn ipc_settings(&self) -> IpcConfiguration {
|
||||
IpcConfiguration {
|
||||
enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off),
|
||||
enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off || self.args.flag_no_ipc),
|
||||
socket_addr: self.ipc_path(),
|
||||
apis: self.args.flag_ipcapi.clone().unwrap_or(self.args.flag_ipc_apis.clone()),
|
||||
}
|
||||
@@ -311,7 +433,7 @@ impl Configuration {
|
||||
chain: self.chain(),
|
||||
max_peers: self.max_peers(),
|
||||
network_port: self.net_port(),
|
||||
rpc_enabled: !self.args.flag_jsonrpc_off,
|
||||
rpc_enabled: !self.args.flag_jsonrpc_off && !self.args.flag_no_jsonrpc,
|
||||
rpc_interface: self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone()),
|
||||
rpc_port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
|
||||
}
|
||||
@@ -357,17 +479,51 @@ impl Configuration {
|
||||
}
|
||||
|
||||
fn ipc_path(&self) -> String {
|
||||
if self.args.flag_geth { self.geth_ipc_path() }
|
||||
else { Configuration::replace_home(&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) }
|
||||
if self.args.flag_geth {
|
||||
self.geth_ipc_path()
|
||||
} else if cfg!(windows) {
|
||||
r"\\.\pipe\parity.jsonrpc".to_owned()
|
||||
} else {
|
||||
Configuration::replace_home(&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn have_color(&self) -> bool {
|
||||
!self.args.flag_no_color && !cfg!(windows)
|
||||
}
|
||||
|
||||
pub fn signer_port(&self) -> Option<u16> {
|
||||
if self.args.flag_signer {
|
||||
Some(self.args.flag_signer_port)
|
||||
} else {
|
||||
if !self.signer_enabled() {
|
||||
None
|
||||
} else {
|
||||
Some(self.args.flag_signer_port)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rpc_interface(&self) -> String {
|
||||
match self.network_settings().rpc_interface.as_str() {
|
||||
"all" => "0.0.0.0",
|
||||
"local" => "127.0.0.1",
|
||||
x => x,
|
||||
}.into()
|
||||
}
|
||||
|
||||
pub fn dapps_interface(&self) -> String {
|
||||
match self.args.flag_dapps_interface.as_str() {
|
||||
"all" => "0.0.0.0",
|
||||
"local" => "127.0.0.1",
|
||||
x => x,
|
||||
}.into()
|
||||
}
|
||||
|
||||
pub fn dapps_enabled(&self) -> bool {
|
||||
!self.args.flag_dapps_off && !self.args.flag_no_dapps
|
||||
}
|
||||
|
||||
pub fn signer_enabled(&self) -> bool {
|
||||
(self.args.cmd_ui && !self.args.flag_no_signer) ||
|
||||
(!self.args.cmd_ui && self.args.flag_signer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -45,12 +45,7 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Option<WebappSer
|
||||
return None;
|
||||
}
|
||||
|
||||
let interface = match configuration.interface.as_str() {
|
||||
"all" => "0.0.0.0",
|
||||
"local" => "127.0.0.1",
|
||||
x => x,
|
||||
};
|
||||
let url = format!("{}:{}", interface, configuration.port);
|
||||
let url = format!("{}:{}", configuration.interface, configuration.port);
|
||||
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid Webapps listen host/port given.", url));
|
||||
|
||||
let auth = configuration.user.as_ref().map(|username| {
|
||||
|
||||
@@ -14,38 +14,52 @@
|
||||
// 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 std::sync::{Arc, Weak};
|
||||
use ethcore::client::Client;
|
||||
use ethcore::service::NetSyncMessage;
|
||||
use ethcore::service::{NetSyncMessage, SyncMessage};
|
||||
use ethsync::EthSync;
|
||||
use util::keys::store::AccountService;
|
||||
use util::{TimerToken, IoHandler, IoContext};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use util::{TimerToken, IoHandler, IoContext, NetworkService, NetworkIoMessage};
|
||||
|
||||
use informant::Informant;
|
||||
|
||||
const INFO_TIMER: TimerToken = 0;
|
||||
|
||||
const ACCOUNT_TICK_TIMER: TimerToken = 10;
|
||||
const ACCOUNT_TICK_MS: u64 = 60000;
|
||||
|
||||
pub struct ClientIoHandler {
|
||||
pub client: Arc<Client>,
|
||||
pub sync: Arc<EthSync>,
|
||||
pub accounts: Arc<AccountService>,
|
||||
pub accounts: Arc<AccountProvider>,
|
||||
pub info: Informant,
|
||||
pub network: Weak<NetworkService<SyncMessage>>,
|
||||
}
|
||||
|
||||
impl IoHandler<NetSyncMessage> for ClientIoHandler {
|
||||
fn initialize(&self, io: &IoContext<NetSyncMessage>) {
|
||||
io.register_timer(INFO_TIMER, 5000).expect("Error registering timer");
|
||||
io.register_timer(ACCOUNT_TICK_TIMER, ACCOUNT_TICK_MS).expect("Error registering account timer");
|
||||
}
|
||||
|
||||
fn timeout(&self, _io: &IoContext<NetSyncMessage>, timer: TimerToken) {
|
||||
match timer {
|
||||
INFO_TIMER => { self.info.tick(&self.client, Some(&self.sync)); }
|
||||
ACCOUNT_TICK_TIMER => { self.accounts.tick(); },
|
||||
_ => {}
|
||||
if let INFO_TIMER = timer {
|
||||
self.info.tick(&self.client, Some(&self.sync));
|
||||
}
|
||||
}
|
||||
|
||||
fn message(&self, _io: &IoContext<NetSyncMessage>, message: &NetSyncMessage) {
|
||||
match *message {
|
||||
NetworkIoMessage::User(SyncMessage::StartNetwork) => {
|
||||
info!("Starting network");
|
||||
if let Some(network) = self.network.upgrade() {
|
||||
network.start().unwrap_or_else(|e| warn!("Error starting network: {:?}", e));
|
||||
EthSync::register(&*network, self.sync.clone()).unwrap_or_else(|e| warn!("Error registering eth protocol handler: {}", e));
|
||||
}
|
||||
},
|
||||
NetworkIoMessage::User(SyncMessage::StopNetwork) => {
|
||||
info!("Stopping network");
|
||||
if let Some(network) = self.network.upgrade() {
|
||||
network.stop().unwrap_or_else(|e| warn!("Error stopping network: {:?}", e));
|
||||
}
|
||||
},
|
||||
_ => {/* Ignore other messages */},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
159
parity/main.rs
159
parity/main.rs
@@ -32,6 +32,7 @@ extern crate log as rlog;
|
||||
extern crate env_logger;
|
||||
extern crate ctrlc;
|
||||
extern crate fdlimit;
|
||||
#[cfg(not(windows))]
|
||||
extern crate daemonize;
|
||||
extern crate time;
|
||||
extern crate number_prefix;
|
||||
@@ -67,6 +68,7 @@ mod configuration;
|
||||
mod migration;
|
||||
mod signer;
|
||||
mod rpc_apis;
|
||||
mod url;
|
||||
|
||||
use std::io::{Write, Read, BufReader, BufRead};
|
||||
use std::ops::Deref;
|
||||
@@ -78,7 +80,7 @@ use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use rustc_serialize::hex::FromHex;
|
||||
use ctrlc::CtrlC;
|
||||
use util::{H256, ToPretty, NetworkConfiguration, PayloadInfo, Bytes};
|
||||
use util::{H256, ToPretty, NetworkConfiguration, PayloadInfo, Bytes, UtilError};
|
||||
use util::panics::{MayPanic, ForwardPanic, PanicHandler};
|
||||
use ethcore::client::{BlockID, BlockChainClient, ClientConfig, get_db_path};
|
||||
use ethcore::error::{Error, ImportError};
|
||||
@@ -86,7 +88,6 @@ use ethcore::service::ClientService;
|
||||
use ethcore::spec::Spec;
|
||||
use ethsync::EthSync;
|
||||
use ethcore::miner::{Miner, MinerService, ExternalMiner};
|
||||
use daemonize::Daemonize;
|
||||
use migration::migrate;
|
||||
use informant::Informant;
|
||||
|
||||
@@ -109,17 +110,18 @@ fn execute(conf: Configuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
if conf.args.cmd_signer {
|
||||
execute_signer(conf);
|
||||
return;
|
||||
}
|
||||
|
||||
let spec = conf.spec();
|
||||
let client_config = conf.client_config(&spec);
|
||||
|
||||
execute_upgrades(&conf, &spec, &client_config);
|
||||
|
||||
if conf.args.cmd_daemon {
|
||||
Daemonize::new()
|
||||
.pid_file(conf.args.arg_pid_file.clone())
|
||||
.chown_pid_file(true)
|
||||
.start()
|
||||
.unwrap_or_else(|e| die!("Couldn't daemonize; {}", e));
|
||||
daemonize(&conf);
|
||||
}
|
||||
|
||||
if conf.args.cmd_account {
|
||||
@@ -127,6 +129,11 @@ fn execute(conf: Configuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
if conf.args.cmd_wallet {
|
||||
execute_wallet_cli(conf);
|
||||
return;
|
||||
}
|
||||
|
||||
if conf.args.cmd_export {
|
||||
execute_export(conf);
|
||||
return;
|
||||
@@ -137,14 +144,23 @@ fn execute(conf: Configuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
if conf.args.cmd_signer {
|
||||
execute_signer(conf);
|
||||
return;
|
||||
}
|
||||
|
||||
execute_client(conf, spec, client_config);
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn daemonize(conf: &Configuration) {
|
||||
use daemonize::Daemonize;
|
||||
Daemonize::new()
|
||||
.pid_file(conf.args.arg_pid_file.clone())
|
||||
.chown_pid_file(true)
|
||||
.start()
|
||||
.unwrap_or_else(|e| die!("Couldn't daemonize; {}", e));
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn daemonize(_conf: &Configuration) {
|
||||
}
|
||||
|
||||
fn execute_upgrades(conf: &Configuration, spec: &Spec, client_config: &ClientConfig) {
|
||||
match ::upgrade::upgrade(Some(&conf.path())) {
|
||||
Ok(upgrades_applied) if upgrades_applied > 0 => {
|
||||
@@ -175,20 +191,34 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
||||
let net_settings = conf.net_settings(&spec);
|
||||
let sync_config = conf.sync_config(&spec);
|
||||
|
||||
// Create and display a new token for UIs.
|
||||
if conf.signer_enabled() && !conf.args.flag_no_token {
|
||||
new_token(conf.directories().signer).unwrap_or_else(|e| {
|
||||
die!("Error generating token: {:?}", e)
|
||||
});
|
||||
}
|
||||
|
||||
// Display warning about using unlock with signer
|
||||
if conf.signer_enabled() && conf.args.flag_unlock.is_some() {
|
||||
warn!("Using Trusted Signer and --unlock is not recommended!");
|
||||
warn!("NOTE that Signer will not ask you to confirm transactions from unlocked account.");
|
||||
}
|
||||
|
||||
// Secret Store
|
||||
let account_service = Arc::new(conf.account_service());
|
||||
|
||||
// Miner
|
||||
let miner = Miner::with_accounts(conf.args.flag_force_sealing, conf.spec(), account_service.clone());
|
||||
miner.set_author(conf.author());
|
||||
let miner = Miner::new(conf.miner_options(), conf.spec(), Some(account_service.clone()));
|
||||
miner.set_author(conf.author().unwrap_or_default());
|
||||
miner.set_gas_floor_target(conf.gas_floor_target());
|
||||
miner.set_gas_ceil_target(conf.gas_ceil_target());
|
||||
miner.set_extra_data(conf.extra_data());
|
||||
miner.set_minimal_gas_price(conf.gas_price());
|
||||
miner.set_transactions_limit(conf.args.flag_tx_limit);
|
||||
miner.set_transactions_limit(conf.args.flag_tx_queue_size);
|
||||
|
||||
// Build client
|
||||
let mut service = ClientService::start(
|
||||
client_config, spec, net_settings, Path::new(&conf.path()), miner.clone()
|
||||
client_config, spec, net_settings, Path::new(&conf.path()), miner.clone(), !conf.args.flag_no_network
|
||||
).unwrap_or_else(|e| die_with_error("Client", e));
|
||||
|
||||
panic_handler.forward_from(&service);
|
||||
@@ -198,7 +228,8 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
||||
let network_settings = Arc::new(conf.network_settings());
|
||||
|
||||
// Sync
|
||||
let sync = EthSync::register(service.network(), sync_config, client.clone());
|
||||
let sync = EthSync::new(sync_config, client.clone());
|
||||
EthSync::register(&*service.network(), sync.clone()).unwrap_or_else(|e| die_with_error("Error registering eth protocol handler", UtilError::from(e).into()));
|
||||
|
||||
let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies {
|
||||
signer_port: conf.signer_port(),
|
||||
@@ -210,6 +241,8 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
||||
external_miner: external_miner.clone(),
|
||||
logger: logger.clone(),
|
||||
settings: network_settings.clone(),
|
||||
allow_pending_receipt_query: !conf.args.flag_geth,
|
||||
net_service: service.network(),
|
||||
});
|
||||
|
||||
let dependencies = rpc::Dependencies {
|
||||
@@ -220,7 +253,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
||||
// Setup http rpc
|
||||
let rpc_server = rpc::new_http(rpc::HttpConfiguration {
|
||||
enabled: network_settings.rpc_enabled,
|
||||
interface: network_settings.rpc_interface.clone(),
|
||||
interface: conf.rpc_interface(),
|
||||
port: network_settings.rpc_port,
|
||||
apis: conf.rpc_apis(),
|
||||
cors: conf.rpc_cors(),
|
||||
@@ -228,11 +261,12 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
||||
|
||||
// setup ipc rpc
|
||||
let _ipc_server = rpc::new_ipc(conf.ipc_settings(), &dependencies);
|
||||
debug!("IPC: {}", conf.ipc_settings());
|
||||
|
||||
if conf.args.flag_webapp { println!("WARNING: Flag -w/--webapp is deprecated. Dapps server is now on by default. Ignoring."); }
|
||||
let dapps_server = dapps::new(dapps::Configuration {
|
||||
enabled: !conf.args.flag_dapps_off,
|
||||
interface: conf.args.flag_dapps_interface.clone(),
|
||||
enabled: conf.dapps_enabled(),
|
||||
interface: conf.dapps_interface(),
|
||||
port: conf.args.flag_dapps_port,
|
||||
user: conf.args.flag_dapps_user.clone(),
|
||||
pass: conf.args.flag_dapps_pass.clone(),
|
||||
@@ -244,7 +278,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
||||
|
||||
// Set up a signer
|
||||
let signer_server = signer::start(signer::Configuration {
|
||||
enabled: deps_for_rpc_apis.signer_port.is_some(),
|
||||
enabled: conf.signer_enabled(),
|
||||
port: conf.args.flag_signer_port,
|
||||
signer_path: conf.directories().signer,
|
||||
}, signer::Dependencies {
|
||||
@@ -255,11 +289,19 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
||||
// Register IO handler
|
||||
let io_handler = Arc::new(ClientIoHandler {
|
||||
client: service.client(),
|
||||
info: Informant::new(!conf.args.flag_no_color),
|
||||
info: Informant::new(conf.have_color()),
|
||||
sync: sync.clone(),
|
||||
accounts: account_service.clone(),
|
||||
network: Arc::downgrade(&service.network()),
|
||||
});
|
||||
service.io().register_handler(io_handler).expect("Error registering IO handler");
|
||||
service.register_io_handler(io_handler).expect("Error registering IO handler");
|
||||
|
||||
if conf.args.cmd_ui {
|
||||
if !conf.dapps_enabled() {
|
||||
die_with_message("Cannot use UI command with Dapps turned off.");
|
||||
}
|
||||
url::open(&format!("http://{}:{}/", conf.dapps_interface(), conf.args.flag_dapps_port));
|
||||
}
|
||||
|
||||
// Handle exit
|
||||
wait_for_exit(panic_handler, rpc_server, dapps_server, signer_server);
|
||||
@@ -289,16 +331,17 @@ fn execute_export(conf: Configuration) {
|
||||
udp_port: None,
|
||||
nat_enabled: false,
|
||||
discovery_enabled: false,
|
||||
pin: true,
|
||||
boot_nodes: Vec::new(),
|
||||
use_secret: None,
|
||||
ideal_peers: 0,
|
||||
reserved_nodes: Vec::new(),
|
||||
non_reserved_mode: ::util::network::NonReservedPeerMode::Accept,
|
||||
};
|
||||
let client_config = conf.client_config(&spec);
|
||||
|
||||
// Build client
|
||||
let service = ClientService::start(
|
||||
client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::default()),
|
||||
client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::with_spec(conf.spec())), false
|
||||
).unwrap_or_else(|e| die_with_error("Client", e));
|
||||
|
||||
panic_handler.forward_from(&service);
|
||||
@@ -360,33 +403,36 @@ fn execute_import(conf: Configuration) {
|
||||
udp_port: None,
|
||||
nat_enabled: false,
|
||||
discovery_enabled: false,
|
||||
pin: true,
|
||||
boot_nodes: Vec::new(),
|
||||
use_secret: None,
|
||||
ideal_peers: 0,
|
||||
reserved_nodes: Vec::new(),
|
||||
non_reserved_mode: ::util::network::NonReservedPeerMode::Accept,
|
||||
};
|
||||
let client_config = conf.client_config(&spec);
|
||||
|
||||
// Build client
|
||||
let service = ClientService::start(
|
||||
client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::default()),
|
||||
client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::with_spec(conf.spec())), false
|
||||
).unwrap_or_else(|e| die_with_error("Client", e));
|
||||
|
||||
panic_handler.forward_from(&service);
|
||||
let client = service.client();
|
||||
|
||||
let mut instream: Box<Read> = if let Some(f) = conf.args.arg_file {
|
||||
let f = File::open(&f).unwrap_or_else(|_| die!("Cannot open the file given: {}", f));
|
||||
let mut instream: Box<Read> = if let Some(ref f) = conf.args.arg_file {
|
||||
let f = File::open(f).unwrap_or_else(|_| die!("Cannot open the file given: {}", f));
|
||||
Box::new(f)
|
||||
} else {
|
||||
Box::new(::std::io::stdin())
|
||||
};
|
||||
|
||||
let mut first_bytes: Bytes = vec![0; 3];
|
||||
const READAHEAD_BYTES: usize = 8;
|
||||
|
||||
let mut first_bytes: Bytes = vec![0; READAHEAD_BYTES];
|
||||
let mut first_read = 0;
|
||||
|
||||
let format = match conf.args.flag_format {
|
||||
Some(x) => match x.deref() {
|
||||
Some(ref x) => match x.deref() {
|
||||
"binary" | "bin" => DataFormat::Binary,
|
||||
"hex" => DataFormat::Hex,
|
||||
x => die!("Invalid --format parameter given: {:?}", x),
|
||||
@@ -407,7 +453,7 @@ fn execute_import(conf: Configuration) {
|
||||
}
|
||||
};
|
||||
|
||||
let informant = Informant::new(!conf.args.flag_no_color);
|
||||
let informant = Informant::new(conf.have_color());
|
||||
|
||||
let do_import = |bytes| {
|
||||
while client.queue_info().is_full() { sleep(Duration::from_secs(1)); }
|
||||
@@ -422,13 +468,13 @@ fn execute_import(conf: Configuration) {
|
||||
match format {
|
||||
DataFormat::Binary => {
|
||||
loop {
|
||||
let mut bytes: Bytes = if first_read > 0 {first_bytes.clone()} else {vec![0; 3]};
|
||||
let mut bytes: Bytes = if first_read > 0 {first_bytes.clone()} else {vec![0; READAHEAD_BYTES]};
|
||||
let n = if first_read > 0 {first_read} else {instream.read(&mut(bytes[..])).unwrap_or_else(|_| die!("Error reading from the file/stream."))};
|
||||
if n == 0 { break; }
|
||||
first_read = 0;
|
||||
let s = PayloadInfo::from(&(bytes[..])).unwrap_or_else(|e| die!("Invalid RLP in the file/stream: {:?}", e)).total();
|
||||
bytes.resize(s, 0);
|
||||
instream.read_exact(&mut(bytes[3..])).unwrap_or_else(|_| die!("Error reading from the file/stream."));
|
||||
instream.read_exact(&mut(bytes[READAHEAD_BYTES..])).unwrap_or_else(|_| die!("Error reading from the file/stream."));
|
||||
do_import(bytes);
|
||||
}
|
||||
}
|
||||
@@ -457,9 +503,15 @@ fn execute_signer(conf: Configuration) {
|
||||
}
|
||||
|
||||
fn execute_account_cli(conf: Configuration) {
|
||||
use util::keys::store::SecretStore;
|
||||
use ethcore::ethstore::{EthStore, import_accounts};
|
||||
use ethcore::ethstore::dir::DiskDirectory;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use rpassword::read_password;
|
||||
let mut secret_store = SecretStore::with_security(Path::new(&conf.keys_path()), conf.keys_iterations());
|
||||
|
||||
let dir = Box::new(DiskDirectory::create(conf.keys_path()).unwrap());
|
||||
let iterations = conf.keys_iterations();
|
||||
let secret_store = AccountProvider::new(Box::new(EthStore::open_with_iterations(dir, iterations).unwrap()));
|
||||
|
||||
if conf.args.cmd_new {
|
||||
println!("Please note that password is NOT RECOVERABLE.");
|
||||
print!("Type password: ");
|
||||
@@ -477,19 +529,50 @@ fn execute_account_cli(conf: Configuration) {
|
||||
println!("{:?}", new_address);
|
||||
return;
|
||||
}
|
||||
|
||||
if conf.args.cmd_list {
|
||||
println!("Known addresses:");
|
||||
for &(addr, _) in &secret_store.accounts().unwrap() {
|
||||
for addr in &secret_store.accounts() {
|
||||
println!("{:?}", addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if conf.args.cmd_import {
|
||||
let imported = util::keys::import_keys_paths(&mut secret_store, &conf.args.arg_path).unwrap();
|
||||
let to = DiskDirectory::create(conf.keys_path()).unwrap();
|
||||
let mut imported = 0;
|
||||
for path in &conf.args.arg_path {
|
||||
let from = DiskDirectory::at(path);
|
||||
imported += import_accounts(&from, &to).unwrap_or_else(|e| die!("Could not import accounts {}", e)).len();
|
||||
}
|
||||
println!("Imported {} keys", imported);
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_wallet_cli(conf: Configuration) {
|
||||
use ethcore::ethstore::{PresaleWallet, EthStore};
|
||||
use ethcore::ethstore::dir::DiskDirectory;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
|
||||
let wallet_path = conf.args.arg_path.first().unwrap();
|
||||
let filename = conf.args.flag_password.first().unwrap();
|
||||
let mut file = File::open(filename).unwrap_or_else(|_| die!("{} Unable to read password file.", filename));
|
||||
let mut file_content = String::new();
|
||||
file.read_to_string(&mut file_content).unwrap_or_else(|_| die!("{} Unable to read password file.", filename));
|
||||
|
||||
let dir = Box::new(DiskDirectory::create(conf.keys_path()).unwrap());
|
||||
let iterations = conf.keys_iterations();
|
||||
let store = AccountProvider::new(Box::new(EthStore::open_with_iterations(dir, iterations).unwrap()));
|
||||
|
||||
// remove eof
|
||||
let pass = &file_content[..file_content.len() - 1];
|
||||
let wallet = PresaleWallet::open(wallet_path).unwrap_or_else(|_| die!("Unable to open presale wallet."));
|
||||
let kp = wallet.decrypt(pass).unwrap_or_else(|_| die!("Invalid password"));
|
||||
let address = store.insert_account(kp.secret().clone(), pass).unwrap();
|
||||
|
||||
println!("Imported account: {}", address);
|
||||
}
|
||||
|
||||
fn wait_for_exit(
|
||||
panic_handler: Arc<PanicHandler>,
|
||||
_rpc_server: Option<RpcServer>,
|
||||
|
||||
@@ -20,7 +20,7 @@ use std::io::{Read, Write, Error as IoError, ErrorKind};
|
||||
use std::path::PathBuf;
|
||||
use std::fmt::{Display, Formatter, Error as FmtError};
|
||||
use util::migration::{Manager as MigrationManager, Config as MigrationConfig, MigrationIterator};
|
||||
use util::kvdb::{Database, DatabaseConfig};
|
||||
use util::kvdb::{Database, DatabaseConfig, CompactionProfile};
|
||||
use ethcore::migrations;
|
||||
|
||||
/// Database is assumed to be at default version, when no version file is found.
|
||||
@@ -89,6 +89,7 @@ fn current_version(path: &PathBuf) -> Result<u32, Error> {
|
||||
/// Writes current database version to the file.
|
||||
/// Creates a new file if the version file does not exist yet.
|
||||
fn update_version(path: &PathBuf) -> Result<(), Error> {
|
||||
try!(fs::create_dir_all(path));
|
||||
let mut file = try!(File::create(version_file_path(path)));
|
||||
try!(file.write_all(format!("{}", CURRENT_VERSION).as_bytes()));
|
||||
Ok(())
|
||||
@@ -151,8 +152,6 @@ fn migrate_database(version: u32, path: PathBuf, migrations: MigrationManager) -
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
println!("Migrating database {} from version {} to {}", path.to_string_lossy(), version, CURRENT_VERSION);
|
||||
|
||||
let temp_path = temp_database_path(&path);
|
||||
let backup_path = backup_database_path(&path);
|
||||
// remote the dir if it exists
|
||||
@@ -163,6 +162,8 @@ fn migrate_database(version: u32, path: PathBuf, migrations: MigrationManager) -
|
||||
let db_config = DatabaseConfig {
|
||||
prefix_size: None,
|
||||
max_open_files: 64,
|
||||
cache_size: None,
|
||||
compaction: CompactionProfile::default(),
|
||||
};
|
||||
|
||||
// open old database
|
||||
@@ -187,20 +188,26 @@ fn migrate_database(version: u32, path: PathBuf, migrations: MigrationManager) -
|
||||
|
||||
// remove backup
|
||||
try!(fs::remove_dir_all(&backup_path));
|
||||
println!("Migration finished");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn exists(path: &PathBuf) -> bool {
|
||||
fs::metadata(path).is_ok()
|
||||
}
|
||||
|
||||
/// Migrates the database.
|
||||
pub fn migrate(path: &PathBuf) -> Result<(), Error> {
|
||||
// read version file.
|
||||
let version = try!(current_version(path));
|
||||
|
||||
// migrate the databases.
|
||||
if version != CURRENT_VERSION {
|
||||
// main db directory may already exists, so let's check if we have blocks dir
|
||||
if version != CURRENT_VERSION && exists(&blocks_database_path(path)) {
|
||||
println!("Migrating database from version {} to {}", version, CURRENT_VERSION);
|
||||
try!(migrate_database(version, blocks_database_path(path), try!(blocks_database_migrations())));
|
||||
try!(migrate_database(version, extras_database_path(path), try!(extras_database_migrations())));
|
||||
println!("Migration finished");
|
||||
}
|
||||
|
||||
// update version file.
|
||||
|
||||
@@ -22,6 +22,7 @@ use util::panics::PanicHandler;
|
||||
use die::*;
|
||||
use jsonipc;
|
||||
use rpc_apis;
|
||||
use std::fmt;
|
||||
|
||||
#[cfg(feature = "rpc")]
|
||||
pub use ethcore_rpc::Server as RpcServer;
|
||||
@@ -44,6 +45,17 @@ pub struct IpcConfiguration {
|
||||
pub apis: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for IpcConfiguration {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.enabled {
|
||||
write!(f, "endpoint address [{}], api list [{}]", self.socket_addr, self.apis)
|
||||
}
|
||||
else {
|
||||
write!(f, "disabled")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Dependencies {
|
||||
pub panic_handler: Arc<PanicHandler>,
|
||||
pub apis: Arc<rpc_apis::Dependencies>,
|
||||
@@ -54,24 +66,13 @@ pub fn new_http(conf: HttpConfiguration, deps: &Dependencies) -> Option<RpcServe
|
||||
return None;
|
||||
}
|
||||
|
||||
let interface = match conf.interface.as_str() {
|
||||
"all" => "0.0.0.0",
|
||||
"local" => "127.0.0.1",
|
||||
x => x,
|
||||
};
|
||||
let apis = conf.apis.split(',').collect();
|
||||
let url = format!("{}:{}", interface, conf.port);
|
||||
let url = format!("{}:{}", conf.interface, conf.port);
|
||||
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url));
|
||||
|
||||
Some(setup_http_rpc_server(deps, &addr, conf.cors, apis))
|
||||
}
|
||||
|
||||
pub fn new_ipc(conf: IpcConfiguration, deps: &Dependencies) -> Option<jsonipc::Server> {
|
||||
if !conf.enabled { return None; }
|
||||
let apis = conf.apis.split(',').collect();
|
||||
Some(setup_ipc_rpc_server(deps, &conf.socket_addr, apis))
|
||||
}
|
||||
|
||||
fn setup_rpc_server(apis: Vec<&str>, deps: &Dependencies) -> Server {
|
||||
let apis = rpc_apis::from_str(apis);
|
||||
let server = Server::new();
|
||||
@@ -109,10 +110,18 @@ pub fn setup_http_rpc_server(
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "rpc"))]
|
||||
pub fn setup_ipc_rpc_server(_dependencies: &Dependencies, _addr: &str, _apis: Vec<&str>) -> ! {
|
||||
die!("Your Parity version has been compiled without JSON-RPC support.")
|
||||
}
|
||||
|
||||
pub fn new_ipc(conf: IpcConfiguration, deps: &Dependencies) -> Option<jsonipc::Server> {
|
||||
if !conf.enabled { return None; }
|
||||
let apis = conf.apis.split(',').collect();
|
||||
Some(setup_ipc_rpc_server(deps, &conf.socket_addr, apis))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rpc")]
|
||||
pub fn setup_ipc_rpc_server(dependencies: &Dependencies, addr: &str, apis: Vec<&str>) -> jsonipc::Server {
|
||||
let server = setup_rpc_server(apis, dependencies);
|
||||
|
||||
@@ -23,8 +23,9 @@ use ethsync::EthSync;
|
||||
use ethcore::miner::{Miner, ExternalMiner};
|
||||
use ethcore::client::Client;
|
||||
use util::RotatingLogger;
|
||||
use util::keys::store::AccountService;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use util::network_settings::NetworkSettings;
|
||||
use util::network::NetworkService;
|
||||
|
||||
#[cfg(feature="rpc")]
|
||||
pub use ethcore_rpc::ConfirmationsQueue;
|
||||
@@ -83,11 +84,13 @@ pub struct Dependencies {
|
||||
pub signer_queue: Arc<ConfirmationsQueue>,
|
||||
pub client: Arc<Client>,
|
||||
pub sync: Arc<EthSync>,
|
||||
pub secret_store: Arc<AccountService>,
|
||||
pub secret_store: Arc<AccountProvider>,
|
||||
pub miner: Arc<Miner>,
|
||||
pub external_miner: Arc<ExternalMiner>,
|
||||
pub logger: Arc<RotatingLogger>,
|
||||
pub settings: Arc<NetworkSettings>,
|
||||
pub allow_pending_receipt_query: bool,
|
||||
pub net_service: Arc<NetworkService<::ethcore::service::SyncMessage>>,
|
||||
}
|
||||
|
||||
fn to_modules(apis: &[Api]) -> BTreeMap<String, String> {
|
||||
@@ -122,10 +125,10 @@ fn list_apis(apis: ApiSet) -> Vec<Api> {
|
||||
match apis {
|
||||
ApiSet::List(apis) => apis,
|
||||
ApiSet::UnsafeContext => {
|
||||
vec![Api::Web3, Api::Net, Api::Eth, Api::Personal, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc]
|
||||
vec![Api::Web3, Api::Net, Api::Eth, Api::Personal, Api::Ethcore, Api::Traces, Api::Rpc]
|
||||
},
|
||||
_ => {
|
||||
vec![Api::Web3, Api::Net, Api::Eth, Api::Personal, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc]
|
||||
vec![Api::Web3, Api::Net, Api::Eth, Api::Personal, Api::Signer, Api::Ethcore, Api::Traces, Api::Rpc]
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -143,11 +146,11 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
|
||||
server.add_delegate(NetClient::new(&deps.sync).to_delegate());
|
||||
},
|
||||
Api::Eth => {
|
||||
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate());
|
||||
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner, deps.allow_pending_receipt_query).to_delegate());
|
||||
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
|
||||
|
||||
if deps.signer_port.is_some() {
|
||||
server.add_delegate(EthSigningQueueClient::new(&deps.signer_queue).to_delegate());
|
||||
server.add_delegate(EthSigningQueueClient::new(&deps.signer_queue, &deps.client, &deps.miner, &deps.secret_store).to_delegate());
|
||||
} else {
|
||||
server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate());
|
||||
}
|
||||
@@ -159,10 +162,11 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
|
||||
server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_queue).to_delegate());
|
||||
},
|
||||
Api::Ethcore => {
|
||||
server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate())
|
||||
let queue = deps.signer_port.map(|_| deps.signer_queue.clone());
|
||||
server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone(), queue).to_delegate())
|
||||
},
|
||||
Api::EthcoreSet => {
|
||||
server.add_delegate(EthcoreSetClient::new(&deps.miner).to_delegate())
|
||||
server.add_delegate(EthcoreSetClient::new(&deps.miner, &deps.net_service).to_delegate())
|
||||
},
|
||||
Api::Traces => {
|
||||
server.add_delegate(TracesClient::new(&deps.client, &deps.miner).to_delegate())
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
extern crate ansi_term;
|
||||
use self::ansi_term::Colour::White;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use util::panics::{PanicHandler, ForwardPanic};
|
||||
use util::keys::directory::restrict_permissions_owner;
|
||||
use util::path::restrict_permissions_owner;
|
||||
use die::*;
|
||||
use rpc_apis;
|
||||
|
||||
@@ -65,8 +67,7 @@ pub fn new_token(path: String) -> io::Result<()> {
|
||||
let mut codes = try!(signer::AuthCodes::from_file(&path));
|
||||
let code = try!(codes.generate_new());
|
||||
try!(codes.to_file(&path));
|
||||
println!("New token has been generated. Copy the code below to your Signer UI:");
|
||||
println!("{}", code);
|
||||
println!("This key code will authorise your System Signer UI: {}", White.bold().paint(code));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
59
parity/url.rs
Normal file
59
parity/url.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Cross-platform open url in default browser
|
||||
|
||||
#[cfg(windows)]
|
||||
mod shell {
|
||||
extern crate winapi;
|
||||
|
||||
use self::winapi::*;
|
||||
extern "system" {
|
||||
pub fn ShellExecuteA(
|
||||
hwnd: HWND, lpOperation: LPCSTR, lpFile: LPCSTR, lpParameters: LPCSTR, lpDirectory: LPCSTR,
|
||||
nShowCmd: c_int
|
||||
) -> HINSTANCE;
|
||||
}
|
||||
|
||||
pub use self::winapi::SW_SHOWNORMAL as Normal;
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn open(url: &str) {
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
unsafe {
|
||||
shell::ShellExecuteA(ptr::null_mut(),
|
||||
CString::new("open").unwrap().as_ptr(),
|
||||
CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(),
|
||||
ptr::null(),
|
||||
ptr::null(),
|
||||
shell::Normal);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os="macos")]
|
||||
pub fn open(url: &str) {
|
||||
use std;
|
||||
let _ = std::process::Command::new("open").arg(url).spawn();
|
||||
}
|
||||
|
||||
#[cfg(target_os="linux")]
|
||||
pub fn open(url: &str) {
|
||||
use std;
|
||||
let _ = std::process::Command::new("xdg-open").arg(url).spawn();
|
||||
}
|
||||
Reference in New Issue
Block a user