1#![allow(clippy::wrong_self_convention)]
23
24use crate::crypto::PublicKey;
25
26use multiaddr::{Multiaddr, Protocol};
27use multihash::{Code, Error, Multihash, MultihashDigest};
28use rand::Rng;
29use serde::{Deserialize, Serialize};
30use thiserror::Error;
31
32use std::{convert::TryFrom, fmt, str::FromStr};
33
34const MAX_INLINE_KEY_LENGTH: usize = 42;
37
38#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
43pub struct PeerId {
44 multihash: Multihash,
45}
46
47impl fmt::Debug for PeerId {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 f.debug_tuple("PeerId").field(&self.to_base58()).finish()
50 }
51}
52
53impl fmt::Display for PeerId {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 self.to_base58().fmt(f)
56 }
57}
58
59impl PeerId {
60 pub fn from_public_key(key: &PublicKey) -> PeerId {
62 Self::from_public_key_protobuf(&key.to_protobuf_encoding())
63 }
64
65 pub fn from_public_key_protobuf(key_enc: &[u8]) -> PeerId {
67 let hash_algorithm = if key_enc.len() <= MAX_INLINE_KEY_LENGTH {
68 Code::Identity
69 } else {
70 Code::Sha2_256
71 };
72
73 let multihash = hash_algorithm.digest(key_enc);
74
75 PeerId { multihash }
76 }
77
78 pub fn from_bytes(data: &[u8]) -> Result<PeerId, Error> {
80 PeerId::from_multihash(Multihash::from_bytes(data)?)
81 .map_err(|mh| Error::UnsupportedCode(mh.code()))
82 }
83
84 pub fn from_multihash(multihash: Multihash) -> Result<PeerId, Multihash> {
90 match Code::try_from(multihash.code()) {
91 Ok(Code::Sha2_256) => Ok(PeerId { multihash }),
92 Ok(Code::Identity) if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH =>
93 Ok(PeerId { multihash }),
94 _ => Err(multihash),
95 }
96 }
97
98 pub fn try_from_multiaddr(address: &Multiaddr) -> Option<PeerId> {
103 address.iter().last().and_then(|p| match p {
104 Protocol::P2p(hash) => PeerId::from_multihash(hash).ok(),
105 _ => None,
106 })
107 }
108
109 pub fn random() -> PeerId {
113 let peer_id = rand::thread_rng().gen::<[u8; 32]>();
114 PeerId {
115 multihash: Multihash::wrap(Code::Identity.into(), &peer_id)
116 .expect("The digest size is never too large"),
117 }
118 }
119
120 pub fn to_bytes(&self) -> Vec<u8> {
122 self.multihash.to_bytes()
123 }
124
125 pub fn to_base58(&self) -> String {
127 bs58::encode(self.to_bytes()).into_string()
128 }
129
130 pub fn is_public_key(&self, public_key: &PublicKey) -> Option<bool> {
135 let alg = Code::try_from(self.multihash.code())
136 .expect("Internal multihash is always a valid `Code`");
137 let enc = public_key.to_protobuf_encoding();
138 Some(alg.digest(&enc) == self.multihash)
139 }
140}
141
142impl From<PublicKey> for PeerId {
143 fn from(key: PublicKey) -> PeerId {
144 PeerId::from_public_key(&key)
145 }
146}
147
148impl From<&PublicKey> for PeerId {
149 fn from(key: &PublicKey) -> PeerId {
150 PeerId::from_public_key(key)
151 }
152}
153
154impl TryFrom<Vec<u8>> for PeerId {
155 type Error = Vec<u8>;
156
157 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
158 PeerId::from_bytes(&value).map_err(|_| value)
159 }
160}
161
162impl TryFrom<Multihash> for PeerId {
163 type Error = Multihash;
164
165 fn try_from(value: Multihash) -> Result<Self, Self::Error> {
166 PeerId::from_multihash(value)
167 }
168}
169
170impl AsRef<Multihash> for PeerId {
171 fn as_ref(&self) -> &Multihash {
172 &self.multihash
173 }
174}
175
176impl From<PeerId> for Multihash {
177 fn from(peer_id: PeerId) -> Self {
178 peer_id.multihash
179 }
180}
181
182impl From<PeerId> for Vec<u8> {
183 fn from(peer_id: PeerId) -> Self {
184 peer_id.to_bytes()
185 }
186}
187
188impl Serialize for PeerId {
189 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
190 where
191 S: serde::Serializer,
192 {
193 if serializer.is_human_readable() {
194 serializer.serialize_str(&self.to_base58())
195 } else {
196 serializer.serialize_bytes(&self.to_bytes()[..])
197 }
198 }
199}
200
201impl<'de> Deserialize<'de> for PeerId {
202 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
203 where
204 D: serde::Deserializer<'de>,
205 {
206 use serde::de::*;
207
208 struct PeerIdVisitor;
209
210 impl Visitor<'_> for PeerIdVisitor {
211 type Value = PeerId;
212
213 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
214 write!(f, "valid peer id")
215 }
216
217 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
218 where
219 E: Error,
220 {
221 PeerId::from_bytes(v).map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self))
222 }
223
224 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
225 where
226 E: Error,
227 {
228 PeerId::from_str(v).map_err(|_| Error::invalid_value(Unexpected::Str(v), &self))
229 }
230 }
231
232 if deserializer.is_human_readable() {
233 deserializer.deserialize_str(PeerIdVisitor)
234 } else {
235 deserializer.deserialize_bytes(PeerIdVisitor)
236 }
237 }
238}
239
240#[derive(Debug, Error)]
241pub enum ParseError {
242 #[error("base-58 decode error: {0}")]
243 B58(#[from] bs58::decode::Error),
244 #[error("decoding multihash failed")]
245 MultiHash,
246}
247
248impl FromStr for PeerId {
249 type Err = ParseError;
250
251 #[inline]
252 fn from_str(s: &str) -> Result<Self, Self::Err> {
253 let bytes = bs58::decode(s).into_vec()?;
254 PeerId::from_bytes(&bytes).map_err(|_| ParseError::MultiHash)
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use crate::{crypto::ed25519::Keypair, PeerId};
261 use multiaddr::{Multiaddr, Protocol};
262 use multihash::Multihash;
263
264 #[test]
265 fn peer_id_is_public_key() {
266 let key = Keypair::generate().public();
267 let peer_id = key.to_peer_id();
268 assert_eq!(peer_id.is_public_key(&key.into()), Some(true));
269 }
270
271 #[test]
272 fn peer_id_into_bytes_then_from_bytes() {
273 let peer_id = Keypair::generate().public().to_peer_id();
274 let second = PeerId::from_bytes(&peer_id.to_bytes()).unwrap();
275 assert_eq!(peer_id, second);
276 }
277
278 #[test]
279 fn peer_id_to_base58_then_back() {
280 let peer_id = Keypair::generate().public().to_peer_id();
281 let second: PeerId = peer_id.to_base58().parse().unwrap();
282 assert_eq!(peer_id, second);
283 }
284
285 #[test]
286 fn random_peer_id_is_valid() {
287 for _ in 0..5000 {
288 let peer_id = PeerId::random();
289 assert_eq!(peer_id, PeerId::from_bytes(&peer_id.to_bytes()).unwrap());
290 }
291 }
292
293 #[test]
294 fn peer_id_from_multiaddr() {
295 let address = "[::1]:1337".parse::<std::net::SocketAddr>().unwrap();
296 let peer = PeerId::random();
297 let address = Multiaddr::empty()
298 .with(Protocol::from(address.ip()))
299 .with(Protocol::Tcp(address.port()))
300 .with(Protocol::P2p(Multihash::from(peer)));
301
302 assert_eq!(peer, PeerId::try_from_multiaddr(&address).unwrap());
303 }
304
305 #[test]
306 fn peer_id_from_multiaddr_no_peer_id() {
307 let address = "[::1]:1337".parse::<std::net::SocketAddr>().unwrap();
308 let address = Multiaddr::empty()
309 .with(Protocol::from(address.ip()))
310 .with(Protocol::Tcp(address.port()));
311
312 assert!(PeerId::try_from_multiaddr(&address).is_none());
313 }
314
315 #[test]
316 fn peer_id_from_bytes() {
317 let peer = PeerId::random();
318 let bytes = peer.to_bytes();
319
320 assert_eq!(PeerId::try_from(bytes).unwrap(), peer);
321 }
322
323 #[test]
324 fn peer_id_as_multihash() {
325 let peer = PeerId::random();
326 let multihash = Multihash::from(peer);
327
328 assert_eq!(&multihash, peer.as_ref());
329 assert_eq!(PeerId::try_from(multihash).unwrap(), peer);
330 }
331
332 #[test]
333 fn serialize_deserialize() {
334 let peer = PeerId::random();
335 let serialized = serde_json::to_string(&peer).unwrap();
336 let deserialized = serde_json::from_str(&serialized).unwrap();
337
338 assert_eq!(peer, deserialized);
339 }
340
341 #[test]
342 fn invalid_multihash() {
343 fn test() -> crate::Result<PeerId> {
344 let bytes = [
345 0x16, 0x20, 0x64, 0x4b, 0xcc, 0x7e, 0x56, 0x43, 0x73, 0x04, 0x09, 0x99, 0xaa, 0xc8,
346 0x9e, 0x76, 0x22, 0xf3, 0xca, 0x71, 0xfb, 0xa1, 0xd9, 0x72, 0xfd, 0x94, 0xa3, 0x1c,
347 0x3b, 0xfb, 0xf2, 0x4e, 0x39, 0x38,
348 ];
349
350 PeerId::from_multihash(Multihash::from_bytes(&bytes).unwrap()).map_err(From::from)
351 }
352 let _error = test().unwrap_err();
353 }
354}