diff --git a/Cargo.toml b/Cargo.toml index 2b07647..a0f2395 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ repository = "https://github.com/Revertron/Alfis" [dependencies] getopts = "0.2.21" log = "0.4.14" -toml = "0.5.8" simple_logger = "1.11.0" +toml = "0.5.8" rust-crypto = "^0.2" blakeout = "0.1.0" num_cpus = "1.13.0" @@ -27,7 +27,7 @@ num-traits = "0.2" bincode = "1.2.0" base64 = "0.11.0" chrono = { version = "0.4.13", features = ["serde"] } -rand = "0.7.2" +rand = "0.8.3" sqlite = "0.25.3" uuid = { version = "0.8.2", features = ["serde", "v4"] } mio = { version = "0.7", features = ["os-poll", "net"] } diff --git a/other-tlds.txt b/other-tlds.txt new file mode 100644 index 0000000..955a50c --- /dev/null +++ b/other-tlds.txt @@ -0,0 +1,32 @@ +# OpenNIC zones +bbs +chan +cyb +dyn +geek +gopher +indy +libre +neo +null +o +oss +oz +parody +pirate +# Namecoin zone +bit +# Etherium +eth +# EmerCoin +emc +coin +lib +bazar +# Reserved +example +invalid +local +localhost +onion +test \ No newline at end of file diff --git a/src/blockchain/chain.rs b/src/blockchain/chain.rs index de5c2c5..dd079ff 100644 --- a/src/blockchain/chain.rs +++ b/src/blockchain/chain.rs @@ -7,13 +7,12 @@ use log::{debug, error, info, trace, warn}; use sqlite::{Connection, State, Statement}; use crate::{Block, Bytes, Keystore, Transaction}; -use crate::blockchain::constants::{BLOCK_DIFFICULTY, CHAIN_VERSION, LOCKER_BLOCK_COUNT, LOCKER_BLOCK_INTERVAL, LOCKER_BLOCK_START, LOCKER_DIFFICULTY}; +use crate::blockchain::constants::*; 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 ( @@ -37,6 +36,7 @@ const SQL_GET_LAST_BLOCK: &str = "SELECT * FROM blocks ORDER BY id DESC LIMIT 1; const SQL_ADD_TRANSACTION: &str = "INSERT INTO transactions (identity, confirmation, method, data, pub_key) VALUES (?, ?, ?, ?, ?)"; 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 `transaction`<>'' ORDER BY id DESC LIMIT 1;"; +const SQL_GET_LAST_FULL_BLOCK_FOR_KEY: &str = "SELECT * FROM blocks WHERE `transaction`<>'' AND pub_key = ? ORDER BY id DESC LIMIT 1;"; const SQL_GET_PUBLIC_KEY_BY_ID: &str = "SELECT pub_key FROM transactions WHERE identity = ? ORDER BY id DESC LIMIT 1;"; const SQL_GET_ID_BY_ID: &str = "SELECT identity FROM transactions WHERE identity = ? ORDER BY id DESC LIMIT 1;"; const SQL_GET_TRANSACTION_BY_ID: &str = "SELECT * FROM transactions WHERE identity = ? ORDER BY id DESC LIMIT 1;"; @@ -112,7 +112,7 @@ impl Chain { if block.transaction.is_some() { self.last_full_block = Some(block); } else { - self.last_full_block = self.get_last_full_block(); + self.last_full_block = self.get_last_full_block(None); } } } @@ -195,28 +195,30 @@ impl Chain { } /// Gets last block that has a Transaction within - pub fn get_last_full_block(&self) -> Option { - match self.db.prepare(SQL_GET_LAST_FULL_BLOCK) { - Ok(mut statement) => { - while statement.next().unwrap() == State::Row { - return match Self::get_block_from_statement(&mut statement) { - None => { - error!("Something wrong with block in DB!"); - None - } - Some(block) => { - trace!("Got last full block: {:?}", &block); - Some(block) - } - }; + pub fn get_last_full_block(&self, pub_key: Option<&[u8]>) -> Option { + let mut statement = match pub_key { + None => { + self.db.prepare(SQL_GET_LAST_FULL_BLOCK).expect("Unable to prepare") + } + Some(pub_key) => { + let mut statement = self.db.prepare(SQL_GET_LAST_FULL_BLOCK_FOR_KEY).expect("Unable to prepare"); + statement.bind(1, pub_key).expect("Unable to bind"); + statement + } + }; + while statement.next().unwrap() == State::Row { + return match Self::get_block_from_statement(&mut statement) { + None => { + error!("Something wrong with block in DB!"); + None } - None - } - Err(e) => { - warn!("Can't find any full blocks: {}", e); - None - } + Some(block) => { + trace!("Got last full block: {:?}", &block); + Some(block) + } + }; } + None } /// Checks if any domain is available to mine for this client (pub_key) @@ -368,6 +370,13 @@ impl Chain { warn!("Block {:?} is trying to spoof an identity!", &block); return Bad; } + // TODO check only blocks with new identity + if let Some(last) = self.get_last_full_block(Some(&block.pub_key)) { + if last.timestamp + FULL_BLOCKS_INTERVAL > block.timestamp { + warn!("Block {:?} is mined too early!", &block); + return Bad; + } + } } match &self.last_block { None => { @@ -426,7 +435,7 @@ impl Chain { if block.index < LOCKER_BLOCK_START { return None; } - match self.get_last_full_block() { + match self.get_last_full_block(None) { Some(b) => { if b.index + LOCKER_BLOCK_COUNT <= block.index { trace!("Block {} is locked enough", b.index); diff --git a/src/blockchain/constants.rs b/src/blockchain/constants.rs index a737b1a..0ebc1e2 100644 --- a/src/blockchain/constants.rs +++ b/src/blockchain/constants.rs @@ -7,3 +7,5 @@ pub const KEYSTORE_DIFFICULTY: usize = 25; pub const LOCKER_BLOCK_START: u64 = 10; pub const LOCKER_BLOCK_COUNT: u64 = 3; pub const LOCKER_BLOCK_INTERVAL: i64 = 300; + +pub const FULL_BLOCKS_INTERVAL: i64 = 86400; // One day in seconds diff --git a/src/context.rs b/src/context.rs index 0aa8bff..788ef55 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,4 +1,4 @@ -use crate::{Chain, Bus, Keystore, Settings, Iana}; +use crate::{Chain, Bus, Keystore, Settings, ExternalZones}; use crate::event::Event; #[allow(unused_imports)] use log::{trace, debug, info, warn, error}; @@ -7,14 +7,14 @@ pub struct Context { pub settings: Settings, pub keystore: Keystore, pub chain: Chain, - pub iana: Iana, + pub iana: ExternalZones, pub bus: Bus, } impl Context { /// Creating an essential context to work with pub fn new(settings: Settings, keystore: Keystore, chain: Chain) -> Context { - Context { settings, keystore, chain, iana: Iana::new(), bus: Bus::new() } + Context { settings, keystore, chain, iana: ExternalZones::new(), bus: Bus::new() } } /// Load keystore and return Context diff --git a/src/iana.rs b/src/iana.rs deleted file mode 100644 index da58145..0000000 --- a/src/iana.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::collections::HashSet; - -pub struct Iana { - zones: HashSet, - hashes: HashSet -} - -impl Iana { - pub fn new() -> Self { - let zones: HashSet<_> = include_str!("../iana-tlds.txt") - .split("\n") - .map(String::from) - .collect(); - let hashes: HashSet<_> = include_str!("../iana-hashes.txt") - .split("\n") - .map(String::from) - .collect(); - Self { zones, hashes } - } - - pub fn has_zone(&self, zone: &str) -> bool { - self.zones.contains(zone) - } - - pub fn has_hash(&self, hash: &str) -> bool { - self.hashes.contains(hash) - } -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 19b14bd..10abe0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ pub use crate::p2p::Network; pub use crate::settings::Settings; pub use crate::bytes::Bytes; pub use crate::keys::Keystore; -pub use crate::iana::Iana; +pub use crate::x_zones::ExternalZones; pub use crate::simplebus::*; pub use crate::utils::*; @@ -24,5 +24,5 @@ pub mod dns; pub mod dns_utils; pub mod settings; pub mod bytes; -pub mod iana; +pub mod x_zones; diff --git a/src/x_zones.rs b/src/x_zones.rs new file mode 100644 index 0000000..e0af438 --- /dev/null +++ b/src/x_zones.rs @@ -0,0 +1,41 @@ +use std::collections::HashSet; +use crate::blockchain::hash_utils::hash_identity; + +pub struct ExternalZones { + zones: HashSet, + hashes: HashSet +} + +impl ExternalZones { + pub fn new() -> Self { + let mut zones: HashSet<_> = include_str!("../iana-tlds.txt") + .split("\n") + .map(String::from) + .collect(); + let mut hashes: HashSet<_> = include_str!("../iana-hashes.txt") + .split("\n") + .map(String::from) + .collect(); + let open_nic: HashSet<_> = include_str!("../other-tlds.txt") + .split("\n") + .map(String::from) + .collect(); + for zone in open_nic.iter() { + if zone.is_empty() || zone.starts_with("#") { + continue; + } + zones.insert(zone.to_string()); + hashes.insert(hash_identity(zone, None).to_string()); + } + + Self { zones, hashes } + } + + pub fn has_zone(&self, zone: &str) -> bool { + self.zones.contains(zone) + } + + pub fn has_hash(&self, hash: &str) -> bool { + self.hashes.contains(hash) + } +} \ No newline at end of file