diff --git a/src/blockchain/chain.rs b/src/blockchain/chain.rs index b16a800..ffa6131 100644 --- a/src/blockchain/chain.rs +++ b/src/blockchain/chain.rs @@ -19,7 +19,6 @@ use std::cmp::max; use crate::blockchain::transaction::{ZoneData, DomainData}; use std::ops::Deref; use crate::blockchain::types::MineResult::*; -use crate::event::Event; const DB_NAME: &str = "blockchain.db"; const TEMP_DB_NAME: &str = "temp.db"; @@ -57,6 +56,7 @@ pub struct Chain { max_height: u64, db: Connection, zones: RefCell>, + signers: RefCell, } impl Chain { @@ -65,7 +65,7 @@ impl Chain { let db = sqlite::open(DB_NAME).expect("Unable to open blockchain DB"); let zones = RefCell::new(HashSet::new()); - let mut chain = Chain { origin, last_block: None, last_full_block: None, max_height: 0, db, zones }; + let mut chain = Chain { origin, last_block: None, last_full_block: None, max_height: 0, db, zones, signers: SignersCache::new() }; chain.init_db(); chain } @@ -262,7 +262,7 @@ impl Chain { Ok(()) } - pub fn update(&mut self, keystore: &Option) -> Option { + pub fn get_sign_block(&self, keystore: &Option) -> Option { if self.get_height() < BLOCK_SIGNERS_START { trace!("Too early to start block signings"); return None; @@ -292,6 +292,11 @@ impl Chain { return None; } } + let (last_hash, last_index) = match &self.last_block { + Some(block) => (block.hash.clone(), block.index), + None => { return None; } + }; + let keystore = keystore.clone().unwrap().clone(); let signers: HashSet = self.get_block_signers(&block).into_iter().collect(); if signers.contains(&keystore.get_public()) { @@ -304,10 +309,9 @@ impl Chain { } info!("We have an honor to mine signing block!"); - let keystore = Box::new(keystore); - // We start mining sign block after some time, not everyone in the same time - let start = Utc::now().timestamp() + (rand::random::() % BLOCK_SIGNERS_START_RANDOM); - return Some(Event::ActionMineSigning { start, index: block.index + 1, hash: block.hash, keystore }); + let mut block = Block::new(None, Bytes::default(), last_hash, SIGNER_DIFFICULTY); + block.index = last_index + 1; + return Some(block); } else if !signers.is_empty() { info!("Signing block must be mined by other nodes"); } @@ -973,6 +977,12 @@ impl Chain { if block.index < BLOCK_SIGNERS_START || self.get_height() < block.index { return result; } + + assert!(block.transaction.is_some()); + if self.signers.borrow().has_signers_for(block.index) { + return self.signers.borrow().signers.clone(); + } + let mut set = HashSet::new(); let tail = block.signature.get_tail_u64(); let mut count = 1; @@ -988,6 +998,9 @@ impl Chain { count += 1; } trace!("Got signers for block {}: {:?}", block.index, &result); + let mut signers = self.signers.borrow_mut(); + signers.index = block.index; + signers.signers = result.clone(); result } @@ -1005,4 +1018,20 @@ impl Chain { let signature = Bytes::from_bytes(statement.read::>(10).unwrap().as_slice()); Some(Block::from_all_params(index, timestamp, version, difficulty, random, nonce, prev_block_hash, hash, pub_key, signature, transaction)) } +} + +struct SignersCache { + index: u64, + signers: Vec +} + +impl SignersCache { + pub fn new() -> RefCell { + let cache = SignersCache { index: 0, signers: Vec::new() }; + RefCell::new(cache) + } + + pub fn has_signers_for(&self, index: u64) -> bool { + self.index == index && !self.signers.is_empty() + } } \ No newline at end of file diff --git a/src/event.rs b/src/event.rs index 0415a46..f37869b 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,5 +1,3 @@ -use crate::{Bytes, Keystore}; - #[derive(Clone, PartialEq, Debug)] pub enum Event { MinerStarted, @@ -13,7 +11,6 @@ pub enum Event { NewBlockReceived, BlockchainChanged { index: u64 }, ActionStopMining, - ActionMineSigning { start: i64, index: u64, hash: Bytes, keystore: Box }, ActionQuit, NetworkStatus { nodes: usize, blocks: u64 }, Syncing { have: u64, height: u64 }, diff --git a/src/miner.rs b/src/miner.rs index 22f3c7f..d2c6f71 100644 --- a/src/miner.rs +++ b/src/miner.rs @@ -9,13 +9,12 @@ use log::{debug, error, info, trace, warn}; use num_cpus; use crate::{Block, Bytes, Context, Keystore, setup_miner_thread}; -use crate::commons::{CHAIN_VERSION, SIGNER_DIFFICULTY, KEYSTORE_DIFFICULTY}; +use crate::commons::*; use crate::blockchain::types::BlockQuality; use crate::blockchain::hash_utils::*; use crate::keys::check_public_key_strength; use crate::event::Event; use blakeout::Blakeout; -use std::ops::Deref; #[derive(Clone)] pub struct MineJob { @@ -74,7 +73,7 @@ impl Miner { let cond_var = self.cond_var.clone(); thread::spawn(move || { running.store(true, Ordering::SeqCst); - let delay = Duration::from_millis(1000); + let delay = Duration::from_secs(30); while running.load(Ordering::SeqCst) { // If some transaction is being mined now, we yield if mining.load(Ordering::SeqCst) { @@ -92,16 +91,22 @@ impl Miner { } else { debug!("This job will wait for now"); jobs.insert(0, job); - let _ = cond_var.wait_timeout(jobs, delay).expect("Error in wait lock!"); } - } else { - let _ = cond_var.wait(jobs).expect("Error in wait lock!"); + } else if !mining.load(Ordering::SeqCst) { + if let Ok(context) = context.try_lock() { + let keystore = context.get_keystore(); + if let Some(block) = context.chain.get_sign_block(&keystore) { + info!("Got signing job, adding to queue"); + // We start mining sign block after some time, not everyone in the same time + let start = Utc::now().timestamp() + (rand::random::() % BLOCK_SIGNERS_START_RANDOM); + jobs.push(MineJob { start, block, keystore: keystore.unwrap() }); + } + } } + let _ = cond_var.wait_timeout(jobs, delay).expect("Error in wait lock!"); } }); let mining = self.mining.clone(); - let jobs = self.jobs.clone(); - let cond_var = self.cond_var.clone(); self.context.lock().unwrap().bus.register(move |_uuid, e| { match e { Event::NewBlockReceived => {} @@ -109,15 +114,6 @@ impl Miner { Event::ActionStopMining => { mining.store(false, Ordering::SeqCst); } - Event::ActionMineSigning { start, index, hash, keystore } => { - if !mining.load(Ordering::SeqCst) { - let mut block = Block::new(None, Bytes::default(), hash, SIGNER_DIFFICULTY); - block.index = index; - jobs.lock().unwrap().push(MineJob { start, block, keystore: keystore.deref().clone() }); - cond_var.notify_all(); - info!("Added a signing block to mine"); - } - } _ => {} } true diff --git a/src/p2p/network.rs b/src/p2p/network.rs index d3c6a19..964e265 100644 --- a/src/p2p/network.rs +++ b/src/p2p/network.rs @@ -66,8 +66,6 @@ impl Network { let mut log_timer = Instant::now(); let mut bootstrap_timer = Instant::now(); let mut last_events_time = Instant::now(); - let mut sent_mining_event_index = 0u64; - let mut sent_mining_event_time = Instant::now(); loop { if peers.get_peers_count() == 0 && bootstrap_timer.elapsed().as_secs() > 60 { // Starting peer connections to bootstrap nodes @@ -166,16 +164,6 @@ impl Network { warn!("Last network events time {} seconds ago", elapsed); } log_timer = Instant::now(); - let mining = context.miner_state.mining; - if !mining && (sent_mining_event_index < height || sent_mining_event_time.elapsed().as_secs() >= 600) { - let keystore = context.keystore.clone(); - if let Some(event) = context.chain.update(&keystore) { - context.bus.post(event); - trace!("Posted an event to mine signing block"); - sent_mining_event_index = height; - sent_mining_event_time = Instant::now(); - } - } } (height, context.chain.last_hash()) };