les: use negotiated protocol version

This commit is contained in:
Robert Habermeier 2016-12-09 15:04:54 +01:00
parent eec1929658
commit 5f37c93659
3 changed files with 32 additions and 5 deletions

View File

@ -38,6 +38,9 @@ pub trait IoContext {
/// Disable a peer -- this is a disconnect + a time-out. /// Disable a peer -- this is a disconnect + a time-out.
fn disable_peer(&self, peer: PeerId); fn disable_peer(&self, peer: PeerId);
/// Get a peer's protocol version.
fn protocol_version(&self, peer: PeerId) -> Option<u8>;
} }
impl<'a> IoContext for NetworkContext<'a> { impl<'a> IoContext for NetworkContext<'a> {
@ -60,6 +63,10 @@ impl<'a> IoContext for NetworkContext<'a> {
fn disable_peer(&self, peer: PeerId) { fn disable_peer(&self, peer: PeerId) {
NetworkContext::disable_peer(self, peer); NetworkContext::disable_peer(self, peer);
} }
fn protocol_version(&self, peer: PeerId) -> Option<u8> {
self.protocol_version(self.subprotocol_name(), peer)
}
} }
/// Context for a protocol event. /// Context for a protocol event.

View File

@ -58,6 +58,10 @@ pub enum Error {
UnsolicitedResponse, UnsolicitedResponse,
/// Not a server. /// Not a server.
NotServer, NotServer,
/// Unsupported protocol version.
UnsupportedProtocolVersion(u8),
/// Bad protocol version.
BadProtocolVersion,
} }
impl Error { impl Error {
@ -73,6 +77,8 @@ impl Error {
Error::UnknownPeer => Punishment::Disconnect, Error::UnknownPeer => Punishment::Disconnect,
Error::UnsolicitedResponse => Punishment::Disable, Error::UnsolicitedResponse => Punishment::Disable,
Error::NotServer => Punishment::Disable, Error::NotServer => Punishment::Disable,
Error::UnsupportedProtocolVersion(_) => Punishment::Disable,
Error::BadProtocolVersion => Punishment::Disable,
} }
} }
} }
@ -101,6 +107,8 @@ impl fmt::Display for Error {
Error::UnknownPeer => write!(f, "Unknown peer"), Error::UnknownPeer => write!(f, "Unknown peer"),
Error::UnsolicitedResponse => write!(f, "Peer provided unsolicited data"), Error::UnsolicitedResponse => write!(f, "Peer provided unsolicited data"),
Error::NotServer => write!(f, "Peer not a server."), Error::NotServer => write!(f, "Peer not a server."),
Error::UnsupportedProtocolVersion(pv) => write!(f, "Unsupported protocol version: {}", pv),
Error::BadProtocolVersion => write!(f, "Bad protocol version in handshake"),
} }
} }
} }

View File

@ -23,7 +23,7 @@ use ethcore::transaction::SignedTransaction;
use ethcore::receipt::Receipt; use ethcore::receipt::Receipt;
use io::TimerToken; use io::TimerToken;
use network::{NetworkProtocolHandler, NetworkContext, NetworkError, PeerId}; use network::{NetworkProtocolHandler, NetworkContext, PeerId};
use rlp::{RlpStream, Stream, UntrustedRlp, View}; use rlp::{RlpStream, Stream, UntrustedRlp, View};
use util::hash::H256; use util::hash::H256;
use util::{Bytes, Mutex, RwLock, U256}; use util::{Bytes, Mutex, RwLock, U256};
@ -111,6 +111,7 @@ pub struct ReqId(usize);
struct PendingPeer { struct PendingPeer {
sent_head: H256, sent_head: H256,
last_update: SteadyTime, last_update: SteadyTime,
proto_version: u8,
} }
// data about each peer. // data about each peer.
@ -121,6 +122,7 @@ struct Peer {
remote_flow: Option<(Buffer, FlowParams)>, remote_flow: Option<(Buffer, FlowParams)>,
sent_head: H256, // last head we've given them. sent_head: H256, // last head we've given them.
last_update: SteadyTime, last_update: SteadyTime,
proto_version: u8,
} }
impl Peer { impl Peer {
@ -507,17 +509,21 @@ impl LightProtocol {
} }
// send status to a peer. // send status to a peer.
fn send_status(&self, peer: PeerId, io: &IoContext) -> Result<PendingPeer, NetworkError> { fn send_status(&self, peer: PeerId, io: &IoContext) -> Result<PendingPeer, Error> {
let chain_info = self.provider.chain_info(); let proto_version = try!(io.protocol_version(peer).ok_or(Error::WrongNetwork));
// TODO: could update capabilities here. if PROTOCOL_VERSIONS.iter().find(|x| **x == proto_version).is_none() {
return Err(Error::UnsupportedProtocolVersion(proto_version));
}
let chain_info = self.provider.chain_info();
let status = Status { let status = Status {
head_td: chain_info.total_difficulty, head_td: chain_info.total_difficulty,
head_hash: chain_info.best_block_hash, head_hash: chain_info.best_block_hash,
head_num: chain_info.best_block_number, head_num: chain_info.best_block_number,
genesis_hash: chain_info.genesis_hash, genesis_hash: chain_info.genesis_hash,
protocol_version: MAX_PROTOCOL_VERSION as u32, protocol_version: proto_version as u32, // match peer proto version
network_id: self.network_id, network_id: self.network_id,
last_head: None, last_head: None,
}; };
@ -530,6 +536,7 @@ impl LightProtocol {
Ok(PendingPeer { Ok(PendingPeer {
sent_head: chain_info.best_block_hash, sent_head: chain_info.best_block_hash,
last_update: SteadyTime::now(), last_update: SteadyTime::now(),
proto_version: proto_version,
}) })
} }
@ -550,6 +557,10 @@ impl LightProtocol {
return Err(Error::WrongNetwork); return Err(Error::WrongNetwork);
} }
if Some(status.protocol_version as u8) != io.protocol_version(*peer) {
return Err(Error::BadProtocolVersion);
}
let remote_flow = flow_params.map(|params| (params.create_buffer(), params)); let remote_flow = flow_params.map(|params| (params.create_buffer(), params));
self.peers.write().insert(*peer, Mutex::new(Peer { self.peers.write().insert(*peer, Mutex::new(Peer {
@ -559,6 +570,7 @@ impl LightProtocol {
remote_flow: remote_flow, remote_flow: remote_flow,
sent_head: pending.sent_head, sent_head: pending.sent_head,
last_update: pending.last_update, last_update: pending.last_update,
proto_version: pending.proto_version,
})); }));
for handler in &self.handlers { for handler in &self.handlers {