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