diff --git a/Cargo.toml b/Cargo.toml index 836967631..fb52d14d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ env_logger = "0.3" rustc-serialize = "0.3" docopt = "0.6" docopt_macros = "0.6" -ctrlc = "1.0" +ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } clippy = "0.0.37" ethcore-util = { path = "util" } ethcore = { path = "ethcore" } diff --git a/parity/main.rs b/parity/main.rs index cc59aacb8..036edefd7 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -64,6 +64,7 @@ Options: --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. --public-address URL Specify the IP/port on which peers may connect [default: 0.0.0.0:30304]. --address URL Equivalent to --listen-address URL --public-address URL. + --upnp Use UPnP to try to figure out the correct network settings. --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 bytes [default: 262144]. @@ -89,14 +90,13 @@ fn setup_log(init: &str) { builder.init().unwrap(); } - #[cfg(feature = "rpc")] fn setup_rpc_server(client: Arc, sync: Arc, url: &str) { use rpc::v1::*; let mut server = rpc::HttpServer::new(1); server.add_delegate(Web3Client::new().to_delegate()); - server.add_delegate(EthClient::new(client.clone()).to_delegate()); + server.add_delegate(EthClient::new(client.clone(), sync.clone()).to_delegate()); server.add_delegate(EthFilterClient::new(client).to_delegate()); server.add_delegate(NetClient::new(sync).to_delegate()); server.start_async(url); @@ -106,18 +106,8 @@ fn setup_rpc_server(client: Arc, sync: Arc, url: &str) { fn setup_rpc_server(_client: Arc, _sync: Arc, _url: &str) { } -struct Configuration { - args: Args -} -impl Configuration { - fn parse() -> Self { - Configuration { - args: Args::docopt().decode().unwrap_or_else(|e| e.exit()) - } - } - - fn print_version(&self) { - println!("\ +fn print_version() { + println!("\ Parity version {} ({}-{}-{}) Copyright 2015, 2016 Ethcore (UK) Limited License GPLv3+: GNU GPL version 3 or later . @@ -126,6 +116,17 @@ There is NO WARRANTY, to the extent permitted by law. By Wood/Paronyan/Kotewicz/Drwięga/Volf.\ ", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()); +} + +struct Configuration { + args: Args +} + +impl Configuration { + fn parse() -> Self { + Configuration { + args: Args::docopt().decode().unwrap_or_else(|e| e.exit()) + } } fn get_spec(&self) -> Spec { @@ -178,7 +179,7 @@ fn wait_for_exit(client_service: &ClientService) { fn main() { let conf = Configuration::parse(); if conf.args.flag_version { - conf.print_version(); + print_version(); return; } @@ -190,10 +191,10 @@ fn main() { unsafe { ::fdlimit::raise_fd_limit(); } // Configure network - let init_nodes = conf.get_init_nodes(&spec); - let (listen, public) = conf.get_net_addresses(); let mut net_settings = NetworkConfiguration::new(); - net_settings.boot_nodes = init_nodes; + net_settings.nat_enabled = conf.args.flag_upnp; + net_settings.boot_nodes = conf.get_init_nodes(&spec); + let (listen, public) = conf.get_net_addresses(); net_settings.listen_address = listen; net_settings.public_address = public; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 5d60b40a6..19ab7a389 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -16,6 +16,7 @@ //! Eth rpc implementation. use std::sync::Arc; +use ethsync::{EthSync, SyncState}; use jsonrpc_core::*; use util::hash::*; use util::uint::*; @@ -23,36 +24,48 @@ use util::sha3::*; use ethcore::client::*; use ethcore::views::*; use ethcore::blockchain::{BlockId, TransactionId}; +use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, Transaction, OptionalValue, Index}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index}; /// Eth rpc implementation. pub struct EthClient { client: Arc, + sync: Arc } impl EthClient { /// Creates new EthClient. - pub fn new(client: Arc) -> Self { + pub fn new(client: Arc, sync: Arc) -> Self { EthClient { - client: client + client: client, + sync: sync } } } impl Eth for EthClient { - // TODO: do not hardcode protocol version fn protocol_version(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::U64(63)), + Params::None => to_value(&U256::from(self.sync.status().protocol_version)), _ => Err(Error::invalid_params()) } } - // TODO: do no hardcode default sync status fn syncing(&self, params: Params) -> Result { match params { - Params::None => to_value(&SyncStatus::default()), + Params::None => { + let status = self.sync.status(); + let res = match status.state { + SyncState::NotSynced | SyncState::Idle => SyncStatus::None, + SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks => SyncStatus::Info(SyncInfo { + starting_block: U256::from(status.start_block_number), + current_block: U256::from(self.client.chain_info().best_block_number), + highest_block: U256::from(status.highest_block_number.unwrap_or(status.start_block_number)) + }) + }; + to_value(&res) + } _ => Err(Error::invalid_params()) } } @@ -76,22 +89,21 @@ impl Eth for EthClient { // TODO: return real hashrate once we have mining fn hashrate(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::U64(0)), + Params::None => to_value(&U256::zero()), _ => Err(Error::invalid_params()) } } - // TODO: do not hardode gas_price fn gas_price(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::U64(0)), + Params::None => to_value(&(shannon() * U256::from(50))), _ => Err(Error::invalid_params()) } } fn block_number(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::U64(self.client.chain_info().best_block_number)), + Params::None => to_value(&U256::from(self.client.chain_info().best_block_number)), _ => Err(Error::invalid_params()) } } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index bdbd157ff..c4c6e8295 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -29,5 +29,5 @@ pub use self::bytes::Bytes; pub use self::filter::Filter; pub use self::index::Index; pub use self::optionals::OptionalValue; -pub use self::sync::SyncStatus; +pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index 595da6032..b5568acda 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -14,14 +14,55 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use util::hash::*; +use serde::{Serialize, Serializer}; +use util::uint::*; -#[derive(Default, Debug, Serialize)] -pub struct SyncStatus { +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct SyncInfo { #[serde(rename="startingBlock")] - pub starting_block: H256, + pub starting_block: U256, #[serde(rename="currentBlock")] - pub current_block: H256, + pub current_block: U256, #[serde(rename="highestBlock")] - pub highest_block: H256, + pub highest_block: U256, +} + +#[derive(Debug, PartialEq)] +pub enum SyncStatus { + Info(SyncInfo), + None +} + +impl Serialize for SyncStatus { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: Serializer { + match *self { + SyncStatus::Info(ref info) => info.serialize(serializer), + SyncStatus::None => false.serialize(serializer) + } + } +} + +#[cfg(test)] +mod tests { + use serde_json; + use super::*; + + #[test] + fn test_serialize_sync_info() { + let t = SyncInfo::default(); + let serialized = serde_json::to_string(&t).unwrap(); + assert_eq!(serialized, r#"{"startingBlock":"0x00","currentBlock":"0x00","highestBlock":"0x00"}"#); + } + + #[test] + fn test_serialize_sync_status() { + let t = SyncStatus::None; + let serialized = serde_json::to_string(&t).unwrap(); + assert_eq!(serialized, "false"); + + let t = SyncStatus::Info(SyncInfo::default()); + let serialized = serde_json::to_string(&t).unwrap(); + assert_eq!(serialized, r#"{"startingBlock":"0x00","currentBlock":"0x00","highestBlock":"0x00"}"#); + } } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index b2d1fc29f..522062778 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -76,7 +76,7 @@ pub struct EthSync { sync: RwLock } -pub use self::chain::SyncStatus; +pub use self::chain::{SyncStatus, SyncState}; impl EthSync { /// Creates and register protocol with the network service @@ -132,4 +132,4 @@ impl NetworkProtocolHandler for EthSync { self.sync.write().unwrap().chain_blocks_verified(&mut NetSyncIo::new(io, self.chain.deref())); } } -} \ No newline at end of file +} diff --git a/util/Cargo.toml b/util/Cargo.toml index a123aecca..733b08701 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -29,3 +29,4 @@ serde = "0.6.7" clippy = "0.0.37" json-tests = { path = "json-tests" } target_info = "0.1.0" +igd = "0.4.2" diff --git a/util/src/lib.rs b/util/src/lib.rs index 260ef4301..bdd595014 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -100,6 +100,7 @@ extern crate crossbeam; extern crate serde; #[macro_use] extern crate log as rlog; +extern crate igd; pub mod standard; #[macro_use] diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 50cf294bc..fb1e8e1df 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::net::{SocketAddr}; +use std::net::{SocketAddr, SocketAddrV4}; use std::collections::{HashMap}; use std::hash::{Hasher}; use std::str::{FromStr}; @@ -36,6 +36,7 @@ use network::NetworkProtocolHandler; use network::node::*; use network::stats::NetworkStats; use network::error::DisconnectReason; +use igd::{PortMappingProtocol,search_gateway}; type Slab = ::slab::Slab; @@ -86,6 +87,42 @@ impl NetworkConfiguration { config.public_address = SocketAddr::from_str(&format!("0.0.0.0:{}", port)).unwrap(); config } + + /// Conduct NAT if needed. + pub fn prepared(self) -> Self { + let mut listen = self.listen_address; + let mut public = self.public_address; + + if self.nat_enabled { + info!("Enabling NAT..."); + match search_gateway() { + Err(ref err) => info!("Error: {}", err), + Ok(gateway) => { + let int_addr = SocketAddrV4::from_str("127.0.0.1:30304").unwrap(); + match gateway.get_any_address(PortMappingProtocol::TCP, int_addr, 0, "Parity Node/TCP") { + Err(ref err) => { + info!("There was an error! {}", err); + }, + Ok(ext_addr) => { + info!("Local gateway: {}, External ip address: {}", gateway, ext_addr); + public = SocketAddr::V4(ext_addr); + listen = SocketAddr::V4(int_addr); + }, + } + }, + } + } + + NetworkConfiguration { + listen_address: listen, + public_address: public, + nat_enabled: false, + discovery_enabled: self.discovery_enabled, + pin: self.pin, + boot_nodes: self.boot_nodes, + use_secret: self.use_secret, + } + } } // Tokens @@ -296,6 +333,8 @@ pub struct Host where Message: Send + Sync + Clone { impl Host where Message: Send + Sync + Clone { /// Create a new instance pub fn new(config: NetworkConfiguration) -> Host { + let config = config.prepared(); + let addr = config.listen_address; // Setup the server socket let tcp_listener = TcpListener::bind(&addr).unwrap();