#[macro_use]
extern crate tracing;
pub mod error;
pub mod messages;
pub mod storage;
use self::storage::{ChunkAddress, RegisterAddress, SpendAddress};
use libp2p::{
kad::{KBucketDistance as Distance, KBucketKey as Key, RecordKey},
PeerId,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use sha2::{Digest, Sha256};
use std::{
borrow::Cow,
fmt::{self, Debug, Display, Formatter},
};
use xor_name::XorName;
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum NetworkAddress {
PeerId(Vec<u8>),
ChunkAddress(ChunkAddress),
SpendAddress(SpendAddress),
RegisterAddress(RegisterAddress),
RecordKey(Vec<u8>),
}
impl NetworkAddress {
pub fn from_chunk_address(chunk_address: ChunkAddress) -> Self {
NetworkAddress::ChunkAddress(chunk_address)
}
pub fn from_cash_note_address(cash_note_address: SpendAddress) -> Self {
NetworkAddress::SpendAddress(cash_note_address)
}
pub fn from_register_address(register_address: RegisterAddress) -> Self {
NetworkAddress::RegisterAddress(register_address)
}
pub fn from_peer(peer_id: PeerId) -> Self {
NetworkAddress::PeerId(peer_id.to_bytes())
}
pub fn from_record_key(record_key: RecordKey) -> Self {
NetworkAddress::RecordKey(record_key.to_vec())
}
pub fn as_bytes(&self) -> Vec<u8> {
match self {
NetworkAddress::PeerId(bytes) | NetworkAddress::RecordKey(bytes) => bytes.to_vec(),
NetworkAddress::ChunkAddress(chunk_address) => chunk_address.xorname().0.to_vec(),
NetworkAddress::SpendAddress(cash_note_address) => {
cash_note_address.xorname().0.to_vec()
}
NetworkAddress::RegisterAddress(register_address) => {
register_address.xorname().0.to_vec()
}
}
}
pub fn as_peer_id(&self) -> Option<PeerId> {
if let NetworkAddress::PeerId(bytes) = self {
if let Ok(peer_id) = PeerId::from_bytes(bytes) {
return Some(peer_id);
}
}
None
}
pub fn as_xorname(&self) -> Option<XorName> {
match self {
NetworkAddress::SpendAddress(cash_note_address) => Some(*cash_note_address.xorname()),
NetworkAddress::ChunkAddress(chunk_address) => Some(*chunk_address.xorname()),
NetworkAddress::RegisterAddress(register_address) => Some(register_address.xorname()),
_ => None,
}
}
pub fn as_record_key(&self) -> Option<RecordKey> {
match self {
NetworkAddress::RecordKey(bytes) => Some(RecordKey::new(bytes)),
_ => None,
}
}
pub fn to_record_key(&self) -> RecordKey {
match self {
NetworkAddress::RecordKey(bytes) => RecordKey::new(bytes),
NetworkAddress::ChunkAddress(chunk_address) => RecordKey::new(chunk_address.xorname()),
NetworkAddress::RegisterAddress(register_address) => {
RecordKey::new(®ister_address.xorname())
}
NetworkAddress::SpendAddress(cash_note_address) => {
RecordKey::new(cash_note_address.xorname())
}
NetworkAddress::PeerId(bytes) => RecordKey::new(bytes),
}
}
pub fn as_kbucket_key(&self) -> Key<Vec<u8>> {
Key::new(self.as_bytes())
}
pub fn distance(&self, other: &NetworkAddress) -> Distance {
self.as_kbucket_key().distance(&other.as_kbucket_key())
}
}
impl Debug for NetworkAddress {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name_str = match self {
NetworkAddress::PeerId(_) => {
if let Some(peer_id) = self.as_peer_id() {
format!("NetworkAddress::PeerId({peer_id} - ")
} else {
"NetworkAddress::PeerId(".to_string()
}
}
NetworkAddress::ChunkAddress(chunk_address) => {
format!(
"NetworkAddress::ChunkAddress({:?} - ",
chunk_address.xorname()
)
}
NetworkAddress::SpendAddress(cash_note_address) => {
format!(
"NetworkAddress::SpendAddress({:?} - ",
cash_note_address.xorname()
)
}
NetworkAddress::RegisterAddress(register_address) => format!(
"NetworkAddress::RegisterAddress({:?} - ",
register_address.xorname()
),
NetworkAddress::RecordKey(bytes) => format!(
"NetworkAddress::RecordKey({:?} - ",
PrettyPrintRecordKey::from(&RecordKey::new(bytes))
),
};
write!(
f,
"{name_str}{:?})",
PrettyPrintKBucketKey(self.as_kbucket_key()),
)
}
}
impl Display for NetworkAddress {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
NetworkAddress::PeerId(id) => {
write!(f, "NetworkAddress::PeerId({})", hex::encode(id))
}
NetworkAddress::ChunkAddress(addr) => {
write!(f, "NetworkAddress::ChunkAddress({addr:?})")
}
NetworkAddress::SpendAddress(addr) => {
write!(f, "NetworkAddress::SpendAddress({addr:?})")
}
NetworkAddress::RegisterAddress(addr) => {
write!(f, "NetworkAddress::RegisterAddress({addr:?})")
}
NetworkAddress::RecordKey(key) => {
write!(f, "NetworkAddress::RecordKey({})", hex::encode(key))
}
}
}
}
#[derive(Clone)]
pub struct PrettyPrintKBucketKey(pub Key<Vec<u8>>);
impl std::fmt::Display for PrettyPrintKBucketKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let generic_array = Sha256::digest(self.0.preimage());
for byte in generic_array {
f.write_fmt(format_args!("{:02x}", byte))?;
}
Ok(())
}
}
impl std::fmt::Debug for PrettyPrintKBucketKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct PrettyPrintRecordKey<'a> {
key: Cow<'a, RecordKey>,
}
impl<'a> Serialize for PrettyPrintRecordKey<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.key.to_vec().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for PrettyPrintRecordKey<'static> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let bytes = Vec::<u8>::deserialize(deserializer)?;
Ok(PrettyPrintRecordKey {
key: Cow::Owned(RecordKey::new(&bytes)),
})
}
}
impl<'a> From<&'a RecordKey> for PrettyPrintRecordKey<'a> {
fn from(key: &'a RecordKey) -> Self {
PrettyPrintRecordKey {
key: Cow::Borrowed(key),
}
}
}
impl<'a> PrettyPrintRecordKey<'a> {
pub fn into_owned(self) -> PrettyPrintRecordKey<'static> {
let cloned_key = match self.key {
Cow::Borrowed(key) => Cow::Owned(key.clone()),
Cow::Owned(key) => Cow::Owned(key),
};
PrettyPrintRecordKey { key: cloned_key }
}
}
impl<'a> std::fmt::Display for PrettyPrintRecordKey<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let record_key_bytes = match &self.key {
Cow::Borrowed(borrowed_key) => borrowed_key.as_ref(),
Cow::Owned(owned_key) => owned_key.as_ref(),
};
for byte in record_key_bytes {
f.write_fmt(format_args!("{:02x}", byte))?;
}
let key = self.key.clone().into_owned();
write!(
f,
"({:?})",
PrettyPrintKBucketKey(NetworkAddress::from_record_key(key).as_kbucket_key())
)
}
}
impl<'a> std::fmt::Debug for PrettyPrintRecordKey<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
#[cfg(test)]
mod tests {
use crate::{NetworkAddress, PrettyPrintRecordKey};
use bls::rand::thread_rng;
use bytes::Bytes;
use libp2p::kad::{KBucketKey, RecordKey};
use sha2::{Digest, Sha256};
struct OldRecordKeyPrint(RecordKey);
impl std::fmt::Display for OldRecordKeyPrint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let b: Vec<u8> = self.0.as_ref().to_vec();
let record_key_b = Bytes::from(b);
write!(
f,
"{:64x}({:?})",
record_key_b,
OldKBucketKeyPrint(
NetworkAddress::from_record_key(self.0.clone()).as_kbucket_key()
)
)
}
}
impl std::fmt::Debug for OldRecordKeyPrint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
pub struct OldKBucketKeyPrint(KBucketKey<Vec<u8>>);
impl std::fmt::Display for OldKBucketKeyPrint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let generic_array = Sha256::digest(self.0.preimage());
let kbucket_key_b = Bytes::from(generic_array.to_vec());
write!(f, "{:64x}", kbucket_key_b)
}
}
impl std::fmt::Debug for OldKBucketKeyPrint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
#[test]
fn verify_custom_hex_representation() {
let random = xor_name::XorName::random(&mut thread_rng());
let key = RecordKey::new(&random.0);
let pretty_key = PrettyPrintRecordKey::from(&key).into_owned();
let old_record_key = OldRecordKeyPrint(key);
assert_eq!(format!("{pretty_key:?}"), format!("{old_record_key:?}"));
}
}