Improved error handling in mining thread. Fixes #539

This commit is contained in:
Ignotus Peverell 2018-01-06 22:33:26 +00:00
parent a69b5af7c2
commit abcecd82c1
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211
2 changed files with 44 additions and 27 deletions

View file

@ -18,7 +18,7 @@
use rand::{self, Rng}; use rand::{self, Rng};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::thread; use std::thread;
use std; use std::time::Duration;
use time; use time;
use adapters::PoolToChainAdapter; use adapters::PoolToChainAdapter;
@ -231,8 +231,7 @@ impl Miner {
} }
} }
// avoid busy wait // avoid busy wait
let sleep_dur = std::time::Duration::from_millis(100); thread::sleep(Duration::from_millis(100));
thread::sleep(sleep_dur);
} }
if sol == None { if sol == None {
debug!( debug!(
@ -322,7 +321,7 @@ impl Miner {
if self.config.slow_down_in_millis != None if self.config.slow_down_in_millis != None
&& self.config.slow_down_in_millis.unwrap() > 0 && self.config.slow_down_in_millis.unwrap() > 0
{ {
thread::sleep(std::time::Duration::from_millis( thread::sleep(Duration::from_millis(
self.config.slow_down_in_millis.unwrap(), self.config.slow_down_in_millis.unwrap(),
)); ));
} }
@ -351,7 +350,7 @@ impl Miner {
latest_hash: &mut Hash, latest_hash: &mut Hash,
) -> Option<Proof> { ) -> Option<Proof> {
// look for a pow for at most 2 sec on the same block (to give a chance to new // look for a pow for at most 2 sec on the same block (to give a chance to new
// transactions) and as long as the head hasn't changed // transactions) and as long as the head hasn't changed
let deadline = time::get_time().sec + attempt_time_per_block as i64; let deadline = time::get_time().sec + attempt_time_per_block as i64;
debug!( debug!(
@ -393,7 +392,7 @@ impl Miner {
if self.config.slow_down_in_millis != None if self.config.slow_down_in_millis != None
&& self.config.slow_down_in_millis.unwrap() > 0 && self.config.slow_down_in_millis.unwrap() > 0
{ {
thread::sleep(std::time::Duration::from_millis( thread::sleep(Duration::from_millis(
self.config.slow_down_in_millis.unwrap(), self.config.slow_down_in_millis.unwrap(),
)); ));
} }
@ -410,6 +409,7 @@ impl Miner {
sol sol
} }
/// Starts the mining loop, building a new block on top of the existing /// Starts the mining loop, building a new block on top of the existing
/// chain anytime required and looking for PoW solution. /// chain anytime required and looking for PoW solution.
pub fn run_loop(&self, miner_config: MinerConfig, cuckoo_size: u32, proof_size: usize) { pub fn run_loop(&self, miner_config: MinerConfig, cuckoo_size: u32, proof_size: usize) {
@ -436,8 +436,8 @@ impl Miner {
} }
// to prevent the wallet from generating a new HD key derivation for each // to prevent the wallet from generating a new HD key derivation for each
// iteration, we keep the returned derivation to provide it back when // iteration, we keep the returned derivation to provide it back when
// nothing has changed // nothing has changed
let mut key_id = None; let mut key_id = None;
loop { loop {
@ -447,15 +447,21 @@ impl Miner {
// get the latest chain state and build a block on top of it // get the latest chain state and build a block on top of it
let head = self.chain.head_header().unwrap(); let head = self.chain.head_header().unwrap();
let mut latest_hash = self.chain.head().unwrap().last_block_h; let mut latest_hash = self.chain.head().unwrap().last_block_h;
let mut result = self.build_block(&head, key_id.clone()); let mut result = self.build_block(&head, key_id.clone());
while let Err(e) = result { while let Err(e) = result {
result = self.build_block(&head, key_id.clone()); match e {
if let self::Error::Chain(chain::Error::DuplicateCommitment(_)) = e { self::Error::Chain(chain::Error::DuplicateCommitment(_)) => {
warn!(LOGGER, "Duplicate commit for potential coinbase detected. Trying next derivation."); debug!(LOGGER, "Duplicate commit for potential coinbase detected. Trying next derivation.");
} else { }
break; ae => {
warn!(LOGGER, "Error building new block: {:?}. Retrying.", ae);
}
} }
thread::sleep(Duration::from_millis(100));
result = self.build_block(&head, key_id.clone());
} }
let (mut b, block_fees) = result.unwrap(); let (mut b, block_fees) = result.unwrap();
let mut sol = None; let mut sol = None;
@ -536,6 +542,7 @@ impl Miner {
head: &core::BlockHeader, head: &core::BlockHeader,
key_id: Option<Identifier>, key_id: Option<Identifier>,
) -> Result<(core::Block, BlockFees), Error> { ) -> Result<(core::Block, BlockFees), Error> {
// prepare the block header timestamp // prepare the block header timestamp
let mut now_sec = time::get_time().sec; let mut now_sec = time::get_time().sec;
let head_sec = head.timestamp.to_timespec().sec; let head_sec = head.timestamp.to_timespec().sec;
@ -563,10 +570,8 @@ impl Miner {
height, height,
}; };
// TODO - error handling, things can go wrong with get_coinbase (wallet api let (output, kernel, block_fees) = self.get_coinbase(block_fees)?;
// down etc.) let mut b = core::Block::with_reward(head, txs, output, kernel)?;
let (output, kernel, block_fees) = self.get_coinbase(block_fees).unwrap();
let mut b = core::Block::with_reward(head, txs, output, kernel).unwrap();
debug!( debug!(
LOGGER, LOGGER,
@ -578,25 +583,29 @@ impl Miner {
); );
// making sure we're not spending time mining a useless block // making sure we're not spending time mining a useless block
b.validate().expect("Built an invalid block!"); b.validate()?;
let mut rng = rand::OsRng::new().unwrap(); let mut rng = rand::OsRng::new().unwrap();
b.header.nonce = rng.gen(); b.header.nonce = rng.gen();
b.header.difficulty = difficulty; b.header.difficulty = difficulty;
b.header.timestamp = time::at_utc(time::Timespec::new(now_sec, 0)); b.header.timestamp = time::at_utc(time::Timespec::new(now_sec, 0));
trace!(LOGGER, "Block: {:?}", b); trace!(LOGGER, "Block: {:?}", b);
let result=self.chain.set_sumtree_roots(&mut b);
match result { let roots_result = self.chain.set_sumtree_roots(&mut b);
match roots_result {
Ok(_) => Ok((b, block_fees)), Ok(_) => Ok((b, block_fees)),
//If it's a duplicate commitment, it's likely trying to use
//a key that's already been derived but not in the wallet // If it's a duplicate commitment, it's likely trying to use
//for some reason, allow caller to retry // a key that's already been derived but not in the wallet
Err(chain::Error::DuplicateCommitment(e)) => // for some reason, allow caller to retry
Err(Error::Chain(chain::Error::DuplicateCommitment(e))), Err(chain::Error::DuplicateCommitment(e)) => {
//Some other issue is worth a panic Err(Error::Chain(chain::Error::DuplicateCommitment(e)))
}
//Some other issue, possibly duplicate kernel
Err(e) => { Err(e) => {
error!(LOGGER, "Error setting sumtree root to build a block: {:?}", e); error!(LOGGER, "Error setting sumtree root to build a block: {:?}", e);
panic!(e); Err(Error::Chain(chain::Error::Other(format!("{:?}", e))))
} }
} }
} }

View file

@ -16,6 +16,7 @@ use std::convert::From;
use api; use api;
use chain; use chain;
use core::core;
use p2p; use p2p;
use pool; use pool;
use store; use store;
@ -26,6 +27,8 @@ use core::global::ChainTypes;
/// Error type wrapping underlying module errors. /// Error type wrapping underlying module errors.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// Error originating from the core implementation.
Core(core::block::Error),
/// Error originating from the db storage. /// Error originating from the db storage.
Store(store::Error), Store(store::Error),
/// Error originating from the blockchain implementation. /// Error originating from the blockchain implementation.
@ -39,6 +42,11 @@ pub enum Error {
Cuckoo(pow::cuckoo::Error), Cuckoo(pow::cuckoo::Error),
} }
impl From<core::block::Error> for Error {
fn from(e: core::block::Error) -> Error {
Error::Core(e)
}
}
impl From<chain::Error> for Error { impl From<chain::Error> for Error {
fn from(e: chain::Error) -> Error { fn from(e: chain::Error) -> Error {
Error::Chain(e) Error::Chain(e)