1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
// Copyright 2023 MaidSafe.net limited.
//
// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.
/// Errors.
pub mod error;
/// Messages types
pub mod messages;
/// Storage types for spends, chunks and registers.
pub mod storage;
use self::storage::{ChunkAddress, DbcAddress, RegisterAddress};
use libp2p::{
kad::{record::Key as RecordKey, KBucketDistance as Distance, KBucketKey as Key},
PeerId,
};
use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug, Display, Formatter};
use xor_name::XorName;
/// This is the address in the network by which proximity/distance
/// to other items (whether nodes or data chunks) are calculated.
///
/// This is the mapping from the XOR name used
/// by for example self encryption, or the libp2p `PeerId`,
/// to the key used in the Kademlia DHT.
/// All our xorname calculations shall be replaced with the `KBucketKey` calculations,
/// for getting proximity/distance to other items (whether nodes or data).
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum NetworkAddress {
/// The NetworkAddress is representing a PeerId.
PeerId(Vec<u8>),
/// The NetworkAddress is representing a ChunkAddress.
ChunkAddress(ChunkAddress),
/// The NetworkAddress is representing a DbcAddress.
DbcAddress(DbcAddress),
/// The NetworkAddress is representing a ChunkAddress.
RegisterAddress(RegisterAddress),
/// The NetworkAddress is representing a RecordKey.
RecordKey(Vec<u8>),
}
impl NetworkAddress {
/// Return a `NetworkAddress` representation of the `ChunkAddress`.
pub fn from_chunk_address(chunk_address: ChunkAddress) -> Self {
NetworkAddress::ChunkAddress(chunk_address)
}
/// Return a `NetworkAddress` representation of the `DbcAddress`.
pub fn from_dbc_address(dbc_address: DbcAddress) -> Self {
NetworkAddress::DbcAddress(dbc_address)
}
/// Return a `NetworkAddress` representation of the `RegisterAddress`.
pub fn from_register_address(register_address: RegisterAddress) -> Self {
NetworkAddress::RegisterAddress(register_address)
}
/// Return a `NetworkAddress` representation of the `PeerId` by encapsulating its bytes.
pub fn from_peer(peer_id: PeerId) -> Self {
NetworkAddress::PeerId(peer_id.to_bytes())
}
/// Return a `NetworkAddress` representation of the `RecordKey` by encapsulating its bytes.
pub fn from_record_key(record_key: RecordKey) -> Self {
NetworkAddress::RecordKey(record_key.to_vec())
}
/// Return the encapsulated bytes of this `NetworkAddress`.
pub fn as_bytes(&self) -> Vec<u8> {
match self {
NetworkAddress::PeerId(bytes) | NetworkAddress::RecordKey(bytes) => bytes.to_vec(),
NetworkAddress::ChunkAddress(chunk_address) => chunk_address.name().0.to_vec(),
NetworkAddress::DbcAddress(dbc_address) => dbc_address.name().0.to_vec(),
NetworkAddress::RegisterAddress(register_address) => register_address.id().0.to_vec(),
}
}
/// Try to return the represented `PeerId`.
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
}
/// Try to return the represented `RecordKey`.
pub fn as_record_key(&self) -> Option<RecordKey> {
match self {
NetworkAddress::RecordKey(bytes) => Some(RecordKey::new(bytes)),
_ => None,
}
}
/// Return the convertable `RecordKey`.
pub fn to_record_key(&self) -> RecordKey {
match self {
NetworkAddress::RecordKey(bytes) => RecordKey::new(bytes),
NetworkAddress::ChunkAddress(chunk_address) => RecordKey::new(chunk_address.name()),
NetworkAddress::RegisterAddress(register_address) => {
let mut reg_name: Vec<u8> = register_address.name().to_vec();
reg_name.extend(register_address.tag.to_be_bytes());
RecordKey::new(&XorName::from_content(®_name))
}
NetworkAddress::DbcAddress(dbc_address) => RecordKey::new(dbc_address.name()),
NetworkAddress::PeerId(bytes) => RecordKey::new(bytes),
}
}
/// Return the `KBucketKey` representation of this `NetworkAddress`.
///
/// The `KBucketKey` is used for calculating proximity/distance to other items (whether nodes or data).
/// Important to note is that it will always SHA256 hash any bytes it receives.
/// Therefore, the canonical use of distance/proximity calculations in the network
/// is via the `KBucketKey`, or the convenience methods of `NetworkAddress`.
pub fn as_kbucket_key(&self) -> Key<Vec<u8>> {
Key::new(self.as_bytes())
}
/// Compute the distance of the keys according to the XOR metric.
pub fn distance(&self, other: &NetworkAddress) -> Distance {
self.as_kbucket_key().distance(&other.as_kbucket_key())
}
// NB: Leaving this here as to demonstrate what we can do with this.
// /// Return the uniquely determined key with the given distance to `self`.
// ///
// /// This implements the following equivalence:
// ///
// /// `self xor other = distance <==> other = self xor distance`
// pub fn for_distance(&self, d: Distance) -> libp2p::kad::kbucket::KeyBytes {
// self.as_kbucket_key().for_distance(d)
// }
}
impl Debug for NetworkAddress {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name_str = match self {
NetworkAddress::PeerId(_) => "NetworkAddress::PeerId(".to_string(),
NetworkAddress::ChunkAddress(chunk_address) => {
format!("NetworkAddress::ChunkAddress({:?} - ", chunk_address.name())
}
NetworkAddress::DbcAddress(dbc_address) => {
format!("NetworkAddress::DbcAddress({:?} - ", dbc_address.name())
}
NetworkAddress::RegisterAddress(register_address) => format!(
"NetworkAddress::RegisterAddress({:?} - ",
register_address.id()
),
NetworkAddress::RecordKey(_) => "NetworkAddress::RecordKey(".to_string(),
};
write!(
f,
"{name_str} - {:?} - {:?})",
self.to_record_key(),
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::DbcAddress(addr) => {
write!(f, "NetworkAddress::DbcAddress({addr:?})")
}
NetworkAddress::RegisterAddress(addr) => {
write!(f, "NetworkAddress::RegisterAddress({addr:?})")
}
NetworkAddress::RecordKey(key) => {
write!(f, "NetworkAddress::RecordKey({})", hex::encode(key))
}
}
}
}