From fcb920e0de834f2846fab0f46e7e3d2c2e888fe6 Mon Sep 17 00:00:00 2001 From: Revertron Date: Mon, 26 Apr 2021 21:49:01 +0200 Subject: [PATCH] Refactored Chain a lot to make it possible to test. Added a CPU hard test for Chain, checking all current DB. Added an option to config file to set a count of checked top blocks on start. --- Cargo.toml | 2 +- alfis.toml | 2 + src/blockchain/chain.rs | 228 ++++++++++++++++++++------------------- src/blockchain/filter.rs | 4 +- src/commons/constants.rs | 1 + src/main.rs | 7 +- src/miner.rs | 4 +- src/settings.rs | 11 +- src/web_ui.rs | 6 +- tests/blockchain.db | Bin 0 -> 176128 bytes 10 files changed, 142 insertions(+), 123 deletions(-) create mode 100644 tests/blockchain.db diff --git a/Cargo.toml b/Cargo.toml index b65479f..e71bbbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "alfis" -version = "0.4.30" +version = "0.4.31" authors = ["Revertron "] edition = "2018" build = "build.rs" diff --git a/alfis.toml b/alfis.toml index 0c8d1e0..05b6135 100644 --- a/alfis.toml +++ b/alfis.toml @@ -2,6 +2,8 @@ origin = "0AE588D62D710422A7972EA1E8A659CC8E93DB59489ACE32C499CD279B000000" # A path to your key file to load automatically key_file = "default.key" +# How many last blocks to check on start +check_blocks = 8 # Network settings [net] diff --git a/src/blockchain/chain.rs b/src/blockchain/chain.rs index 2b3abb7..a156cf7 100644 --- a/src/blockchain/chain.rs +++ b/src/blockchain/chain.rs @@ -8,7 +8,7 @@ use chrono::Utc; use log::{debug, error, info, trace, warn}; use sqlite::{Connection, State, Statement}; -use crate::{Block, Bytes, Keystore, Transaction, check_domain, get_domain_zone, is_yggdrasil_record, from_hex}; +use crate::{Block, Bytes, Keystore, Transaction, check_domain, get_domain_zone, is_yggdrasil_record}; use crate::commons::constants::*; use crate::blockchain::types::{BlockQuality, MineResult, Options}; use crate::blockchain::types::BlockQuality::*; @@ -20,14 +20,11 @@ use crate::blockchain::transaction::{ZoneData, DomainData}; use std::ops::Deref; use crate::blockchain::types::MineResult::*; -const DB_NAME: &str = "blockchain.db"; const TEMP_DB_NAME: &str = "temp.db"; const SQL_CREATE_TABLES: &str = include_str!("sql/create_db.sql"); const SQL_ADD_BLOCK: &str = "INSERT INTO blocks (id, timestamp, version, difficulty, random, nonce, 'transaction',\ prev_block_hash, hash, pub_key, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; const SQL_GET_LAST_BLOCK: &str = "SELECT * FROM blocks ORDER BY id DESC LIMIT 1;"; -const SQL_GET_FIRST_BLOCK_FOR_KEY: &str = "SELECT id FROM blocks WHERE pub_key = ? LIMIT 1;"; -const SQL_DELETE_BLOCK_AND_TRANSACTIONS: &str = "DELETE FROM blocks WHERE id = ?; DELETE FROM domains WHERE id = ?; DELETE FROM zones WHERE id = ?;"; const SQL_TRUNCATE_BLOCKS: &str = "DELETE FROM blocks WHERE id >= ?;"; const SQL_TRUNCATE_DOMAINS: &str = "DELETE FROM domains WHERE id >= ?;"; const SQL_TRUNCATE_ZONES: &str = "DELETE FROM zones WHERE id >= ?;"; @@ -37,8 +34,8 @@ const SQL_ADD_ZONE: &str = "INSERT INTO zones (id, timestamp, identity, confirma const SQL_GET_BLOCK_BY_ID: &str = "SELECT * FROM blocks WHERE id=? LIMIT 1;"; const SQL_GET_LAST_FULL_BLOCK: &str = "SELECT * FROM blocks WHERE id < ? AND `transaction`<>'' ORDER BY id DESC LIMIT 1;"; const SQL_GET_LAST_FULL_BLOCK_FOR_KEY: &str = "SELECT * FROM blocks WHERE id < ? AND `transaction`<>'' AND pub_key = ? ORDER BY id DESC LIMIT 1;"; -const SQL_GET_DOMAIN_PUBLIC_KEY_BY_ID: &str = "SELECT pub_key FROM domains WHERE identity = ? ORDER BY id DESC LIMIT 1;"; -const SQL_GET_ZONE_PUBLIC_KEY_BY_ID: &str = "SELECT pub_key FROM zones WHERE identity = ? ORDER BY id DESC LIMIT 1;"; +const SQL_GET_DOMAIN_PUBLIC_KEY_BY_ID: &str = "SELECT pub_key FROM domains WHERE id < ? AND identity = ? LIMIT 1;"; +const SQL_GET_ZONE_PUBLIC_KEY_BY_ID: &str = "SELECT pub_key FROM zones WHERE id < ? AND identity = ? LIMIT 1;"; const SQL_GET_DOMAIN_BY_ID: &str = "SELECT * FROM domains WHERE identity = ? ORDER BY id DESC LIMIT 1;"; const SQL_GET_DOMAINS_BY_KEY: &str = "SELECT * FROM domains WHERE pub_key = ?;"; const SQL_GET_ZONES: &str = "SELECT data FROM zones;"; @@ -59,10 +56,10 @@ pub struct Chain { } impl Chain { - pub fn new(settings: &Settings) -> Self { + pub fn new(settings: &Settings, db_name: &str) -> Self { let origin = settings.get_origin(); - let db = sqlite::open(DB_NAME).expect("Unable to open blockchain DB"); + 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, signers: SignersCache::new() }; chain.init_db(); @@ -90,17 +87,33 @@ impl Chain { self.last_full_block = self.get_last_full_block(MAX, None); } } - // TODO Add env-var and commandline switches for full check - //self.check_chain(); } - #[allow(dead_code)] - fn check_chain(&mut self) { + pub fn check_chain(&mut self, count: u64) { let height = self.get_height(); - info!("Local blockchain height is {}, starting full blockchain check...", height); - for id in 1..=height { - info!("Checking block {}", id); - match self.get_block(id) { + let start = if height > count { + info!("Checking last {} blocks...", count); + height - count + 1 + } else { + info!("Local blockchain height is {}, starting full blockchain check...", height); + 1 + }; + let mut last_block: Option = None; + let mut last_full_block: Option = None; + if start > 1 { + last_block = self.get_block(start - 1); + if let Some(last) = &last_block { + last_full_block = match &last.transaction { + None => { self.get_last_full_block(last.index, None) } + Some(_) => { Some(last.clone()) } + }; + } + } + + for id in start..=height { + debug!("Checking block {}", id); + let block = self.get_block(id); + match block { None => { panic!("Blockchain is corrupted! Please, delete 'blockchain.db' and restart."); } @@ -109,12 +122,13 @@ impl Chain { if block.hash != self.origin { panic!("Loaded DB is not of origin {:?}! Please, delete 'blockchain.db' and restart.", &self.origin); } - self.last_block = Some(block); + debug!("Block {} with hash {:?} is good!", block.index, &block.hash); + last_block = Some(block); continue; } //let last = self.last_block.clone().unwrap(); - if self.check_new_block(&block) != BlockQuality::Good { + if self.check_block(&block, &last_block, &last_full_block) != BlockQuality::Good { error!("Block {} is bad:\n{:?}", block.index, &block); info!("Truncating database from block {}...", block.index); match self.truncate_db_from_block(block.index) { @@ -126,29 +140,22 @@ impl Chain { } break; } - info!("Block {} with hash {:?} is good!", block.index, &block.hash); + debug!("Block {} with hash {:?} is good!", block.index, &block.hash); if block.transaction.is_some() { self.last_full_block = Some(block.clone()); } - self.last_block = Some(block); + if block.transaction.is_some() { + last_full_block = Some(block.clone()); + } + last_block = Some(block); } } } self.last_block = self.load_last_block(); self.last_full_block = self.get_last_full_block(MAX, None); - info!("Last block after chain check: {:?}", &self.last_block); + debug!("Last block after chain check: {:?}", &self.last_block); } - #[allow(dead_code)] - fn delete_block(&mut self, index: u64) -> sqlite::Result { - let mut statement = self.db.prepare(SQL_DELETE_BLOCK_AND_TRANSACTIONS)?; - statement.bind(1, index as i64)?; - statement.bind(2, index as i64)?; - statement.bind(3, index as i64)?; - statement.next() - } - - #[allow(dead_code)] fn truncate_db_from_block(&mut self, index: u64) -> sqlite::Result { let mut statement = self.db.prepare(SQL_TRUNCATE_BLOCKS)?; statement.bind(1, index as i64)?; @@ -396,13 +403,15 @@ impl Chain { } /// Gets last block that has a Transaction within - pub fn get_last_full_block(&self, index: u64, pub_key: Option<&[u8]>) -> Option { + pub fn get_last_full_block(&self, before: u64, pub_key: Option<&[u8]>) -> Option { if let Some(block) = &self.last_full_block { - match pub_key { - None => { return Some(block.clone()); } - Some(key) => { - if block.pub_key.deref().eq(key) { - return Some(block.clone()); + if block.index < before { + match pub_key { + None => { return Some(block.clone()); } + Some(key) => { + if block.pub_key.deref().eq(key) { + return Some(block.clone()); + } } } } @@ -411,12 +420,12 @@ impl Chain { let mut statement = match pub_key { None => { let mut statement = self.db.prepare(SQL_GET_LAST_FULL_BLOCK).expect("Unable to prepare"); - statement.bind(1, index as i64).expect("Unable to bind"); + statement.bind(1, before as i64).expect("Unable to bind"); statement } Some(pub_key) => { let mut statement = self.db.prepare(SQL_GET_LAST_FULL_BLOCK_FOR_KEY).expect("Unable to prepare"); - statement.bind(1, index as i64).expect("Unable to bind"); + statement.bind(1, before as i64).expect("Unable to bind"); statement.bind(2, pub_key).expect("Unable to bind"); statement } @@ -437,12 +446,12 @@ impl Chain { } /// Checks if any domain is available to mine for this client (pub_key) - pub fn is_domain_available(&self, domain: &str, keystore: &Keystore) -> bool { + pub fn is_domain_available(&self, height: u64, domain: &str, keystore: &Keystore) -> bool { if domain.is_empty() { return false; } let identity_hash = hash_identity(domain, None); - if !self.is_id_available(&identity_hash, &keystore.get_public(), false) { + if !self.is_id_available(height, &identity_hash, &keystore.get_public(), false) { return false; } @@ -452,20 +461,21 @@ impl Chain { if parts.last().unwrap().contains(".") { return false; } - return self.is_zone_in_blockchain(parts.first().unwrap()); + return self.is_zone_in_blockchain(height, parts.first().unwrap()); } true } /// Checks if this identity is free or is owned by the same pub_key - pub fn is_id_available(&self, identity: &Bytes, public_key: &Bytes, zone: bool) -> bool { + pub fn is_id_available(&self, height: u64, identity: &Bytes, public_key: &Bytes, zone: bool) -> bool { let sql = match zone { true => { SQL_GET_ZONE_PUBLIC_KEY_BY_ID } false => { SQL_GET_DOMAIN_PUBLIC_KEY_BY_ID } }; let mut statement = self.db.prepare(sql).unwrap(); - statement.bind(1, &***identity).expect("Error in bind"); + statement.bind(1, height as i64).expect("Error in bind"); + statement.bind(2, &***identity).expect("Error in bind"); while let State::Row = statement.next().unwrap() { let pub_key = Bytes::from_bytes(&statement.read::>(0).unwrap()); if !pub_key.eq(public_key) { @@ -496,14 +506,14 @@ impl Chain { } /// Checks if some zone exists in our blockchain - pub fn is_zone_in_blockchain(&self, zone: &str) -> bool { + pub fn is_zone_in_blockchain(&self, height: u64, zone: &str) -> bool { if self.zones.borrow().contains(zone) { return true; } // Checking for existing zone in DB let identity_hash = hash_identity(zone, None); - if self.is_id_in_blockchain(&identity_hash, true) { + if self.is_id_in_blockchain(height, &identity_hash, true) { // If there is such a zone self.zones.borrow_mut().insert(zone.to_owned()); return true; @@ -512,14 +522,15 @@ impl Chain { } /// Checks if some id exists in our blockchain - pub fn is_id_in_blockchain(&self, id: &Bytes, zone: bool) -> bool { + pub fn is_id_in_blockchain(&self, height: u64, id: &Bytes, zone: bool) -> bool { let sql = match zone { true => { SQL_GET_ZONE_PUBLIC_KEY_BY_ID } false => { SQL_GET_DOMAIN_PUBLIC_KEY_BY_ID } }; // Checking for existing zone in DB let mut statement = self.db.prepare(sql).unwrap(); - statement.bind(1, &***id).expect("Error in bind"); + statement.bind(1, height as i64).expect("Error in bind"); + statement.bind(2, &***id).expect("Error in bind"); while let State::Row = statement.next().unwrap() { // If there is such a zone return true; @@ -527,13 +538,13 @@ impl Chain { false } - pub fn can_mine_domain(&self, domain: &str, pub_key: &Bytes) -> MineResult { + pub fn can_mine_domain(&self, height: u64, domain: &str, pub_key: &Bytes) -> MineResult { let name = domain.to_lowercase(); if !check_domain(&name, true) { return WrongName; } let zone = get_domain_zone(&name); - if !self.is_zone_in_blockchain(&zone) { + if !self.is_zone_in_blockchain(height, &zone) { return WrongZone; } if let Some(transaction) = self.get_domain_transaction(&name) { @@ -543,7 +554,7 @@ impl Chain { } let identity_hash = hash_identity(&name, None); if let Some(last) = self.get_last_full_block(MAX, Some(&pub_key)) { - let new_id = !self.is_id_in_blockchain(&identity_hash, false); + let new_id = !self.is_id_in_blockchain(height, &identity_hash, false); let time = last.timestamp + NEW_DOMAINS_INTERVAL - Utc::now().timestamp(); if new_id && time > 0 { return Cooldown { time } @@ -684,8 +695,12 @@ impl Chain { self.max_height = height; } - /// Check if this block can be added to our blockchain pub fn check_new_block(&self, block: &Block) -> BlockQuality { + self.check_block(block, &self.last_block, &self.last_full_block) + } + + /// Check if this block can be added to our blockchain + pub fn check_block(&self, block: &Block, last_block: &Option, last_full_block: &Option) -> BlockQuality { if block.version > CHAIN_VERSION { warn!("Ignoring block from unsupported version:\n{:?}", &block); return Bad; @@ -695,9 +710,11 @@ impl Chain { warn!("Ignoring block from the future:\n{:?}", &block); return Bad; } - if block.index > self.get_height() + 1 { - info!("Ignoring future block:\n{:?}", &block); - return Future; + if let Some(last) = last_block { + if block.index > last.index + 1 { + info!("Ignoring future block:\n{:?}", &block); + return Future; + } } if !check_public_key_strength(&block.pub_key, KEYSTORE_DIFFICULTY) { warn!("Ignoring block with weak public key:\n{:?}", &block); @@ -736,36 +753,28 @@ impl Chain { } } - let faulty_blocks = vec![ - "0000133B790B61460D757E1F1F2D04480C8340D28CA73AE5AF27DBBF60548D00", - "8564E56AB50AE8473C3A26D7F5FF768A0238D463FAAE4A2049B2A6052F140000", - "0000FD8442CE01D9F25A4F53BE21A8552E83182184F2FF75E2A77718CF87483E", - "000CF01FA8E538A5AEA1E0E7B5FAB14914A4407B1CBE93CBB0F2129782661160", - ]; - for hash in faulty_blocks { - let bytes = Bytes::from_bytes(&from_hex(hash).unwrap()); - if block.hash == bytes { - warn!("Block {:?} is faulty! Ignoring!", &block); - return Bad; - } - } - if let Some(transaction) = &block.transaction { + let current_height = match last_block { + None => { 0 } + Some(block) => { block.index } + }; // TODO check for zone transaction - if !self.is_id_available(&transaction.identity, &block.pub_key, false) || !self.is_id_available(&transaction.identity, &block.pub_key, true) { + let is_domain_available = self.is_id_available(current_height, &transaction.identity, &block.pub_key, false); + let is_zone_available = self.is_id_available(current_height, &transaction.identity, &block.pub_key, true); + if !is_domain_available || !is_zone_available { warn!("Block {:?} is trying to spoof an identity!", &block); return Bad; } if let Some(last) = self.get_last_full_block(block.index, Some(&block.pub_key)) { if last.index < block.index { - let new_id = !self.is_id_in_blockchain(&transaction.identity, false); + let new_id = !self.is_id_in_blockchain(block.index, &transaction.identity, false); if new_id && last.timestamp + NEW_DOMAINS_INTERVAL > block.timestamp { warn!("Block {:?} is mined too early!", &block); return Bad; } } } - // Check if yggdrasil only quality of zone is not violated + // Check if yggdrasil only property of zone is not violated if let Some(block_data) = transaction.get_domain_data() { let zones = self.get_zones(); for z in &zones { @@ -782,7 +791,7 @@ impl Chain { } } } - match &self.last_block { + match last_block { None => { if !block.is_genesis() { warn!("Block is from the future, how is this possible?"); @@ -804,7 +813,7 @@ impl Chain { } if block.index > BLOCK_SIGNERS_START { // If this block is main, signed part of blockchain - if !self.is_good_sign_block(&block) { + if !self.is_good_sign_block(&block, last_full_block) { return Bad; } } @@ -834,12 +843,12 @@ impl Chain { } /// 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, last_full_block: &Option) -> bool { // If this is not a signing block if block.transaction.is_some() { return true; } - if let Some(full_block) = &self.last_full_block { + if let Some(full_block) = &last_full_block { let sign_count = self.get_height() - full_block.index; if sign_count < BLOCK_SIGNERS_MIN { // Last full block is not locked enough @@ -847,12 +856,12 @@ impl Chain { warn!("Not enough signing blocks over full {} block!", full_block.index); return false; } else { - if !self.is_good_signer_for_block(&block, full_block, sign_count) { + if !self.is_good_signer_for_block(&block, full_block) { return false; } } } else if sign_count < BLOCK_SIGNERS_ALL && block.transaction.is_none() { - if !self.is_good_signer_for_block(&block, full_block, sign_count) { + if !self.is_good_signer_for_block(&block, full_block) { return false; } } @@ -861,11 +870,7 @@ impl Chain { } /// Check if this block's owner is a good candidate to sign last full block - fn is_good_signer_for_block(&self, block: &Block, full_block: &Block, sign_count: u64) -> bool { - // If the time for chosen signers is up - if self.can_sign_by_pos(sign_count, full_block.timestamp, block.timestamp, &block.pub_key) { - return true; - } + fn is_good_signer_for_block(&self, block: &Block, full_block: &Block) -> bool { // If we got a signing block let signers: HashSet = self.get_block_signers(full_block).into_iter().collect(); if !signers.contains(&block.pub_key) { @@ -883,33 +888,6 @@ impl Chain { true } - /// Gets an id of first block of this public key - fn get_first_block_id_for_key(&self, key: &Bytes) -> u64 { - match self.db.prepare(SQL_GET_FIRST_BLOCK_FOR_KEY) { - Ok(mut statement) => { - statement.bind(1, &***key).expect("Error in bind"); - while statement.next().unwrap() == State::Row { - return statement.read::(0).unwrap() as u64; - } - 0 - } - Err(_) => { - 0 - } - } - } - - /// Check if an owner of this public key can sign full block by PoS scheme (be in first 1000 users) - fn can_sign_by_pos(&self, sign_count: u64, block_time: i64, now: i64, pub_key: &Bytes) -> bool { - if sign_count < BLOCK_SIGNERS_MIN && block_time - now > BLOCK_SIGNERS_TIME { - let index = self.get_first_block_id_for_key(&pub_key); - if index > 0 && index <= BLOCK_POS_SIGNERS { - return true; - } - } - false - } - fn get_difficulty_for_transaction(&self, transaction: &Transaction) -> u32 { match transaction.class.as_ref() { "domain" => { @@ -997,4 +975,34 @@ impl SignersCache { pub fn has_signers_for(&self, index: u64) -> bool { self.index == index && !self.signers.is_empty() } +} + +#[cfg(test)] +pub mod tests { + use crate::{Chain, Settings}; + use simplelog::{ConfigBuilder, TermLogger, TerminalMode, ColorChoice}; + use log::LevelFilter; + + fn init_logger() { + let config = ConfigBuilder::new() + .add_filter_ignore_str("mio::poll") + .set_thread_level(LevelFilter::Off) + .set_location_level(LevelFilter::Off) + .set_target_level(LevelFilter::Error) + .set_time_level(LevelFilter::Error) + .set_time_to_local(true) + .build(); + if let Err(e) = TermLogger::init(LevelFilter::Trace, config, TerminalMode::Stdout, ColorChoice::Auto) { + println!("Unable to initialize logger!\n{}", e); + } + } + + #[test] + pub fn load_and_check() { + init_logger(); + let settings = Settings::default(); + let mut chain = Chain::new(&settings, "./tests/blockchain.db"); + chain.check_chain(u64::MAX); + assert_eq!(chain.get_height(), 214); + } } \ No newline at end of file diff --git a/src/blockchain/filter.rs b/src/blockchain/filter.rs index f7bb6d7..3e1d44c 100644 --- a/src/blockchain/filter.rs +++ b/src/blockchain/filter.rs @@ -48,7 +48,7 @@ impl DnsFilter for BlockchainFilter { let zone = parts[0].to_owned(); match data { None => { - if self.context.lock().unwrap().chain.is_zone_in_blockchain(&zone) { + if self.context.lock().unwrap().chain.is_zone_in_blockchain(u64::MAX, &zone) { trace!("Not found data for domain {}", &search); // Create DnsPacket let mut packet = DnsPacket::new(); @@ -192,7 +192,7 @@ impl BlockchainFilter { } fn get_zone_response(&self, zone: &str, mut packet: &mut DnsPacket) -> bool { - let have_zone = self.context.lock().unwrap().chain.is_zone_in_blockchain(zone); + let have_zone = self.context.lock().unwrap().chain.is_zone_in_blockchain(i64::MAX as u64, zone); if have_zone { BlockchainFilter::add_soa_record(zone.to_owned(), &mut packet); } diff --git a/src/commons/constants.rs b/src/commons/constants.rs index ab7ca42..d8a6a87 100644 --- a/src/commons/constants.rs +++ b/src/commons/constants.rs @@ -32,6 +32,7 @@ pub const DOMAIN_LIFETIME: i64 = 86400 * 365; // One year pub const ZONE_MAX_LENGTH: usize = 10; pub const MAX_RECONNECTS: u32 = 5; +pub const DB_NAME: &str = "blockchain.db"; pub const CLASS_ZONE: &str = "zone"; pub const CLASS_DOMAIN: &str = "domain"; pub const ALFIS_DEBUG: &str = "ALFIS_DEBUG"; diff --git a/src/main.rs b/src/main.rs index 6d37077..510a796 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ use simplelog::*; #[cfg(windows)] use winapi::um::wincon::{ATTACH_PARENT_PROCESS, AttachConsole, FreeConsole}; -use alfis::{Block, Bytes, Chain, Miner, Context, Network, Settings, dns_utils, Keystore, ZONE_DIFFICULTY, ALFIS_DEBUG}; +use alfis::{Block, Bytes, Chain, Miner, Context, Network, Settings, dns_utils, Keystore, ZONE_DIFFICULTY, ALFIS_DEBUG, DB_NAME}; use std::fs::OpenOptions; use std::process::exit; use std::io::{Seek, SeekFrom}; @@ -103,9 +103,9 @@ fn main() { info!(target: LOG_TARGET_MAIN, "Starting ALFIS {}", env!("CARGO_PKG_VERSION")); let settings = Settings::load(&config_name).expect(&format!("Cannot load settings from {}!", &config_name)); - info!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings); + debug!(target: LOG_TARGET_MAIN, "Loaded settings: {:?}", &settings); let keystore = Keystore::from_file(&settings.key_file, ""); - let chain: Chain = Chain::new(&settings); + let mut chain: Chain = Chain::new(&settings, DB_NAME); if opt_matches.opt_present("b") { for i in 1..(chain.get_height() + 1) { if let Some(block) = chain.get_block(i) { @@ -114,6 +114,7 @@ fn main() { } return; } + chain.check_chain(settings.check_blocks); match chain.get_block(1) { None => { info!(target: LOG_TARGET_MAIN, "No blocks found in DB"); } diff --git a/src/miner.rs b/src/miner.rs index a61aef3..12fdaa9 100644 --- a/src/miner.rs +++ b/src/miner.rs @@ -147,7 +147,7 @@ impl Miner { } if !signing_waits { - if let Ok(context) = context.try_lock() { + if let Ok(context) = context.lock() { let keystore = context.get_keystore(); // Ask the blockchain if we have to sign something if let Some(block) = context.chain.get_sign_block(&keystore) { @@ -175,7 +175,7 @@ impl Miner { } } else { // If our queue is empty - if let Ok(context) = context.try_lock() { + if let Ok(context) = context.lock() { let keystore = context.get_keystore(); // Ask the blockchain if we have to sign something if let Some(block) = context.chain.get_sign_block(&keystore) { diff --git a/src/settings.rs b/src/settings.rs index 563a73d..307239f 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -13,6 +13,8 @@ pub struct Settings { pub origin: String, #[serde(default)] pub key_file: String, + #[serde(default = "default_check_blocks")] + pub check_blocks: u64, #[serde(default)] pub net: Net, #[serde(default)] @@ -50,8 +52,9 @@ impl Settings { impl Default for Settings { fn default() -> Self { Self { - origin: String::from("00000102C2F9BFD2803284D93327F089D60FC72A06F19AF2384567F2646B8348"), + origin: String::from("0AE588D62D710422A7972EA1E8A659CC8E93DB59489ACE32C499CD279B000000"), key_file: String::from("default.key"), + check_blocks: default_check_blocks(), net: Net::default(), dns: Default::default(), mining: Mining::default() @@ -121,5 +124,9 @@ fn default_listen_dns() -> String { } fn default_threads() -> usize { - 20 + 100 +} + +fn default_check_blocks() -> u64 { + 8 } \ No newline at end of file diff --git a/src/web_ui.rs b/src/web_ui.rs index 751e224..f393369 100644 --- a/src/web_ui.rs +++ b/src/web_ui.rs @@ -117,7 +117,7 @@ fn action_check_zone(context: &Arc>, web_view: &mut WebView<()>, } else { let c = context.lock().unwrap(); if let Some(keystore) = c.get_keystore() { - let available = c.get_chain().is_domain_available(&name, &keystore); + let available = c.get_chain().is_domain_available(c.get_chain().get_height(), &name, &keystore); web_view.eval(&format!("zoneAvailable({})", available)).expect("Error evaluating!"); } } @@ -134,7 +134,7 @@ fn action_check_domain(context: &Arc>, web_view: &mut WebView<()> let c = context.lock().unwrap(); if let Some(keystore) = c.get_keystore() { let name = name.to_lowercase(); - let available = c.get_chain().is_domain_available(&name, &keystore); + let available = c.get_chain().is_domain_available(c.get_chain().get_height(), &name, &keystore); web_view.eval(&format!("domainAvailable({})", available)).expect("Error evaluating!"); } } @@ -380,7 +380,7 @@ fn action_create_domain(context: Arc>, miner: Arc>, } } } - match context.chain.can_mine_domain(&name, &pub_key) { + match context.chain.can_mine_domain(context.chain.get_height(), &name, &pub_key) { MineResult::Fine => { let zone = get_domain_zone(&name); let difficulty = context.chain.get_zone_difficulty(&zone); diff --git a/tests/blockchain.db b/tests/blockchain.db new file mode 100644 index 0000000000000000000000000000000000000000..e44189d42459dc707e834e5d1ed2128e895be683 GIT binary patch literal 176128 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 sP3UzFcyVaKwAq)}8*eNY