-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Networking and backend fixes #155
Changes from 1 commit
c5cc70a
6111c62
eeaf645
168ff05
8fb71bc
1c2311b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,18 +18,14 @@ | |
|
|
||
| use std::collections::{HashMap, HashSet}; | ||
| use futures::sync::{oneshot, mpsc}; | ||
| use std::time::{Instant, Duration}; | ||
| use std::collections::hash_map::Entry; | ||
| use io::SyncIo; | ||
| use protocol::Protocol; | ||
| use network::PeerId; | ||
| use primitives::Hash; | ||
| use primitives::{Hash, block::HeaderHash, block::Id as BlockId}; | ||
| use client::BlockStatus; | ||
| use message::{self, Message}; | ||
| use runtime_support::Hashable; | ||
|
|
||
| // TODO: Add additional spam/DoS attack protection. | ||
| const MESSAGE_LIFETIME_SECONDS: u64 = 600; | ||
|
|
||
| struct CandidateRequest { | ||
| id: message::RequestId, | ||
| completion: oneshot::Sender<Vec<u8>>, | ||
|
|
@@ -47,7 +43,8 @@ pub struct Consensus { | |
| our_candidate: Option<(Hash, Vec<u8>)>, | ||
| statement_sink: Option<mpsc::UnboundedSender<message::Statement>>, | ||
| bft_message_sink: Option<(mpsc::UnboundedSender<message::LocalizedBftMessage>, Hash)>, | ||
| messages: HashMap<Hash, (Instant, message::Message)>, | ||
| messages: Vec<(Hash, message::Message)>, | ||
| message_hashes: HashSet<Hash>, | ||
| } | ||
|
|
||
| impl Consensus { | ||
|
|
@@ -59,6 +56,7 @@ impl Consensus { | |
| statement_sink: None, | ||
| bft_message_sink: None, | ||
| messages: Default::default(), | ||
| message_hashes: Default::default(), | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -75,9 +73,9 @@ impl Consensus { | |
| // Send out all known messages. | ||
| // TODO: limit by size | ||
| let mut known_messages = HashSet::new(); | ||
| for (hash, &(_, ref m)) in self.messages.iter() { | ||
| for &(ref hash, ref message) in self.messages.iter() { | ||
| known_messages.insert(hash.clone()); | ||
| protocol.send_message(io, peer_id, m.clone()); | ||
| protocol.send_message(io, peer_id, message.clone()); | ||
| } | ||
| self.peers.insert(peer_id, PeerConsensus { | ||
| candidate_fetch: None, | ||
|
|
@@ -96,13 +94,13 @@ impl Consensus { | |
| } | ||
|
|
||
| fn register_message(&mut self, hash: Hash, message: message::Message) { | ||
| if let Entry::Vacant(entry) = self.messages.entry(hash) { | ||
| entry.insert((Instant::now(), message)); | ||
| if self.message_hashes.insert(hash) { | ||
| self.messages.push((hash, message)); | ||
| } | ||
| } | ||
|
|
||
| pub fn on_statement(&mut self, io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId, statement: message::Statement, hash: Hash) { | ||
| if self.messages.contains_key(&hash) { | ||
| if self.message_hashes.contains(&hash) { | ||
| trace!(target:"sync", "Ignored already known statement from {}", peer_id); | ||
| } | ||
| if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { | ||
|
|
@@ -137,11 +135,24 @@ impl Consensus { | |
| } | ||
|
|
||
| pub fn on_bft_message(&mut self, io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId, message: message::LocalizedBftMessage, hash: Hash) { | ||
| if self.messages.contains_key(&hash) { | ||
| if self.message_hashes.contains(&hash) { | ||
| trace!(target:"sync", "Ignored already known BFT message from {}", peer_id); | ||
| return; | ||
| } | ||
|
|
||
| match protocol.chain().block_status(&BlockId::Hash(message.parent_hash)) { | ||
| Err(e) => { | ||
| debug!(target:"sync", "Error reading blockchain: {:?}", e); | ||
| return; | ||
| }, | ||
| Ok(status) => { | ||
| if status != BlockStatus::InChain { | ||
| trace!(target:"sync", "Ignored unknown parent BFT message from {}, hash={}", peer_id, message.parent_hash); | ||
|
||
| return; | ||
| } | ||
| }, | ||
| } | ||
|
|
||
| if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { | ||
| peer.known_messages.insert(hash); | ||
| // TODO: validate signature? | ||
|
|
@@ -168,9 +179,9 @@ impl Consensus { | |
| pub fn bft_messages(&mut self, parent_hash: Hash) -> mpsc::UnboundedReceiver<message::LocalizedBftMessage>{ | ||
| let (sink, stream) = mpsc::unbounded(); | ||
|
|
||
| for (_, message) in self.messages.iter() { | ||
| for &(_, ref message) in self.messages.iter() { | ||
| let bft_message = match *message { | ||
| (_, Message::BftMessage(ref msg)) => msg, | ||
| Message::BftMessage(ref msg) => msg, | ||
| _ => continue, | ||
| }; | ||
|
|
||
|
|
@@ -266,17 +277,28 @@ impl Consensus { | |
| self.peers.remove(&peer_id); | ||
| } | ||
|
|
||
| pub fn collect_garbage(&mut self) { | ||
| let expiration = Duration::from_secs(MESSAGE_LIFETIME_SECONDS); | ||
| let now = Instant::now(); | ||
| pub fn collect_garbage(&mut self, best_block_parent: Option<HeaderHash>) { | ||
| let before = self.messages.len(); | ||
| self.messages.retain(|_, &mut (timestamp, _)| timestamp < now + expiration); | ||
| let hashes = &mut self.message_hashes; | ||
| self.messages.retain(|&(ref hash, ref message)| { | ||
| best_block_parent.map_or(true, |parent_hash| { | ||
|
||
| if match *message { | ||
| Message::BftMessage(ref msg) => msg.parent_hash != parent_hash, | ||
| Message::Statement(ref msg) => msg.parent_hash != parent_hash, | ||
| _ => true, | ||
| } { | ||
| hashes.remove(hash); | ||
| true | ||
| } else { | ||
| false | ||
| } | ||
| }) | ||
| }); | ||
| if self.messages.len() != before { | ||
| trace!(target:"sync", "Cleaned up {} stale messages", before - self.messages.len()); | ||
| } | ||
| let messages = &self.messages; | ||
| for (_, ref mut peer) in self.peers.iter_mut() { | ||
| peer.known_messages.retain(|h| messages.contains_key(h)); | ||
| peer.known_messages.retain(|h| hashes.contains(h)); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,7 +36,7 @@ use io::SyncIo; | |
| use error; | ||
| use super::header_hash; | ||
|
|
||
| const REQUEST_TIMEOUT_SEC: u64 = 15; | ||
| const REQUEST_TIMEOUT_SEC: u64 = 40; | ||
| const PROTOCOL_VERSION: u32 = 0; | ||
|
|
||
| // Maximum allowed entries in `BlockResponse` | ||
|
|
@@ -344,7 +344,7 @@ impl Protocol { | |
| /// Perform time based maintenance. | ||
| pub fn tick(&self, io: &mut SyncIo) { | ||
| self.maintain_peers(io); | ||
| self.consensus.lock().collect_garbage(); | ||
| self.consensus.lock().collect_garbage(None); | ||
| } | ||
|
|
||
| fn maintain_peers(&self, io: &mut SyncIo) { | ||
|
|
@@ -387,6 +387,8 @@ impl Protocol { | |
| return; | ||
| } | ||
|
|
||
| let mut sync = self.sync.write(); | ||
| let mut consensus = self.consensus.lock(); | ||
| { | ||
| let mut peers = self.peers.write(); | ||
| let mut handshaking_peers = self.handshaking_peers.write(); | ||
|
|
@@ -420,8 +422,8 @@ impl Protocol { | |
| handshaking_peers.remove(&peer_id); | ||
| debug!(target: "sync", "Connected {} {}", peer_id, io.peer_info(peer_id)); | ||
| } | ||
| self.sync.write().new_peer(io, self, peer_id); | ||
| self.consensus.lock().new_peer(io, self, peer_id, &status.roles); | ||
| sync.new_peer(io, self, peer_id); | ||
| consensus.new_peer(io, self, peer_id, &status.roles); | ||
| } | ||
|
|
||
| /// Called when peer sends us new transactions | ||
|
|
@@ -511,6 +513,8 @@ impl Protocol { | |
| })); | ||
| } | ||
| } | ||
|
|
||
| self.consensus.lock().collect_garbage(Some(header.parent_hash)); | ||
|
||
| } | ||
|
|
||
| pub fn transactions_stats(&self) -> BTreeMap<ExtrinsicHash, TransactionStats> { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is fixed and tested in #152
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reverted