Skip to content

Commit

Permalink
fix!: use configured network string in networking protocol (#864)
Browse files Browse the repository at this point in the history
Description
---
Use string from `Network::as_str` in the protocol identifier

Motivation and Context
---
This change uses the configured network in the
`/tari/{network}/{version}` protocol string. This string is used to
identify different networks. If peers are on a different network (by
libp2p identify) the peers disconnect.

How Has This Been Tested?
---
Partially manually by checking that the protocol string is set per the
network. Cucumbers also partially test this case.

What process can a PR reviewer use to test or verify this change?
---
Try connect two VNs, one with `--network localnet` and the other with
`--network igor`

Breaking Changes
---

- [ ] None
- [ ] Requires data directory to be deleted
- [x] Other - previous nodes will not stay connected to new nodes and
vice versa
  • Loading branch information
sdbondi authored Jan 11, 2024
1 parent bc5f0f4 commit b7ccff2
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 102 deletions.
2 changes: 1 addition & 1 deletion applications/tari_indexer/src/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub async fn spawn_services(
tari_networking::Config {
listener_port: config.indexer.p2p.listener_port,
swarm: SwarmConfig {
protocol_version: "/tari/devnet/0.0.1".try_into().unwrap(),
protocol_version: format!("/tari/{}/0.0.1", config.network).parse().unwrap(),
user_agent: "/tari/indexer/0.0.1".to_string(),
enable_mdns: config.indexer.p2p.enable_mdns,
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion applications/tari_validator_node/src/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ pub async fn spawn_services(
tari_networking::Config {
listener_port: config.validator_node.p2p.listener_port,
swarm: SwarmConfig {
protocol_version: "/tari/devnet/0.0.1".try_into().unwrap(),
protocol_version: format!("/tari/{}/0.0.1", config.network).parse().unwrap(),
user_agent: "/tari/validator/0.0.1".to_string(),
enable_mdns: config.validator_node.p2p.enable_mdns,
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion networking/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub use config::*;
pub use connection::*;
pub use handle::*;
pub use spawn::*;
pub use tari_swarm::{is_supported_multiaddr, Config as SwarmConfig, TariNetwork};
pub use tari_swarm::{is_supported_multiaddr, Config as SwarmConfig};

#[async_trait]
pub trait NetworkingService<TMsg> {
Expand Down
11 changes: 3 additions & 8 deletions networking/core/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ use tari_swarm::{
peersync,
substream,
substream::{NegotiatedSubstream, ProtocolNotification, StreamId},
ProtocolVersion,
TariNodeBehaviourEvent,
TariSwarm,
};
Expand Down Expand Up @@ -739,14 +738,10 @@ where
}

fn on_peer_identified(&mut self, peer_id: PeerId, info: identify::Info) -> Result<(), NetworkingError> {
if !self
.config
.swarm
.protocol_version
.is_compatible(&ProtocolVersion::try_from(info.protocol_version.as_str())?)
{
if !self.config.swarm.protocol_version.is_compatible(&info.protocol_version) {
info!(target: LOG_TARGET, "🚨 Peer {} is using an incompatible protocol version: {}. Our version {}", peer_id, info.protocol_version, self.config.swarm.protocol_version);
// Errors just indicate that there was no connection to the peer.
// Error can be ignored as the docs indicate that an error only occurs if there was no connection to the
// peer.
let _ignore = self.swarm.disconnect_peer_id(peer_id);
return Ok(());
}
Expand Down
4 changes: 2 additions & 2 deletions networking/swarm/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::protocol_version::ProtocolVersion;

#[derive(Debug, Clone)]
pub struct Config {
pub protocol_version: ProtocolVersion<'static>,
pub protocol_version: ProtocolVersion,
pub user_agent: String,
pub messaging_protocol: String,
pub ping: ping::Config,
Expand All @@ -22,7 +22,7 @@ pub struct Config {
impl Default for Config {
fn default() -> Self {
Self {
protocol_version: "/tari/devnet/0.0.1".try_into().unwrap(),
protocol_version: "/tari/localnet/0.0.1".parse().unwrap(),
user_agent: "/tari/unknown/0.0.1".to_string(),
messaging_protocol: "/tari/messaging/0.0.1".to_string(),
ping: ping::Config::default(),
Expand Down
6 changes: 4 additions & 2 deletions networking/swarm/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub enum TariSwarmError {
InvalidProtocol(#[from] InvalidProtocol),
#[error("Behaviour error: {0}")]
BehaviourError(String),
#[error("Failed to parse protocol version field '{field}'")]
ProtocolVersionParseFailed { field: &'static str },
#[error("'{given}' is not a valid protocol version string")]
ProtocolVersionParseFailed { given: String },
#[error("Invalid version string: {given}")]
InvalidVersionString { given: String },
}
2 changes: 0 additions & 2 deletions networking/swarm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
mod behaviour;
mod config;
mod error;
mod network;
mod protocol_version;

pub use behaviour::*;
pub use config::*;
pub use error::*;
pub use network::*;
pub use protocol_version::*;

pub type TariSwarm<TMsg> = libp2p::Swarm<TariNodeBehaviour<TMsg>>;
Expand Down
36 changes: 0 additions & 36 deletions networking/swarm/src/network.rs

This file was deleted.

107 changes: 58 additions & 49 deletions networking/swarm/src/protocol_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,84 +3,93 @@

use std::{fmt, fmt::Display, str::FromStr};

use crate::{TariNetwork, TariSwarmError};
use crate::TariSwarmError;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProtocolVersion<'a> {
domain: &'a str,
network: TariNetwork,
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProtocolVersion {
domain: String,
network: String,
version: Version,
}

impl<'a> ProtocolVersion<'a> {
pub const fn new(domain: &'a str, network: TariNetwork, version: Version) -> Self {
impl ProtocolVersion {
pub const fn new(domain: String, network: String, version: Version) -> Self {
Self {
domain,
network,
version,
}
}

pub const fn domain(&self) -> &'a str {
self.domain
pub fn domain(&self) -> &str {
&self.domain
}

pub const fn network(&self) -> TariNetwork {
self.network
pub fn network(&self) -> &str {
&self.network
}

pub const fn version(&self) -> Version {
self.version
}

pub fn is_compatible(&self, other: &ProtocolVersion) -> bool {
self.domain == other.domain && self.network == other.network && self.version.semantic_version_eq(&other.version)
pub fn is_compatible(&self, protocol_str: &str) -> bool {
let Some((domain, network, version)) = parse_protocol_str(protocol_str) else {
return false;
};
self.domain == domain && self.network == network && self.version.semantic_version_eq(&version)
}
}

impl PartialEq<String> for ProtocolVersion<'_> {
impl PartialEq<String> for ProtocolVersion {
fn eq(&self, other: &String) -> bool {
let mut parts = other.split('/');
let Some(domain) = parts.next() else {
return false;
};

let Some(network) = parts.next() else {
return false;
};

let Some(version) = parts.next().and_then(|s| s.parse().ok()) else {
let Some((domain, network, version)) = parse_protocol_str(other) else {
return false;
};
self.domain == domain && self.network == network && self.version == version
}
}

self.domain == domain && self.network.as_str() == network && self.version == version
impl Display for ProtocolVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "/{}/{}/{}", self.domain, self.network, self.version)
}
}

impl<'a> TryFrom<&'a str> for ProtocolVersion<'a> {
type Error = TariSwarmError;
impl FromStr for ProtocolVersion {
type Err = TariSwarmError;

fn try_from(value: &'a str) -> Result<Self, Self::Error> {
fn from_str(value: &str) -> Result<Self, Self::Err> {
let mut parts = value.split('/');
// Must have a leading '/'
let leading = parts.next();
if leading.filter(|l| l.is_empty()).is_none() {
return Err(TariSwarmError::ProtocolVersionParseFailed { field: "leading '/'" });
return Err(TariSwarmError::ProtocolVersionParseFailed {
given: value.to_string(),
});
}

let mut next = move |field| parts.next().ok_or(TariSwarmError::ProtocolVersionParseFailed { field });
Ok(Self::new(
next("domain")?,
next("network")?.parse()?,
next("version")?.parse()?,
))
let Some((domain, network, version)) = parse_protocol_str(value) else {
return Err(TariSwarmError::ProtocolVersionParseFailed {
given: value.to_string(),
});
};
Ok(Self::new(domain.to_string(), network.to_string(), version))
}
}

impl Display for ProtocolVersion<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "/{}/{}/{}", self.domain, self.network, self.version)
fn parse_protocol_str(protocol_str: &str) -> Option<(&str, &str, Version)> {
let mut parts = protocol_str.split('/');
// Must have a leading '/'
let leading = parts.next()?;
if !leading.is_empty() {
return None;
}

let domain = parts.next()?;
let network = parts.next()?;
let version = parts.next().and_then(|s| s.parse().ok())?;
Some((domain, network, version))
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -129,17 +138,17 @@ impl FromStr for Version {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split('.');

let mut next = move |field| {
let mut next = move || {
parts
.next()
.ok_or(TariSwarmError::ProtocolVersionParseFailed { field })?
.ok_or(TariSwarmError::InvalidVersionString { given: s.to_string() })?
.parse()
.map_err(|_| TariSwarmError::ProtocolVersionParseFailed { field })
.map_err(|_| TariSwarmError::InvalidVersionString { given: s.to_string() })
};
Ok(Self {
major: next("version.major")?,
minor: next("version.minor")?,
patch: next("version.patch")?,
major: next()?,
minor: next()?,
patch: next()?,
})
}
}
Expand All @@ -156,13 +165,13 @@ mod tests {

#[test]
fn it_parses_correctly() {
let version = ProtocolVersion::try_from("/tari/devnet/0.0.1").unwrap();
let version = ProtocolVersion::from_str("/tari/igor/1.2.3").unwrap();
assert_eq!(version.domain(), "tari");
assert_eq!(version.network(), TariNetwork::DevNet);
assert_eq!(version.network(), "igor");
assert_eq!(version.version(), Version {
major: 0,
minor: 0,
patch: 1
major: 1,
minor: 2,
patch: 3
});
}
}

0 comments on commit b7ccff2

Please sign in to comment.