informalsystems_malachitebft_peer/
lib.rs1#![no_std]
21extern crate alloc;
22
23use alloc::{
24 string::{String, ToString},
25 vec::Vec,
26};
27use core::{fmt, str::FromStr};
28
29use thiserror::Error;
30
31#[cfg(feature = "rand")]
32use rand::Rng;
33
34mod ser;
35
36type Multihash = multihash::Multihash<64>;
42
43#[cfg(feature = "serde")]
44use serde::{Deserialize, Serialize};
45
46const MAX_INLINE_KEY_LENGTH: usize = 42;
49
50const MULTIHASH_IDENTITY_CODE: u64 = 0;
51const MULTIHASH_SHA256_CODE: u64 = 0x12;
52
53#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
58pub struct PeerId {
59 multihash: Multihash,
60}
61
62impl fmt::Debug for PeerId {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.debug_tuple("PeerId").field(&self.to_base58()).finish()
65 }
66}
67
68impl fmt::Display for PeerId {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 self.to_base58().fmt(f)
71 }
72}
73
74impl PeerId {
75 pub fn from_bytes(data: &[u8]) -> Result<PeerId, ParseError> {
77 PeerId::from_multihash(
78 Multihash::from_bytes(data).map_err(|e| ParseError::InvalidMultihash(e.to_string()))?,
79 )
80 .map_err(|mh| ParseError::UnsupportedCode(mh.code()))
81 }
82
83 pub fn from_multihash(multihash: Multihash) -> Result<PeerId, Multihash> {
89 match multihash.code() {
90 MULTIHASH_SHA256_CODE => Ok(PeerId { multihash }),
91 MULTIHASH_IDENTITY_CODE if multihash.digest().len() <= MAX_INLINE_KEY_LENGTH => {
92 Ok(PeerId { multihash })
93 }
94 _ => Err(multihash),
95 }
96 }
97
98 #[cfg(feature = "rand")]
102 pub fn random() -> PeerId {
103 let peer_id = rand::thread_rng().gen::<[u8; 32]>();
104 PeerId {
105 multihash: Multihash::wrap(0x0, &peer_id).expect("The digest size is never too large"),
106 }
107 }
108
109 pub fn to_bytes(self) -> Vec<u8> {
111 self.multihash.to_bytes()
112 }
113
114 pub fn to_base58(self) -> String {
116 bs58::encode(self.to_bytes()).into_string()
117 }
118}
119
120impl TryFrom<Vec<u8>> for PeerId {
121 type Error = Vec<u8>;
122
123 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
124 PeerId::from_bytes(&value).map_err(|_| value)
125 }
126}
127
128impl TryFrom<Multihash> for PeerId {
129 type Error = Multihash;
130
131 fn try_from(value: Multihash) -> Result<Self, Self::Error> {
132 PeerId::from_multihash(value)
133 }
134}
135
136impl AsRef<Multihash> for PeerId {
137 fn as_ref(&self) -> &Multihash {
138 &self.multihash
139 }
140}
141
142impl From<PeerId> for Multihash {
143 fn from(peer_id: PeerId) -> Self {
144 peer_id.multihash
145 }
146}
147
148impl From<PeerId> for Vec<u8> {
149 fn from(peer_id: PeerId) -> Self {
150 peer_id.to_bytes()
151 }
152}
153
154#[cfg(feature = "serde")]
155impl Serialize for PeerId {
156 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
157 where
158 S: serde::Serializer,
159 {
160 if serializer.is_human_readable() {
161 serializer.serialize_str(&self.to_base58())
162 } else {
163 serializer.serialize_bytes(&self.to_bytes()[..])
164 }
165 }
166}
167
168#[cfg(feature = "serde")]
169impl<'de> Deserialize<'de> for PeerId {
170 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
171 where
172 D: serde::Deserializer<'de>,
173 {
174 use serde::de::*;
175
176 struct PeerIdVisitor;
177
178 impl Visitor<'_> for PeerIdVisitor {
179 type Value = PeerId;
180
181 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 write!(f, "valid peer id")
183 }
184
185 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
186 where
187 E: Error,
188 {
189 PeerId::from_bytes(v).map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self))
190 }
191
192 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
193 where
194 E: Error,
195 {
196 PeerId::from_str(v).map_err(|_| Error::invalid_value(Unexpected::Str(v), &self))
197 }
198 }
199
200 if deserializer.is_human_readable() {
201 deserializer.deserialize_str(PeerIdVisitor)
202 } else {
203 deserializer.deserialize_bytes(PeerIdVisitor)
204 }
205 }
206}
207
208#[derive(Debug, Error)]
210pub enum ParseError {
211 #[error("base-58 decode error: {0}")]
212 B58(String),
213 #[error("unsupported multihash code '{0}'")]
214 UnsupportedCode(u64),
215 #[error("invalid multihash: {0}")]
216 InvalidMultihash(String),
217}
218
219impl FromStr for PeerId {
220 type Err = ParseError;
221
222 #[inline]
223 fn from_str(s: &str) -> Result<Self, Self::Err> {
224 let bytes = bs58::decode(s)
225 .into_vec()
226 .map_err(|e| ParseError::B58(e.to_string()))?;
227 let peer_id = PeerId::from_bytes(&bytes)?;
228
229 Ok(peer_id)
230 }
231}