use crate::config::{PeerRole, RoleType};
use diem_types::PeerId;
use serde::{Deserialize, Serialize, Serializer};
use short_hex_str::AsShortHexStr;
use std::{cmp::Ordering, fmt};
#[derive(Clone, Eq, PartialEq, Serialize)]
pub struct NetworkContext {
role: RoleType,
#[serde(serialize_with = "NetworkId::serialize_str")]
network_id: NetworkId,
peer_id: PeerId,
}
impl fmt::Debug for NetworkContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl fmt::Display for NetworkContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"[{},{},{}]",
self.role,
self.network_id.as_str(),
self.peer_id.short_str(),
)
}
}
impl NetworkContext {
pub fn new(
role: RoleType, network_id: NetworkId, peer_id: PeerId,
) -> NetworkContext {
NetworkContext {
role,
network_id,
peer_id,
}
}
pub fn role(&self) -> RoleType { self.role }
pub fn network_id(&self) -> &NetworkId { &self.network_id }
pub fn peer_id(&self) -> PeerId { self.peer_id }
#[cfg(any(test, feature = "testing", feature = "fuzzing"))]
pub fn mock_with_peer_id(peer_id: PeerId) -> std::sync::Arc<Self> {
std::sync::Arc::new(Self::new(
RoleType::Validator,
NetworkId::Validator,
peer_id,
))
}
#[cfg(any(test, feature = "testing", feature = "fuzzing"))]
pub fn mock() -> std::sync::Arc<Self> {
std::sync::Arc::new(Self::new(
RoleType::Validator,
NetworkId::Validator,
PeerId::random(),
))
}
}
#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename = "NetworkId", rename_all = "snake_case")]
pub enum NetworkId {
Validator,
Public,
Private(String),
}
impl PartialOrd for NetworkId {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for NetworkId {
fn cmp(&self, other: &Self) -> Ordering {
if self == other {
Ordering::Equal
} else {
match self {
NetworkId::Validator => Ordering::Less,
NetworkId::Public => Ordering::Greater,
NetworkId::Private(_) => match other {
NetworkId::Validator => Ordering::Greater,
NetworkId::Public => Ordering::Less,
NetworkId::Private(_) => {
if self.is_vfn_network() {
Ordering::Less
} else {
Ordering::Greater
}
}
},
}
}
}
}
#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct NodeNetworkId(NetworkId, usize);
impl NodeNetworkId {
pub fn new(network_id: NetworkId, num_id: usize) -> Self {
Self(network_id, num_id)
}
pub fn network_id(&self) -> NetworkId { self.0.clone() }
}
impl fmt::Debug for NodeNetworkId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl fmt::Display for NodeNetworkId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.0, self.1)
}
}
impl Default for NetworkId {
fn default() -> NetworkId { NetworkId::Public }
}
impl fmt::Debug for NetworkId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl fmt::Display for NetworkId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_str())
}
}
const VFN_NETWORK: &str = "vfn";
impl NetworkId {
pub fn vfn_network() -> NetworkId {
NetworkId::Private(VFN_NETWORK.to_string())
}
pub fn is_vfn_network(&self) -> bool {
matches!(self, NetworkId::Private(network) if network == VFN_NETWORK)
}
pub fn is_validator_network(&self) -> bool {
matches!(self, NetworkId::Validator)
}
pub fn upstream_roles(&self, role: &RoleType) -> &'static [PeerRole] {
match self {
NetworkId::Validator => &[PeerRole::Validator],
NetworkId::Public => &[
PeerRole::PreferredUpstream,
PeerRole::Upstream,
PeerRole::ValidatorFullNode,
],
NetworkId::Private(_) => {
if self.is_vfn_network() {
match role {
RoleType::Validator => &[],
RoleType::FullNode => &[PeerRole::Validator],
}
} else {
&[PeerRole::PreferredUpstream, PeerRole::Upstream]
}
}
}
}
pub fn downstream_roles(&self, role: &RoleType) -> &'static [PeerRole] {
match self {
NetworkId::Validator => &[PeerRole::Validator],
NetworkId::Public => &[
PeerRole::ValidatorFullNode,
PeerRole::Downstream,
PeerRole::Known,
PeerRole::Unknown,
],
NetworkId::Private(_) => {
if self.is_vfn_network() {
match role {
RoleType::Validator => &[PeerRole::ValidatorFullNode],
RoleType::FullNode => &[],
}
} else {
&[PeerRole::Downstream, PeerRole::Known]
}
}
}
}
pub fn as_str(&self) -> &str {
match self {
NetworkId::Validator => "Validator",
NetworkId::Public => "Public",
NetworkId::Private(info) => info.as_ref(),
}
}
fn serialize_str<S>(
&self, serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where S: Serializer {
self.as_str().serialize(serializer)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_ensure_network_id_order() {
assert!(NetworkId::Validator < NetworkId::vfn_network());
assert!(NetworkId::vfn_network() < NetworkId::Public);
assert!(NetworkId::Validator < NetworkId::Public);
}
#[test]
fn test_serialization() {
let id = NetworkId::vfn_network();
let encoded = serde_yaml::to_string(&id).unwrap();
let decoded: NetworkId =
serde_yaml::from_str(encoded.as_str()).unwrap();
assert_eq!(id, decoded);
let encoded = serde_yaml::to_vec(&id).unwrap();
let decoded: NetworkId =
serde_yaml::from_slice(encoded.as_slice()).unwrap();
assert_eq!(id, decoded);
let id = NetworkId::Validator;
let encoded = serde_yaml::to_string(&id).unwrap();
let decoded: NetworkId =
serde_yaml::from_str(encoded.as_str()).unwrap();
assert_eq!(id, decoded);
let encoded = serde_yaml::to_vec(&id).unwrap();
let decoded: NetworkId =
serde_yaml::from_slice(encoded.as_slice()).unwrap();
assert_eq!(id, decoded);
}
#[test]
fn test_network_context_serialization() {
let peer_id = PeerId::random();
let context = NetworkContext::new(
RoleType::Validator,
NetworkId::vfn_network(),
peer_id,
);
let expected = format!(
"---\nrole: {}\nnetwork_id: {}\npeer_id: {:x}\n",
RoleType::Validator,
VFN_NETWORK,
peer_id
);
assert_eq!(expected, serde_yaml::to_string(&context).unwrap());
}
}