Implement minimal version handshaking (#295)

Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
Co-authored-by: Henry de Valence <hdevalence@hdevalence.ca>
This commit is contained in:
George Tankersley 2020-04-13 18:33:15 -04:00 committed by GitHub
parent 05ca1c0c8a
commit df79fa75e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 8 deletions

View File

@ -81,4 +81,7 @@ pub enum HandshakeError {
/// A serialization error occurred while reading or writing a message. /// A serialization error occurred while reading or writing a message.
#[error("Serialization error")] #[error("Serialization error")]
Serialization(#[from] SerializationError), Serialization(#[from] SerializationError),
/// The remote peer offered a version older than our minimum version.
#[error("Peer offered obsolete version: {0:?}")]
ObsoleteVersion(crate::protocol::external::types::Version),
} }

View File

@ -128,7 +128,9 @@ where
nonce: local_nonce, nonce: local_nonce,
user_agent, user_agent,
// XXX eventually the `PeerConnector` will need to have a handle // XXX eventually the `PeerConnector` will need to have a handle
// for a service that gets the current block height. // for a service that gets the current block height. Among other
// things we need it to reject peers who don't know about the
// current protocol epoch.
start_height: BlockHeight(0), start_height: BlockHeight(0),
relay: false, relay: false,
}; };
@ -143,11 +145,14 @@ where
// Check that we got a Version and destructure its fields into the local scope. // Check that we got a Version and destructure its fields into the local scope.
debug!(?remote_msg, "got message from remote peer"); debug!(?remote_msg, "got message from remote peer");
let (remote_nonce, remote_services) = if let Message::Version { let (remote_nonce, remote_services, remote_version) = if let Message::Version {
nonce, services, .. nonce,
services,
version,
..
} = remote_msg } = remote_msg
{ {
(nonce, services) (nonce, services, version)
} else { } else {
return Err(HandshakeError::UnexpectedMessage(Box::new(remote_msg))); return Err(HandshakeError::UnexpectedMessage(Box::new(remote_msg)));
}; };
@ -176,9 +181,31 @@ where
return Err(HandshakeError::UnexpectedMessage(Box::new(remote_msg))); return Err(HandshakeError::UnexpectedMessage(Box::new(remote_msg)));
} }
// XXX here is where we would set the version to the minimum of the // XXX in zcashd remote peer can only send one version message and
// two versions, etc. -- actually is it possible to edit the `Codec` // we would disconnect here if it received a second one. Is it even possible
// after using it to make a framed adapter? // for that to happen to us here?
if remote_version < constants::MIN_VERSION {
// Disconnect if peer is using an obsolete version.
return Err(HandshakeError::ObsoleteVersion(remote_version));
}
// TODO: Reject incoming connections from nodes that don't know about the current epoch.
// zcashd does this:
// const Consensus::Params& consensusParams = chainparams.GetConsensus();
// auto currentEpoch = CurrentEpoch(GetHeight(), consensusParams);
// if (pfrom->nVersion < consensusParams.vUpgrades[currentEpoch].nProtocolVersion)
// Set the connection's version to the minimum of the received version or our own.
let negotiated_version = std::cmp::min(remote_version, constants::CURRENT_VERSION);
// Reconfigure the codec to use the negotiated version.
//
// XXX The tokio documentation says not to do this while any frames are still being processed.
// Since we don't know that here, another way might be to release the tcp
// stream from the unversioned Framed wrapper and construct a new one with a versioned codec.
let bare_codec = stream.codec_mut();
bare_codec.reconfigure_version(negotiated_version);
debug!("constructing client, spawning server"); debug!("constructing client, spawning server");

View File

@ -29,7 +29,7 @@ impl From<Network> for Magic {
} }
/// A protocol version number. /// A protocol version number.
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Version(pub u32); pub struct Version(pub u32);
bitflags! { bitflags! {