diff --git a/Cargo.lock b/Cargo.lock index 14ebabb6e..f7cf5a4de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,7 @@ dependencies = [ "ethminer 1.1.0", "ethsync 1.1.0", "fdlimit 0.1.0", + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -65,6 +66,11 @@ name = "bitflags" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "0.5.0" @@ -119,6 +125,8 @@ name = "cookie" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "openssl 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -342,6 +350,14 @@ name = "gcc" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "gdi32-sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "glob" version = "0.2.11" @@ -404,6 +420,7 @@ dependencies = [ "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -493,6 +510,14 @@ name = "libc" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libressl-pnacl-sys" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "librocksdb-sys" version = "0.2.3" @@ -630,6 +655,54 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "openssl" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys-extras 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-sys" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-sys-extras" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pkg-config" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pnacl-build-helper" +version = "1.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "primal" version = "0.2.3" @@ -867,6 +940,14 @@ name = "target_info" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "tempdir" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term" version = "0.2.14" @@ -973,6 +1054,15 @@ dependencies = [ "uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "user32-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "utf8-ranges" version = "0.1.3" diff --git a/Cargo.toml b/Cargo.toml index 859dadea2..76d2c21ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ ethsync = { path = "sync" } ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } +hyper = "0.8" [features] default = ["rpc"] diff --git a/parity/main.rs b/parity/main.rs index e9833fd38..69b3d4e79 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -36,6 +36,9 @@ extern crate time; extern crate number_prefix; extern crate rpassword; +// for price_info.rs +#[macro_use] extern crate hyper; + #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -60,6 +63,8 @@ use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; +mod price_info; + fn die_with_message(msg: &str) -> ! { println!("ERROR: {}", msg); exit(1); @@ -126,8 +131,11 @@ API and Console Options: [default: web3,eth,net,personal]. Sealing/Mining Options: - --gas-price WEI Minimum amount of Wei to be paid for a transaction - to be accepted for mining [default: 20000000000]. + --usd-per-tx USD Amount of USD to be paid for a basic transaction + [default: 0.005]. The minimum gas price is set + accordingly. + --usd-per-eth SOURCE USD value of a single ETH. SOURCE may be either an + amount in USD or a web service [default: etherscan]. --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 @@ -162,7 +170,9 @@ Geth-compatibility Options: --rpcport PORT Equivalent to --jsonrpc-port PORT. --rpcapi APIS Equivalent to --jsonrpc-apis APIS. --rpccorsdomain URL Equivalent to --jsonrpc-cors URL. - --gasprice WEI Equivalent to --gas-price WEI. + --gasprice WEI Minimum amount of Wei per GAS to be paid for a + transaction to be accepted for mining. Overrides + --basic-tx-usd. --etherbase ADDRESS Equivalent to --author ADDRESS. --extradata STRING Equivalent to --extra-data STRING. @@ -204,7 +214,8 @@ struct Args { flag_jsonrpc_cors: String, flag_jsonrpc_apis: String, flag_author: String, - flag_gas_price: String, + flag_usd_per_tx: String, + flag_usd_per_eth: String, flag_gas_floor_target: String, flag_extra_data: Option, flag_logging: Option, @@ -339,10 +350,29 @@ impl Configuration { } fn gas_price(&self) -> U256 { - let d = self.args.flag_gasprice.as_ref().unwrap_or(&self.args.flag_gas_price); - U256::from_dec_str(d).unwrap_or_else(|_| { - die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", d) - }) + match self.args.flag_gasprice.as_ref() { + Some(d) => { + U256::from_dec_str(d).unwrap_or_else(|_| { + die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", d) + }) + } + _ => { + let usd_per_tx: f32 = FromStr::from_str(&self.args.flag_usd_per_tx).unwrap_or_else(|_| { + die!("{}: Invalid basic transaction price given in USD. Must be a decimal number.", self.args.flag_usd_per_tx) + }); + let usd_per_eth = match self.args.flag_usd_per_eth.as_str() { + "etherscan" => price_info::PriceInfo::get().map(|x| x.ethusd).unwrap_or_else(|| { + die!("Unable to retrieve USD value of ETH from etherscan. Rerun with a different value for --usd-per-eth.") + }), + x => FromStr::from_str(x).unwrap_or_else(|_| die!("{}: Invalid ether price given in USD. Must be a decimal number.", x)) + }; + let wei_per_usd: f32 = 1.0e18 / usd_per_eth; + let gas_per_tx: f32 = 21000.0; + let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; + info!("Using a conversion rate of Ξ1 = US${} ({} wei/gas)", usd_per_eth, wei_per_gas); + U256::from_dec_str(&format!("{:.0}", wei_per_gas)).unwrap() + } + } } fn extra_data(&self) -> Bytes { diff --git a/parity/price_info.rs b/parity/price_info.rs new file mode 100644 index 000000000..1e0c2bfdc --- /dev/null +++ b/parity/price_info.rs @@ -0,0 +1,39 @@ +use rustc_serialize::json::Json; +use std::io::Read; +use hyper::Client; +use hyper::header::Connection; +use std::str::FromStr; + +pub struct PriceInfo { + pub ethusd: f32, +} + +impl PriceInfo { + pub fn get() -> Option { + let mut body = String::new(); + // TODO: actually bother dicking around with the errors and make it proper. + match match match Client::new() + .get("http://api.etherscan.io/api?module=stats&action=ethprice") + .header(Connection::close()) + .send() { + Err(_) => { return None; }, + Ok(mut s) => s.read_to_string(&mut body), + } { + Err(_) => { return None; }, + _ => { Json::from_str(&body) } + } { + Err(_) => { return None; }, + Ok(json) => { + let ethusd: f32 = if let Some(&Json::String(ref s)) = json.find_path(&["result", "ethusd"]) { + FromStr::from_str(&s).unwrap() + } else { + return None; + }; + Some(PriceInfo { + ethusd: ethusd, + }) + } + } + } +} +