Files
grin-node/grin/src/server.rs
T
Ignotus Peverell e8a6b61100 Apply new difficulty algo, remove configurable cuckoo size
Integrate the new difficulty calculation into the block chain
validation, the miner and tests. As the difficulty calculation
doesn't use varying Cuckoo sizes anymore and we narrowed down
reasonable final Cuckoo Cycle parameters, removed all Cuckoo
Cycle sizes from block headers.

Formalized easier Cuckoo Cycle sizes for testing (and possibly
testnet) by introducing a test mode in configuration. Updated
all tests.
2017-06-19 08:59:56 -07:00

217 lines
6.9 KiB
Rust

// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Grin server implementation, glues the different parts of the system (mostly
//! the peer-to-peer server, the blockchain and the transaction pool) and acts
//! as a facade.
use std::net::SocketAddr;
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
use std::time;
use futures::{future, Future, Stream};
use tokio_core::reactor;
use tokio_timer::Timer;
use adapters::*;
use api;
use chain;
use chain::ChainStore;
use core::{self, consensus};
use core::core::hash::Hashed;
use miner;
use p2p;
use pool;
use seed;
use store;
use sync;
use types::*;
/// Grin server holding internal structures.
pub struct Server {
pub config: ServerConfig,
evt_handle: reactor::Handle,
/// handle to our network server
p2p: Arc<p2p::Server>,
/// the reference copy of the current chain state
chain_head: Arc<Mutex<chain::Tip>>,
/// data store access
chain_store: Arc<chain::ChainStore>,
/// chain adapter to net, required for miner and anything that submits
/// blocks
chain_adapter: Arc<ChainToPoolAndNetAdapter>,
/// in-memory transaction pool
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
}
impl Server {
/// Instantiates and starts a new server.
pub fn start(mut config: ServerConfig) -> Result<Server, Error> {
check_config(&mut config);
let mut evtlp = reactor::Core::new().unwrap();
let mining_config = config.mining_config.clone();
let serv = Server::future(config, &evtlp.handle())?;
if mining_config.enable_mining {
serv.start_miner(mining_config);
}
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.
pub fn future(mut config: ServerConfig, evt_handle: &reactor::Handle) -> Result<Server, Error> {
check_config(&mut config);
let (chain_store, head) = try!(store_head(&config));
let shared_head = Arc::new(Mutex::new(head));
let peer_store = Arc::new(p2p::PeerStore::new(config.db_root.clone())?);
let pool_adapter = Arc::new(PoolToChainAdapter::new(shared_head.clone(),
chain_store.clone()));
let tx_pool = Arc::new(RwLock::new(pool::TransactionPool::new(pool_adapter)));
let chain_adapter = Arc::new(ChainToPoolAndNetAdapter::new(tx_pool.clone()));
let net_adapter = Arc::new(NetToChainAdapter::new(config.test_mode,
shared_head.clone(),
chain_store.clone(),
chain_adapter.clone(),
tx_pool.clone(),
peer_store.clone()));
let server =
Arc::new(p2p::Server::new(config.capabilities, config.p2p_config, net_adapter.clone()));
chain_adapter.init(server.clone());
let seed = seed::Seeder::new(config.capabilities, peer_store.clone(), server.clone());
match config.seeding_type.clone() {
Seeding::None => {}
Seeding::List(seeds) => {
seed.connect_and_monitor(evt_handle.clone(), seed::predefined_seeds(seeds));
}
Seeding::WebStatic => {
seed.connect_and_monitor(evt_handle.clone(), seed::web_seeds(evt_handle.clone()));
}
}
let sync = sync::Syncer::new(chain_store.clone(), server.clone());
net_adapter.start_sync(sync);
evt_handle.spawn(server.start(evt_handle.clone()).map_err(|_| ()));
api::start_rest_apis(config.api_http_addr.clone(),
chain_store.clone(),
shared_head.clone(),
tx_pool.clone());
warn!("Grin server started.");
Ok(Server {
config: config,
evt_handle: evt_handle.clone(),
p2p: server,
chain_head: shared_head,
chain_store: chain_store,
chain_adapter: chain_adapter,
tx_pool: tx_pool,
})
}
/// Asks the server to connect to a peer at the provided network address.
pub fn connect_peer(&self, addr: SocketAddr) -> Result<(), Error> {
let handle = self.evt_handle.clone();
handle.spawn(self.p2p.connect_peer(addr, handle.clone()).map(|_| ()).map_err(|_| ()));
Ok(())
}
pub fn peer_count(&self) -> u32 {
self.p2p.peer_count()
}
/// Start mining for blocks on a separate thread. Relies on a toy miner,
/// mostly for testing.
pub fn start_miner(&self, config: MinerConfig) {
let miner = miner::Miner::new(config,
self.chain_head.clone(),
self.chain_store.clone(),
self.chain_adapter.clone(),
self.tx_pool.clone());
thread::spawn(move || {
miner.run_loop();
});
}
pub fn head(&self) -> chain::Tip {
let head = self.chain_head.clone();
let h = head.lock().unwrap();
h.clone()
}
}
// Helper function to create the chain storage and check if it already has a
// genesis block
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::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) => {
info!("No genesis block found, creating and saving one.");
let mut gen = core::genesis::genesis();
let diff = gen.header.difficulty.clone();
core::pow::pow_size(&mut gen.header,
diff,
config.mining_config.cuckoo_size as u32)
.unwrap();
chain_store.save_block(&gen).map_err(&Error::Store)?;
let tip = chain::types::Tip::new(gen.hash());
chain_store.save_head(&tip).map_err(&Error::Store)?;
info!("Saved genesis block with hash {}", gen.hash());
tip
}
Err(e) => return Err(Error::Store(e)),
};
let head = chain_store.head()?;
let head_header = chain_store.head_header()?;
info!("Starting server with head {} at {} and header head {} at {}",
head.last_block_h,
head.height,
head_header.hash(),
head_header.height);
Ok((Arc::new(chain_store), head))
}
fn check_config(config: &mut ServerConfig) {
// applying test/normal config
config.mining_config.cuckoo_size = if config.test_mode {
consensus::TEST_SIZESHIFT as u32
} else {
consensus::DEFAULT_SIZESHIFT as u32
};
}