From 47c398118afa5b411a4316242df840152d35bcd2 Mon Sep 17 00:00:00 2001 From: Revertron Date: Sat, 17 Apr 2021 01:51:14 +0200 Subject: [PATCH] Optimized new block processing. Added quick-ban for those, who send wrong blocks. --- src/blockchain/chain.rs | 4 ++ src/p2p/network.rs | 112 ++++++++++++++++++++-------------------- src/p2p/peer.rs | 11 +++- src/p2p/peers.rs | 2 +- 4 files changed, 72 insertions(+), 57 deletions(-) diff --git a/src/blockchain/chain.rs b/src/blockchain/chain.rs index 27d40e9..fd1d1f3 100644 --- a/src/blockchain/chain.rs +++ b/src/blockchain/chain.rs @@ -611,6 +611,10 @@ impl Chain { /// Check if this block can be added to our blockchain pub fn check_new_block(&self, block: &Block) -> BlockQuality { + if block.version > CHAIN_VERSION { + warn!("Ignoring block from unsupported version:\n{:?}", &block); + return Bad; + } let timestamp = Utc::now().timestamp(); if block.timestamp > timestamp + 60 { warn!("Ignoring block from the future:\n{:?}", &block); diff --git a/src/p2p/network.rs b/src/p2p/network.rs index edb2ddb..cdcbe7c 100644 --- a/src/p2p/network.rs +++ b/src/p2p/network.rs @@ -357,7 +357,6 @@ fn handle_message(context: Arc>, message: Message, peers: &mut Pe }; let answer = match message { Message::Hand { app_version, origin, version, public, rand} => { - debug!("Hello from v{}", &app_version); if peers.is_our_own_connect(&rand) { warn!("Detected loop connect"); State::Banned @@ -365,6 +364,7 @@ fn handle_message(context: Arc>, message: Message, peers: &mut Pe if origin.eq(my_origin) && version == my_version { let peer = peers.get_mut_peer(token).unwrap(); peer.set_public(public); + debug!("Hello from v{} on {}", &app_version, peer.get_addr().ip()); State::message(Message::shake(&origin, version, true, my_height)) } else { warn!("Handshake from unsupported chain or version"); @@ -453,65 +453,67 @@ fn handle_message(context: Arc>, message: Message, peers: &mut Pe Ok(block) => block, Err(_) => return State::Error }; - let peer = peers.get_mut_peer(token).unwrap(); - peer.set_received_block(block.index); - if let Some(transaction) = &block.transaction { - if context.lock().unwrap().x_zones.has_hash(&transaction.identity.to_string()) { - // This peer has mined some of the forbidden zones - return State::Banned; - } - } - let context = Arc::clone(&context); - let peers_count = peers.get_peers_active_count(); - let _ = thread::Builder::new().name(String::from("Message::Block")).spawn(move || { - let mut context = context.lock().unwrap(); - let max_height = context.chain.max_height(); - match context.chain.check_new_block(&block) { - BlockQuality::Good => { - context.chain.add_block(block); - let keystore = context.keystore.clone(); - context.chain.update(&keystore); - let my_height = context.chain.height(); - context.bus.post(crate::event::Event::BlockchainChanged { index: my_height }); - // If it was the last block to sync - 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}); - } - context.bus.post(crate::event::Event::NetworkStatus { nodes: peers_count, blocks: my_height }); - } - BlockQuality::Twin => { debug!("Ignoring duplicate block {}", block.index); } - BlockQuality::Future => { debug!("Ignoring future block {}", block.index); } - BlockQuality::Bad => { - // TODO save bad public keys to banned table - debug!("Ignoring bad block {} with hash {:?}", block.index, block.hash); - let height = context.chain.height(); - context.chain.update_max_height(height); - context.bus.post(crate::event::Event::SyncFinished); - } - 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"); - let keystore = context.keystore.clone(); - context.chain.update(&keystore); - let index = context.chain.height(); - context.bus.post(crate::event::Event::BlockchainChanged { index }); - } - let height = context.chain.height(); - context.chain.update_max_height(height); - context.bus.post(crate::event::Event::SyncFinished); - } - } - }); - State::idle() + process_new_block(context, peers, token, block) } }; answer } +fn process_new_block(context: Arc>, peers: &mut Peers, token: &Token, block: Block) -> State { + let peer = peers.get_mut_peer(token).unwrap(); + peer.set_received_block(block.index); + if let Some(transaction) = &block.transaction { + if context.lock().unwrap().x_zones.has_hash(&transaction.identity.to_string()) { + // This peer has mined some of the forbidden zones + return State::Banned; + } + } + let peers_count = peers.get_peers_active_count(); + let mut context = context.lock().unwrap(); + let max_height = context.chain.max_height(); + match context.chain.check_new_block(&block) { + BlockQuality::Good => { + context.chain.add_block(block); + let keystore = context.keystore.clone(); + context.chain.update(&keystore); + let my_height = context.chain.height(); + context.bus.post(crate::event::Event::BlockchainChanged { index: my_height }); + // If it was the last block to sync + 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 }); + } + context.bus.post(crate::event::Event::NetworkStatus { nodes: peers_count, blocks: my_height }); + } + BlockQuality::Twin => { debug!("Ignoring duplicate block {}", block.index); } + BlockQuality::Future => { debug!("Ignoring future block {}", block.index); } + BlockQuality::Bad => { + // TODO save bad public keys to banned table + debug!("Ignoring bad block {} with hash {:?}", block.index, block.hash); + let height = context.chain.height(); + context.chain.update_max_height(height); + context.bus.post(crate::event::Event::SyncFinished); + return State::Banned; + } + 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"); + let keystore = context.keystore.clone(); + context.chain.update(&keystore); + let index = context.chain.height(); + context.bus.post(crate::event::Event::BlockchainChanged { index }); + } + let height = context.chain.height(); + context.chain.update_max_height(height); + context.bus.post(crate::event::Event::SyncFinished); + } + } + State::idle() +} + #[allow(dead_code)] fn deal_with_fork(context: MutexGuard, peer: &mut Peer, block: Block) { peer.add_fork_block(block); diff --git a/src/p2p/peer.rs b/src/p2p/peer.rs index 6603c05..a8d7c6e 100644 --- a/src/p2p/peer.rs +++ b/src/p2p/peer.rs @@ -79,7 +79,16 @@ impl Peer { } pub fn has_more_blocks(&self, height: u64) -> bool { - self.height > self.received_block && self.height > height && self.get_state().is_idle() + if self.height <= height { + return false; + } + if self.received_block > height { + return false; + } + if !self.get_state().is_idle() { + return false; + } + self.height > height } pub fn is_public(&self) -> bool { diff --git a/src/p2p/peers.rs b/src/p2p/peers.rs index 79e178f..021c65f 100644 --- a/src/p2p/peers.rs +++ b/src/p2p/peers.rs @@ -239,7 +239,7 @@ impl Peers { .choose(&mut rng) { None => {} Some((token, peer)) => { - debug!("Found some peer higher than we are, requesting block {}", height + 1); + debug!("Found some peer higher than we are, requesting block {}, from {}", height + 1, &peer.get_addr().ip()); registry.reregister(peer.get_stream(), token.clone(), Interest::WRITABLE).unwrap(); peer.set_state(State::message(Message::GetBlock { index: height + 1 })); ping_sent = true;