diff --git a/Cargo.toml b/Cargo.toml index 9bcb580..08225ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "alfis" -version = "0.4.21" +version = "0.4.22" authors = ["Revertron "] edition = "2018" build = "build.rs" diff --git a/src/blockchain/chain.rs b/src/blockchain/chain.rs index b8fba12..297d7c6 100644 --- a/src/blockchain/chain.rs +++ b/src/blockchain/chain.rs @@ -25,8 +25,6 @@ const TEMP_DB_NAME: &str = "temp.db"; const SQL_CREATE_TABLES: &str = include_str!("sql/create_db.sql"); const SQL_ADD_BLOCK: &str = "INSERT INTO blocks (id, timestamp, version, difficulty, random, nonce, 'transaction',\ prev_block_hash, hash, pub_key, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; -const SQL_REPLACE_BLOCK: &str = "UPDATE blocks SET timestamp = ?, version = ?, difficulty = ?, random = ?, nonce = ?, 'transaction' = ?,\ - prev_block_hash = ?, hash = ?, pub_key = ?, signature = ? WHERE id = ?;"; const SQL_GET_LAST_BLOCK: &str = "SELECT * FROM blocks ORDER BY id DESC LIMIT 1;"; const SQL_GET_FIRST_BLOCK_FOR_KEY: &str = "SELECT id FROM blocks WHERE pub_key = ? LIMIT 1;"; const SQL_DELETE_BLOCK_AND_TRANSACTIONS: &str = "DELETE FROM blocks WHERE id = ?; DELETE FROM domains WHERE id = ?; DELETE FROM zones WHERE id = ?;"; @@ -36,8 +34,6 @@ 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_ZONE: &str = "INSERT INTO zones (id, timestamp, identity, confirmation, data, pub_key) VALUES (?, ?, ?, ?, ?, ?)"; -const SQL_DELETE_DOMAIN: &str = "DELETE FROM domains WHERE id = ?"; -const SQL_DELETE_ZONE: &str = "DELETE FROM zones WHERE id = ?"; 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_FOR_KEY: &str = "SELECT * FROM blocks WHERE id < ? AND `transaction`<>'' AND pub_key = ? ORDER BY id DESC LIMIT 1;"; @@ -245,25 +241,10 @@ impl Chain { } } - pub fn replace_block(&mut self, index: u64, block: Block) -> sqlite::Result<()> { - debug!("Replacing block {} with:\n{:?}", index, &block); - let old_block = self.get_block(index).unwrap(); - if old_block.transaction.is_some() { - let _ = self.delete_transaction(index); - } - - let index = block.index; - let timestamp = block.timestamp; - self.last_block = Some(block.clone()); - if block.transaction.is_some() { - self.last_full_block = Some(block.clone()); - } - let transaction = block.transaction.clone(); - if self.replace_block_in_table(block).is_ok() { - if let Some(transaction) = transaction { - self.add_transaction_to_table(index, timestamp, &transaction).expect("Error adding transaction"); - } - } + pub fn replace_block(&mut self, block: Block) -> sqlite::Result<()> { + warn!("Replacing block {} with:\n{:?}", block.index, &block); + self.truncate_db_from_block(block.index)?; + self.add_block(block); Ok(()) } @@ -349,17 +330,6 @@ impl Chain { false } - 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 fn add_block_to_table(&mut self, block: Block) -> sqlite::Result { let mut statement = self.db.prepare(SQL_ADD_BLOCK)?; @@ -382,28 +352,6 @@ impl Chain { statement.next() } - /// Replaces block in blocks table on arrival of better block from some fork - fn replace_block_in_table(&mut self, block: Block) -> sqlite::Result { - let mut statement = self.db.prepare(SQL_REPLACE_BLOCK)?; - statement.bind(1, block.timestamp as i64)?; - statement.bind(2, block.version as i64)?; - statement.bind(3, block.difficulty as i64)?; - statement.bind(4, block.random as i64)?; - statement.bind(5, block.nonce as i64)?; - match &block.transaction { - None => { statement.bind(6, "")?; } - Some(transaction) => { - statement.bind(6, transaction.to_string().as_str())?; - } - } - statement.bind(7, &**block.prev_block_hash)?; - statement.bind(8, &**block.hash)?; - statement.bind(9, &**block.pub_key)?; - statement.bind(10, &**block.signature)?; - statement.bind(11, block.index as i64)?; - statement.next() - } - /// Adds transaction to transactions table fn add_transaction_to_table(&mut self, index: u64, timestamp: i64, t: &Transaction) -> sqlite::Result { let sql = match t.class.as_ref() { @@ -774,7 +722,7 @@ impl Chain { if let Some(prev_block) = self.get_block(block.index - 1) { if block.prev_block_hash.ne(&prev_block.hash) { warn!("Ignoring block with wrong previous hash:\n{:?}", &block); - return Bad; + return Rewind; } } diff --git a/src/blockchain/types.rs b/src/blockchain/types.rs index 076b4f2..de8fc00 100644 --- a/src/blockchain/types.rs +++ b/src/blockchain/types.rs @@ -4,6 +4,7 @@ pub enum BlockQuality { Good, Twin, Future, + Rewind, Bad, Fork, } diff --git a/src/p2p/network.rs b/src/p2p/network.rs index 9f624f8..af432d6 100644 --- a/src/p2p/network.rs +++ b/src/p2p/network.rs @@ -19,6 +19,7 @@ use rand::random; use crate::{Block, Context, p2p::Message, p2p::Peer, p2p::Peers, p2p::State}; use crate::blockchain::types::BlockQuality; use crate::commons::*; +use std::cmp::max; const SERVER: Token = Token(0); const POLL_TIMEOUT: Option = Some(Duration::from_millis(500)); @@ -404,7 +405,8 @@ fn handle_message(context: Arc>, message: Message, peers: &mut Pe let mut context = context.lock().unwrap(); if peer.is_higher(my_height) { context.chain.update_max_height(height); - context.bus.post(crate::event::Event::Syncing { have: my_height, height}); + let event = crate::event::Event::Syncing { have: my_height, height: max(height, my_height) }; + context.bus.post(event); } if active_count < 5 || random::() < 10 { debug!("Requesting more peers from {}", peer.get_addr().ip()); @@ -514,7 +516,8 @@ fn process_new_block(context: Arc>, peers: &mut Peers, token: &To if my_height == max_height { context.bus.post(crate::event::Event::SyncFinished); } else { - context.bus.post(crate::event::Event::Syncing { have: my_height, height: max_height }); + let event = crate::event::Event::Syncing { have: my_height, height: max(max_height, my_height) }; + context.bus.post(event); } context.bus.post(crate::event::Event::NetworkStatus { nodes: peers_count, blocks: my_height }); } @@ -528,11 +531,15 @@ fn process_new_block(context: Arc>, peers: &mut Peers, token: &To context.bus.post(crate::event::Event::SyncFinished); return State::Banned; } + BlockQuality::Rewind => { + debug!("Got some orphan block, requesting its parent"); + return State::message(Message::GetBlock { index: block.index - 1 }); + } BlockQuality::Fork => { debug!("Got forked block {} with hash {:?}", block.index, block.hash); let last_block = context.chain.last_block().unwrap(); if block.is_better_than(&last_block) { - context.chain.replace_block(block.index, block).expect("Error replacing block with fork"); + context.chain.replace_block(block).expect("Error replacing block with fork"); let index = context.chain.get_height(); context.bus.post(crate::event::Event::BlockchainChanged { index }); } diff --git a/src/p2p/peers.rs b/src/p2p/peers.rs index ae265ba..22f5701 100644 --- a/src/p2p/peers.rs +++ b/src/p2p/peers.rs @@ -23,6 +23,7 @@ pub struct Peers { ignored: HashSet, my_id: String, block_asked_time: i64, + behind_ping_sent_time: i64, } impl Peers { @@ -32,7 +33,8 @@ impl Peers { new_peers: Vec::new(), ignored: HashSet::new(), my_id: commons::random_string(6), - block_asked_time: 0 + block_asked_time: 0, + behind_ping_sent_time: 0 } } @@ -257,7 +259,7 @@ impl Peers { } // If someone has less blocks (we mined a new block) we send a ping with our height - { + if self.need_behind_ping() { let mut rng = rand::thread_rng(); match self.peers .iter_mut() @@ -268,6 +270,7 @@ impl Peers { debug!("Found some peer lower than we are, sending ping"); registry.reregister(peer.get_stream(), token.clone(), Interest::WRITABLE).unwrap(); peer.set_state(State::message(Message::Ping { height, hash })); + self.update_behind_ping_time(); } } } @@ -383,6 +386,14 @@ impl Peers { pub fn need_ask_block(&self) -> bool { self.block_asked_time + 5 < Utc::now().timestamp() } + + pub fn update_behind_ping_time(&mut self) { + self.behind_ping_sent_time = Utc::now().timestamp(); + } + + pub fn need_behind_ping(&self) -> bool { + self.behind_ping_sent_time + 5 < Utc::now().timestamp() + } } fn skip_private_addr(addr: &SocketAddr) -> bool {