Improved signing blocks operations.

This commit is contained in:
Revertron
2021-04-20 20:54:45 +02:00
parent 3fb70d3a74
commit 5c1c0630a6
7 changed files with 77 additions and 49 deletions
+1 -1
View File
@@ -27,4 +27,4 @@ jobs:
- name: Build - name: Build
run: cargo build --verbose run: cargo build --verbose
- name: Run tests - name: Run tests
run: cargo test --all --verbose run: cargo test --all --verbose
+15 -15
View File
@@ -93,7 +93,7 @@ impl Chain {
} }
fn check_chain(&mut self) { fn check_chain(&mut self) {
let height = self.height(); let height = self.get_height();
info!("Local blockchain height is {}, starting full blockchain check...", height); info!("Local blockchain height is {}, starting full blockchain check...", height);
for id in 1..=height { for id in 1..=height {
info!("Checking block {}", id); info!("Checking block {}", id);
@@ -251,7 +251,7 @@ impl Chain {
} }
pub fn update(&mut self, keystore: &Option<Keystore>) -> Option<Event> { pub fn update(&mut self, keystore: &Option<Keystore>) -> Option<Event> {
if self.height() < BLOCK_SIGNERS_START { if self.get_height() < BLOCK_SIGNERS_START {
trace!("Too early to start block signings"); trace!("Too early to start block signings");
return None; return None;
} }
@@ -259,7 +259,7 @@ impl Chain {
trace!("We can't sign blocks without keys"); trace!("We can't sign blocks without keys");
return None; return None;
} }
if self.height() < self.max_height() { if self.get_height() < self.max_height() {
trace!("No signing while syncing"); trace!("No signing while syncing");
return None; return None;
} }
@@ -269,7 +269,7 @@ impl Chain {
Some(ref block) => { block.clone() } Some(ref block) => { block.clone() }
}; };
// TODO maybe make some config option to mine signing blocks above? // TODO maybe make some config option to mine signing blocks above?
let sign_count = self.height() - block.index; let sign_count = self.get_height() - block.index;
if sign_count >= BLOCK_SIGNERS_MIN { if sign_count >= BLOCK_SIGNERS_MIN {
trace!("Block {} has enough signing blocks", block.index); trace!("Block {} has enough signing blocks", block.index);
return None; return None;
@@ -283,7 +283,7 @@ impl Chain {
let keystore = keystore.clone().unwrap().clone(); let keystore = keystore.clone().unwrap().clone();
let signers: HashSet<Bytes> = self.get_block_signers(&block).into_iter().collect(); let signers: HashSet<Bytes> = self.get_block_signers(&block).into_iter().collect();
if signers.contains(&keystore.get_public()) { if signers.contains(&keystore.get_public()) {
for index in block.index..=self.height() { for index in block.index..=self.get_height() {
let b = self.get_block(index).unwrap(); let b = self.get_block(index).unwrap();
if b.pub_key == keystore.get_public() { if b.pub_key == keystore.get_public() {
info!("We already mined signing block for block {}", block.index); info!("We already mined signing block for block {}", block.index);
@@ -304,7 +304,7 @@ impl Chain {
pub fn update_sign_block_for_mining(&self, mut block: Block) -> Option<Block> { pub fn update_sign_block_for_mining(&self, mut block: Block) -> Option<Block> {
if let Some(full_block) = &self.last_full_block { if let Some(full_block) = &self.last_full_block {
let sign_count = self.height() - full_block.index; let sign_count = self.get_height() - full_block.index;
if sign_count >= BLOCK_SIGNERS_MIN { if sign_count >= BLOCK_SIGNERS_MIN {
return None; return None;
} }
@@ -319,7 +319,7 @@ impl Chain {
pub fn is_waiting_signers(&self) -> bool { pub fn is_waiting_signers(&self) -> bool {
if let Some(full_block) = &self.last_full_block { if let Some(full_block) = &self.last_full_block {
let sign_count = self.height() - full_block.index; let sign_count = self.get_height() - full_block.index;
if sign_count < BLOCK_SIGNERS_MIN { if sign_count < BLOCK_SIGNERS_MIN {
return true; return true;
} }
@@ -668,7 +668,7 @@ impl Chain {
self.last_block.clone() self.last_block.clone()
} }
pub fn height(&self) -> u64 { pub fn get_height(&self) -> u64 {
match self.last_block { match self.last_block {
None => { 0u64 } None => { 0u64 }
Some(ref block) => { Some(ref block) => {
@@ -686,12 +686,12 @@ impl Chain {
pub fn next_allowed_full_block(&self) -> u64 { pub fn next_allowed_full_block(&self) -> u64 {
match self.last_full_block { match self.last_full_block {
None => { self.height() + 1 } None => { self.get_height() + 1 }
Some(ref block) => { Some(ref block) => {
if block.index < BLOCK_SIGNERS_START { if block.index < BLOCK_SIGNERS_START {
self.height() + 1 self.get_height() + 1
} else { } else {
max(block.index + BLOCK_SIGNERS_MIN, self.height() + 1) max(block.index + BLOCK_SIGNERS_MIN, self.get_height() + 1)
} }
} }
} }
@@ -716,7 +716,7 @@ impl Chain {
warn!("Ignoring block from the future:\n{:?}", &block); warn!("Ignoring block from the future:\n{:?}", &block);
return Bad; return Bad;
} }
if block.index > self.height() + 1 { if block.index > self.get_height() + 1 {
info!("Ignoring future block:\n{:?}", &block); info!("Ignoring future block:\n{:?}", &block);
return Future; return Future;
} }
@@ -857,10 +857,10 @@ impl Chain {
/// Checks if this block is a good signature block /// Checks if this block is a good signature block
fn is_good_sign_block(&self, block: &Block) -> bool { fn is_good_sign_block(&self, block: &Block) -> bool {
if let Some(full_block) = &self.last_full_block { if let Some(full_block) = &self.last_full_block {
let sign_count = self.height() - full_block.index; let sign_count = self.get_height() - full_block.index;
if sign_count < BLOCK_SIGNERS_MIN { if sign_count < BLOCK_SIGNERS_MIN {
// Last full block is not locked enough // Last full block is not locked enough
if block.transaction.is_some() { if block.index > full_block.index && block.transaction.is_some() {
warn!("Not enough signing blocks over full {} block!", full_block.index); warn!("Not enough signing blocks over full {} block!", full_block.index);
return false; return false;
} else { } else {
@@ -954,7 +954,7 @@ impl Chain {
/// block - last full block /// block - last full block
pub fn get_block_signers(&self, block: &Block) -> Vec<Bytes> { pub fn get_block_signers(&self, block: &Block) -> Vec<Bytes> {
let mut result = Vec::new(); let mut result = Vec::new();
if block.index < BLOCK_SIGNERS_START || self.height() < block.index { if block.index < BLOCK_SIGNERS_START || self.get_height() < block.index {
return result; return result;
} }
let mut set = HashSet::new(); let mut set = HashSet::new();
+11 -1
View File
@@ -2,6 +2,7 @@ use crate::{Chain, Bus, Keystore, Settings, ExternalZones};
use crate::event::Event; use crate::event::Event;
#[allow(unused_imports)] #[allow(unused_imports)]
use log::{trace, debug, info, warn, error}; use log::{trace, debug, info, warn, error};
use crate::miner::MinerState;
pub struct Context { pub struct Context {
pub app_version: String, pub app_version: String,
@@ -10,12 +11,21 @@ pub struct Context {
pub chain: Chain, pub chain: Chain,
pub x_zones: ExternalZones, pub x_zones: ExternalZones,
pub bus: Bus<Event>, pub bus: Bus<Event>,
pub miner_state: MinerState,
} }
impl Context { impl Context {
/// Creating an essential context to work with /// Creating an essential context to work with
pub fn new(app_version: String, settings: Settings, keystore: Option<Keystore>, chain: Chain) -> Context { pub fn new(app_version: String, settings: Settings, keystore: Option<Keystore>, chain: Chain) -> Context {
Context { app_version, settings, keystore, chain, x_zones: ExternalZones::new(), bus: Bus::new() } Context {
app_version,
settings,
keystore,
chain,
x_zones: ExternalZones::new(),
bus: Bus::new(),
miner_state: MinerState { mining: false, full: false }
}
} }
/// Load keystore and return Context /// Load keystore and return Context
+1 -1
View File
@@ -107,7 +107,7 @@ fn main() {
let keystore = Keystore::from_file(&settings.key_file, ""); let keystore = Keystore::from_file(&settings.key_file, "");
let chain: Chain = Chain::new(&settings); let chain: Chain = Chain::new(&settings);
if opt_matches.opt_present("b") { if opt_matches.opt_present("b") {
for i in 1..(chain.height() + 1) { for i in 1..(chain.get_height() + 1) {
if let Some(block) = chain.get_block(i) { if let Some(block) = chain.get_block(i) {
info!(target: LOG_TARGET_MAIN, "{:?}", &block); info!(target: LOG_TARGET_MAIN, "{:?}", &block);
} }
+30 -18
View File
@@ -17,6 +17,19 @@ use crate::event::Event;
use blakeout::Blakeout; use blakeout::Blakeout;
use std::ops::Deref; use std::ops::Deref;
#[derive(Clone)]
pub struct MineJob {
start: i64,
block: Block,
keystore: Keystore
}
#[derive(Clone, Debug)]
pub struct MinerState {
pub mining: bool,
pub full: bool
}
pub struct Miner { pub struct Miner {
context: Arc<Mutex<Context>>, context: Arc<Mutex<Context>>,
jobs: Arc<Mutex<Vec<MineJob>>>, jobs: Arc<Mutex<Vec<MineJob>>>,
@@ -142,24 +155,28 @@ impl Miner {
} }
} }
} else { } else {
job.block.index = context.lock().unwrap().chain.height() + 1; job.block.index = context.lock().unwrap().chain.get_height() + 1;
job.block.prev_block_hash = match context.lock().unwrap().chain.last_block() { job.block.prev_block_hash = match context.lock().unwrap().chain.last_block() {
None => { Bytes::default() } None => { Bytes::default() }
Some(block) => { block.hash } Some(block) => { block.hash }
}; };
} }
context.lock().unwrap().bus.post(Event::MinerStarted); let (lower, threads) = {
let thread_spawn_interval = Duration::from_millis(10); let mut context = context.lock().unwrap();
let live_threads = Arc::new(AtomicU32::new(0u32)); context.bus.post(Event::MinerStarted);
let lower = context.lock().unwrap().settings.mining.lower; context.miner_state.mining = true;
context.miner_state.full = job.block.transaction.is_some();
(context.settings.mining.lower, context.settings.mining.threads)
};
let cpus = num_cpus::get(); let cpus = num_cpus::get();
let threads = context.lock().unwrap().settings.mining.threads;
let threads = match threads { let threads = match threads {
0 => cpus, 0 => cpus,
_ => threads _ => threads
}; };
debug!("Starting {} threads for mining", threads); debug!("Starting {} threads for mining", threads);
let thread_spawn_interval = Duration::from_millis(100);
let live_threads = Arc::new(AtomicU32::new(0u32));
for cpu in 0..threads { for cpu in 0..threads {
let context = Arc::clone(&context); let context = Arc::clone(&context);
let job = job.clone(); let job = job.clone();
@@ -178,6 +195,7 @@ impl Miner {
// If this is the last thread, but mining was not stopped by another thread // If this is the last thread, but mining was not stopped by another thread
if count == 1 { if count == 1 {
let mut context = context.lock().unwrap(); let mut context = context.lock().unwrap();
context.miner_state.mining = false;
context.bus.post(Event::MinerStopped { success: false, full }); context.bus.post(Event::MinerStopped { success: false, full });
} }
}, },
@@ -198,6 +216,7 @@ impl Miner {
context.chain.add_block(block); context.chain.add_block(block);
success = true; success = true;
} }
context.miner_state.mining = false;
context.bus.post(Event::MinerStopped { success, full }); context.bus.post(Event::MinerStopped { success, full });
mining.store(false, Ordering::SeqCst); mining.store(false, Ordering::SeqCst);
}, },
@@ -208,13 +227,6 @@ impl Miner {
} }
} }
#[derive(Clone)]
pub struct MineJob {
start: i64,
block: Block,
keystore: Keystore
}
fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<AtomicBool>, thread: usize) -> Option<Block> { fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<AtomicBool>, thread: usize) -> Option<Block> {
let difficulty = block.difficulty; let difficulty = block.difficulty;
let full = block.transaction.is_some(); let full = block.transaction.is_some();
@@ -226,7 +238,7 @@ fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<Atomic
let next_allowed_block = { let next_allowed_block = {
let context = context.lock().unwrap(); let context = context.lock().unwrap();
// We use this block to fill some fields of our block as well // We use this block to fill some fields of our block as well
block.index = context.chain.height() + 1; block.index = context.chain.get_height() + 1;
if let Some(b) = context.chain.last_block() { if let Some(b) = context.chain.last_block() {
block.prev_block_hash = b.hash; block.prev_block_hash = b.hash;
} }
@@ -245,7 +257,7 @@ fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<Atomic
debug!("Mining block {}", serde_json::to_string(&block).unwrap()); debug!("Mining block {}", serde_json::to_string(&block).unwrap());
let mut time = Instant::now(); let mut time = Instant::now();
let mut prev_nonce = 0; let mut prev_nonce = 0;
for nonce in 0..std::u64::MAX { for nonce in 0..u64::MAX {
if !running.load(Ordering::Relaxed) { if !running.load(Ordering::Relaxed) {
return None; return None;
} }
@@ -268,7 +280,7 @@ fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<Atomic
if elapsed > 5000 { if elapsed > 5000 {
let speed = (nonce - prev_nonce) / (elapsed as u64 / 1000); let speed = (nonce - prev_nonce) / (elapsed as u64 / 1000);
//debug!("Mining speed {} H/s, max difficulty {}", speed, max_diff); //debug!("Mining speed {} H/s, max difficulty {}", speed, max_diff);
if let Ok(mut context) = context.lock() { if let Ok(mut context) = context.try_lock() {
context.bus.post(Event::MinerStats { thread, speed, max_diff, aim_diff: difficulty }) context.bus.post(Event::MinerStats { thread, speed, max_diff, aim_diff: difficulty })
} }
time = Instant::now(); time = Instant::now();
@@ -276,8 +288,8 @@ fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<Atomic
} }
if block.index > 1 { if block.index > 1 {
if let Ok(context) = context.lock() { if let Ok(context) = context.try_lock() {
if context.chain.height() >= block.index { if context.chain.get_height() >= block.index {
if !full { if !full {
info!("Blockchain changed while mining signing block, dropping work"); info!("Blockchain changed while mining signing block, dropping work");
return None; return None;
+18 -12
View File
@@ -66,6 +66,8 @@ impl Network {
let mut log_timer = Instant::now(); let mut log_timer = Instant::now();
let mut bootstrap_timer = Instant::now(); let mut bootstrap_timer = Instant::now();
let mut last_events_time = 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 { loop {
if peers.get_peers_count() == 0 && bootstrap_timer.elapsed().as_secs() > 60 { if peers.get_peers_count() == 0 && bootstrap_timer.elapsed().as_secs() > 60 {
// Starting peer connections to bootstrap nodes // Starting peer connections to bootstrap nodes
@@ -136,7 +138,7 @@ impl Network {
if !handle_connection_event(Arc::clone(&context), &mut peers, &poll.registry(), &event) { if !handle_connection_event(Arc::clone(&context), &mut peers, &poll.registry(), &event) {
let _ = peers.close_peer(poll.registry(), &token); let _ = peers.close_peer(poll.registry(), &token);
let mut context = context.lock().unwrap(); let mut context = context.lock().unwrap();
let blocks_count = context.chain.height(); let blocks_count = context.chain.get_height();
context.bus.post(crate::event::Event::NetworkStatus { nodes: peers.get_peers_active_count(), blocks: blocks_count }); context.bus.post(crate::event::Event::NetworkStatus { nodes: peers.get_peers_active_count(), blocks: blocks_count });
} }
} }
@@ -151,7 +153,7 @@ impl Network {
// Send pings to idle peers // Send pings to idle peers
let (height, hash) = { let (height, hash) = {
let mut context = context.lock().unwrap(); let mut context = context.lock().unwrap();
let height = context.chain.height(); let height = context.chain.get_height();
let nodes = peers.get_peers_active_count(); let nodes = peers.get_peers_active_count();
let banned = peers.get_peers_banned_count(); let banned = peers.get_peers_banned_count();
if nodes > 0 { if nodes > 0 {
@@ -164,10 +166,14 @@ impl Network {
warn!("Last network events time {} seconds ago", elapsed); warn!("Last network events time {} seconds ago", elapsed);
} }
log_timer = Instant::now(); log_timer = Instant::now();
let keystore = context.keystore.clone(); if sent_mining_event_index < height || sent_mining_event_time.elapsed().as_secs() >= 600 {
if let Some(event) = context.chain.update(&keystore) { let keystore = context.keystore.clone();
context.bus.post(event); if let Some(event) = context.chain.update(&keystore) {
trace!("Posted an event to mine signing block"); 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()) (height, context.chain.last_hash())
@@ -300,7 +306,7 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
if from.elapsed().as_secs() >= 30 { if from.elapsed().as_secs() >= 30 {
let data: String = { let data: String = {
let c = context.lock().unwrap(); let c = context.lock().unwrap();
let message = Message::ping(c.chain.height(), c.chain.last_hash()); let message = Message::ping(c.chain.get_height(), c.chain.last_hash());
serde_json::to_string(&message).unwrap() serde_json::to_string(&message).unwrap()
}; };
send_message(peer.get_stream(), &data.into_bytes()).unwrap_or_else(|e| warn!("Error sending ping {}", e)); send_message(peer.get_stream(), &data.into_bytes()).unwrap_or_else(|e| warn!("Error sending ping {}", e));
@@ -376,7 +382,7 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
let (my_height, my_hash, my_origin, my_version) = { let (my_height, my_hash, my_origin, my_version) = {
let context = context.lock().unwrap(); let context = context.lock().unwrap();
// TODO cache it somewhere // TODO cache it somewhere
(context.chain.height(), context.chain.last_hash(), &context.settings.origin.clone(), CHAIN_VERSION) (context.chain.get_height(), context.chain.last_hash(), &context.settings.origin.clone(), CHAIN_VERSION)
}; };
let answer = match message { let answer = match message {
Message::Hand { app_version, origin, version, public, rand} => { Message::Hand { app_version, origin, version, public, rand} => {
@@ -502,7 +508,7 @@ fn process_new_block(context: Arc<Mutex<Context>>, peers: &mut Peers, token: &To
match context.chain.check_new_block(&block) { match context.chain.check_new_block(&block) {
BlockQuality::Good => { BlockQuality::Good => {
context.chain.add_block(block); context.chain.add_block(block);
let my_height = context.chain.height(); let my_height = context.chain.get_height();
context.bus.post(crate::event::Event::BlockchainChanged { index: my_height }); context.bus.post(crate::event::Event::BlockchainChanged { index: my_height });
// If it was the last block to sync // If it was the last block to sync
if my_height == max_height { if my_height == max_height {
@@ -517,7 +523,7 @@ fn process_new_block(context: Arc<Mutex<Context>>, peers: &mut Peers, token: &To
BlockQuality::Bad => { BlockQuality::Bad => {
// TODO save bad public keys to banned table // TODO save bad public keys to banned table
debug!("Ignoring bad block from {}:\n{:?}", peer.get_addr(), &block); debug!("Ignoring bad block from {}:\n{:?}", peer.get_addr(), &block);
let height = context.chain.height(); let height = context.chain.get_height();
context.chain.update_max_height(height); context.chain.update_max_height(height);
context.bus.post(crate::event::Event::SyncFinished); context.bus.post(crate::event::Event::SyncFinished);
return State::Banned; return State::Banned;
@@ -527,10 +533,10 @@ fn process_new_block(context: Arc<Mutex<Context>>, peers: &mut Peers, token: &To
let last_block = context.chain.last_block().unwrap(); let last_block = context.chain.last_block().unwrap();
if block.is_better_than(&last_block) { if block.is_better_than(&last_block) {
context.chain.replace_block(block.index, block).expect("Error replacing block with fork"); context.chain.replace_block(block.index, block).expect("Error replacing block with fork");
let index = context.chain.height(); let index = context.chain.get_height();
context.bus.post(crate::event::Event::BlockchainChanged { index }); context.bus.post(crate::event::Event::BlockchainChanged { index });
} }
let height = context.chain.height(); let height = context.chain.get_height();
context.chain.update_max_height(height); context.chain.update_max_height(height);
context.bus.post(crate::event::Event::SyncFinished); context.bus.post(crate::event::Event::SyncFinished);
} }
+1 -1
View File
@@ -317,7 +317,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
let hash = keystore.get_hash().to_string(); let hash = keystore.get_hash().to_string();
c.bus.post(Event::KeyLoaded { path, public, hash }); c.bus.post(Event::KeyLoaded { path, public, hash });
} }
let index = c.chain.height(); let index = c.chain.get_height();
c.bus.post(Event::BlockchainChanged { index }); c.bus.post(Event::BlockchainChanged { index });
event_info(web_view, "Application loaded"); event_info(web_view, "Application loaded");
} }