use std::{
fmt,
sync::{RwLock, RwLockReadGuard},
};
use chrono::Utc;
use multiaddr::Multiaddr;
use rand::{CryptoRng, Rng};
use serde::{Deserialize, Serialize};
use tari_crypto::{keys::SecretKey, tari_utilities::hex::serialize_to_hex};
use super::node_id::deserialize_node_id_from_hex;
use crate::{
net_address::{MultiaddressesWithStats, PeerAddressSource},
peer_manager::{
Peer,
PeerFeatures,
PeerFlags,
PeerIdentityClaim,
identity_signature::IdentitySignature,
node_id::NodeId,
},
types::{CommsPublicKey, CommsSecretKey},
};
#[derive(Serialize, Deserialize)]
pub struct NodeIdentity {
#[serde(serialize_with = "serialize_to_hex")]
#[serde(deserialize_with = "deserialize_node_id_from_hex")]
node_id: NodeId,
public_key: CommsPublicKey,
features: PeerFeatures,
secret_key: CommsSecretKey,
public_addresses: RwLock<Vec<Multiaddr>>,
#[serde(default = "rwlock_none")]
identity_signature: RwLock<Option<IdentitySignature>>,
}
fn rwlock_none() -> RwLock<Option<IdentitySignature>> {
RwLock::new(None)
}
impl NodeIdentity {
pub fn new(secret_key: CommsSecretKey, public_addresses: Vec<Multiaddr>, features: PeerFeatures) -> Self {
let public_key = CommsPublicKey::from_secret_key(&secret_key);
let node_id = NodeId::from_key(&public_key);
let node_identity = NodeIdentity {
node_id,
public_key,
features,
secret_key,
public_addresses: RwLock::new(public_addresses),
identity_signature: RwLock::new(None),
};
node_identity.sign();
node_identity
}
pub fn with_signature_unchecked(
secret_key: CommsSecretKey,
public_addresses: Vec<Multiaddr>,
features: PeerFeatures,
identity_signature: Option<IdentitySignature>,
) -> Self {
let public_key = CommsPublicKey::from_secret_key(&secret_key);
let node_id = NodeId::from_key(&public_key);
NodeIdentity {
node_id,
public_key,
features,
secret_key,
public_addresses: RwLock::new(public_addresses),
identity_signature: RwLock::new(identity_signature),
}
}
pub fn random<R>(rng: &mut R, public_address: Multiaddr, features: PeerFeatures) -> Self
where R: CryptoRng + Rng {
let secret_key = CommsSecretKey::random(rng);
Self::new(secret_key, vec![public_address], features)
}
pub fn random_multiple_addresses<R>(rng: &mut R, public_addresses: Vec<Multiaddr>, features: PeerFeatures) -> Self
where R: CryptoRng + Rng {
let secret_key = CommsSecretKey::random(rng);
Self::new(secret_key, public_addresses, features)
}
pub fn public_addresses(&self) -> Vec<Multiaddr> {
acquire_read_lock!(self.public_addresses).clone()
}
pub fn first_public_address(&self) -> Option<Multiaddr> {
acquire_read_lock!(self.public_addresses).get(0).cloned()
}
pub fn add_public_address(&self, address: Multiaddr) {
let mut must_sign = false;
{
let mut lock = acquire_write_lock!(self.public_addresses);
if !lock.contains(&address) {
lock.push(address);
must_sign = true;
}
}
if must_sign {
self.sign()
}
}
pub fn set_public_addresses(&self, addresses: Vec<Multiaddr>) {
let mut must_sign = false;
{
let mut lock = acquire_write_lock!(self.public_addresses);
if addresses.len() != lock.len() || addresses.iter().any(|a| !lock.contains(a)) {
lock.clear();
lock.extend(addresses);
must_sign = true;
}
}
if must_sign {
self.sign()
}
}
pub fn set_peer_features(&mut self, features: PeerFeatures) {
let must_sign = features != self.features;
self.features = features;
if must_sign {
self.sign()
}
}
#[cfg(test)]
pub fn random_for_test(public_address: Option<Multiaddr>, features: PeerFeatures) -> Self {
Self::random(
&mut rand::rngs::OsRng,
public_address
.or_else(|| "/ip4/127.0.0.1/tcp/9000".parse().ok())
.unwrap(),
features,
)
}
pub fn node_id(&self) -> &NodeId {
&self.node_id
}
pub fn public_key(&self) -> &CommsPublicKey {
&self.public_key
}
pub fn secret_key(&self) -> &CommsSecretKey {
&self.secret_key
}
pub fn features(&self) -> PeerFeatures {
self.features
}
pub fn has_peer_features(&self, peer_features: PeerFeatures) -> bool {
self.features().contains(peer_features)
}
pub fn identity_signature_read(&self) -> RwLockReadGuard<'_, Option<IdentitySignature>> {
acquire_read_lock!(self.identity_signature)
}
pub fn is_signed(&self) -> bool {
self.identity_signature_read().is_some()
}
pub fn sign(&self) {
let identity_sig = IdentitySignature::sign_new(
self.secret_key(),
self.features,
&*acquire_read_lock!(self.public_addresses),
Utc::now(),
);
*acquire_write_lock!(self.identity_signature) = Some(identity_sig);
}
pub fn to_peer(&self) -> Peer {
let peer_identity_claim = PeerIdentityClaim {
addresses: self.public_addresses(),
features: self.features,
signature: IdentitySignature::sign_new(
&self.secret_key,
self.features,
&self.public_addresses(),
Utc::now(),
),
};
Peer::new(
self.public_key().clone(),
self.node_id().clone(),
MultiaddressesWithStats::from_addresses_with_source(
self.public_addresses(),
&PeerAddressSource::FromNodeIdentity { peer_identity_claim },
),
PeerFlags::empty(),
self.features(),
Default::default(),
Default::default(),
)
}
}
impl Clone for NodeIdentity {
fn clone(&self) -> Self {
Self {
node_id: self.node_id.clone(),
public_key: self.public_key.clone(),
features: self.features,
secret_key: self.secret_key.clone(),
public_addresses: RwLock::new(self.public_addresses()),
identity_signature: RwLock::new(self.identity_signature_read().as_ref().cloned()),
}
}
}
impl fmt::Display for NodeIdentity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Public Key: {}", self.public_key)?;
writeln!(f, "Node ID: {}", self.node_id)?;
writeln!(
f,
"Public Addresses: {}",
acquire_read_lock!(self.public_addresses)
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
.join(", ")
)?;
writeln!(f, "Features: {:?}", self.features)?;
Ok(())
}
}
impl fmt::Debug for NodeIdentity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NodeIdentity")
.field("public_key", &self.public_key)
.field("node_id", &self.node_id)
.field("public_address", &self.public_addresses)
.field("features", &self.features)
.field("secret_key", &"<secret>")
.field("identity_signature", &*acquire_read_lock!(self.identity_signature))
.finish()
}
}