Fixed parsing of DomainData, many other fixes.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "alfis"
|
name = "alfis"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
authors = ["Revertron <alfis@revertron.com>"]
|
authors = ["Revertron <alfis@revertron.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|||||||
+76
-24
@@ -8,7 +8,7 @@ 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, Keystore, Transaction, check_domain, get_domain_zone, is_yggdrasil_record, from_hex};
|
||||||
use crate::commons::constants::*;
|
use crate::commons::constants::*;
|
||||||
use crate::blockchain::types::{BlockQuality, MineResult, Options};
|
use crate::blockchain::types::{BlockQuality, MineResult, Options};
|
||||||
use crate::blockchain::types::BlockQuality::*;
|
use crate::blockchain::types::BlockQuality::*;
|
||||||
@@ -27,6 +27,7 @@ const SQL_ADD_BLOCK: &str = "INSERT INTO blocks (id, timestamp, version, difficu
|
|||||||
prev_block_hash, hash, pub_key, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
|
prev_block_hash, hash, pub_key, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
|
||||||
const SQL_REPLACE_BLOCK: &str = "UPDATE blocks SET timestamp = ?, version = ?, difficulty = ?, random = ?, nonce = ?, 'transaction' = ?,\
|
const SQL_REPLACE_BLOCK: &str = "UPDATE blocks SET timestamp = ?, version = ?, difficulty = ?, random = ?, nonce = ?, 'transaction' = ?,\
|
||||||
prev_block_hash = ?, hash = ?, pub_key = ?, signature = ? WHERE id = ?;";
|
prev_block_hash = ?, hash = ?, pub_key = ?, signature = ? WHERE id = ?;";
|
||||||
|
const SQL_DELETE_FAULTY_BLOCKS: &str = "DELETE FROM blocks WHERE id >= ?;";
|
||||||
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_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, pub_key) VALUES (?, ?, ?, ?, ?, ?)";
|
||||||
const SQL_ADD_ZONE: &str = "INSERT INTO zones (id, timestamp, identity, confirmation, data, pub_key) VALUES (?, ?, ?, ?, ?, ?)";
|
const SQL_ADD_ZONE: &str = "INSERT INTO zones (id, timestamp, identity, confirmation, data, pub_key) VALUES (?, ?, ?, ?, ?, ?)";
|
||||||
@@ -73,7 +74,21 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trying to get last block from DB to check its version
|
// Trying to get last block from DB to check its version
|
||||||
let block: Option<Block> = match self.db.prepare(SQL_GET_LAST_BLOCK) {
|
// If some block loaded we check its version and determine if we need some migration
|
||||||
|
if let Some(block) = self.load_last_block() {
|
||||||
|
// Cache some info
|
||||||
|
self.last_block = Some(block.clone());
|
||||||
|
if block.transaction.is_some() {
|
||||||
|
self.last_full_block = Some(block);
|
||||||
|
} else {
|
||||||
|
self.last_full_block = self.get_last_full_block(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.check_chain();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_last_block(&mut self) -> Option<Block> {
|
||||||
|
match self.db.prepare(SQL_GET_LAST_BLOCK) {
|
||||||
Ok(mut statement) => {
|
Ok(mut statement) => {
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
while statement.next().unwrap() == State::Row {
|
while statement.next().unwrap() == State::Row {
|
||||||
@@ -96,16 +111,6 @@ impl Chain {
|
|||||||
self.db.execute(SQL_CREATE_TABLES).expect("Error creating DB tables");
|
self.db.execute(SQL_CREATE_TABLES).expect("Error creating DB tables");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
|
||||||
// If some block loaded we check its version and determine if we need some migration
|
|
||||||
if let Some(block) = block {
|
|
||||||
// Cache some info
|
|
||||||
self.last_block = Some(block.clone());
|
|
||||||
if block.transaction.is_some() {
|
|
||||||
self.last_full_block = Some(block);
|
|
||||||
} else {
|
|
||||||
self.last_full_block = self.get_last_full_block(None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +133,30 @@ impl Chain {
|
|||||||
let _ = fs::remove_file(&file).is_err();
|
let _ = fs::remove_file(&file).is_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_chain(&mut self) {
|
||||||
|
let height = self.height();
|
||||||
|
info!("Local blockchain height is {}", height);
|
||||||
|
for id in (1..=height).rev() {
|
||||||
|
info!("Checking block {}", id);
|
||||||
|
match self.get_block(id) {
|
||||||
|
None => {}
|
||||||
|
Some(block) => {
|
||||||
|
let faulty_block_hash = "0000133B790B61460D757E1F1F2D04480C8340D28CA73AE5AF27DBBF60548D00";
|
||||||
|
let bytes = Bytes::from_bytes(&from_hex(faulty_block_hash).unwrap());
|
||||||
|
if block.hash == bytes {
|
||||||
|
if block.transaction.is_some() {
|
||||||
|
let _ = self.delete_transaction(block.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = self.delete_faulty_blocks(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.last_block = self.load_last_block();
|
||||||
|
info!("Last block after chain check: {:?}", &self.last_block);
|
||||||
|
}
|
||||||
|
|
||||||
fn get_options(&self) -> Options {
|
fn get_options(&self) -> Options {
|
||||||
let mut options = Options::empty();
|
let mut options = Options::empty();
|
||||||
if let Ok(mut statement) = self.db.prepare(SQL_GET_OPTIONS) {
|
if let Ok(mut statement) = self.db.prepare(SQL_GET_OPTIONS) {
|
||||||
@@ -144,6 +173,13 @@ impl Chain {
|
|||||||
options
|
options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn delete_faulty_blocks(&mut self, from: u64) -> sqlite::Result<State> {
|
||||||
|
warn!("Removing block with error {}", from);
|
||||||
|
let mut statement = self.db.prepare(SQL_DELETE_FAULTY_BLOCKS)?;
|
||||||
|
statement.bind(1, from as i64)?;
|
||||||
|
statement.next()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_block(&mut self, block: Block) {
|
pub fn add_block(&mut self, block: Block) {
|
||||||
debug!("Adding block:\n{:?}", &block);
|
debug!("Adding block:\n{:?}", &block);
|
||||||
let index = block.index;
|
let index = block.index;
|
||||||
@@ -164,13 +200,7 @@ impl Chain {
|
|||||||
debug!("Replacing block {} with:\n{:?}", index, &block);
|
debug!("Replacing block {} with:\n{:?}", index, &block);
|
||||||
let old_block = self.get_block(index).unwrap();
|
let old_block = self.get_block(index).unwrap();
|
||||||
if old_block.transaction.is_some() {
|
if old_block.transaction.is_some() {
|
||||||
let mut statement = self.db.prepare(SQL_DELETE_DOMAIN)?;
|
let _ = self.delete_transaction(index);
|
||||||
statement.bind(1, index as i64)?;
|
|
||||||
statement.next()?;
|
|
||||||
|
|
||||||
let mut statement = self.db.prepare(SQL_DELETE_ZONE)?;
|
|
||||||
statement.bind(1, index as i64)?;
|
|
||||||
statement.next()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = block.index;
|
let index = block.index;
|
||||||
@@ -188,6 +218,17 @@ impl Chain {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn delete_transaction(&mut self, index: u64) -> sqlite::Result<()> {
|
||||||
|
let mut statement = self.db.prepare(SQL_DELETE_DOMAIN)?;
|
||||||
|
statement.bind(1, index as i64)?;
|
||||||
|
statement.next()?;
|
||||||
|
|
||||||
|
let mut statement = self.db.prepare(SQL_DELETE_ZONE)?;
|
||||||
|
statement.bind(1, index as i64)?;
|
||||||
|
statement.next()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds block to blocks table
|
/// Adds block to blocks table
|
||||||
fn add_block_to_table(&mut self, block: Block) -> sqlite::Result<State> {
|
fn add_block_to_table(&mut self, block: Block) -> sqlite::Result<State> {
|
||||||
let mut statement = self.db.prepare(SQL_ADD_BLOCK)?;
|
let mut statement = self.db.prepare(SQL_ADD_BLOCK)?;
|
||||||
@@ -447,10 +488,10 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
let identity = Bytes::from_bytes(&statement.read::<Vec<u8>>(2).unwrap());
|
let identity = Bytes::from_bytes(&statement.read::<Vec<u8>>(2).unwrap());
|
||||||
let confirmation = Bytes::from_bytes(&statement.read::<Vec<u8>>(3).unwrap());
|
let confirmation = Bytes::from_bytes(&statement.read::<Vec<u8>>(3).unwrap());
|
||||||
let method = statement.read::<String>(4).unwrap();
|
let class = String::from("domain");
|
||||||
let data = statement.read::<String>(5).unwrap();
|
let data = statement.read::<String>(4).unwrap();
|
||||||
let pub_key = Bytes::from_bytes(&statement.read::<Vec<u8>>(6).unwrap());
|
let pub_key = Bytes::from_bytes(&statement.read::<Vec<u8>>(5).unwrap());
|
||||||
let transaction = Transaction { identity, confirmation, class: method, data, pub_key };
|
let transaction = Transaction { identity, confirmation, class, 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) {
|
||||||
return Some(transaction);
|
return Some(transaction);
|
||||||
@@ -556,6 +597,14 @@ impl Chain {
|
|||||||
warn!("Block {:?} has wrong signature! Ignoring!", &block);
|
warn!("Block {:?} has wrong signature! Ignoring!", &block);
|
||||||
return Bad;
|
return Bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let faulty_block_hash = "0000133B790B61460D757E1F1F2D04480C8340D28CA73AE5AF27DBBF60548D00";
|
||||||
|
let bytes = Bytes::from_bytes(&from_hex(faulty_block_hash).unwrap());
|
||||||
|
if block.hash == bytes {
|
||||||
|
warn!("Block {:?} is faulty! Ignoring!", &block);
|
||||||
|
return Bad;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(transaction) = &block.transaction {
|
if let Some(transaction) = &block.transaction {
|
||||||
// TODO check for zone transaction
|
// TODO check for zone transaction
|
||||||
if !self.is_id_available(&transaction.identity, &block.pub_key, false) || !self.is_id_available(&transaction.identity, &block.pub_key, true) {
|
if !self.is_id_available(&transaction.identity, &block.pub_key, false) || !self.is_id_available(&transaction.identity, &block.pub_key, true) {
|
||||||
@@ -662,7 +711,10 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
u32::max_value()
|
u32::max_value()
|
||||||
}
|
}
|
||||||
Err(_) => { u32::max_value() }
|
Err(_) => {
|
||||||
|
warn!("Error parsing DomainData from {:?}", transaction);
|
||||||
|
u32::max_value()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"zone" => { ZONE_DIFFICULTY }
|
"zone" => { ZONE_DIFFICULTY }
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ pub fn hash_identity(identity: &str, key: Option<&Bytes>) -> Bytes {
|
|||||||
None => { Bytes::from_bytes(&identity) }
|
None => { Bytes::from_bytes(&identity) }
|
||||||
Some(key) => {
|
Some(key) => {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
buf.append(&mut identity.clone());
|
buf.append(&mut base.clone());
|
||||||
buf.append(&mut key.to_vec());
|
buf.append(&mut key.to_vec());
|
||||||
Bytes::from_bytes(&hash_sha256(&buf))
|
Bytes::from_bytes(&hash_sha256(&buf))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ impl Serialize for Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, 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,
|
||||||
|
|||||||
+7
-5
@@ -144,22 +144,24 @@ impl<'de> Visitor<'de> for BytesVisitor {
|
|||||||
type Value = Bytes;
|
type Value = Bytes;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
fn expecting(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
||||||
formatter.write_str("32 or 64 bytes")
|
formatter.write_str("bytes in HEX format")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: DeError, {
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: DeError, {
|
||||||
if value.len() == 64 || value.len() == 128 {
|
if !value.is_empty() && value.len() % 2 == 0 {
|
||||||
Ok(Bytes::new(crate::from_hex(value).unwrap()))
|
Ok(Bytes::new(crate::from_hex(value).unwrap()))
|
||||||
|
} else if value.is_empty() {
|
||||||
|
Ok(Bytes::default())
|
||||||
} else {
|
} else {
|
||||||
Err(E::custom("Key must be 32 or 64 bytes!"))
|
Err(E::custom("Expected bytes in HEX format!"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> where E: DeError, {
|
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> where E: DeError, {
|
||||||
if value.len() == 32 || value.len() == 64 {
|
if !value.is_empty() {
|
||||||
Ok(Bytes::from_bytes(value))
|
Ok(Bytes::from_bytes(value))
|
||||||
} else {
|
} else {
|
||||||
Err(E::custom("Key must be 32 or 64 bytes!"))
|
Ok(Bytes::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -331,8 +331,9 @@ fn action_create_domain(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>,
|
|||||||
let pub_key = keystore.get_public();
|
let pub_key = keystore.get_public();
|
||||||
let mut data = match serde_json::from_str::<DomainData>(&data) {
|
let mut data = match serde_json::from_str::<DomainData>(&data) {
|
||||||
Ok(data) => { data }
|
Ok(data) => { data }
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
show_warning(web_view, "Something wrong with domain data. I cannot mine it.");
|
show_warning(web_view, "Something wrong with domain data. I cannot mine it.");
|
||||||
|
warn!("Error parsing data: {}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
<div class="buttons has-addons">
|
<div class="buttons has-addons">
|
||||||
<button class="button is-info is-light" onclick="loadKey();" title="Load keypair from file">Load key</button>
|
<button class="button is-info is-light" onclick="loadKey();" title="Load keypair from file">Load key</button>
|
||||||
<button class="button is-info is-light" id="save_key" onclick="saveKey();" disabled title="Save current keypair to file">Save key</button>
|
<button class="button is-info is-light" id="save_key" onclick="saveKey();" disabled title="Save current keypair to file">Save key</button>
|
||||||
<button class="button is-info" onclick="createKey();" title="Generate new keypair, suitable to mine domains">Mine new key</button>
|
<button class="button is-info" 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 (or zones) you need to mine a strong pair of keys.</p>
|
||||||
|
|||||||
+18
-6
@@ -159,20 +159,26 @@ function recordOkay(okay) {
|
|||||||
|
|
||||||
function createDomain() {
|
function createDomain() {
|
||||||
var new_domain = document.getElementById("new_domain").value.toLowerCase();
|
var new_domain = document.getElementById("new_domain").value.toLowerCase();
|
||||||
var new_dom_records = JSON.stringify(recordsBuffer);
|
|
||||||
var domain = new_domain + "." + currentZone.name;
|
var domain = new_domain + "." + currentZone.name;
|
||||||
var data = {};
|
var data = {};
|
||||||
data.domain = [];
|
data.domain = "";
|
||||||
data.zone = currentZone.name;
|
data.zone = currentZone.name;
|
||||||
data.records = new_dom_records;
|
data.records = recordsBuffer;
|
||||||
data.owners = []; // TODO make a dialog to fill them
|
data.owners = []; // TODO make a dialog to fill them
|
||||||
data.contacts = []; // TODO make a dialog to fill them
|
data.contacts = []; // TODO make a dialog to fill them
|
||||||
external.invoke(JSON.stringify({cmd: 'mineDomain', name: domain, records: new_dom_records}));
|
data = JSON.stringify(data);
|
||||||
|
external.invoke(JSON.stringify({cmd: 'mineDomain', name: domain, data: data}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function domainMiningStarted() {
|
function domainMiningStarted() {
|
||||||
recordsBuffer = [];
|
//recordsBuffer = [];
|
||||||
refreshRecordsList();
|
//refreshRecordsList();
|
||||||
|
document.getElementById("tab_domains").disabled = true;
|
||||||
|
document.getElementById("domain_records").disabled = true;
|
||||||
|
document.getElementById("add_record_button").disabled = true;
|
||||||
|
document.getElementById("new_domain_button").disabled = true;
|
||||||
|
document.getElementById("new_zone_button").disabled = true;
|
||||||
|
document.getElementById("new_key_button").disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createZone() {
|
function createZone() {
|
||||||
@@ -309,6 +315,12 @@ function showMiningIndicator(visible, blue) {
|
|||||||
} else {
|
} else {
|
||||||
indicator.className = 'busy_indicator is-hidden';
|
indicator.className = 'busy_indicator is-hidden';
|
||||||
parent.style.display = 'none';
|
parent.style.display = 'none';
|
||||||
|
document.getElementById("tab_domains").disabled = false;
|
||||||
|
document.getElementById("domain_records").disabled = false;
|
||||||
|
document.getElementById("add_record_button").disabled = false;
|
||||||
|
document.getElementById("new_domain_button").disabled = false;
|
||||||
|
document.getElementById("new_zone_button").disabled = false;
|
||||||
|
document.getElementById("new_key_button").disabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ body {
|
|||||||
|
|
||||||
.notification.is-success {
|
.notification.is-success {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10pt;
|
bottom: 30pt;
|
||||||
right: 10pt;
|
right: 10pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,4 +81,8 @@ path {
|
|||||||
|
|
||||||
.is-danger > span.icon > svg > path {
|
.is-danger > span.icon > svg > path {
|
||||||
fill: #f14668;
|
fill: #f14668;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-danger:hover > span.icon > svg > path {
|
||||||
|
fill: #ffffff;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user