Fixed a problem with forks longer than one.
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "alfis"
|
name = "alfis"
|
||||||
version = "0.4.21"
|
version = "0.4.22"
|
||||||
authors = ["Revertron <alfis@revertron.com>"]
|
authors = ["Revertron <alfis@revertron.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|||||||
+5
-57
@@ -25,8 +25,6 @@ const TEMP_DB_NAME: &str = "temp.db";
|
|||||||
const SQL_CREATE_TABLES: &str = include_str!("sql/create_db.sql");
|
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',\
|
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_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_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_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 = ?;";
|
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_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 (?, ?, ?, ?, ?, ?)";
|
||||||
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_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;";
|
||||||
@@ -245,25 +241,10 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_block(&mut self, index: u64, block: Block) -> sqlite::Result<()> {
|
pub fn replace_block(&mut self, block: Block) -> sqlite::Result<()> {
|
||||||
debug!("Replacing block {} with:\n{:?}", index, &block);
|
warn!("Replacing block {} with:\n{:?}", block.index, &block);
|
||||||
let old_block = self.get_block(index).unwrap();
|
self.truncate_db_from_block(block.index)?;
|
||||||
if old_block.transaction.is_some() {
|
self.add_block(block);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,17 +330,6 @@ impl Chain {
|
|||||||
false
|
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
|
/// 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)?;
|
||||||
@@ -382,28 +352,6 @@ impl Chain {
|
|||||||
statement.next()
|
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
|
/// Adds transaction to transactions table
|
||||||
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() {
|
||||||
@@ -774,7 +722,7 @@ impl Chain {
|
|||||||
if let Some(prev_block) = self.get_block(block.index - 1) {
|
if let Some(prev_block) = self.get_block(block.index - 1) {
|
||||||
if block.prev_block_hash.ne(&prev_block.hash) {
|
if block.prev_block_hash.ne(&prev_block.hash) {
|
||||||
warn!("Ignoring block with wrong previous hash:\n{:?}", &block);
|
warn!("Ignoring block with wrong previous hash:\n{:?}", &block);
|
||||||
return Bad;
|
return Rewind;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ pub enum BlockQuality {
|
|||||||
Good,
|
Good,
|
||||||
Twin,
|
Twin,
|
||||||
Future,
|
Future,
|
||||||
|
Rewind,
|
||||||
Bad,
|
Bad,
|
||||||
Fork,
|
Fork,
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-3
@@ -19,6 +19,7 @@ use rand::random;
|
|||||||
use crate::{Block, Context, p2p::Message, p2p::Peer, p2p::Peers, p2p::State};
|
use crate::{Block, Context, p2p::Message, p2p::Peer, p2p::Peers, p2p::State};
|
||||||
use crate::blockchain::types::BlockQuality;
|
use crate::blockchain::types::BlockQuality;
|
||||||
use crate::commons::*;
|
use crate::commons::*;
|
||||||
|
use std::cmp::max;
|
||||||
|
|
||||||
const SERVER: Token = Token(0);
|
const SERVER: Token = Token(0);
|
||||||
const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(500));
|
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();
|
let mut context = context.lock().unwrap();
|
||||||
if peer.is_higher(my_height) {
|
if peer.is_higher(my_height) {
|
||||||
context.chain.update_max_height(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 {
|
if active_count < 5 || random::<u8>() < 10 {
|
||||||
debug!("Requesting more peers from {}", peer.get_addr().ip());
|
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 {
|
if my_height == max_height {
|
||||||
context.bus.post(crate::event::Event::SyncFinished);
|
context.bus.post(crate::event::Event::SyncFinished);
|
||||||
} else {
|
} 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 });
|
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);
|
context.bus.post(crate::event::Event::SyncFinished);
|
||||||
return State::Banned;
|
return State::Banned;
|
||||||
}
|
}
|
||||||
|
BlockQuality::Rewind => {
|
||||||
|
debug!("Got some orphan block, requesting its parent");
|
||||||
|
return State::message(Message::GetBlock { index: block.index - 1 });
|
||||||
|
}
|
||||||
BlockQuality::Fork => {
|
BlockQuality::Fork => {
|
||||||
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) {
|
||||||
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();
|
let index = context.chain.get_height();
|
||||||
context.bus.post(crate::event::Event::BlockchainChanged { index });
|
context.bus.post(crate::event::Event::BlockchainChanged { index });
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-2
@@ -23,6 +23,7 @@ pub struct Peers {
|
|||||||
ignored: HashSet<IpAddr>,
|
ignored: HashSet<IpAddr>,
|
||||||
my_id: String,
|
my_id: String,
|
||||||
block_asked_time: i64,
|
block_asked_time: i64,
|
||||||
|
behind_ping_sent_time: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Peers {
|
impl Peers {
|
||||||
@@ -32,7 +33,8 @@ impl Peers {
|
|||||||
new_peers: Vec::new(),
|
new_peers: Vec::new(),
|
||||||
ignored: HashSet::new(),
|
ignored: HashSet::new(),
|
||||||
my_id: commons::random_string(6),
|
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 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();
|
let mut rng = rand::thread_rng();
|
||||||
match self.peers
|
match self.peers
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@@ -268,6 +270,7 @@ impl Peers {
|
|||||||
debug!("Found some peer lower than we are, sending ping");
|
debug!("Found some peer lower than we are, sending ping");
|
||||||
registry.reregister(peer.get_stream(), token.clone(), Interest::WRITABLE).unwrap();
|
registry.reregister(peer.get_stream(), token.clone(), Interest::WRITABLE).unwrap();
|
||||||
peer.set_state(State::message(Message::Ping { height, hash }));
|
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 {
|
pub fn need_ask_block(&self) -> bool {
|
||||||
self.block_asked_time + 5 < Utc::now().timestamp()
|
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 {
|
fn skip_private_addr(addr: &SocketAddr) -> bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user