Fixed a problem with forks longer than one.
This commit is contained in:
+1
-1
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ pub enum BlockQuality {
|
||||
Good,
|
||||
Twin,
|
||||
Future,
|
||||
Rewind,
|
||||
Bad,
|
||||
Fork,
|
||||
}
|
||||
|
||||
+10
-3
@@ -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
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user