Eliminated connection loops.

Optimized network processes.
Removed some unnecessary logging.
Fixed status bar info inconsistency.
pull/5/head
Revertron 3 years ago
parent 4497dc515b
commit dcf5bb72b0

@ -26,7 +26,7 @@ chrono = { version = "0.4.13", features = ["serde"] }
rand = "0.8.3"
sqlite = "0.25.3"
uuid = { version = "0.8.2", features = ["serde", "v4"] }
mio = { version = "0.7", features = ["os-poll", "net"] }
mio = { version = "0.7.10", features = ["os-poll", "net"] }
# for DNS from hermes
derive_more = "0.99.9"

@ -185,7 +185,7 @@ impl Chain {
None
}
Some(block) => {
trace!("Loaded block: {:?}", &block);
//trace!("Loaded block: {:?}", &block);
Some(block)
}
};
@ -229,7 +229,7 @@ impl Chain {
None
}
Some(block) => {
trace!("Got last full block: {:?}", &block);
//trace!("Got last full block: {:?}", &block);
Some(block)
}
};

@ -43,12 +43,12 @@ impl DnsFilter for BlockchainFilter {
let mut packet = DnsPacket::new();
packet.questions.push(DnsQuestion::new(String::from(qname), qtype));
packet.header.rescode = ResultCode::SERVFAIL;
trace!("Returning packet: {:?}", &packet);
//trace!("Returning packet: {:?}", &packet);
return Some(packet);
}
}
Some(data) => {
info!("Found data for domain {}", &search);
debug!("Found data for domain {}", &search);
let mut data: DomainData = match serde_json::from_str(&data) {
Err(_) => { return None; }
Ok(data) => { data }
@ -136,14 +136,14 @@ impl DnsFilter for BlockchainFilter {
for answer in answers {
packet.answers.push(answer);
}
trace!("Returning packet: {:?}", &packet);
//trace!("Returning packet: {:?}", &packet);
Some(packet)
} else {
// Create DnsPacket
let mut packet = DnsPacket::new();
packet.questions.push(DnsQuestion::new(String::from(qname), qtype));
packet.header.rescode = ResultCode::SERVFAIL;
trace!("Returning packet: {:?}", &packet);
//trace!("Returning packet: {:?}", &packet);
Some(packet)
}
}

@ -59,7 +59,7 @@ impl Bytes {
}
pub fn to_string(&self) -> String {
crate::utils::to_hex(&self.data)
crate::commons::to_hex(&self.data)
}
pub fn get_tail_u64(&self) -> u64 {
@ -127,14 +127,14 @@ impl Deref for Bytes {
impl fmt::Debug for Bytes {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(&crate::utils::to_hex(&self.data))
fmt.write_str(&crate::commons::to_hex(&self.data))
}
}
impl Serialize for Bytes {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
S: Serializer {
serializer.serialize_str(&crate::utils::to_hex(&self.data))
serializer.serialize_str(&crate::commons::to_hex(&self.data))
}
}

@ -1,4 +1,5 @@
use std::num;
use rand::Rng;
#[cfg(not(target_os = "macos"))]
use thread_priority::*;
@ -79,6 +80,19 @@ fn split_n(s: &str, n: usize) -> Vec<&str> {
.collect()
}
/// Generates random string of given length
pub fn random_string(length: usize) -> String {
let chars: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?".chars().collect();
let mut rng = rand::thread_rng();
let mut result = String::with_capacity(length);
for _ in 0..length {
let position: usize = rng.gen::<usize>() % chars.len();
let c: char = *chars.get(position).unwrap();
result.push(c);
}
result
}
#[cfg(test)]
mod test {
use crate::check_domain;

@ -10,10 +10,10 @@ pub use crate::bytes::Bytes;
pub use crate::keys::Keystore;
pub use crate::x_zones::ExternalZones;
pub use crate::simplebus::*;
pub use crate::utils::*;
pub use crate::commons::*;
pub mod blockchain;
pub mod utils;
pub mod commons;
pub mod simplebus;
pub mod keys;
pub mod miner;

@ -71,7 +71,7 @@ fn main() {
None => { SETTINGS_FILENAME.to_owned() }
Some(path) => { path }
};
SimpleLogger::new().with_level(level).init().unwrap();
SimpleLogger::new().with_level(level).with_module_level("mio::poll", LevelFilter::Warn).init().unwrap();
info!(target: LOG_TARGET_MAIN, "Starting ALFIS {}", env!("CARGO_PKG_VERSION"));
let settings = Settings::load(&config_name);

@ -7,7 +7,7 @@ use crate::Bytes;
#[derive(Debug, Serialize, Deserialize)]
pub enum Message {
Error,
Hand { origin: String, version: u32, public: bool },
Hand { origin: String, version: u32, public: bool, #[serde(default)] rand: String },
Shake { origin: String, version: u32, ok: bool, height: u64 },
Ping { height: u64, hash: Bytes },
Pong { height: u64, hash: Bytes },
@ -26,8 +26,8 @@ impl Message {
}
}
pub fn hand(origin: &str, version: u32, public: bool) -> Self {
Message::Hand { origin: origin.to_owned(), version, public }
pub fn hand(origin: &str, version: u32, public: bool, rand: &str) -> Self {
Message::Hand { origin: origin.to_owned(), version, public, rand: rand.to_owned() }
}
pub fn shake(origin: &str, version: u32, ok: bool, height: u64) -> Self {
@ -46,3 +46,16 @@ impl Message {
Message::Block { index: height, block: str }
}
}
#[cfg(test)]
mod tests {
use crate::p2p::Message;
#[test]
pub fn test_hand() {
assert!(serde_json::from_str::<Message>("\"Error\"").is_ok());
assert!(serde_json::from_str::<Message>("{\"Hand\":{\"origin\":\"\",\"version\":1,\"public\":false,\"rand\":\"123\"}}").is_ok());
assert!(serde_json::from_str::<Message>("{\"Hand\":{\"origin\":\"\",\"version\":1,\"public\":false}}").is_ok());
}
}

@ -13,11 +13,11 @@ use mio::net::{TcpListener, TcpStream};
#[allow(unused_imports)]
use log::{trace, debug, info, warn, error};
use std::net::{SocketAddr, IpAddr, SocketAddrV4, Shutdown};
use std::collections::HashSet;
use crate::{Context, Block, p2p::Message, p2p::State, p2p::Peer, p2p::Peers, Bytes};
use std::net::{SocketAddr, IpAddr, SocketAddrV4, ToSocketAddrs};
use crate::blockchain::enums::BlockQuality;
use crate::blockchain::CHAIN_VERSION;
use std::collections::HashSet;
const SERVER: Token = Token(0);
const POLL_TIMEOUT: Option<Duration> = Some(Duration::from_millis(3000));
@ -57,7 +57,7 @@ impl Network {
// States of peer connections, and some data to send when sockets become writable
let mut peers = Peers::new();
// Starting peer connections to bootstrap nodes
connect_peers(peers_addrs, &mut poll, &mut peers, &mut unique_token);
peers.connect_peers(peers_addrs, &poll.registry(), &mut unique_token);
loop {
// Poll Mio for events, blocking until we get an event.
@ -65,7 +65,7 @@ impl Network {
// Process each event.
for event in events.iter() {
trace!("Event for socket {} is {:?}", event.token().0, &event);
//trace!("Event for socket {} is {:?}", event.token().0, &event);
// We can use the token we previously provided to `register` to determine for which socket the event is.
match event.token() {
SERVER => {
@ -82,10 +82,18 @@ impl Network {
}
}
info!("Accepted connection from: {}", address);
let token = next(&mut unique_token);
poll.registry().register(&mut stream, token, Interest::READABLE).expect("Error registering poll");
peers.add_peer(token, Peer::new(address, stream, State::Connected, true));
// If connection is from the same IP and not from loopback we ignore it to avoid connection loops
let local_ip = stream.local_addr().unwrap_or("0.0.0.0:0".parse().unwrap());
if !local_ip.ip().is_loopback() && local_ip.ip() == address.ip() {
peers.ignore_ip(&address.ip());
stream.shutdown(Shutdown::Both);
warn!("Detected connection loop, ignoring IP: {}", &address.ip());
} else {
info!("Accepted connection from: {} to local IP: {}", address, local_ip);
let token = next(&mut unique_token);
poll.registry().register(&mut stream, token, Interest::READABLE).expect("Error registering poll");
peers.add_peer(token, Peer::new(address, stream, State::Connected, true));
}
}
Err(_) => {}
}
@ -105,8 +113,13 @@ impl Network {
// Send pings to idle peers
let (height, hash) = {
let context = context.lock().unwrap();
(context.chain.height(), context.chain.last_hash())
let mut context = context.lock().unwrap();
let height = context.chain.height();
let nodes = peers.get_peers_active_count();
if nodes > 0 {
context.bus.post(crate::event::Event::NetworkStatus { nodes, blocks: height });
}
(height, context.chain.last_hash())
};
mine_locker_block(context.clone());
peers.send_pings(poll.registry(), height, hash);
@ -153,7 +166,9 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
State::Idle { .. } => {
peer.set_state(State::idle());
}
State::Error => {}
State::Error => {
peers.ignore_peer(registry, &event.token());
}
State::Banned => {}
State::Offline { .. } => {
peer.set_state(State::offline());
@ -168,7 +183,7 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
}
if event.is_writable() {
trace!("Socket {} is writable", event.token().0);
//trace!("Socket {} is writable", event.token().0);
match peers.get_mut_peer(&event.token()) {
None => {}
Some(peer) => {
@ -177,11 +192,11 @@ fn handle_connection_event(context: Arc<Mutex<Context>>, peers: &mut Peers, regi
debug!("Sending hello to {}", &peer.get_addr());
let data: String = {
let c = context.lock().unwrap();
let message = Message::hand(&c.settings.origin, CHAIN_VERSION, c.settings.public);
let message = Message::hand(&c.settings.origin, CHAIN_VERSION, c.settings.public, peer.get_rand());
serde_json::to_string(&message).unwrap()
};
send_message(peer.get_stream(), &data.into_bytes());
debug!("Sent hello to {}", &peer.get_addr());
//debug!("Sent hello to {}", &peer.get_addr());
}
State::Message { data } => {
debug!("Sending data to {}: {}", &peer.get_addr(), &String::from_utf8(data.clone()).unwrap());
@ -220,7 +235,7 @@ fn read_message(stream: &mut TcpStream) -> Result<Vec<u8>, ()> {
0
}
};
trace!("Payload size is {}", data_size);
//trace!("Payload size is {}", data_size);
if data_size > MAX_PACKET_SIZE || data_size == 0 {
return Err(());
}
@ -256,11 +271,10 @@ fn read_message(stream: &mut TcpStream) -> Result<Vec<u8>, ()> {
}
}
fn send_message(connection: &mut TcpStream, data: &Vec<u8>) {
// TODO handle errors
connection.write_u32::<BigEndian>(data.len() as u32).expect("Error sending message");
connection.write_all(&data).expect("Error writing to socket");
connection.flush().expect("Error sending message");
fn send_message(connection: &mut TcpStream, data: &Vec<u8>) -> io::Result<()> {
connection.write_u32::<BigEndian>(data.len() as u32)?;
connection.write_all(&data)?;
connection.flush()
}
fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Peers, token: &Token) -> State {
@ -270,14 +284,19 @@ fn handle_message(context: Arc<Mutex<Context>>, message: Message, peers: &mut Pe
(context.chain.height(), context.chain.last_hash(), &context.settings.origin.clone(), CHAIN_VERSION)
};
match message {
Message::Hand { origin, version, public } => {
if origin.eq(my_origin) && version == my_version {
let peer = peers.get_mut_peer(token).unwrap();
peer.set_public(public);
State::message(Message::shake(&origin, version, true, my_height))
} else {
warn!("Handshake from unsupported chain or version");
Message::Hand { origin, version, public, rand} => {
if peers.is_our_own_connect(&rand) {
warn!("Detected loop connect");
State::Error
} else {
if origin.eq(my_origin) && version == my_version {
let peer = peers.get_mut_peer(token).unwrap();
peer.set_public(public);
State::message(Message::shake(&origin, version, true, my_height))
} else {
warn!("Handshake from unsupported chain or version");
State::Error
}
}
}
Message::Shake { origin, version, ok, height } => {
@ -456,32 +475,6 @@ fn check_block(block: &Block, prev: &Block) -> bool {
prev.index == block.index - 1 && prev.hash == block.prev_block_hash
}
/// Connecting to configured (bootstrap) peers
fn connect_peers(peers_addrs: Vec<String>, poll: &mut Poll, peers: &mut Peers, unique_token: &mut Token) {
for peer in peers_addrs.iter() {
let addresses: Vec<SocketAddr> = match peer.to_socket_addrs() {
Ok(peers) => { peers.collect() }
Err(_) => { error!("Can't resolve address {}", &peer); continue; }
};
for addr in addresses {
match TcpStream::connect(addr.clone()) {
Ok(mut stream) => {
info!("Created connection to peer {}", &addr);
let token = next(unique_token);
poll.registry().register(&mut stream, token, Interest::WRITABLE).unwrap();
let mut peer = Peer::new(addr, stream, State::Connecting, false);
peer.set_public(true);
peers.add_peer(token, peer);
}
Err(e) => {
error!("Error connecting to peer {}: {}", &addr, e);
}
}
}
}
}
pub(crate) fn next(current: &mut Token) -> Token {
let next = current.0;
current.0 += 1;

@ -2,13 +2,14 @@ use std::net::SocketAddr;
use std::collections::HashMap;
use mio::net::TcpStream;
use crate::p2p::State;
use crate::Block;
use crate::{Block, commons};
#[derive(Debug)]
pub struct Peer {
addr: SocketAddr,
stream: TcpStream,
state: State,
rand: String,
height: u64,
inbound: bool,
public: bool,
@ -19,7 +20,7 @@ pub struct Peer {
impl Peer {
pub fn new(addr: SocketAddr, stream: TcpStream, state: State, inbound: bool) -> Self {
Peer { addr, stream, state, height: 0, inbound, public: false, active: false, received_block: 0, fork: HashMap::new() }
Peer { addr, stream, state, rand: commons::random_string(6), height: 0, inbound, public: false, active: false, received_block: 0, fork: HashMap::new() }
}
pub fn get_addr(&self) -> SocketAddr {
@ -42,6 +43,10 @@ impl Peer {
self.state = state;
}
pub fn get_rand(&self) -> &str {
&self.rand
}
pub fn set_height(&mut self, height: u64) {
self.height = height;
}

@ -1,5 +1,5 @@
use std::collections::{HashMap, HashSet};
use std::net::{SocketAddr, Shutdown};
use std::net::{SocketAddr, IpAddr, Shutdown, ToSocketAddrs};
use mio::{Token, Interest, Registry};
use mio::net::TcpStream;
use crate::p2p::{Peer, State, Message};
@ -13,14 +13,15 @@ use crate::Bytes;
pub struct Peers {
peers: HashMap<Token, Peer>,
new_peers: Vec<SocketAddr>
new_peers: Vec<SocketAddr>,
ignored: HashSet<IpAddr>
}
const PING_PERIOD: u64 = 30;
impl Peers {
pub fn new() -> Self {
Peers { peers: HashMap::new(), new_peers: Vec::new() }
Peers { peers: HashMap::new(), new_peers: Vec::new(), ignored: HashSet::new() }
}
pub fn add_peer(&mut self, token: Token, peer: Peer) {
@ -65,26 +66,32 @@ impl Peers {
debug!("Got {} peers: {:?}", peers.len(), &peers);
// TODO make it return error if these peers are wrong and seem like an attack
for peer in peers.iter() {
let addr: SocketAddr = peer.parse().expect(&format!("Error parsing peer {}", peer));
let addr: SocketAddr = match peer.parse() {
Err(_) => {
warn!("Error parsing peer {}", peer);
continue;
}
Ok(addr) => addr
};
if self.peers
.iter()
.find(|(_token, peer)| peer.get_addr() == addr)
.find(|(_token, peer)| peer.get_addr().ip() == addr.ip())
.is_some() {
debug!("Skipping address from exchange: {}", &addr);
//debug!("Skipping address from exchange: {}", &addr);
continue;
}
if self.new_peers
.iter()
.find(|a| a.clone().eq(&addr))
.find(|a| a.ip().eq(&addr.ip()))
.is_some() {
debug!("Skipping address from exchange: {}", &addr);
//debug!("Skipping address from exchange: {}", &addr);
continue;
}
if skip_addr(&addr) {
debug!("Skipping address from exchange: {}", &addr);
//debug!("Skipping address from exchange: {}", &addr);
continue; // Return error in future
}
let mut found = false;
@ -101,6 +108,15 @@ impl Peers {
}
}
pub fn is_our_own_connect(&self, rand: &str) -> bool {
match self.peers.values().find(|p| p.get_rand() == rand) {
None => { false }
Some(p) => {
!p.is_inbound()
}
}
}
pub fn get_peers_for_exchange(&self, peer_address: &SocketAddr) -> Vec<String> {
let mut result: Vec<String> = Vec::new();
for (_, peer) in self.peers.iter() {
@ -124,6 +140,28 @@ impl Peers {
count
}
pub fn ignore_peer(&mut self, registry: &Registry, token: &Token) {
let peer = self.peers.get_mut(token).unwrap();
peer.set_state(State::Banned);
let ip = peer.get_addr().ip().clone();
self.close_peer(registry, token);
self.ignored.insert(ip);
match self.peers
.iter()
.find(|(_, p)| p.get_addr().ip() == ip)
.map(|(t, _)| t.clone()) {
None => {}
Some(t) => {
self.close_peer(registry, &t);
self.peers.remove(&t);
}
}
}
pub fn ignore_ip(&mut self, ip: &IpAddr) {
self.ignored.insert(ip.clone());
}
pub fn skip_peer_connection(&self, addr: &SocketAddr) -> bool {
for (_, peer) in self.peers.iter() {
if peer.equals(addr) && (!peer.is_public() || peer.active() || peer.disabled()) {
@ -138,7 +176,8 @@ impl Peers {
for (token, peer) in self.peers.iter_mut() {
match peer.get_state() {
State::Idle { from } => {
if from.elapsed().as_secs() >= PING_PERIOD {
let random_time = random::<u64>() % PING_PERIOD;
if from.elapsed().as_secs() >= PING_PERIOD + random_time {
// Sometimes we check for new peers instead of pinging
let random: u8 = random();
let message = if random < 16 {
@ -195,10 +234,10 @@ impl Peers {
let addr = peer.get_addr();
match TcpStream::connect(addr.clone()) {
Ok(mut stream) => {
info!("Created connection to peer {}, state = {:?}", &addr, peer.get_state());
registry.register(&mut stream, token.clone(), Interest::WRITABLE).unwrap();
peer.set_state(State::Connecting);
peer.set_stream(stream);
info!("Created connection to peer {}", &addr);
}
Err(e) => {
error!("Error connecting to peer {}: {}", &addr, e);
@ -213,6 +252,9 @@ impl Peers {
return;
}
for addr in self.new_peers.iter() {
if self.ignored.contains(&addr.ip()) {
continue;
}
match TcpStream::connect(addr.clone()) {
Ok(mut stream) => {
info!("Created connection to peer {}", &addr);
@ -229,6 +271,32 @@ impl Peers {
}
self.new_peers.clear();
}
/// Connecting to configured (bootstrap) peers
pub fn connect_peers(&mut self, peers_addrs: Vec<String>, registry: &Registry, unique_token: &mut Token) {
for peer in peers_addrs.iter() {
let addresses: Vec<SocketAddr> = match peer.to_socket_addrs() {
Ok(peers) => { peers.collect() }
Err(_) => { error!("Can't resolve address {}", &peer); continue; }
};
for addr in addresses {
match TcpStream::connect(addr.clone()) {
Ok(mut stream) => {
info!("Created connection to peer {}", &addr);
let token = next(unique_token);
registry.register(&mut stream, token, Interest::WRITABLE).unwrap();
let mut peer = Peer::new(addr, stream, State::Connecting, false);
peer.set_public(true);
self.add_peer(token, peer);
}
Err(e) => {
error!("Error connecting to peer {}: {}", &addr, e);
}
}
}
}
}
}
fn skip_addr(addr: &SocketAddr) -> bool {

@ -165,7 +165,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
let mut status = Status::new();
let mut c = context.lock().unwrap();
c.bus.register(move |_uuid, e| {
debug!("Got event from bus {:?}", &e);
//debug!("Got event from bus {:?}", &e);
let eval = match e {
Event::KeyCreated { path, public, hash } |
Event::KeyLoaded { path, public, hash } |
@ -213,7 +213,7 @@ fn action_loaded(context: &Arc<Mutex<Context>>, web_view: &mut WebView<()>) {
};
if !eval.is_empty() {
debug!("Evaluating {}", &eval);
//debug!("Evaluating {}", &eval);
handle.dispatch(move |web_view| {
web_view.eval(&eval.replace("\\", "\\\\"))
}).expect("Error dispatching!");

@ -338,7 +338,7 @@
</div>
</div>
<div class="level-item">
<div id="status_bar_left">Connecting and syncing...</div>
<div id="status_bar_left">Connecting...</div>
</div>
</div>

Loading…
Cancel
Save