Fixed a problem with forks longer than one.

This commit is contained in:
Revertron
2021-04-22 14:52:14 +02:00
parent 7e1ea8e23d
commit b248d839e1
5 changed files with 30 additions and 63 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "alfis"
version = "0.4.21"
version = "0.4.22"
authors = ["Revertron <alfis@revertron.com>"]
edition = "2018"
build = "build.rs"
+5 -57
View File
@@ -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<State> {
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<State> {
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<State> {
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;
}
}
+1
View File
@@ -4,6 +4,7 @@ pub enum BlockQuality {
Good,
Twin,
Future,
Rewind,
Bad,
Fork,
}
+10 -3
View File
@@ -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<Duration> = Some(Duration::from_millis(500));
@@ -404,7 +405,8 @@ fn handle_message(context: Arc<Mutex<Context>>, 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::<u8>() < 10 {
debug!("Requesting more peers from {}", peer.get_addr().ip());
@@ -514,7 +516,8 @@ fn process_new_block(context: Arc<Mutex<Context>>, 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<Mutex<Context>>, 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 });
}
+13 -2
View File
@@ -23,6 +23,7 @@ pub struct Peers {
ignored: HashSet<IpAddr>,
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 {