Miner tweaks (#1797)
* Mining fixes. - Use queue to determine whether we're mining - Kick stale hash rates Fixes #1794 Fixes #1641 * Fix tests. * Address grumbles.
This commit is contained in:
@@ -178,15 +178,15 @@ impl Client {
|
||||
db_config.compaction = config.db_compaction.compaction_profile();
|
||||
db_config.wal = config.db_wal;
|
||||
|
||||
let db = Arc::new(Database::open(&db_config, &path.to_str().unwrap()).expect("Error opening database"));
|
||||
let db = Arc::new(try!(Database::open(&db_config, &path.to_str().unwrap()).map_err(ClientError::Database)));
|
||||
let chain = Arc::new(BlockChain::new(config.blockchain, &gb, db.clone()));
|
||||
let tracedb = Arc::new(try!(TraceDB::new(config.tracing, db.clone(), chain.clone())));
|
||||
|
||||
let mut state_db = journaldb::new(db.clone(), config.pruning, DB_COL_STATE);
|
||||
if state_db.is_empty() && spec.ensure_db_good(state_db.as_hashdb_mut()) {
|
||||
let batch = DBTransaction::new(&db);
|
||||
state_db.commit(&batch, 0, &spec.genesis_header().hash(), None).expect("Error commiting genesis state to state DB");
|
||||
db.write(batch).expect("Error writing genesis state to state DB");
|
||||
try!(state_db.commit(&batch, 0, &spec.genesis_header().hash(), None));
|
||||
try!(db.write(batch).map_err(ClientError::Database));
|
||||
}
|
||||
|
||||
if !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.contains(h.state_root())) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use trace::Error as TraceError;
|
||||
use util::UtilError;
|
||||
use std::fmt::{Display, Formatter, Error as FmtError};
|
||||
|
||||
/// Client configuration errors.
|
||||
@@ -6,6 +7,10 @@ use std::fmt::{Display, Formatter, Error as FmtError};
|
||||
pub enum Error {
|
||||
/// TraceDB configuration error.
|
||||
Trace(TraceError),
|
||||
/// Database error
|
||||
Database(String),
|
||||
/// Util error
|
||||
Util(UtilError),
|
||||
}
|
||||
|
||||
impl From<TraceError> for Error {
|
||||
@@ -14,10 +19,18 @@ impl From<TraceError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UtilError> for Error {
|
||||
fn from(err: UtilError) -> Self {
|
||||
Error::Util(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
||||
match *self {
|
||||
Error::Trace(ref err) => write!(f, "{}", err)
|
||||
Error::Trace(ref err) => write!(f, "{}", err),
|
||||
Error::Util(ref err) => write!(f, "{}", err),
|
||||
Error::Database(ref s) => write!(f, "Database error: {}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use util::{RwLock, U256, H256};
|
||||
use std::time::{Instant, Duration};
|
||||
use util::{Mutex, U256, H256};
|
||||
|
||||
/// External miner interface.
|
||||
pub trait ExternalMinerService: Send + Sync {
|
||||
@@ -25,50 +26,50 @@ pub trait ExternalMinerService: Send + Sync {
|
||||
|
||||
/// Total hashrate.
|
||||
fn hashrate(&self) -> U256;
|
||||
|
||||
/// Returns true if external miner is mining.
|
||||
fn is_mining(&self) -> bool;
|
||||
}
|
||||
|
||||
/// External Miner.
|
||||
pub struct ExternalMiner {
|
||||
hashrates: Arc<RwLock<HashMap<H256, U256>>>,
|
||||
hashrates: Arc<Mutex<HashMap<H256, (Instant, U256)>>>,
|
||||
}
|
||||
|
||||
impl Default for ExternalMiner {
|
||||
fn default() -> Self {
|
||||
ExternalMiner {
|
||||
hashrates: Arc::new(RwLock::new(HashMap::new())),
|
||||
hashrates: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalMiner {
|
||||
/// Creates new external miner with prefilled hashrates.
|
||||
pub fn new(hashrates: Arc<RwLock<HashMap<H256, U256>>>) -> Self {
|
||||
pub fn new(hashrates: Arc<Mutex<HashMap<H256, (Instant, U256)>>>) -> Self {
|
||||
ExternalMiner {
|
||||
hashrates: hashrates
|
||||
hashrates: hashrates,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ENTRY_TIMEOUT: u64 = 2;
|
||||
|
||||
impl ExternalMinerService for ExternalMiner {
|
||||
fn submit_hashrate(&self, hashrate: U256, id: H256) {
|
||||
self.hashrates.write().insert(id, hashrate);
|
||||
self.hashrates.lock().insert(id, (Instant::now() + Duration::from_secs(ENTRY_TIMEOUT), hashrate));
|
||||
}
|
||||
|
||||
fn hashrate(&self) -> U256 {
|
||||
self.hashrates.read().iter().fold(U256::from(0), |sum, (_, v)| sum + *v)
|
||||
}
|
||||
|
||||
fn is_mining(&self) -> bool {
|
||||
!self.hashrates.read().is_empty()
|
||||
let mut hashrates = self.hashrates.lock();
|
||||
let h = hashrates.drain().filter(|&(_, (t, _))| t > Instant::now()).collect();
|
||||
*hashrates = h;
|
||||
hashrates.iter().fold(U256::from(0), |sum, (_, &(_, v))| sum + v)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use util::{H256, U256};
|
||||
|
||||
fn miner() -> ExternalMiner {
|
||||
@@ -76,16 +77,18 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_that_is_mining_if_there_is_at_least_one_entry() {
|
||||
fn it_should_forget_old_hashrates() {
|
||||
// given
|
||||
let m = miner();
|
||||
assert_eq!(m.is_mining(), false);
|
||||
assert_eq!(m.hashrate(), U256::from(0));
|
||||
m.submit_hashrate(U256::from(10), H256::from(1));
|
||||
assert_eq!(m.hashrate(), U256::from(10));
|
||||
|
||||
// when
|
||||
m.submit_hashrate(U256::from(10), H256::from(1));
|
||||
sleep(Duration::from_secs(3));
|
||||
|
||||
// then
|
||||
assert_eq!(m.is_mining(), true);
|
||||
assert_eq!(m.hashrate(), U256::from(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -780,6 +780,10 @@ impl MinerService for Miner {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_sealing(&self) -> bool {
|
||||
self.sealing_work.lock().queue.is_in_use()
|
||||
}
|
||||
|
||||
fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
|
||||
trace!(target: "miner", "map_sealing_work: entering");
|
||||
self.enable_and_prepare_sealing(chain);
|
||||
|
||||
@@ -150,6 +150,9 @@ pub trait MinerService : Send + Sync {
|
||||
/// Returns highest transaction nonce for given address.
|
||||
fn last_nonce(&self, address: &Address) -> Option<U256>;
|
||||
|
||||
/// Is it currently sealing?
|
||||
fn is_sealing(&self) -> bool;
|
||||
|
||||
/// Suggested gas price.
|
||||
fn sensible_gas_price(&self) -> U256 { 20000000000u64.into() }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user