A lot of optimization for block checks. Will speed up initial sync by about 15-20% of time.
This commit is contained in:
+16
-3
@@ -1,6 +1,7 @@
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -27,7 +28,9 @@ pub struct Block {
|
|||||||
#[serde(default, skip_serializing_if = "Bytes::is_zero")]
|
#[serde(default, skip_serializing_if = "Bytes::is_zero")]
|
||||||
pub signature: Bytes,
|
pub signature: Bytes,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub transaction: Option<Transaction>
|
pub transaction: Option<Transaction>,
|
||||||
|
#[serde(default, skip)]
|
||||||
|
hash_good: RefCell<bool>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
@@ -43,7 +46,8 @@ impl Block {
|
|||||||
prev_block_hash,
|
prev_block_hash,
|
||||||
hash: Bytes::default(),
|
hash: Bytes::default(),
|
||||||
pub_key,
|
pub_key,
|
||||||
signature: Bytes::default()
|
signature: Bytes::default(),
|
||||||
|
hash_good: RefCell::new(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +64,8 @@ impl Block {
|
|||||||
prev_block_hash,
|
prev_block_hash,
|
||||||
hash,
|
hash,
|
||||||
pub_key,
|
pub_key,
|
||||||
signature
|
signature,
|
||||||
|
hash_good: RefCell::new(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +79,14 @@ impl Block {
|
|||||||
self.prev_block_hash == Bytes::default()
|
self.prev_block_hash == Bytes::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_hash_good(&self) -> bool {
|
||||||
|
*self.hash_good.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_hash_good(&self, good: bool) {
|
||||||
|
*self.hash_good.borrow_mut() = good;
|
||||||
|
}
|
||||||
|
|
||||||
/// Serializes block to CBOR for network
|
/// Serializes block to CBOR for network
|
||||||
pub fn as_bytes(&self) -> Vec<u8> {
|
pub fn as_bytes(&self) -> Vec<u8> {
|
||||||
serde_cbor::to_vec(&self).unwrap()
|
serde_cbor::to_vec(&self).unwrap()
|
||||||
|
|||||||
+22
-25
@@ -35,7 +35,7 @@ const SQL_ADD_DOMAIN: &str = "INSERT INTO domains (id, timestamp, identity, conf
|
|||||||
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_OWNER_BY_ID: &str = "SELECT signing FROM domains WHERE id < ? AND identity = ? ORDER BY id DESC LIMIT 1;";
|
const SQL_GET_DOMAIN_OWNER_BY_ID: &str = "SELECT signing, timestamp FROM domains WHERE id < ? AND identity = ? ORDER BY id DESC LIMIT 1;";
|
||||||
const SQL_GET_DOMAIN_BY_ID: &str = "SELECT * FROM domains WHERE identity = ? AND id < ? ORDER BY id DESC LIMIT 1;";
|
const SQL_GET_DOMAIN_BY_ID: &str = "SELECT * FROM domains WHERE identity = ? AND id < ? ORDER BY id DESC LIMIT 1;";
|
||||||
const SQL_GET_DOMAINS_BY_KEY: &str = "SELECT timestamp, identity, data, signing FROM domains WHERE signing = ? ORDER BY id;";
|
const SQL_GET_DOMAINS_BY_KEY: &str = "SELECT timestamp, identity, data, signing FROM domains WHERE signing = ? ORDER BY id;";
|
||||||
const SQL_GET_DOMAINS_COUNT: &str = "SELECT count(DISTINCT identity) FROM domains;";
|
const SQL_GET_DOMAINS_COUNT: &str = "SELECT count(DISTINCT identity) FROM domains;";
|
||||||
@@ -152,7 +152,7 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//let last = self.last_block.clone().unwrap();
|
//let last = self.last_block.clone().unwrap();
|
||||||
if self.check_block(&block, &last_block, &last_full_block) != BlockQuality::Good {
|
if self.check_block(&block, &last_block, &last_full_block) != Good {
|
||||||
error!("Block {} is bad:\n{:?}", block.index, &block);
|
error!("Block {} is bad:\n{:?}", block.index, &block);
|
||||||
info!("Truncating database from block {}...", block.index);
|
info!("Truncating database from block {}...", block.index);
|
||||||
match self.truncate_db_from_block(block.index) {
|
match self.truncate_db_from_block(block.index) {
|
||||||
@@ -391,10 +391,10 @@ impl Chain {
|
|||||||
statement.bind(7, transaction.to_string().as_str())?;
|
statement.bind(7, transaction.to_string().as_str())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statement.bind(8, &**block.prev_block_hash)?;
|
statement.bind(8, block.prev_block_hash.as_slice())?;
|
||||||
statement.bind(9, &**block.hash)?;
|
statement.bind(9, block.hash.as_slice())?;
|
||||||
statement.bind(10, &**block.pub_key)?;
|
statement.bind(10, block.pub_key.as_slice())?;
|
||||||
statement.bind(11, &**block.signature)?;
|
statement.bind(11, block.signature.as_slice())?;
|
||||||
statement.next()
|
statement.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,11 +409,11 @@ impl Chain {
|
|||||||
let mut statement = self.db.prepare(sql)?;
|
let mut statement = self.db.prepare(sql)?;
|
||||||
statement.bind(1, index as i64)?;
|
statement.bind(1, index as i64)?;
|
||||||
statement.bind(2, timestamp)?;
|
statement.bind(2, timestamp)?;
|
||||||
statement.bind(3, &**t.identity)?;
|
statement.bind(3, t.identity.as_slice())?;
|
||||||
statement.bind(4, &**t.confirmation)?;
|
statement.bind(4, t.confirmation.as_slice())?;
|
||||||
statement.bind(5, t.data.as_ref() as &str)?;
|
statement.bind(5, t.data.as_ref() as &str)?;
|
||||||
statement.bind(6, &**t.signing)?;
|
statement.bind(6, t.signing.as_slice())?;
|
||||||
statement.bind(7, &**t.encryption)?;
|
statement.bind(7, t.encryption.as_slice())?;
|
||||||
statement.next()
|
statement.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,12 +488,13 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if any domain is available to mine for this client (pub_key)
|
/// Checks if any domain is available to mine for this client (pub_key)
|
||||||
pub fn is_domain_available(&self, height: u64, domain: &str, keystore: &Keystore) -> bool {
|
pub fn is_domain_available(&self, height: u64, domain: &str, public_key: &Bytes) -> bool {
|
||||||
if domain.is_empty() {
|
if domain.is_empty() {
|
||||||
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()) {
|
if !self.is_id_available(height, &identity_hash, public_key) {
|
||||||
|
warn!("Domain {} is not available!", domain);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,7 +513,7 @@ impl Chain {
|
|||||||
pub fn is_id_available(&self, height: u64, identity: &Bytes, public_key: &Bytes) -> bool {
|
pub fn is_id_available(&self, height: u64, identity: &Bytes, public_key: &Bytes) -> bool {
|
||||||
let mut statement = self.db.prepare(SQL_GET_DOMAIN_OWNER_BY_ID).unwrap();
|
let mut statement = self.db.prepare(SQL_GET_DOMAIN_OWNER_BY_ID).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.as_slice()).expect("Error in bind");
|
||||||
while let State::Row = statement.next().unwrap() {
|
while let State::Row = statement.next().unwrap() {
|
||||||
let pub_key = Bytes::from_bytes(&statement.read::<Vec<u8>>(0).unwrap());
|
let pub_key = Bytes::from_bytes(&statement.read::<Vec<u8>>(0).unwrap());
|
||||||
if !pub_key.eq(public_key) {
|
if !pub_key.eq(public_key) {
|
||||||
@@ -557,7 +558,7 @@ impl Chain {
|
|||||||
// Checking for existing domain in DB
|
// Checking for existing domain in DB
|
||||||
let mut statement = self.db.prepare(SQL_GET_DOMAIN_OWNER_BY_ID).unwrap();
|
let mut statement = self.db.prepare(SQL_GET_DOMAIN_OWNER_BY_ID).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.as_slice()).expect("Error in bind");
|
||||||
if let State::Row = statement.next().unwrap() {
|
if let State::Row = statement.next().unwrap() {
|
||||||
// If there is such an ID
|
// If there is such an ID
|
||||||
return true;
|
return true;
|
||||||
@@ -705,7 +706,7 @@ impl Chain {
|
|||||||
let keystore = keystore.unwrap();
|
let keystore = keystore.unwrap();
|
||||||
let pub_key = keystore.get_public();
|
let pub_key = keystore.get_public();
|
||||||
let mut statement = self.db.prepare(SQL_GET_DOMAINS_BY_KEY).unwrap();
|
let mut statement = self.db.prepare(SQL_GET_DOMAINS_BY_KEY).unwrap();
|
||||||
statement.bind(1, &**pub_key).expect("Error in bind");
|
statement.bind(1, pub_key.as_slice()).expect("Error in bind");
|
||||||
let height = self.get_height();
|
let height = self.get_height();
|
||||||
while let State::Row = statement.next().unwrap() {
|
while let State::Row = statement.next().unwrap() {
|
||||||
let timestamp = statement.read::<i64>(0).unwrap();
|
let timestamp = statement.read::<i64>(0).unwrap();
|
||||||
@@ -805,14 +806,10 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
if let Some(last) = last_block {
|
if let Some(last) = last_block {
|
||||||
if block.index > last.index + 1 {
|
if block.index > last.index + 1 {
|
||||||
info!("Got future block {}", block.index);
|
debug!("Got future block {}", block.index);
|
||||||
return Future;
|
return Future;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !check_public_key_strength(&block.pub_key, KEYSTORE_DIFFICULTY) {
|
|
||||||
warn!("Ignoring block with weak public key:\n{:?}", &block);
|
|
||||||
return Bad;
|
|
||||||
}
|
|
||||||
let difficulty = match &block.transaction {
|
let difficulty = match &block.transaction {
|
||||||
None => {
|
None => {
|
||||||
if block.index == 1 {
|
if block.index == 1 {
|
||||||
@@ -853,12 +850,12 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(transaction) = &block.transaction {
|
if let Some(transaction) = &block.transaction {
|
||||||
let current_height = match last_block {
|
if !check_public_key_strength(&block.pub_key, KEYSTORE_DIFFICULTY) {
|
||||||
None => 0,
|
warn!("Ignoring block with weak public key:\n{:?}", &block);
|
||||||
Some(block) => block.index
|
return Bad;
|
||||||
};
|
}
|
||||||
// If this domain is not available to this public key
|
// If this domain is not available to this public key
|
||||||
if !self.is_id_available(current_height, &transaction.identity, &block.pub_key) {
|
if !self.is_id_available(block.index - 1, &transaction.identity, &block.pub_key) {
|
||||||
warn!("Block {:?} is trying to spoof an identity!", &block);
|
warn!("Block {:?} is trying to spoof an identity!", &block);
|
||||||
return Bad;
|
return Bad;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,16 @@ use crate::{Block, Bytes, Keystore};
|
|||||||
|
|
||||||
/// Checks block's hash and returns true on valid hash or false otherwise
|
/// Checks block's hash and returns true on valid hash or false otherwise
|
||||||
pub fn check_block_hash(block: &Block) -> bool {
|
pub fn check_block_hash(block: &Block) -> bool {
|
||||||
|
// If this block's hash was already checked as good
|
||||||
|
if block.is_hash_good() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
let mut copy: Block = block.clone();
|
let mut copy: Block = block.clone();
|
||||||
copy.hash = Bytes::default();
|
copy.hash = Bytes::default();
|
||||||
copy.signature = Bytes::default();
|
copy.signature = Bytes::default();
|
||||||
blakeout_data(©.as_bytes_compact()) == block.hash
|
let good = blakeout_data(©.as_bytes_compact()) == block.hash;
|
||||||
|
block.set_hash_good(good);
|
||||||
|
good
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hashes data by given hasher
|
/// Hashes data by given hasher
|
||||||
|
|||||||
+1
-1
@@ -598,7 +598,7 @@ impl Network {
|
|||||||
if index != block.index {
|
if index != block.index {
|
||||||
return State::Banned;
|
return State::Banned;
|
||||||
}
|
}
|
||||||
info!("Received block {} with hash {:?}", block.index, &block.hash);
|
debug!("Received block {} with hash {:?}", block.index, &block.hash);
|
||||||
if !seen_blocks.contains(&block.hash) {
|
if !seen_blocks.contains(&block.hash) {
|
||||||
self.handle_block(token, block, seen_blocks)
|
self.handle_block(token, block, seen_blocks)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -126,7 +126,7 @@ fn action_check_domain(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>
|
|||||||
let c = context.lock().unwrap();
|
let c = context.lock().unwrap();
|
||||||
if let Some(keystore) = c.get_keystore() {
|
if let Some(keystore) = c.get_keystore() {
|
||||||
let name = name.to_lowercase();
|
let name = name.to_lowercase();
|
||||||
let available = c.get_chain().is_domain_available(c.get_chain().get_height(), &name, keystore);
|
let available = c.get_chain().is_domain_available(c.get_chain().get_height(), &name, &keystore.get_public());
|
||||||
web_view.eval(&format!("domainAvailable({})", available)).expect("Error evaluating!");
|
web_view.eval(&format!("domainAvailable({})", available)).expect("Error evaluating!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user