First commit of 0.5.* branch.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "alfis"
|
name = "alfis"
|
||||||
version = "0.4.37"
|
version = "0.5.0"
|
||||||
authors = ["Revertron <alfis@revertron.com>"]
|
authors = ["Revertron <alfis@revertron.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Alternative Free Identity System
|
Alternative Free Identity System
|
||||||
|
|
||||||
This project represents a minimal blockchain without cryptocurrency, capable of sustaining any number of domain name zones and domains.
|
This project represents a minimal blockchain without cryptocurrency, capable of sustaining any number of domain names in a bunch of original alternative zones.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -32,4 +32,5 @@ onion
|
|||||||
i2p
|
i2p
|
||||||
meshname
|
meshname
|
||||||
meship
|
meship
|
||||||
|
mem
|
||||||
test
|
test
|
||||||
+63
-108
@@ -1,6 +1,8 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashSet, HashMap};
|
use std::cmp::max;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
@@ -8,38 +10,32 @@ use chrono::Utc;
|
|||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use sqlite::{Connection, State, Statement};
|
use sqlite::{Connection, State, Statement};
|
||||||
|
|
||||||
use crate::{Block, Bytes, Keystore, Transaction, check_domain, get_domain_zone, is_yggdrasil_record};
|
use crate::{Block, Bytes, check_domain, get_domain_zone, is_yggdrasil_record, Keystore, Transaction};
|
||||||
use crate::blockchain::transaction::TransactionType;
|
|
||||||
use crate::commons::constants::*;
|
|
||||||
use crate::blockchain::types::{BlockQuality, MineResult, Options};
|
|
||||||
use crate::blockchain::types::BlockQuality::*;
|
|
||||||
use crate::blockchain::hash_utils::*;
|
use crate::blockchain::hash_utils::*;
|
||||||
use crate::settings::Settings;
|
use crate::blockchain::transaction::DomainData;
|
||||||
use crate::keys::check_public_key_strength;
|
use crate::blockchain::types::{BlockQuality, MineResult, Options, ZoneData};
|
||||||
use std::cmp::max;
|
use crate::blockchain::types::BlockQuality::*;
|
||||||
use crate::blockchain::transaction::{ZoneData, DomainData};
|
|
||||||
use std::ops::Deref;
|
|
||||||
use crate::blockchain::types::MineResult::*;
|
use crate::blockchain::types::MineResult::*;
|
||||||
|
use crate::commons::constants::*;
|
||||||
|
use crate::keys::check_public_key_strength;
|
||||||
|
use crate::settings::Settings;
|
||||||
|
|
||||||
const TEMP_DB_NAME: &str = "temp.db";
|
const TEMP_DB_NAME: &str = ":memory:";
|
||||||
const SQL_CREATE_TABLES: &str = include_str!("sql/create_db.sql");
|
const SQL_CREATE_TABLES: &str = include_str!("data/create_db.sql");
|
||||||
|
const ZONES_TXT: &str = include_str!("data/zones.txt");
|
||||||
const SQL_ADD_BLOCK: &str = "INSERT INTO blocks (id, timestamp, version, difficulty, random, nonce, 'transaction',\
|
const SQL_ADD_BLOCK: &str = "INSERT INTO blocks (id, timestamp, version, difficulty, random, nonce, 'transaction',\
|
||||||
prev_block_hash, hash, pub_key, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
|
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_LAST_BLOCK: &str = "SELECT * FROM blocks ORDER BY id DESC LIMIT 1;";
|
||||||
const SQL_TRUNCATE_BLOCKS: &str = "DELETE FROM blocks 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_DOMAINS: &str = "DELETE FROM domains WHERE id >= ?;";
|
||||||
const SQL_TRUNCATE_ZONES: &str = "DELETE FROM zones WHERE id >= ?;";
|
|
||||||
|
|
||||||
const SQL_ADD_DOMAIN: &str = "INSERT INTO domains (id, timestamp, identity, confirmation, data, pub_key) VALUES (?, ?, ?, ?, ?, ?)";
|
const SQL_ADD_DOMAIN: &str = "INSERT INTO domains (id, timestamp, identity, confirmation, data, owner) VALUES (?, ?, ?, ?, ?, ?)";
|
||||||
const SQL_ADD_ZONE: &str = "INSERT INTO zones (id, timestamp, identity, confirmation, data, pub_key) VALUES (?, ?, ?, ?, ?, ?)";
|
|
||||||
const SQL_GET_BLOCK_BY_ID: &str = "SELECT * FROM blocks WHERE id=? LIMIT 1;";
|
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: &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_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 id < ? AND identity = ? LIMIT 1;";
|
const SQL_GET_DOMAIN_OWNER_BY_ID: &str = "SELECT owner 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_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_DOMAINS_BY_KEY: &str = "SELECT * FROM domains WHERE owner = ?;";
|
||||||
const SQL_GET_ZONES: &str = "SELECT data FROM zones;";
|
|
||||||
|
|
||||||
const SQL_GET_OPTIONS: &str = "SELECT * FROM options;";
|
const SQL_GET_OPTIONS: &str = "SELECT * FROM options;";
|
||||||
|
|
||||||
@@ -52,7 +48,7 @@ pub struct Chain {
|
|||||||
last_full_block: Option<Block>,
|
last_full_block: Option<Block>,
|
||||||
max_height: u64,
|
max_height: u64,
|
||||||
db: Connection,
|
db: Connection,
|
||||||
zones: RefCell<HashSet<String>>,
|
zones: Vec<ZoneData>,
|
||||||
signers: RefCell<SignersCache>,
|
signers: RefCell<SignersCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +57,7 @@ impl Chain {
|
|||||||
let origin = settings.get_origin();
|
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 zones = Self::load_zones();
|
||||||
let mut chain = Chain { origin, last_block: None, last_full_block: None, max_height: 0, db, zones, signers: SignersCache::new() };
|
let mut chain = Chain { origin, last_block: None, last_full_block: None, max_height: 0, db, zones, signers: SignersCache::new() };
|
||||||
chain.init_db();
|
chain.init_db();
|
||||||
chain
|
chain
|
||||||
@@ -164,10 +160,6 @@ impl Chain {
|
|||||||
|
|
||||||
let mut statement = self.db.prepare(SQL_TRUNCATE_DOMAINS)?;
|
let mut statement = self.db.prepare(SQL_TRUNCATE_DOMAINS)?;
|
||||||
statement.bind(1, index as i64)?;
|
statement.bind(1, index as i64)?;
|
||||||
statement.next()?;
|
|
||||||
|
|
||||||
let mut statement = self.db.prepare(SQL_TRUNCATE_ZONES)?;
|
|
||||||
statement.bind(1, index as i64)?;
|
|
||||||
statement.next()
|
statement.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +357,6 @@ impl Chain {
|
|||||||
fn add_transaction_to_table(&mut self, index: u64, timestamp: i64, t: &Transaction) -> sqlite::Result<State> {
|
fn add_transaction_to_table(&mut self, index: u64, timestamp: i64, t: &Transaction) -> sqlite::Result<State> {
|
||||||
let sql = match t.class.as_ref() {
|
let sql = match t.class.as_ref() {
|
||||||
"domain" => SQL_ADD_DOMAIN,
|
"domain" => SQL_ADD_DOMAIN,
|
||||||
"zone" => SQL_ADD_ZONE,
|
|
||||||
_ => return Err(sqlite::Error { code: None, message: None })
|
_ => return Err(sqlite::Error { code: None, message: None })
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -375,7 +366,7 @@ impl Chain {
|
|||||||
statement.bind(3, &**t.identity)?;
|
statement.bind(3, &**t.identity)?;
|
||||||
statement.bind(4, &**t.confirmation)?;
|
statement.bind(4, &**t.confirmation)?;
|
||||||
statement.bind(5, t.data.as_ref() as &str)?;
|
statement.bind(5, t.data.as_ref() as &str)?;
|
||||||
statement.bind(6, &**t.pub_key)?;
|
statement.bind(6, &**t.owner)?;
|
||||||
statement.next()
|
statement.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,7 +444,7 @@ impl Chain {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let identity_hash = hash_identity(domain, None);
|
let identity_hash = hash_identity(domain, None);
|
||||||
if !self.is_id_available(height, &identity_hash, &keystore.get_public(), false) {
|
if !self.is_id_available(height, &identity_hash, &keystore.get_public()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,19 +454,15 @@ impl Chain {
|
|||||||
if parts.last().unwrap().contains(".") {
|
if parts.last().unwrap().contains(".") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return self.is_zone_in_blockchain(height, parts.first().unwrap());
|
return self.is_available_zone(parts.first().unwrap());
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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, height: u64, identity: &Bytes, public_key: &Bytes, zone: bool) -> bool {
|
pub fn is_id_available(&self, height: u64, identity: &Bytes, public_key: &Bytes) -> bool {
|
||||||
let sql = match zone {
|
// TODO check for `owner` field
|
||||||
true => { SQL_GET_ZONE_PUBLIC_KEY_BY_ID }
|
let mut statement = self.db.prepare(SQL_GET_DOMAIN_OWNER_BY_ID).unwrap();
|
||||||
false => { SQL_GET_DOMAIN_PUBLIC_KEY_BY_ID }
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut statement = self.db.prepare(sql).unwrap();
|
|
||||||
statement.bind(1, height as i64).expect("Error in bind");
|
statement.bind(1, height as i64).expect("Error in bind");
|
||||||
statement.bind(2, &***identity).expect("Error in bind");
|
statement.bind(2, &***identity).expect("Error in bind");
|
||||||
while let State::Row = statement.next().unwrap() {
|
while let State::Row = statement.next().unwrap() {
|
||||||
@@ -487,50 +474,39 @@ impl Chain {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_zones(&self) -> Vec<ZoneData> {
|
pub fn get_zones(&self) -> &Vec<ZoneData> {
|
||||||
let mut map = HashMap::new();
|
&self.zones
|
||||||
match self.db.prepare(SQL_GET_ZONES) {
|
|
||||||
Ok(mut statement) => {
|
|
||||||
while statement.next().unwrap() == State::Row {
|
|
||||||
let data = statement.read::<String>(0).unwrap();
|
|
||||||
//debug!("Got zone data {}", &data);
|
|
||||||
if let Ok(zone_data) = serde_json::from_str::<ZoneData>(&data) {
|
|
||||||
map.insert(zone_data.name.clone(), zone_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_zones() -> Vec<ZoneData> {
|
||||||
|
let mut result: Vec<ZoneData> = Vec::new();
|
||||||
|
let zones: Vec<_> = ZONES_TXT.split("\n").collect();
|
||||||
|
for zone in zones {
|
||||||
|
let yggdrasil = zone == "ygg" || zone == "anon";
|
||||||
|
result.push(ZoneData {name: zone.to_owned(), yggdrasil})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("Can't get zones from DB {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let result: Vec<ZoneData> = map.drain().map(|(_, value)| value).collect();
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if some zone exists in our blockchain
|
pub fn get_zones_hash() -> Bytes {
|
||||||
pub fn is_zone_in_blockchain(&self, height: u64, zone: &str) -> bool {
|
Bytes::from_bytes(hash_sha256(&ZONES_TXT.as_bytes()).as_slice())
|
||||||
if self.zones.borrow().contains(zone) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checking for existing zone in DB
|
/// Checks if some zone exists in our blockchain
|
||||||
let identity_hash = hash_identity(zone, None);
|
pub fn is_available_zone(&self, zone: &str) -> bool {
|
||||||
if self.is_id_in_blockchain(height, &identity_hash, true) {
|
for z in &self.zones {
|
||||||
// If there is such a zone
|
if z.name == zone {
|
||||||
self.zones.borrow_mut().insert(zone.to_owned());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if some id exists in our blockchain
|
/// Checks if some id exists in our blockchain
|
||||||
pub fn is_id_in_blockchain(&self, height: u64, id: &Bytes, zone: bool) -> bool {
|
pub fn is_domain_in_blockchain(&self, height: u64, id: &Bytes) -> bool {
|
||||||
let sql = match zone {
|
// Checking for existing domain in DB
|
||||||
true => { SQL_GET_ZONE_PUBLIC_KEY_BY_ID }
|
let mut statement = self.db.prepare(SQL_GET_DOMAIN_OWNER_BY_ID).unwrap();
|
||||||
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, height as i64).expect("Error in bind");
|
statement.bind(1, height as i64).expect("Error in bind");
|
||||||
statement.bind(2, &***id).expect("Error in bind");
|
statement.bind(2, &***id).expect("Error in bind");
|
||||||
while let State::Row = statement.next().unwrap() {
|
while let State::Row = statement.next().unwrap() {
|
||||||
@@ -546,17 +522,18 @@ impl Chain {
|
|||||||
return WrongName;
|
return WrongName;
|
||||||
}
|
}
|
||||||
let zone = get_domain_zone(&name);
|
let zone = get_domain_zone(&name);
|
||||||
if !self.is_zone_in_blockchain(height, &zone) {
|
if !self.is_available_zone(&zone) {
|
||||||
return WrongZone;
|
return WrongZone;
|
||||||
}
|
}
|
||||||
if let Some(transaction) = self.get_domain_transaction(&name) {
|
if let Some(transaction) = self.get_domain_transaction(&name) {
|
||||||
if transaction.pub_key.ne(pub_key) {
|
if transaction.owner.ne(pub_key) {
|
||||||
return NotOwned;
|
return NotOwned;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let identity_hash = hash_identity(&name, None);
|
let identity_hash = hash_identity(&name, None);
|
||||||
|
// TODO extract method
|
||||||
if let Some(last) = self.get_last_full_block(MAX, Some(&pub_key)) {
|
if let Some(last) = self.get_last_full_block(MAX, Some(&pub_key)) {
|
||||||
let new_id = !self.is_id_in_blockchain(height, &identity_hash, false);
|
let new_id = !self.is_domain_in_blockchain(height, &identity_hash);
|
||||||
let time = last.timestamp + NEW_DOMAINS_INTERVAL - Utc::now().timestamp();
|
let time = last.timestamp + NEW_DOMAINS_INTERVAL - Utc::now().timestamp();
|
||||||
if new_id && time > 0 {
|
if new_id && time > 0 {
|
||||||
return Cooldown { time }
|
return Cooldown { time }
|
||||||
@@ -586,7 +563,7 @@ impl Chain {
|
|||||||
let class = String::from("domain");
|
let class = String::from("domain");
|
||||||
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());
|
let pub_key = Bytes::from_bytes(&statement.read::<Vec<u8>>(5).unwrap());
|
||||||
let transaction = Transaction { identity, confirmation, class, data, pub_key };
|
let transaction = Transaction { identity, confirmation, class, data, owner: 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) {
|
||||||
return Some(transaction);
|
return Some(transaction);
|
||||||
@@ -619,8 +596,8 @@ impl Chain {
|
|||||||
let confirmation = Bytes::from_bytes(&statement.read::<Vec<u8>>(3).unwrap());
|
let confirmation = Bytes::from_bytes(&statement.read::<Vec<u8>>(3).unwrap());
|
||||||
let class = String::from("domain");
|
let class = String::from("domain");
|
||||||
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());
|
let owner = Bytes::from_bytes(&statement.read::<Vec<u8>>(5).unwrap());
|
||||||
let transaction = Transaction { identity: identity.clone(), confirmation: confirmation.clone(), class, data, pub_key };
|
let transaction = Transaction { identity: identity.clone(), confirmation: confirmation.clone(), class, data, owner };
|
||||||
//debug!("Found transaction for domain {}: {:?}", domain, &transaction);
|
//debug!("Found transaction for domain {}: {:?}", domain, &transaction);
|
||||||
if let Some(data) = transaction.get_domain_data() {
|
if let Some(data) = transaction.get_domain_data() {
|
||||||
let mut domain = keystore.decrypt(data.domain.as_slice(), &confirmation.as_slice()[..12]);
|
let mut domain = keystore.decrypt(data.domain.as_slice(), &confirmation.as_slice()[..12]);
|
||||||
@@ -646,16 +623,6 @@ impl Chain {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_zone_difficulty(&self, zone: &str) -> u32 {
|
|
||||||
let zones = self.get_zones();
|
|
||||||
for z in zones.iter() {
|
|
||||||
if z.name.eq(zone) {
|
|
||||||
return z.difficulty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u32::MAX
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn last_block(&self) -> Option<Block> {
|
pub fn last_block(&self) -> Option<Block> {
|
||||||
self.last_block.clone()
|
self.last_block.clone()
|
||||||
}
|
}
|
||||||
@@ -732,7 +699,7 @@ impl Chain {
|
|||||||
let difficulty = match &block.transaction {
|
let difficulty = match &block.transaction {
|
||||||
None => {
|
None => {
|
||||||
if block.index == 1 {
|
if block.index == 1 {
|
||||||
ZONE_DIFFICULTY
|
ORIGIN_DIFFICULTY
|
||||||
} else {
|
} else {
|
||||||
SIGNER_DIFFICULTY
|
SIGNER_DIFFICULTY
|
||||||
}
|
}
|
||||||
@@ -767,28 +734,20 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if matches!(Transaction::get_type(&block.transaction), TransactionType::Zone) {
|
|
||||||
if self.get_zones().len() >= MAXIMUM_ZONES {
|
|
||||||
warn!("Ignoring excess zone block");
|
|
||||||
return Bad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(transaction) = &block.transaction {
|
if let Some(transaction) = &block.transaction {
|
||||||
let current_height = match last_block {
|
let current_height = match last_block {
|
||||||
None => { 0 }
|
None => { 0 }
|
||||||
Some(block) => { block.index }
|
Some(block) => { block.index }
|
||||||
};
|
};
|
||||||
// TODO check for zone transaction
|
// If this domain is available to this public key
|
||||||
let is_domain_available = self.is_id_available(current_height, &transaction.identity, &block.pub_key, false);
|
if !self.is_id_available(current_height, &transaction.identity, &block.pub_key) {
|
||||||
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);
|
warn!("Block {:?} is trying to spoof an identity!", &block);
|
||||||
return Bad;
|
return Bad;
|
||||||
}
|
}
|
||||||
if let Some(last) = self.get_last_full_block(block.index, Some(&block.pub_key)) {
|
if let Some(last) = self.get_last_full_block(block.index, Some(&block.pub_key)) {
|
||||||
if last.index < block.index {
|
if last.index < block.index {
|
||||||
let new_id = !self.is_id_in_blockchain(block.index, &transaction.identity, false);
|
let new_id = !self.is_domain_in_blockchain(block.index, &transaction.identity);
|
||||||
if new_id && last.timestamp + NEW_DOMAINS_INTERVAL > block.timestamp {
|
if new_id && last.timestamp + NEW_DOMAINS_INTERVAL > block.timestamp {
|
||||||
warn!("Block {:?} is mined too early!", &block);
|
warn!("Block {:?} is mined too early!", &block);
|
||||||
return Bad;
|
return Bad;
|
||||||
@@ -798,7 +757,7 @@ impl Chain {
|
|||||||
// Check if yggdrasil only property of zone is not violated
|
// Check if yggdrasil only property of zone is not violated
|
||||||
if let Some(block_data) = transaction.get_domain_data() {
|
if let Some(block_data) = transaction.get_domain_data() {
|
||||||
let zones = self.get_zones();
|
let zones = self.get_zones();
|
||||||
for z in &zones {
|
for z in zones {
|
||||||
if z.name == block_data.zone {
|
if z.name == block_data.zone {
|
||||||
if z.yggdrasil {
|
if z.yggdrasil {
|
||||||
for record in &block_data.records {
|
for record in &block_data.records {
|
||||||
@@ -911,15 +870,10 @@ impl Chain {
|
|||||||
|
|
||||||
fn get_difficulty_for_transaction(&self, transaction: &Transaction) -> u32 {
|
fn get_difficulty_for_transaction(&self, transaction: &Transaction) -> u32 {
|
||||||
match transaction.class.as_ref() {
|
match transaction.class.as_ref() {
|
||||||
"domain" => {
|
CLASS_DOMAIN => {
|
||||||
return match serde_json::from_str::<DomainData>(&transaction.data) {
|
return match serde_json::from_str::<DomainData>(&transaction.data) {
|
||||||
Ok(data) => {
|
Ok(_) => {
|
||||||
for zone in self.get_zones().iter() {
|
DOMAIN_DIFFICULTY
|
||||||
if zone.name == data.zone {
|
|
||||||
return zone.difficulty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u32::MAX
|
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!("Error parsing DomainData from {:?}", transaction);
|
warn!("Error parsing DomainData from {:?}", transaction);
|
||||||
@@ -927,7 +881,7 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"zone" => { ZONE_DIFFICULTY }
|
CLASS_ORIGIN => { ORIGIN_DIFFICULTY }
|
||||||
_ => { u32::MAX }
|
_ => { u32::MAX }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1005,9 +959,10 @@ impl SignersCache {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use crate::{Chain, Settings};
|
|
||||||
use simplelog::{ConfigBuilder, TermLogger, TerminalMode, ColorChoice};
|
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
|
use simplelog::{ColorChoice, ConfigBuilder, TerminalMode, TermLogger};
|
||||||
|
|
||||||
|
use crate::{Chain, Settings};
|
||||||
|
|
||||||
fn init_logger() {
|
fn init_logger() {
|
||||||
let config = ConfigBuilder::new()
|
let config = ConfigBuilder::new()
|
||||||
|
|||||||
@@ -20,17 +20,8 @@ CREATE TABLE domains (
|
|||||||
'identity' BINARY,
|
'identity' BINARY,
|
||||||
'confirmation' BINARY,
|
'confirmation' BINARY,
|
||||||
'data' TEXT,
|
'data' TEXT,
|
||||||
'pub_key' BINARY
|
'owner' BINARY
|
||||||
);
|
);
|
||||||
CREATE INDEX ids ON domains ('identity');
|
CREATE INDEX ids ON domains ('identity');
|
||||||
|
|
||||||
CREATE TABLE zones (
|
|
||||||
'id' BIGINT NOT NULL PRIMARY KEY,
|
|
||||||
'timestamp' BIGINT NOT NULL,
|
|
||||||
'identity' BINARY,
|
|
||||||
'confirmation' BINARY,
|
|
||||||
'data' TEXT,
|
|
||||||
'pub_key' BINARY
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE options ('name' TEXT NOT NULL, 'value' TEXT NOT NULL);
|
CREATE TABLE options ('name' TEXT NOT NULL, 'value' TEXT NOT NULL);
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
anon
|
||||||
|
btn
|
||||||
|
conf
|
||||||
|
index
|
||||||
|
merch
|
||||||
|
mirror
|
||||||
|
mob
|
||||||
|
screen
|
||||||
|
srv
|
||||||
|
ygg
|
||||||
@@ -48,7 +48,7 @@ impl DnsFilter for BlockchainFilter {
|
|||||||
let zone = parts[0].to_owned();
|
let zone = parts[0].to_owned();
|
||||||
match data {
|
match data {
|
||||||
None => {
|
None => {
|
||||||
if self.context.lock().unwrap().chain.is_zone_in_blockchain(i64::MAX as u64, &zone) {
|
if self.context.lock().unwrap().chain.is_available_zone(&zone) {
|
||||||
trace!("Not found data for domain {}", &search);
|
trace!("Not found data for domain {}", &search);
|
||||||
// Create DnsPacket
|
// Create DnsPacket
|
||||||
let mut packet = DnsPacket::new();
|
let mut packet = DnsPacket::new();
|
||||||
@@ -194,7 +194,7 @@ impl BlockchainFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_zone_response(&self, zone: &str, serial: u32, mut packet: &mut DnsPacket) -> bool {
|
fn get_zone_response(&self, zone: &str, serial: u32, mut packet: &mut DnsPacket) -> bool {
|
||||||
let have_zone = self.context.lock().unwrap().chain.is_zone_in_blockchain(i64::MAX as u64, zone);
|
let have_zone = self.context.lock().unwrap().chain.is_available_zone(zone);
|
||||||
if have_zone {
|
if have_zone {
|
||||||
BlockchainFilter::add_soa_record(zone.to_owned(), serial, &mut packet);
|
BlockchainFilter::add_soa_record(zone.to_owned(), serial, &mut packet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use serde::ser::SerializeStruct;
|
use serde::ser::SerializeStruct;
|
||||||
@@ -6,29 +7,37 @@ use serde::ser::SerializeStruct;
|
|||||||
use crate::blockchain::hash_utils::*;
|
use crate::blockchain::hash_utils::*;
|
||||||
use crate::bytes::Bytes;
|
use crate::bytes::Bytes;
|
||||||
use crate::dns::protocol::DnsRecord;
|
use crate::dns::protocol::DnsRecord;
|
||||||
use std::fmt::{Display, Formatter};
|
use crate::{CLASS_ORIGIN, CLASS_DOMAIN};
|
||||||
|
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, PartialEq)]
|
#[derive(Clone, Deserialize, PartialEq)]
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
|
#[serde(default, skip_serializing_if = "Bytes::is_zero")]
|
||||||
pub identity: Bytes,
|
pub identity: Bytes,
|
||||||
|
#[serde(default, skip_serializing_if = "Bytes::is_zero")]
|
||||||
pub confirmation: Bytes,
|
pub confirmation: Bytes,
|
||||||
pub class: String,
|
pub class: String,
|
||||||
pub data: String,
|
pub data: String,
|
||||||
pub pub_key: Bytes,
|
#[serde(default, skip_serializing_if = "Bytes::is_zero")]
|
||||||
|
pub owner: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transaction {
|
impl Transaction {
|
||||||
pub fn from_str(identity: String, method: String, data: String, pub_key: Bytes) -> Self {
|
pub fn from_str(identity: String, method: String, data: String, owner: Bytes) -> Self {
|
||||||
let hash = hash_identity(&identity, None);
|
let hash = hash_identity(&identity, None);
|
||||||
let confirmation = hash_identity(&identity, Some(&pub_key));
|
let confirmation = hash_identity(&identity, Some(&owner));
|
||||||
return Self::new(hash, confirmation, method, data, pub_key);
|
return Self::new(hash, confirmation, method, data, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(identity: Bytes, confirmation: Bytes, method: String, data: String, pub_key: Bytes) -> Self {
|
pub fn new(identity: Bytes, confirmation: Bytes, method: String, data: String, owner: Bytes) -> Self {
|
||||||
Transaction { identity, confirmation, class: method, data, pub_key }
|
Transaction { identity, confirmation, class: method, data, owner }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn origin(hash: Bytes, owner: Bytes) -> Self {
|
||||||
|
let data = serde_json::to_string(&Origin { zones: hash }).unwrap();
|
||||||
|
Transaction { identity: Bytes::default(), confirmation: Bytes::default(), class: String::from(CLASS_ORIGIN), data, owner }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_json(json: &str) -> Option<Self> {
|
pub fn from_json(json: &str) -> Option<Self> {
|
||||||
@@ -50,13 +59,13 @@ impl Transaction {
|
|||||||
|
|
||||||
pub fn check_identity(&self, domain: &str) -> bool {
|
pub fn check_identity(&self, domain: &str) -> bool {
|
||||||
let hash = hash_identity(&domain, None);
|
let hash = hash_identity(&domain, None);
|
||||||
let confirmation = hash_identity(&domain, Some(&self.pub_key));
|
let confirmation = hash_identity(&domain, Some(&self.owner));
|
||||||
self.identity.eq(&hash) && self.confirmation.eq(&confirmation)
|
self.identity.eq(&hash) && self.confirmation.eq(&confirmation)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns [DomainData] from this transaction if it has it
|
/// Returns [DomainData] from this transaction if it has it
|
||||||
pub fn get_domain_data(&self) -> Option<DomainData> {
|
pub fn get_domain_data(&self) -> Option<DomainData> {
|
||||||
if self.class == "domain" {
|
if self.class == CLASS_DOMAIN {
|
||||||
if let Ok(data) = serde_json::from_str::<DomainData>(&self.data) {
|
if let Ok(data) = serde_json::from_str::<DomainData>(&self.data) {
|
||||||
return Some(data)
|
return Some(data)
|
||||||
}
|
}
|
||||||
@@ -69,12 +78,9 @@ impl Transaction {
|
|||||||
match what {
|
match what {
|
||||||
None => { TransactionType::Signing }
|
None => { TransactionType::Signing }
|
||||||
Some(transaction) => {
|
Some(transaction) => {
|
||||||
if let Some(_) = transaction.get_domain_data() {
|
if transaction.class == CLASS_DOMAIN {
|
||||||
return TransactionType::Domain;
|
return TransactionType::Domain;
|
||||||
}
|
}
|
||||||
if let Ok(_) = serde_json::from_str::<ZoneData>(&transaction.data) {
|
|
||||||
return TransactionType::Zone;
|
|
||||||
}
|
|
||||||
TransactionType::Unknown
|
TransactionType::Unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +94,7 @@ impl fmt::Debug for Transaction {
|
|||||||
.field("confirmation", &self.confirmation)
|
.field("confirmation", &self.confirmation)
|
||||||
.field("class", &self.class)
|
.field("class", &self.class)
|
||||||
.field("data", &self.data)
|
.field("data", &self.data)
|
||||||
.field("pub_key", &&self.pub_key)
|
.field("pub_key", &&self.owner)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,7 +106,7 @@ impl Serialize for Transaction {
|
|||||||
structure.serialize_field("confirmation", &self.confirmation)?;
|
structure.serialize_field("confirmation", &self.confirmation)?;
|
||||||
structure.serialize_field("class", &self.class)?;
|
structure.serialize_field("class", &self.class)?;
|
||||||
structure.serialize_field("data", &self.data)?;
|
structure.serialize_field("data", &self.data)?;
|
||||||
structure.serialize_field("pub_key", &self.pub_key)?;
|
structure.serialize_field("pub_key", &self.owner)?;
|
||||||
structure.end()
|
structure.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,38 +115,28 @@ pub enum TransactionType {
|
|||||||
Unknown,
|
Unknown,
|
||||||
Signing,
|
Signing,
|
||||||
Domain,
|
Domain,
|
||||||
Zone,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct DomainData {
|
pub struct DomainData {
|
||||||
pub domain: Bytes,
|
pub domain: Bytes,
|
||||||
pub zone: String,
|
pub zone: String,
|
||||||
|
pub info: String,
|
||||||
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
pub records: Vec<DnsRecord>,
|
pub records: Vec<DnsRecord>,
|
||||||
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
pub contacts: Vec<ContactsData>,
|
pub contacts: Vec<ContactsData>,
|
||||||
#[serde(default)]
|
|
||||||
pub owners: Vec<Bytes>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DomainData {
|
impl DomainData {
|
||||||
pub fn new(domain: Bytes, zone: String, records: Vec<DnsRecord>, contacts: Vec<ContactsData>, owners: Vec<Bytes>) -> Self {
|
pub fn new(domain: Bytes, zone: String, info: String, records: Vec<DnsRecord>, contacts: Vec<ContactsData>) -> Self {
|
||||||
Self { domain, zone, records, contacts, owners }
|
Self { domain, zone, info, records, contacts }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct ZoneData {
|
pub struct Origin {
|
||||||
pub name: String,
|
zones: Bytes
|
||||||
pub difficulty: u32,
|
|
||||||
pub yggdrasil: bool,
|
|
||||||
#[serde(default)]
|
|
||||||
pub owners: Vec<Bytes>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ZoneData {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
|
||||||
f.write_str(&format!("{} ({})", self.name, self.difficulty))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Represents a result of block check on block's arrival
|
/// Represents a result of block check on block's arrival
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum BlockQuality {
|
pub enum BlockQuality {
|
||||||
@@ -35,3 +38,15 @@ impl Options {
|
|||||||
Options { origin: String::new(), version: 0 }
|
Options { origin: String::new(), version: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct ZoneData {
|
||||||
|
pub name: String,
|
||||||
|
pub yggdrasil: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ZoneData {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.write_str(&format!("{}, yggdrasil: {}", self.name, self.yggdrasil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub const DB_VERSION: u32 = 0;
|
pub const DB_VERSION: u32 = 0;
|
||||||
pub const CHAIN_VERSION: u32 = 0;
|
pub const CHAIN_VERSION: u32 = 1;
|
||||||
|
|
||||||
pub const ZONE_DIFFICULTY: u32 = 28;
|
pub const ORIGIN_DIFFICULTY: u32 = 30;
|
||||||
pub const ZONE_MIN_DIFFICULTY: u32 = 22;
|
pub const DOMAIN_DIFFICULTY: u32 = 24;
|
||||||
pub const SIGNER_DIFFICULTY: u32 = 16;
|
pub const SIGNER_DIFFICULTY: u32 = 16;
|
||||||
pub const KEYSTORE_DIFFICULTY: u32 = 23;
|
pub const KEYSTORE_DIFFICULTY: u32 = 23;
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ pub const ZONE_MAX_LENGTH: usize = 10;
|
|||||||
pub const MAX_RECONNECTS: u32 = 5;
|
pub const MAX_RECONNECTS: u32 = 5;
|
||||||
|
|
||||||
pub const DB_NAME: &str = "blockchain.db";
|
pub const DB_NAME: &str = "blockchain.db";
|
||||||
pub const CLASS_ZONE: &str = "zone";
|
pub const CLASS_ORIGIN: &str = "origin";
|
||||||
pub const CLASS_DOMAIN: &str = "domain";
|
pub const CLASS_DOMAIN: &str = "domain";
|
||||||
pub const ALFIS_DEBUG: &str = "ALFIS_DEBUG";
|
pub const ALFIS_DEBUG: &str = "ALFIS_DEBUG";
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ pub const LISTEN_PORT: u16 = 4244;
|
|||||||
pub const UI_REFRESH_DELAY_MS: u128 = 250;
|
pub const UI_REFRESH_DELAY_MS: u128 = 250;
|
||||||
pub const LOG_REFRESH_DELAY_SEC: u64 = 60;
|
pub const LOG_REFRESH_DELAY_SEC: u64 = 60;
|
||||||
|
|
||||||
pub const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(250));
|
pub const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(25000));
|
||||||
pub const MAX_PACKET_SIZE: usize = 1 * 1024 * 1024; // 1 Mb
|
pub const MAX_PACKET_SIZE: usize = 1 * 1024 * 1024; // 1 Mb
|
||||||
pub const MAX_READ_BLOCK_TIME: u128 = 500;
|
pub const MAX_READ_BLOCK_TIME: u128 = 500;
|
||||||
pub const MAX_IDLE_SECONDS: u64 = 180;
|
pub const MAX_IDLE_SECONDS: u64 = 180;
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ pub fn check_domain(name: &str, allow_dots: bool) -> bool {
|
|||||||
if name.starts_with('.') || name.starts_with('-') || name.ends_with('.') || name.ends_with('-') {
|
if name.starts_with('.') || name.starts_with('-') || name.ends_with('.') || name.ends_with('-') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
let parts: Vec<&str> = name.rsplitn(2, ".").collect();
|
||||||
|
if parts.len() == 2 {
|
||||||
|
if parts[1].len() < 3 && is_numeric(parts[1]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut last_dot = false;
|
let mut last_dot = false;
|
||||||
let mut last_hyphen = false;
|
let mut last_hyphen = false;
|
||||||
for char in name.chars() {
|
for char in name.chars() {
|
||||||
@@ -60,6 +67,15 @@ pub fn check_domain(name: &str, allow_dots: bool) -> bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_numeric(str: &str) -> bool {
|
||||||
|
for char in str.chars() {
|
||||||
|
if !char.is_numeric() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_domain_zone(domain: &str) -> String {
|
pub fn get_domain_zone(domain: &str) -> String {
|
||||||
let parts: Vec<&str> = domain.rsplitn(2, ".").collect();
|
let parts: Vec<&str> = domain.rsplitn(2, ".").collect();
|
||||||
if !parts.is_empty() {
|
if !parts.is_empty() {
|
||||||
@@ -160,6 +176,9 @@ mod test {
|
|||||||
assert!(!check_domain("ab.c-", true));
|
assert!(!check_domain("ab.c-", true));
|
||||||
assert!(!check_domain(".ab.c", true));
|
assert!(!check_domain(".ab.c", true));
|
||||||
assert!(!check_domain("ab.c-", true));
|
assert!(!check_domain("ab.c-", true));
|
||||||
|
assert!(check_domain("777.com", true));
|
||||||
|
assert!(!check_domain("77.com", true));
|
||||||
|
assert!(!check_domain("7.com", true));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+26
-35
@@ -169,14 +169,6 @@ impl VectorPacketBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PacketBuffer for VectorPacketBuffer {
|
impl PacketBuffer for VectorPacketBuffer {
|
||||||
fn find_label(&self, label: &str) -> Option<usize> {
|
|
||||||
self.label_lookup.get(label).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_label(&mut self, label: &str, pos: usize) {
|
|
||||||
self.label_lookup.insert(label.to_string(), pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self) -> Result<u8> {
|
fn read(&mut self) -> Result<u8> {
|
||||||
let res = self.buffer[self.pos];
|
let res = self.buffer[self.pos];
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
@@ -220,42 +212,33 @@ impl PacketBuffer for VectorPacketBuffer {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_label(&self, label: &str) -> Option<usize> {
|
||||||
|
self.label_lookup.get(label).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StreamPacketBuffer<'a, T>
|
fn save_label(&mut self, label: &str, pos: usize) {
|
||||||
where
|
self.label_lookup.insert(label.to_string(), pos);
|
||||||
T: Read,
|
}
|
||||||
{
|
}
|
||||||
|
|
||||||
|
pub struct StreamPacketBuffer<'a, T> where T: Read {
|
||||||
pub stream: &'a mut T,
|
pub stream: &'a mut T,
|
||||||
pub buffer: Vec<u8>,
|
pub buffer: Vec<u8>,
|
||||||
pub pos: usize,
|
pub pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> StreamPacketBuffer<'a, T>
|
impl<'a, T> StreamPacketBuffer<'a, T> where T: Read + 'a {
|
||||||
where
|
|
||||||
T: Read + 'a,
|
|
||||||
{
|
|
||||||
pub fn new(stream: &'a mut T) -> StreamPacketBuffer<'_, T> {
|
pub fn new(stream: &'a mut T) -> StreamPacketBuffer<'_, T> {
|
||||||
StreamPacketBuffer {
|
StreamPacketBuffer {
|
||||||
stream: stream,
|
stream,
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
pos: 0,
|
pos: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> PacketBuffer for StreamPacketBuffer<'a, T>
|
impl<'a, T> PacketBuffer for StreamPacketBuffer<'a, T> where T: Read + 'a {
|
||||||
where
|
|
||||||
T: Read + 'a,
|
|
||||||
{
|
|
||||||
fn find_label(&self, _: &str) -> Option<usize> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_label(&mut self, _: &str, _: usize) {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self) -> Result<u8> {
|
fn read(&mut self) -> Result<u8> {
|
||||||
while self.pos >= self.buffer.len() {
|
while self.pos >= self.buffer.len() {
|
||||||
let mut local_buffer = [0; 1];
|
let mut local_buffer = [0; 1];
|
||||||
@@ -310,6 +293,14 @@ where
|
|||||||
self.pos += steps;
|
self.pos += steps;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_label(&self, _: &str) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_label(&mut self, _: &str, _: usize) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BytePacketBuffer {
|
pub struct BytePacketBuffer {
|
||||||
@@ -333,12 +324,6 @@ impl Default for BytePacketBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PacketBuffer for BytePacketBuffer {
|
impl PacketBuffer for BytePacketBuffer {
|
||||||
fn find_label(&self, _: &str) -> Option<usize> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_label(&mut self, _: &str, _: usize) {}
|
|
||||||
|
|
||||||
fn read(&mut self) -> Result<u8> {
|
fn read(&mut self) -> Result<u8> {
|
||||||
if self.pos >= 512 {
|
if self.pos >= 512 {
|
||||||
return Err(BufferError::EndOfBuffer);
|
return Err(BufferError::EndOfBuffer);
|
||||||
@@ -393,6 +378,12 @@ impl PacketBuffer for BytePacketBuffer {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_label(&self, _: &str) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_label(&mut self, _: &str, _: usize) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ pub enum Event {
|
|||||||
KeyCreated { path: String, public: String, hash: String },
|
KeyCreated { path: String, public: String, hash: String },
|
||||||
KeyLoaded { path: String, public: String, hash: String },
|
KeyLoaded { path: String, public: String, hash: String },
|
||||||
KeySaved { path: String, public: String, hash: String },
|
KeySaved { path: String, public: String, hash: String },
|
||||||
ZonesChanged,
|
|
||||||
NewBlockReceived,
|
NewBlockReceived,
|
||||||
BlockchainChanged { index: u64 },
|
BlockchainChanged { index: u64 },
|
||||||
ActionStopMining,
|
ActionStopMining,
|
||||||
|
|||||||
+3
-2
@@ -16,7 +16,7 @@ use simplelog::*;
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use winapi::um::wincon::{ATTACH_PARENT_PROCESS, AttachConsole, FreeConsole};
|
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, DB_NAME};
|
use alfis::{Block, Bytes, Chain, Miner, Context, Network, Settings, dns_utils, Keystore, ORIGIN_DIFFICULTY, ALFIS_DEBUG, DB_NAME, Transaction};
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::io::{Seek, SeekFrom};
|
use std::io::{Seek, SeekFrom};
|
||||||
@@ -208,7 +208,8 @@ fn create_genesis_if_needed(context: &Arc<Mutex<Context>>, miner: &Arc<Mutex<Min
|
|||||||
if origin.is_empty() && last_block.is_none() {
|
if origin.is_empty() && last_block.is_none() {
|
||||||
if let Some(keystore) = &context.keystore {
|
if let Some(keystore) = &context.keystore {
|
||||||
// If blockchain is empty, we are going to mine a Genesis block
|
// If blockchain is empty, we are going to mine a Genesis block
|
||||||
let block = Block::new(None, context.get_keystore().unwrap().get_public(), Bytes::default(), ZONE_DIFFICULTY);
|
let transaction = Transaction::origin(Chain::get_zones_hash(), context.get_keystore().unwrap().get_public());
|
||||||
|
let block = Block::new(Some(transaction), context.get_keystore().unwrap().get_public(), Bytes::default(), ORIGIN_DIFFICULTY);
|
||||||
miner.lock().unwrap().add_block(block, keystore.clone());
|
miner.lock().unwrap().add_block(block, keystore.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -349,7 +349,7 @@ fn find_hash(context: Arc<Mutex<Context>>, mut block: Block, running: Arc<Atomic
|
|||||||
let elapsed = time.elapsed().as_millis();
|
let elapsed = time.elapsed().as_millis();
|
||||||
if elapsed >= 1000 {
|
if elapsed >= 1000 {
|
||||||
block.timestamp = Utc::now().timestamp();
|
block.timestamp = Utc::now().timestamp();
|
||||||
if elapsed > 5000 {
|
if elapsed > 10000 {
|
||||||
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.try_lock() {
|
if let Ok(mut context) = context.try_lock() {
|
||||||
|
|||||||
+1
-10
@@ -17,8 +17,7 @@ use mio::event::Event;
|
|||||||
use mio::net::{TcpListener, TcpStream};
|
use mio::net::{TcpListener, TcpStream};
|
||||||
use rand::random;
|
use rand::random;
|
||||||
|
|
||||||
use crate::{Block, Context, p2p::Message, p2p::Peer, p2p::Peers, p2p::State, Transaction};
|
use crate::{Block, Context, p2p::Message, p2p::Peer, p2p::Peers, p2p::State};
|
||||||
use crate::blockchain::transaction::TransactionType;
|
|
||||||
use crate::blockchain::types::BlockQuality;
|
use crate::blockchain::types::BlockQuality;
|
||||||
use crate::commons::*;
|
use crate::commons::*;
|
||||||
|
|
||||||
@@ -539,13 +538,9 @@ fn handle_block(context: Arc<Mutex<Context>>, peers: &mut Peers, token: &Token,
|
|||||||
let max_height = context.chain.max_height();
|
let max_height = context.chain.max_height();
|
||||||
match context.chain.check_new_block(&block) {
|
match context.chain.check_new_block(&block) {
|
||||||
BlockQuality::Good => {
|
BlockQuality::Good => {
|
||||||
let zone = matches!(Transaction::get_type(&block.transaction), TransactionType::Zone);
|
|
||||||
context.chain.add_block(block);
|
context.chain.add_block(block);
|
||||||
let my_height = context.chain.get_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 zone {
|
|
||||||
context.bus.post(crate::event::Event::ZonesChanged);
|
|
||||||
}
|
|
||||||
// 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 {
|
||||||
context.bus.post(crate::event::Event::SyncFinished);
|
context.bus.post(crate::event::Event::SyncFinished);
|
||||||
@@ -573,13 +568,9 @@ fn handle_block(context: Arc<Mutex<Context>>, peers: &mut Peers, token: &Token,
|
|||||||
debug!("Got forked block {} with hash {:?}", block.index, block.hash);
|
debug!("Got forked block {} with hash {:?}", block.index, block.hash);
|
||||||
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) {
|
||||||
let zone = matches!(Transaction::get_type(&block.transaction), TransactionType::Zone);
|
|
||||||
context.chain.replace_block(block).expect("Error replacing block with fork");
|
context.chain.replace_block(block).expect("Error replacing block with fork");
|
||||||
let index = context.chain.get_height();
|
let index = context.chain.get_height();
|
||||||
context.bus.post(crate::event::Event::BlockchainChanged { index });
|
context.bus.post(crate::event::Event::BlockchainChanged { index });
|
||||||
if zone {
|
|
||||||
context.bus.post(crate::event::Event::ZonesChanged);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
debug!("Fork in not better than our block, dropping.");
|
debug!("Fork in not better than our block, dropping.");
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-116
@@ -14,18 +14,18 @@ use log::{debug, error, info, LevelFilter, trace, warn};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use web_view::Content;
|
use web_view::Content;
|
||||||
|
|
||||||
use alfis::{Block, Bytes, Context, get_domain_zone, Keystore, Transaction, ZONE_MIN_DIFFICULTY, is_yggdrasil_record};
|
use alfis::{Block, Bytes, Context, Keystore, Transaction};
|
||||||
use alfis::{check_domain, keys};
|
use alfis::keys;
|
||||||
use alfis::blockchain::transaction::{DomainData, ZoneData};
|
use alfis::blockchain::hash_utils::hash_identity;
|
||||||
|
use alfis::blockchain::transaction::DomainData;
|
||||||
use alfis::blockchain::types::MineResult;
|
use alfis::blockchain::types::MineResult;
|
||||||
use alfis::commons::{ZONE_DIFFICULTY, ZONE_MAX_LENGTH, CLASS_DOMAIN, CLASS_ZONE};
|
use alfis::commons::*;
|
||||||
use alfis::dns::protocol::DnsRecord;
|
use alfis::dns::protocol::DnsRecord;
|
||||||
use alfis::event::Event;
|
use alfis::event::Event;
|
||||||
use alfis::miner::Miner;
|
use alfis::miner::Miner;
|
||||||
use Cmd::*;
|
use Cmd::*;
|
||||||
|
|
||||||
use self::web_view::{Handle, WebView};
|
use self::web_view::{Handle, WebView};
|
||||||
use alfis::blockchain::hash_utils::hash_identity;
|
|
||||||
|
|
||||||
pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
||||||
let file_content = include_str!("webview/index.html");
|
let file_content = include_str!("webview/index.html");
|
||||||
@@ -57,10 +57,6 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>) {
|
|||||||
action_create_domain(Arc::clone(&context), Arc::clone(&miner), web_view, name, data);
|
action_create_domain(Arc::clone(&context), Arc::clone(&miner), web_view, name, data);
|
||||||
}
|
}
|
||||||
TransferDomain { .. } => {}
|
TransferDomain { .. } => {}
|
||||||
CheckZone { name } => { action_check_zone(&context, web_view, name); }
|
|
||||||
MineZone { name, data } => {
|
|
||||||
action_create_zone(Arc::clone(&context), Arc::clone(&miner), web_view, name, data);
|
|
||||||
}
|
|
||||||
StopMining => { context.lock().unwrap().bus.post(Event::ActionStopMining); }
|
StopMining => { context.lock().unwrap().bus.post(Event::ActionStopMining); }
|
||||||
Open { link } => {
|
Open { link } => {
|
||||||
if open::that(&link).is_err() {
|
if open::that(&link).is_err() {
|
||||||
@@ -110,19 +106,6 @@ fn run_interface_loop(context: &mut Arc<Mutex<Context>>, interface: &mut WebView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action_check_zone(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>, name: String) {
|
|
||||||
let name = name.to_lowercase();
|
|
||||||
if name.len() > ZONE_MAX_LENGTH || !check_domain(&name, false) || context.lock().unwrap().x_zones.has_zone(&name) {
|
|
||||||
web_view.eval("zoneAvailable(false)").expect("Error evaluating!");
|
|
||||||
} else {
|
|
||||||
let c = context.lock().unwrap();
|
|
||||||
if let Some(keystore) = c.get_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!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn action_check_record(web_view: &mut WebView<()>, data: String) {
|
fn action_check_record(web_view: &mut WebView<()>, data: String) {
|
||||||
match serde_json::from_str::<DnsRecord>(&data) {
|
match serde_json::from_str::<DnsRecord>(&data) {
|
||||||
Ok(_) => { web_view.eval("recordOkay(true)").expect("Error evaluating!"); }
|
Ok(_) => { web_view.eval("recordOkay(true)").expect("Error evaluating!"); }
|
||||||
@@ -296,15 +279,6 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
format!("setLeftStatusBarText('Idle'); setRightStatusBarText('Nodes: {}, Blocks: {}')", nodes, blocks)
|
format!("setLeftStatusBarText('Idle'); setRightStatusBarText('Nodes: {}, Blocks: {}')", nodes, blocks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::ZonesChanged => {
|
|
||||||
info!("New zone arrived");
|
|
||||||
if let Ok(zones) = serde_json::to_string(&context.chain.get_zones()) {
|
|
||||||
let _ = handle.dispatch(move |web_view|{
|
|
||||||
web_view.eval(&format!("zonesChanged('{}');", &zones))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
String::new() // Nothing
|
|
||||||
}
|
|
||||||
Event::BlockchainChanged {index} => {
|
Event::BlockchainChanged {index} => {
|
||||||
debug!("Current blockchain height is {}", index);
|
debug!("Current blockchain height is {}", index);
|
||||||
event_handle_info(&handle, &format!("Blockchain changed, current block count is {} now.", index));
|
event_handle_info(&handle, &format!("Blockchain changed, current block count is {} now.", index));
|
||||||
@@ -331,10 +305,10 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
|
|||||||
let index = c.chain.get_height();
|
let index = c.chain.get_height();
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
c.bus.post(Event::BlockchainChanged { index });
|
c.bus.post(Event::BlockchainChanged { index });
|
||||||
|
}
|
||||||
if let Ok(zones) = serde_json::to_string(&c.chain.get_zones()) {
|
if let Ok(zones) = serde_json::to_string(&c.chain.get_zones()) {
|
||||||
let _ = web_view.eval(&format!("zonesChanged('{}');", &zones));
|
let _ = web_view.eval(&format!("zonesChanged('{}');", &zones));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
event_info(web_view, "Application loaded");
|
event_info(web_view, "Application loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +358,7 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
|
|||||||
};
|
};
|
||||||
// Check if yggdrasil only quality of zone is not violated
|
// Check if yggdrasil only quality of zone is not violated
|
||||||
let zones = context.chain.get_zones();
|
let zones = context.chain.get_zones();
|
||||||
for z in &zones {
|
for z in zones {
|
||||||
if z.name == data.zone {
|
if z.name == data.zone {
|
||||||
if z.yggdrasil {
|
if z.yggdrasil {
|
||||||
for record in &data.records {
|
for record in &data.records {
|
||||||
@@ -399,10 +373,8 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
|
|||||||
}
|
}
|
||||||
match context.chain.can_mine_domain(context.chain.get_height(), &name, &pub_key) {
|
match context.chain.can_mine_domain(context.chain.get_height(), &name, &pub_key) {
|
||||||
MineResult::Fine => {
|
MineResult::Fine => {
|
||||||
let zone = get_domain_zone(&name);
|
|
||||||
let difficulty = context.chain.get_zone_difficulty(&zone);
|
|
||||||
std::mem::drop(context);
|
std::mem::drop(context);
|
||||||
create_domain(c, miner, CLASS_DOMAIN, &name, data, difficulty, &keystore);
|
create_domain(c, miner, CLASS_DOMAIN, &name, data, DOMAIN_DIFFICULTY, &keystore);
|
||||||
let _ = web_view.eval("domainMiningStarted();");
|
let _ = web_view.eval("domainMiningStarted();");
|
||||||
event_info(web_view, &format!("Mining of domain \\'{}\\' has started", &name));
|
event_info(web_view, &format!("Mining of domain \\'{}\\' has started", &name));
|
||||||
}
|
}
|
||||||
@@ -434,72 +406,6 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action_create_zone(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, web_view: &mut WebView<()>, name: String, data: String) {
|
|
||||||
if context.lock().unwrap().chain.is_waiting_signers() {
|
|
||||||
show_warning(web_view, "Waiting for last full block to be signed. Try again later.");
|
|
||||||
info!("Waiting for last full block to be signed. Try again later.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = name.to_lowercase();
|
|
||||||
if name.len() > ZONE_MAX_LENGTH || !check_domain(&name, false) || context.lock().unwrap().x_zones.has_zone(&name) {
|
|
||||||
warn!("This zone is unavailable for mining!");
|
|
||||||
show_warning(web_view, "This zone is unavailable for mining!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let data = data.to_lowercase();
|
|
||||||
let mut data = match serde_json::from_str::<ZoneData>(&data) {
|
|
||||||
Ok(zone) => {
|
|
||||||
if zone.difficulty < ZONE_MIN_DIFFICULTY {
|
|
||||||
warn!("Zone difficulty cannot be lower than {}!", ZONE_MIN_DIFFICULTY);
|
|
||||||
show_warning(web_view, &format!("Zone difficulty cannot be lower than {}!", ZONE_MIN_DIFFICULTY));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if name != zone.name {
|
|
||||||
warn!("Something wrong with zone data!");
|
|
||||||
show_warning(web_view, "Something wrong with zone data!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
zone
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
warn!("Something wrong with zone data!");
|
|
||||||
show_warning(web_view, "Something wrong with zone data!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let (keystore, transaction) = {
|
|
||||||
let context = context.lock().unwrap();
|
|
||||||
(context.get_keystore(), context.chain.get_domain_transaction(&name))
|
|
||||||
};
|
|
||||||
if let Some(keystore) = keystore {
|
|
||||||
data.owners = if data.owners.is_empty() {
|
|
||||||
vec!(keystore.get_public())
|
|
||||||
} else {
|
|
||||||
data.owners
|
|
||||||
};
|
|
||||||
let data = serde_json::to_string(&data).unwrap();
|
|
||||||
match transaction {
|
|
||||||
None => {
|
|
||||||
create_zone(Arc::clone(&context), miner.clone(), CLASS_ZONE, &name, &data, ZONE_DIFFICULTY, &keystore);
|
|
||||||
event_info(web_view, &format!("Mining of zone \\'{}\\' has started", &name));
|
|
||||||
}
|
|
||||||
Some(transaction) => {
|
|
||||||
if transaction.pub_key == keystore.get_public() {
|
|
||||||
create_zone(Arc::clone(&context), miner.clone(), CLASS_ZONE, &name, &data, ZONE_DIFFICULTY, &keystore);
|
|
||||||
event_info(web_view, &format!("Mining of zone \\'{}\\' has started", &name));
|
|
||||||
} else {
|
|
||||||
warn!("Tried to mine not owned domain!");
|
|
||||||
show_warning(web_view, "You cannot change domain that you don't own!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!("Can not mine without keys!");
|
|
||||||
show_warning(web_view, "You don't have keys loaded!<br>Load or mine the keys and try again.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_warning(web_view: &mut WebView<()>, text: &str) {
|
fn show_warning(web_view: &mut WebView<()>, text: &str) {
|
||||||
let str = text.replace('\'', "\\'");
|
let str = text.replace('\'', "\\'");
|
||||||
match web_view.eval(&format!("showWarning('{}');", &str)) {
|
match web_view.eval(&format!("showWarning('{}');", &str)) {
|
||||||
@@ -574,18 +480,6 @@ fn format_event_now(kind: &str, message: &str) -> String {
|
|||||||
format!("addEvent('{}', '{}', '{}');", kind, time.format("%d.%m.%y %X"), message)
|
format!("addEvent('{}', '{}', '{}');", kind, time.format("%d.%m.%y %X"), message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_zone(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, class: &str, name: &str, data: &str, difficulty: u32, keystore: &Keystore) {
|
|
||||||
let name = name.to_owned();
|
|
||||||
info!("Generating domain or zone {}", &name);
|
|
||||||
if context.lock().unwrap().x_zones.has_zone(&name) {
|
|
||||||
error!("Unable to mine IANA/OpenNIC/etc zone {}!", &name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let transaction = Transaction::from_str(name, class.to_owned(), data.to_owned(), keystore.get_public().clone());
|
|
||||||
let block = Block::new(Some(transaction), keystore.get_public(), Bytes::default(), difficulty);
|
|
||||||
miner.lock().unwrap().add_block(block, keystore.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_domain(_context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, class: &str, name: &str, mut data: DomainData, difficulty: u32, keystore: &Keystore) {
|
fn create_domain(_context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, class: &str, name: &str, mut data: DomainData, difficulty: u32, keystore: &Keystore) {
|
||||||
let name = name.to_owned();
|
let name = name.to_owned();
|
||||||
let confirmation = hash_identity(&name, Some(&keystore.get_public()));
|
let confirmation = hash_identity(&name, Some(&keystore.get_public()));
|
||||||
@@ -604,8 +498,6 @@ pub enum Cmd {
|
|||||||
LoadKey,
|
LoadKey,
|
||||||
CreateKey,
|
CreateKey,
|
||||||
SaveKey,
|
SaveKey,
|
||||||
CheckZone { name: String },
|
|
||||||
MineZone { name: String, data: String },
|
|
||||||
CheckRecord { data: String },
|
CheckRecord { data: String },
|
||||||
CheckDomain { name: String },
|
CheckDomain { name: String },
|
||||||
MineDomain { name: String, data: String },
|
MineDomain { name: String, data: String },
|
||||||
|
|||||||
+2
-36
@@ -29,14 +29,6 @@
|
|||||||
<span>Domains</span>
|
<span>Domains</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="tab">
|
|
||||||
<a onclick="openTab(this, 'tab_zones')">
|
|
||||||
<span class="icon">
|
|
||||||
<svg viewBox="0 0 24 24" style="width: 20px; height: 20px;"><path d="M18.25,22L15.5,19L16.66,17.82L18.25,19.41L21.84,15.82L23,17.23M20.5,3A0.5,0.5 0 0,1 21,3.5V13.36C20.36,13.13 19.69,13 19,13C17.46,13 16.06,13.6 15,14.56V7.1L9,5V16.9L13.04,18.3C13,18.54 13,18.77 13,19C13,19.46 13.06,19.92 13.16,20.36L9,18.9L3.66,20.97C3.59,21 3.55,21 3.5,21A0.5,0.5 0 0,1 3,20.5V5.38C3,5.15 3.16,4.97 3.35,4.9L9,3L15,5.1L20.33,3"></path></svg>
|
|
||||||
</span>
|
|
||||||
<span>Zones</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="tab">
|
<li class="tab">
|
||||||
<a onclick="openTab(this, 'tab_events')">
|
<a onclick="openTab(this, 'tab_events')">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
@@ -71,7 +63,7 @@
|
|||||||
<button class="button is-link" id="new_key_button" onclick="createKey();" title="Generate new keypair, suitable to mine domains">Mine new key</button>
|
<button class="button is-link" id="new_key_button" onclick="createKey();" title="Generate new keypair, suitable to mine domains">Mine new key</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help">To mine domains (or zones) you need to mine a strong pair of keys.</p>
|
<p class="help">To mine domains you need to mine a strong pair of keys.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Domain mining -->
|
<!-- Domain mining -->
|
||||||
@@ -82,32 +74,6 @@
|
|||||||
<button class="button is-link mt-2" onclick="showNewDomainDialog()" style="max-width: 200px;">New domain</button>
|
<button class="button is-link mt-2" onclick="showNewDomainDialog()" style="max-width: 200px;">New domain</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Zone mining -->
|
|
||||||
<div class="tab row page is-hidden" id="tab_zones">
|
|
||||||
<div class="field is-grouped">
|
|
||||||
<div class="control is-expanded has-icons-left">
|
|
||||||
<input class="input" type="text" placeholder="ygg" id="new_zone" oninput="onZoneChange()" title="The name of your zone, like com, net or 007, who knows?">
|
|
||||||
<span class="icon is-small is-left">
|
|
||||||
<svg viewBox="0 0 24 24" style="width: 20px; height: 20px;"><path d="M18.25,22L15.5,19L16.66,17.82L18.25,19.41L21.84,15.82L23,17.23M20.5,3A0.5,0.5 0 0,1 21,3.5V13.36C20.36,13.13 19.69,13 19,13C17.46,13 16.06,13.6 15,14.56V7.1L9,5V16.9L13.04,18.3C13,18.54 13,18.77 13,19C13,19.46 13.06,19.92 13.16,20.36L9,18.9L3.66,20.97C3.59,21 3.55,21 3.5,21A0.5,0.5 0 0,1 3,20.5V5.38C3,5.15 3.16,4.97 3.35,4.9L9,3L15,5.1L20.33,3"></path></svg>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="control has-icons-left">
|
|
||||||
<input class="input" type="number" placeholder="Difficulty: 22-28" id="new_zone_difficulty" oninput="onZoneChange()" title="How difficult it will be to mine domains in this zone? Good numbers are 20-28.">
|
|
||||||
<span class="icon is-small is-left">
|
|
||||||
<svg viewBox="0 0 24 24" style="width: 24px; height: 24px;"><path d="M17.66 11.2C17.43 10.9 17.15 10.64 16.89 10.38C16.22 9.78 15.46 9.35 14.82 8.72C13.33 7.26 13 4.85 13.95 3C13 3.23 12.17 3.75 11.46 4.32C8.87 6.4 7.85 10.07 9.07 13.22C9.11 13.32 9.15 13.42 9.15 13.55C9.15 13.77 9 13.97 8.8 14.05C8.57 14.15 8.33 14.09 8.14 13.93C8.08 13.88 8.04 13.83 8 13.76C6.87 12.33 6.69 10.28 7.45 8.64C5.78 10 4.87 12.3 5 14.47C5.06 14.97 5.12 15.47 5.29 15.97C5.43 16.57 5.7 17.17 6 17.7C7.08 19.43 8.95 20.67 10.96 20.92C13.1 21.19 15.39 20.8 17.03 19.32C18.86 17.66 19.5 15 18.56 12.72L18.43 12.46C18.22 12 17.66 11.2 17.66 11.2M14.5 17.5C14.22 17.74 13.76 18 13.4 18.1C12.28 18.5 11.16 17.94 10.5 17.28C11.69 17 12.4 16.12 12.61 15.23C12.78 14.43 12.46 13.77 12.33 13C12.21 12.26 12.23 11.63 12.5 10.94C12.69 11.32 12.89 11.7 13.13 12C13.9 13 15.11 13.44 15.37 14.8C15.41 14.94 15.43 15.08 15.43 15.23C15.46 16.05 15.1 16.95 14.5 17.5H14.5Z"></path></svg>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="buttons has-addons">
|
|
||||||
<button class="button is-link" id="new_zone_button" onclick="createZone();" title="Start mining">Mine zone</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<label class="checkbox mb-1" style="align-self: flex-start;" title="This zone's domains will have only IPv6 addresses from Yggdrasil network (200::/7).">
|
|
||||||
<input type="checkbox" id="yggdrasil_only">
|
|
||||||
Restrict this zone to <a onclick="open_link('https://yggdrasil-network.github.io');">Yggdrasil</a> only.
|
|
||||||
</label>
|
|
||||||
<p class="help">If you feel that we need another zone you can mine that too. Just select a name, a difficulty for domains in that zone, and hit "Mine zone".</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Events and notifications -->
|
<!-- Events and notifications -->
|
||||||
<div class="tab row page is-hidden list" id="tab_events" style="margin-bottom: 10pt;">
|
<div class="tab row page is-hidden list" id="tab_events" style="margin-bottom: 10pt;">
|
||||||
<!-- Events are getting here -->
|
<!-- Events are getting here -->
|
||||||
@@ -221,7 +187,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help">Enter domain name, add some DNS-records, then hit the "Mine domain" button!</p>
|
<p class="help">Enter domain name, choose domain zone, add some DNS-records, then hit the "Mine domain" button! Note: zones with * are restricted to <a onclick="open_link('https://yggdrasil-network.github.io');">Yggdrasil</a> only.</p>
|
||||||
|
|
||||||
<div class="list mt-2" id="domain_records">
|
<div class="list mt-2" id="domain_records">
|
||||||
<!-- Here will be our domain records, added by dialog -->
|
<!-- Here will be our domain records, added by dialog -->
|
||||||
|
|||||||
+10
-57
@@ -246,7 +246,6 @@ function domainMiningStarted() {
|
|||||||
document.getElementById("domain_records").disabled = true;
|
document.getElementById("domain_records").disabled = true;
|
||||||
document.getElementById("add_record_button").disabled = true;
|
document.getElementById("add_record_button").disabled = true;
|
||||||
document.getElementById("new_domain_button").disabled = true;
|
document.getElementById("new_domain_button").disabled = true;
|
||||||
document.getElementById("new_zone_button").disabled = true;
|
|
||||||
document.getElementById("new_key_button").disabled = true;
|
document.getElementById("new_key_button").disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,23 +257,9 @@ function domainMiningUnavailable() {
|
|||||||
document.getElementById("domain_records").disabled = true;
|
document.getElementById("domain_records").disabled = true;
|
||||||
document.getElementById("add_record_button").disabled = true;
|
document.getElementById("add_record_button").disabled = true;
|
||||||
document.getElementById("new_domain_button").disabled = true;
|
document.getElementById("new_domain_button").disabled = true;
|
||||||
document.getElementById("new_zone_button").disabled = true;
|
|
||||||
document.getElementById("new_key_button").disabled = true;
|
document.getElementById("new_key_button").disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createZone() {
|
|
||||||
var new_zone = document.getElementById("new_zone").value;
|
|
||||||
var difficulty = document.getElementById("new_zone_difficulty").value;
|
|
||||||
var yggdrasil = document.getElementById("yggdrasil_only").checked;
|
|
||||||
var obj = {};
|
|
||||||
obj.name = new_zone;
|
|
||||||
obj.difficulty = parseInt(difficulty);
|
|
||||||
obj.yggdrasil = yggdrasil;
|
|
||||||
obj.owners = []; // TODO make a dialog to fill them
|
|
||||||
data = JSON.stringify(obj);
|
|
||||||
external.invoke(JSON.stringify({cmd: 'mineZone', name: new_zone, data: data}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendAction(param) {
|
function sendAction(param) {
|
||||||
external.invoke(JSON.stringify(param));
|
external.invoke(JSON.stringify(param));
|
||||||
}
|
}
|
||||||
@@ -301,40 +286,6 @@ function domainAvailable(available) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onZoneChange() {
|
|
||||||
var button = document.getElementById("new_zone_button");
|
|
||||||
var diff = document.getElementById("new_zone_difficulty");
|
|
||||||
d = parseInt(diff.value);
|
|
||||||
// Checking for NaN first
|
|
||||||
if (d != d || d < 15 || d > 30) {
|
|
||||||
button.disabled = true;
|
|
||||||
diff.className = "input is-danger";
|
|
||||||
} else {
|
|
||||||
diff.className = "input";
|
|
||||||
var input = document.getElementById("new_zone");
|
|
||||||
external.invoke(JSON.stringify({cmd: 'checkZone', name: input.value}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function zoneAvailable(available) {
|
|
||||||
var input = document.getElementById("new_zone");
|
|
||||||
var button = document.getElementById("new_zone_button");
|
|
||||||
if (available) {
|
|
||||||
input.className = "input";
|
|
||||||
button.disabled = false;
|
|
||||||
var diff = document.getElementById("new_zone_difficulty");
|
|
||||||
d = parseInt(diff.value);
|
|
||||||
// Checking for NaN first
|
|
||||||
if (d != d || d < 15 || d > 30) {
|
|
||||||
button.disabled = true;
|
|
||||||
diff.className = "input is-danger";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
input.className = "input is-danger";
|
|
||||||
button.disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showModalDialog(text, callback) {
|
function showModalDialog(text, callback) {
|
||||||
var message = document.getElementById("modal_text");
|
var message = document.getElementById("modal_text");
|
||||||
message.textContent = text;
|
message.textContent = text;
|
||||||
@@ -443,7 +394,6 @@ function showMiningIndicator(visible, blue) {
|
|||||||
document.getElementById("domain_records").disabled = false;
|
document.getElementById("domain_records").disabled = false;
|
||||||
document.getElementById("add_record_button").disabled = false;
|
document.getElementById("add_record_button").disabled = false;
|
||||||
document.getElementById("new_domain_button").disabled = false;
|
document.getElementById("new_domain_button").disabled = false;
|
||||||
document.getElementById("new_zone_button").disabled = false;
|
|
||||||
document.getElementById("new_key_button").disabled = false;
|
document.getElementById("new_key_button").disabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -493,11 +443,6 @@ function keystoreChanged(path, pub_key, hash) {
|
|||||||
|
|
||||||
var new_domain = document.getElementById("new_domain");
|
var new_domain = document.getElementById("new_domain");
|
||||||
new_domain.disabled = false;
|
new_domain.disabled = false;
|
||||||
|
|
||||||
var new_zone = document.getElementById("new_zone");
|
|
||||||
new_zone.disabled = false;
|
|
||||||
var new_zone_difficulty = document.getElementById("new_zone_difficulty");
|
|
||||||
new_zone_difficulty.disabled = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeZonesDropdown() {
|
function closeZonesDropdown() {
|
||||||
@@ -520,7 +465,11 @@ function refreshZonesList() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
availableZones.forEach(function(value, index, array) {
|
availableZones.forEach(function(value, index, array) {
|
||||||
var zone = value.name + " (" + value.difficulty + "🔥)";
|
var note = "";
|
||||||
|
if (value.yggdrasil) {
|
||||||
|
note = "*";
|
||||||
|
}
|
||||||
|
var zone = value.name + note;
|
||||||
var add_class = "";
|
var add_class = "";
|
||||||
if (typeof currentZone !== 'undefined' && currentZone.name == value.name) {
|
if (typeof currentZone !== 'undefined' && currentZone.name == value.name) {
|
||||||
add_class = "is-active";
|
add_class = "is-active";
|
||||||
@@ -535,7 +484,11 @@ function refreshZonesList() {
|
|||||||
links.innerHTML = buf;
|
links.innerHTML = buf;
|
||||||
if (typeof currentZone !== 'undefined') {
|
if (typeof currentZone !== 'undefined') {
|
||||||
var cur_name = document.getElementById("zones-current-name");
|
var cur_name = document.getElementById("zones-current-name");
|
||||||
cur_name.innerHTML = "." + currentZone.name + " (" + currentZone.difficulty + "🔥)";
|
var name = "." + currentZone.name;
|
||||||
|
if (currentZone.yggdrasil) {
|
||||||
|
name = name + "*";
|
||||||
|
}
|
||||||
|
cur_name.innerHTML = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user