diff --git a/grin/Cargo.toml b/grin/Cargo.toml index d4f6bb5b4..b4b3a46cd 100644 --- a/grin/Cargo.toml +++ b/grin/Cargo.toml @@ -19,6 +19,8 @@ futures-cpupool = "^0.1.3" hyper = { git = "https://github.com/hyperium/hyper" } log = "^0.3" time = "^0.1" +serde = "~0.9.10" +serde_derive = "~0.9.10" tokio-core="^0.1.1" tokio-timer="^0.1.0" rand = "^0.3" diff --git a/grin/src/lib.rs b/grin/src/lib.rs index 184000468..51a6243cb 100644 --- a/grin/src/lib.rs +++ b/grin/src/lib.rs @@ -28,6 +28,9 @@ extern crate futures; extern crate futures_cpupool as cpupool; extern crate hyper; extern crate rand; +extern crate serde; +#[macro_use] +extern crate serde_derive; extern crate time; extern crate tokio_core; extern crate tokio_timer; @@ -48,4 +51,5 @@ mod seed; mod sync; mod types; -pub use server::{Server, ServerConfig, Seeding}; +pub use server::Server; +pub use types::{ServerConfig, Seeding}; diff --git a/grin/src/server.rs b/grin/src/server.rs index 70f09f7c8..76fbb1284 100644 --- a/grin/src/server.rs +++ b/grin/src/server.rs @@ -19,9 +19,11 @@ use std::net::SocketAddr; use std::sync::{Arc, Mutex}; use std::thread; +use std::time; -use futures::{future, Future}; +use futures::{future, Future, Stream}; use tokio_core::reactor; +use tokio_timer::Timer; use adapters::{NetToChainAdapter, ChainToNetAdapter}; use api; @@ -33,71 +35,7 @@ use p2p; use seed; use store; use sync; - -/// Errors than can be reported by a server implementation, mostly wraps -/// underlying components errors. -#[derive(Debug)] -pub enum Error { - /// Error when trying to add a block to the chain - ChainErr(chain::pipe::Error), - /// Peer connection error - PeerErr(core::ser::Error), - /// Data store error - StoreErr(store::Error), -} - -impl From<store::Error> for Error { - fn from(e: store::Error) -> Error { - Error::StoreErr(e) - } -} - -/// Type of seeding the server will use to find other peers on the network. -#[derive(Debug, Clone)] -pub enum Seeding { - /// No seeding, mostly for tests that programmatically connect - None, - /// A list of seed addresses provided to the server - List(Vec<String>), - /// Automatically download a gist with a list of server addresses - Gist, -} - -/// Full server configuration, aggregating configurations required for the -/// different components. -#[derive(Debug, Clone)] -pub struct ServerConfig { - /// Directory under which the rocksdb stores will be created - pub db_root: String, - - /// Network address for the Rest API HTTP server. - pub api_http_addr: String, - - /// Allows overriding the default cuckoo cycle size - pub cuckoo_size: u8, - - /// Capabilities expose by this node, also conditions which other peers this - /// node will have an affinity toward when connection. - pub capabilities: p2p::Capabilities, - - pub seeding_type: Seeding, - - /// Configuration for the peer-to-peer server - pub p2p_config: p2p::P2PConfig, -} - -impl Default for ServerConfig { - fn default() -> ServerConfig { - ServerConfig { - db_root: ".grin".to_string(), - api_http_addr: "127.0.0.1:13415".to_string(), - cuckoo_size: 0, - capabilities: p2p::FULL_NODE, - seeding_type: Seeding::None, - p2p_config: p2p::P2PConfig::default(), - } - } -} +use types::*; /// Grin server holding internal structures. pub struct Server { @@ -118,9 +56,22 @@ impl Server { /// Instantiates and starts a new server. pub fn start(config: ServerConfig) -> Result<Server, Error> { let mut evtlp = reactor::Core::new().unwrap(); - let serv = Server::future(config, &evtlp.handle()); - evtlp.run(future::ok::<(), ()>(())).unwrap(); - serv + let enable_mining = config.enable_mining; + let serv = Server::future(config, &evtlp.handle())?; + if enable_mining { + serv.start_miner(); + } + + let forever = Timer::default() + .interval(time::Duration::from_secs(60)) + .for_each(move |_| { + debug!("event loop running"); + Ok(()) + }) + .map_err(|_| ()); + + evtlp.run(forever).unwrap(); + Ok(serv) } /// Instantiates a new server associated with the provided future reactor. @@ -145,8 +96,8 @@ impl Server { Seeding::List(seeds) => { seed.connect_and_monitor(evt_handle.clone(), seed::predefined_seeds(seeds)); } - Seeding::Gist => { - seed.connect_and_monitor(evt_handle.clone(), seed::gist_seeds(evt_handle.clone())); + Seeding::WebStatic => { + seed.connect_and_monitor(evt_handle.clone(), seed::web_seeds(evt_handle.clone())); } } @@ -202,25 +153,26 @@ impl Server { fn store_head(config: &ServerConfig) -> Result<(Arc<chain::store::ChainKVStore>, chain::Tip), Error> { let chain_store = try!(chain::store::ChainKVStore::new(config.db_root.clone()) - .map_err(&Error::StoreErr)); + .map_err(&Error::Store)); // check if we have a head in store, otherwise the genesis block is it let head = match chain_store.head() { Ok(tip) => tip, Err(store::Error::NotFoundErr) => { - debug!("No genesis block found, creating and saving one."); + info!("No genesis block found, creating and saving one."); let mut gen = core::genesis::genesis(); if config.cuckoo_size > 0 { gen.header.cuckoo_len = config.cuckoo_size; let diff = gen.header.difficulty.clone(); core::pow::pow(&mut gen.header, diff).unwrap(); } - try!(chain_store.save_block(&gen).map_err(&Error::StoreErr)); + try!(chain_store.save_block(&gen).map_err(&Error::Store)); let tip = chain::types::Tip::new(gen.hash()); - try!(chain_store.save_head(&tip).map_err(&Error::StoreErr)); + try!(chain_store.save_head(&tip).map_err(&Error::Store)); + info!("Saved genesis block with hash {}", gen.hash()); tip } - Err(e) => return Err(Error::StoreErr(e)), + Err(e) => return Err(Error::Store(e)), }; Ok((Arc::new(chain_store), head)) } diff --git a/grin/src/types.rs b/grin/src/types.rs index 3a93d97c3..f5309a539 100644 --- a/grin/src/types.rs +++ b/grin/src/types.rs @@ -18,9 +18,14 @@ use chain; use p2p; use store; +/// Error type wrapping underlying module errors. +#[derive(Debug)] pub enum Error { + /// Error originating from the db storage. Store(store::Error), + /// Error originating from the blockchain implementation. Chain(chain::Error), + /// Error originating from the peer-to-peer network. P2P(p2p::Error), } @@ -41,3 +46,55 @@ impl From<store::Error> for Error { Error::Store(e) } } + +/// Type of seeding the server will use to find other peers on the network. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Seeding { + /// No seeding, mostly for tests that programmatically connect + None, + /// A list of seed addresses provided to the server + List(Vec<String>), + /// Automatically download a text file with a list of server addresses + WebStatic, +} + +/// Full server configuration, aggregating configurations required for the +/// different components. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ServerConfig { + /// Directory under which the rocksdb stores will be created + pub db_root: String, + + /// Network address for the Rest API HTTP server. + pub api_http_addr: String, + + /// Allows overriding the default cuckoo cycle size + pub cuckoo_size: u8, + + /// Capabilities expose by this node, also conditions which other peers this + /// node will have an affinity toward when connection. + pub capabilities: p2p::Capabilities, + + /// Method used to get the list of seed nodes for initial bootstrap. + pub seeding_type: Seeding, + + /// Configuration for the peer-to-peer server + pub p2p_config: p2p::P2PConfig, + + /// Whethere to start the miner with the server + pub enable_mining: bool, +} + +impl Default for ServerConfig { + fn default() -> ServerConfig { + ServerConfig { + db_root: ".grin".to_string(), + api_http_addr: "127.0.0.1:13415".to_string(), + cuckoo_size: 0, + capabilities: p2p::FULL_NODE, + seeding_type: Seeding::None, + p2p_config: p2p::P2PConfig::default(), + enable_mining: false, + } + } +} diff --git a/p2p/Cargo.toml b/p2p/Cargo.toml index 97902e9cc..1614ba775 100644 --- a/p2p/Cargo.toml +++ b/p2p/Cargo.toml @@ -11,6 +11,8 @@ futures = "^0.1.9" log = "^0.3" net2 = "0.2.0" rand = "^0.3" +serde = "~0.9.10" +serde_derive = "~0.9.10" tokio-core="^0.1.1" tokio-timer="^0.1.0" time = "^0.1" diff --git a/p2p/src/lib.rs b/p2p/src/lib.rs index ddcde0d77..f68d4e968 100644 --- a/p2p/src/lib.rs +++ b/p2p/src/lib.rs @@ -35,6 +35,9 @@ extern crate futures; extern crate tokio_core; extern crate tokio_timer; extern crate rand; +extern crate serde; +#[macro_use] +extern crate serde_derive; extern crate time; extern crate num; diff --git a/p2p/src/types.rs b/p2p/src/types.rs index 971bc9a4b..ef2b80e48 100644 --- a/p2p/src/types.rs +++ b/p2p/src/types.rs @@ -63,7 +63,7 @@ impl From<TimerError> for Error { } /// Configuration for the peer-to-peer server. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct P2PConfig { pub host: IpAddr, pub port: u16, @@ -82,6 +82,7 @@ impl Default for P2PConfig { bitflags! { /// Options for what type of interaction a peer supports + #[derive(Serialize, Deserialize)] pub flags Capabilities: u32 { /// We don't know (yet) what the peer can do. const UNKNOWN = 0b00000000,