diff --git a/src/blockchain/chain.rs b/src/blockchain/chain.rs index 78ee988..de5c2c5 100644 --- a/src/blockchain/chain.rs +++ b/src/blockchain/chain.rs @@ -12,6 +12,8 @@ use crate::blockchain::enums::BlockQuality; use crate::blockchain::enums::BlockQuality::*; use crate::blockchain::hash_utils::*; use crate::settings::Settings; +use crate::keys::check_public_key_strength; +use crate::blockchain::KEYSTORE_DIFFICULTY; const DB_NAME: &str = "blockchain.db"; const SQL_CREATE_TABLES: &str = "CREATE TABLE blocks ( @@ -149,21 +151,21 @@ impl Chain { statement.bind(7, transaction.to_string().as_str())?; } } - statement.bind(8, block.prev_block_hash.as_slice())?; - statement.bind(9, block.hash.as_slice())?; - statement.bind(10, block.pub_key.as_slice())?; - statement.bind(11, block.signature.as_slice())?; + statement.bind(8, &**block.prev_block_hash)?; + statement.bind(9, &**block.hash)?; + statement.bind(10, &**block.pub_key)?; + statement.bind(11, &**block.signature)?; statement.next() } /// Adds transaction to transactions table fn add_transaction_to_table(&mut self, t: &Transaction) -> sqlite::Result { let mut statement = self.db.prepare(SQL_ADD_TRANSACTION)?; - statement.bind(1, t.identity.as_slice())?; - statement.bind(2, t.confirmation.as_slice())?; + statement.bind(1, &**t.identity)?; + statement.bind(2, &**t.confirmation)?; statement.bind(3, t.method.as_ref() as &str)?; statement.bind(4, t.data.as_ref() as &str)?; - statement.bind(5, t.pub_key.as_slice())?; + statement.bind(5, &**t.pub_key)?; statement.next() } @@ -241,9 +243,9 @@ impl Chain { /// 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) -> bool { let mut statement = self.db.prepare(SQL_GET_PUBLIC_KEY_BY_ID).unwrap(); - statement.bind(1, identity.as_slice()).expect("Error in bind"); + statement.bind(1, &***identity).expect("Error in bind"); while let State::Row = statement.next().unwrap() { - let pub_key = Bytes::from_bytes(statement.read::>(0).unwrap().as_slice()); + let pub_key = Bytes::from_bytes(&statement.read::>(0).unwrap()); if !pub_key.eq(public_key) { return false; } @@ -260,7 +262,7 @@ impl Chain { // Checking for existing zone in DB let identity_hash = hash_identity(zone, None); let mut statement = self.db.prepare(SQL_GET_ID_BY_ID).unwrap(); - statement.bind(1, identity_hash.as_slice()).expect("Error in bind"); + statement.bind(1, &**identity_hash).expect("Error in bind"); while let State::Row = statement.next().unwrap() { // If there is such a zone self.zones.borrow_mut().insert(zone.to_owned()); @@ -277,13 +279,13 @@ impl Chain { let identity_hash = hash_identity(domain, None); let mut statement = self.db.prepare(SQL_GET_TRANSACTION_BY_ID).unwrap(); - statement.bind(1, identity_hash.as_slice()).expect("Error in bind"); + statement.bind(1, &**identity_hash).expect("Error in bind"); while let State::Row = statement.next().unwrap() { - let identity = Bytes::from_bytes(statement.read::>(1).unwrap().as_slice()); - let confirmation = Bytes::from_bytes(statement.read::>(2).unwrap().as_slice()); + let identity = Bytes::from_bytes(&statement.read::>(1).unwrap()); + let confirmation = Bytes::from_bytes(&statement.read::>(2).unwrap()); let method = statement.read::(3).unwrap(); let data = statement.read::(4).unwrap(); - let pub_key = Bytes::from_bytes(statement.read::>(5).unwrap().as_slice()); + let pub_key = Bytes::from_bytes(&statement.read::>(5).unwrap()); let transaction = Transaction { identity, confirmation, method, data, pub_key }; debug!("Found transaction for domain {}: {:?}", domain, &transaction); if transaction.check_identity(domain) { @@ -337,6 +339,10 @@ impl Chain { warn!("Ignoring block from the future:\n{:?}", &block); return Bad; } + if !check_public_key_strength(&block.pub_key, KEYSTORE_DIFFICULTY) { + warn!("Ignoring block with weak public key:\n{:?}", &block); + return Bad; + } let difficulty = match block.transaction { None => { LOCKER_DIFFICULTY } Some(_) => { BLOCK_DIFFICULTY } @@ -345,7 +351,7 @@ impl Chain { warn!("Block difficulty is lower than needed"); return Bad; } - if !hash_is_good(block.hash.as_slice(), block.difficulty as usize) { + if !hash_is_good(&block.hash, block.difficulty as usize) { warn!("Ignoring block with low difficulty:\n{:?}", &block); return Bad; } diff --git a/src/blockchain/hash_utils.rs b/src/blockchain/hash_utils.rs index 2c3e92a..3918e44 100644 --- a/src/blockchain/hash_utils.rs +++ b/src/blockchain/hash_utils.rs @@ -7,7 +7,7 @@ use num_traits::One; use crate::{Block, Bytes, Keystore}; /// Creates needed hasher by current blockchain version -fn get_hasher_for_version(version: u32) -> Box { +pub(crate) fn get_hasher_for_version(version: u32) -> Box { match version { 2 => Box::new(Blakeout::default()), _ => Box::new(Sha256::new()) @@ -41,7 +41,7 @@ pub fn hash_data(digest: &mut dyn Digest, data: &[u8]) -> Bytes { pub fn check_block_signature(block: &Block) -> bool { let mut copy = block.clone(); copy.signature = Bytes::default(); - Keystore::check(©.as_bytes(), copy.pub_key.as_slice(), block.signature.as_slice()) + Keystore::check(©.as_bytes(), ©.pub_key, &block.signature) } /// Hashes some identity (domain in case of DNS). If you give it a public key, it will hash with it as well. diff --git a/src/bytes.rs b/src/bytes.rs index 586fdaf..55fcb2d 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -11,6 +11,7 @@ use num_bigint::BigUint; use serde::{Deserialize, Deserializer, Serialize, Serializer}; // For deserialization use serde::de::{Error as DeError, Visitor}; +use std::ops::Deref; #[derive(Clone)] pub struct Bytes { @@ -56,10 +57,6 @@ impl Bytes { self.data.as_mut_slice() } - pub fn as_vec(&self) -> &Vec { - &self.data - } - pub fn to_string(&self) -> String { crate::utils::to_hex(&self.data) } @@ -87,11 +84,11 @@ impl Default for Bytes { impl PartialEq for Bytes { fn eq(&self, other: &Self) -> bool { - crate::blockchain::hash_utils::same_hash(&self.data, &other.data) + crate::blockchain::hash_utils::same_hash(&self, &other) } fn ne(&self, other: &Self) -> bool { - !crate::blockchain::hash_utils::same_hash(&self.data, &other.data) + !crate::blockchain::hash_utils::same_hash(&self, &other) } } @@ -99,20 +96,28 @@ impl Eq for Bytes {} impl PartialOrd for Bytes { fn partial_cmp(&self, other: &Self) -> Option { - let self_hash_int = BigUint::from_bytes_be(&self.data); - let other_hash_int = BigUint::from_bytes_be(&other.data); + let self_hash_int = BigUint::from_bytes_le(&self); + let other_hash_int = BigUint::from_bytes_le(&other); Some(self_hash_int.cmp(&other_hash_int)) } } impl Ord for Bytes { fn cmp(&self, other: &Self) -> Ordering { - let self_hash_int = BigUint::from_bytes_be(&self.data); - let other_hash_int = BigUint::from_bytes_be(&other.data); + let self_hash_int = BigUint::from_bytes_le(&self); + let other_hash_int = BigUint::from_bytes_le(&other); self_hash_int.cmp(&other_hash_int) } } +impl Deref for Bytes { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + impl fmt::Debug for Bytes { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str(&crate::utils::to_hex(&self.data)) @@ -161,10 +166,17 @@ impl<'dd> Deserialize<'dd> for Bytes { #[cfg(test)] mod tests { use crate::bytes::Bytes; + use crate::blockchain::hash_utils::same_hash; #[test] pub fn test_tail_bytes() { let bytes = Bytes::new(vec![0, 255, 255, 255, 0, 255, 255, 255]); assert_eq!(bytes.get_tail_u64(), 72057589759737855u64); } + + #[test] + pub fn test_deref() { + let bytes = Bytes::zero32(); + assert!(same_hash(&bytes, &vec!(0u8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))); + } } diff --git a/src/keys.rs b/src/keys.rs index 06a0a0a..a641366 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -94,13 +94,13 @@ impl Keystore { pub fn get_hash(&self) -> Bytes { if self.hash.borrow().is_empty() { - self.hash.replace(hash_data(&mut Blakeout::default(), &self.public_key.as_slice())); + self.hash.replace(hash_data(&mut Blakeout::default(), &self.public_key)); } self.hash.borrow().clone() } pub fn sign(&self, message: &[u8]) -> [u8; 64] { - signature(message, self.private_key.as_slice()) + signature(message, &self.private_key) } pub fn check(message: &[u8], public_key: &[u8], signature: &[u8]) -> bool { @@ -108,6 +108,13 @@ impl Keystore { } } +/// Checks if some public key is "strong" enough to mine domains +/// TODO Optimize by caching Blakeout somewhere +pub fn check_public_key_strength(key: &Bytes, strength: usize) -> bool { + let bytes = hash_data(&mut Blakeout::default(), &key); + hash_is_good(&bytes, strength) +} + pub fn create_key(context: Arc>) { let mining = Arc::new(AtomicBool::new(true)); let miners_count = Arc::new(AtomicUsize::new(0)); @@ -160,7 +167,7 @@ fn generate_key(difficulty: usize, mining: Arc) -> Option rng.fill_bytes(&mut buf); let keystore = Keystore::from_bytes(&buf); digest.reset(); - digest.input(keystore.public_key.as_slice()); + digest.input(&keystore.public_key); digest.result(&mut buf); if hash_is_good(&buf, difficulty) { info!("Generated keypair: {:?}", &keystore); @@ -181,7 +188,7 @@ fn generate_key(difficulty: usize, mining: Arc) -> Option #[cfg(test)] mod tests { - use crate::{Bytes, Keystore}; + use crate::Keystore; #[test] pub fn test_signature() { @@ -189,6 +196,6 @@ mod tests { let data = b"{ identity: 178135D209C697625E3EC71DA5C760382E54936F824EE5083908DA66B14ECE18,\ confirmation: A4A0AFECD1A511825226F0D3437C6C6BDAE83554040AA7AEB49DEFEAB0AE9EA4 }"; let signature = keystore.sign(data); - assert!(Keystore::check(data, keystore.get_public().as_slice(), &signature), "Wrong signature!") + assert!(Keystore::check(data, &keystore.get_public(), &signature), "Wrong signature!") } } \ No newline at end of file diff --git a/src/miner.rs b/src/miner.rs index 9d633d5..25b1663 100644 --- a/src/miner.rs +++ b/src/miner.rs @@ -5,7 +5,6 @@ use std::time::Duration; use chrono::Utc; use crypto::digest::Digest; -use crypto::sha2::Sha256; #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; use num_cpus; @@ -13,9 +12,10 @@ use num_cpus; use thread_priority::*; use crate::{Block, Bytes, Context}; -use crate::blockchain::{BLOCK_DIFFICULTY, CHAIN_VERSION, LOCKER_DIFFICULTY}; +use crate::blockchain::{BLOCK_DIFFICULTY, CHAIN_VERSION, LOCKER_DIFFICULTY, KEYSTORE_DIFFICULTY}; use crate::blockchain::enums::BlockQuality; use crate::blockchain::hash_utils::*; +use crate::keys::check_public_key_strength; use crate::event::Event; pub struct Miner { @@ -113,6 +113,12 @@ impl Miner { info!("Mining locker block"); block.difficulty = LOCKER_DIFFICULTY; block.pub_key = context.lock().unwrap().keystore.get_public(); + if !check_public_key_strength(&block.pub_key, KEYSTORE_DIFFICULTY) { + warn!("Can not mine block with weak public key!"); + context.lock().unwrap().bus.post(Event::MinerStopped); + mining.store(false, Ordering::SeqCst); + return; + } match context.lock().unwrap().chain.last_block() { None => {} Some(last_block) => { @@ -148,7 +154,7 @@ impl Miner { #[cfg(not(target_os = "macos"))] let _ = set_current_thread_priority(ThreadPriority::Min); live_threads.fetch_add(1, Ordering::SeqCst); - match find_hash(&mut Sha256::new(), block, mining.clone()) { + match find_hash(&mut *get_hasher_for_version(block.version), block, mining.clone()) { None => { debug!("Mining was cancelled"); let count = live_threads.fetch_sub(1, Ordering::SeqCst);