referrerpolicy=no-referrer-when-downgrade

sc_network_types/
multiaddr.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use litep2p::types::multiaddr::{
20	Error as LiteP2pError, Iter as LiteP2pIter, Multiaddr as LiteP2pMultiaddr,
21	Protocol as LiteP2pProtocol,
22};
23use multiaddr::Multiaddr as LibP2pMultiaddr;
24use serde_with::{DeserializeFromStr, SerializeDisplay};
25use std::{
26	fmt::{self, Debug, Display},
27	net::{IpAddr, Ipv4Addr, Ipv6Addr},
28	str::FromStr,
29};
30
31mod protocol;
32pub use protocol::Protocol;
33
34// Re-export the macro under shorter name under `multiaddr`.
35pub use crate::build_multiaddr as multiaddr;
36
37/// [`Multiaddr`] type used in Substrate. Converted to libp2p's `Multiaddr`
38/// or litep2p's `Multiaddr` when passed to the corresponding network backend.
39
40#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash, SerializeDisplay, DeserializeFromStr)]
41pub struct Multiaddr {
42	multiaddr: LiteP2pMultiaddr,
43}
44
45impl Multiaddr {
46	/// Create a new, empty multiaddress.
47	pub fn empty() -> Self {
48		Self { multiaddr: LiteP2pMultiaddr::empty() }
49	}
50
51	/// Adds an address component to the end of this multiaddr.
52	pub fn push(&mut self, p: Protocol<'_>) {
53		self.multiaddr.push(p.into())
54	}
55
56	/// Pops the last `Protocol` of this multiaddr, or `None` if the multiaddr is empty.
57	pub fn pop<'a>(&mut self) -> Option<Protocol<'a>> {
58		self.multiaddr.pop().map(Into::into)
59	}
60
61	/// Like [`Multiaddr::push`] but consumes `self`.
62	pub fn with(self, p: Protocol<'_>) -> Self {
63		self.multiaddr.with(p.into()).into()
64	}
65
66	/// Returns the components of this multiaddress.
67	pub fn iter(&self) -> Iter<'_> {
68		self.multiaddr.iter().into()
69	}
70
71	/// Return a copy of this [`Multiaddr`]'s byte representation.
72	pub fn to_vec(&self) -> Vec<u8> {
73		self.multiaddr.to_vec()
74	}
75}
76
77impl Display for Multiaddr {
78	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79		Display::fmt(&self.multiaddr, f)
80	}
81}
82
83/// Remove an extra layer of nestedness by deferring to the wrapped value's [`Debug`].
84impl Debug for Multiaddr {
85	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86		Debug::fmt(&self.multiaddr, f)
87	}
88}
89
90impl AsRef<[u8]> for Multiaddr {
91	fn as_ref(&self) -> &[u8] {
92		self.multiaddr.as_ref()
93	}
94}
95
96impl From<LiteP2pMultiaddr> for Multiaddr {
97	fn from(multiaddr: LiteP2pMultiaddr) -> Self {
98		Self { multiaddr }
99	}
100}
101
102impl From<Multiaddr> for LiteP2pMultiaddr {
103	fn from(multiaddr: Multiaddr) -> Self {
104		multiaddr.multiaddr
105	}
106}
107
108impl From<LibP2pMultiaddr> for Multiaddr {
109	fn from(multiaddr: LibP2pMultiaddr) -> Self {
110		multiaddr.into_iter().map(Into::into).collect()
111	}
112}
113
114impl From<Multiaddr> for LibP2pMultiaddr {
115	fn from(multiaddr: Multiaddr) -> Self {
116		multiaddr.into_iter().map(Into::into).collect()
117	}
118}
119
120impl From<IpAddr> for Multiaddr {
121	fn from(v: IpAddr) -> Multiaddr {
122		match v {
123			IpAddr::V4(a) => a.into(),
124			IpAddr::V6(a) => a.into(),
125		}
126	}
127}
128
129impl From<Ipv4Addr> for Multiaddr {
130	fn from(v: Ipv4Addr) -> Multiaddr {
131		Protocol::Ip4(v).into()
132	}
133}
134
135impl From<Ipv6Addr> for Multiaddr {
136	fn from(v: Ipv6Addr) -> Multiaddr {
137		Protocol::Ip6(v).into()
138	}
139}
140
141impl TryFrom<Vec<u8>> for Multiaddr {
142	type Error = ParseError;
143
144	fn try_from(v: Vec<u8>) -> Result<Self, ParseError> {
145		let multiaddr = LiteP2pMultiaddr::try_from(v)?;
146		Ok(Self { multiaddr })
147	}
148}
149
150/// Error when parsing a [`Multiaddr`] from string.
151#[derive(Debug, thiserror::Error)]
152pub enum ParseError {
153	/// Less data provided than indicated by length.
154	#[error("less data than indicated by length")]
155	DataLessThanLen,
156	/// Invalid multiaddress.
157	#[error("invalid multiaddress")]
158	InvalidMultiaddr,
159	/// Invalid protocol specification.
160	#[error("invalid protocol string")]
161	InvalidProtocolString,
162	/// Unknown protocol string identifier.
163	#[error("unknown protocol '{0}'")]
164	UnknownProtocolString(String),
165	/// Unknown protocol numeric id.
166	#[error("unknown protocol id {0}")]
167	UnknownProtocolId(u32),
168	/// Failed to decode unsigned varint.
169	#[error("failed to decode unsigned varint: {0}")]
170	InvalidUvar(Box<dyn std::error::Error + Send + Sync>),
171	/// Other error emitted when parsing into the wrapped type.
172	#[error("multiaddr parsing error: {0}")]
173	ParsingError(Box<dyn std::error::Error + Send + Sync>),
174}
175
176impl From<LiteP2pError> for ParseError {
177	fn from(error: LiteP2pError) -> Self {
178		match error {
179			LiteP2pError::DataLessThanLen => ParseError::DataLessThanLen,
180			LiteP2pError::InvalidMultiaddr => ParseError::InvalidMultiaddr,
181			LiteP2pError::InvalidProtocolString => ParseError::InvalidProtocolString,
182			LiteP2pError::UnknownProtocolString(s) => ParseError::UnknownProtocolString(s),
183			LiteP2pError::UnknownProtocolId(n) => ParseError::UnknownProtocolId(n),
184			LiteP2pError::InvalidUvar(e) => ParseError::InvalidUvar(Box::new(e)),
185			LiteP2pError::ParsingError(e) => ParseError::ParsingError(e),
186			error => ParseError::ParsingError(Box::new(error)),
187		}
188	}
189}
190
191impl FromStr for Multiaddr {
192	type Err = ParseError;
193
194	fn from_str(s: &str) -> Result<Self, Self::Err> {
195		let multiaddr = LiteP2pMultiaddr::from_str(s)?;
196		Ok(Self { multiaddr })
197	}
198}
199
200impl TryFrom<String> for Multiaddr {
201	type Error = ParseError;
202
203	fn try_from(s: String) -> Result<Multiaddr, Self::Error> {
204		Self::from_str(&s)
205	}
206}
207
208impl<'a> TryFrom<&'a str> for Multiaddr {
209	type Error = ParseError;
210
211	fn try_from(s: &'a str) -> Result<Multiaddr, Self::Error> {
212		Self::from_str(s)
213	}
214}
215
216/// Iterator over `Multiaddr` [`Protocol`]s.
217pub struct Iter<'a>(LiteP2pIter<'a>);
218
219impl<'a> Iterator for Iter<'a> {
220	type Item = Protocol<'a>;
221
222	fn next(&mut self) -> Option<Self::Item> {
223		self.0.next().map(Into::into)
224	}
225}
226
227impl<'a> From<LiteP2pIter<'a>> for Iter<'a> {
228	fn from(iter: LiteP2pIter<'a>) -> Self {
229		Self(iter)
230	}
231}
232
233impl<'a> IntoIterator for &'a Multiaddr {
234	type Item = Protocol<'a>;
235	type IntoIter = Iter<'a>;
236
237	fn into_iter(self) -> Iter<'a> {
238		self.multiaddr.into_iter().into()
239	}
240}
241
242impl<'a> FromIterator<Protocol<'a>> for Multiaddr {
243	fn from_iter<T>(iter: T) -> Self
244	where
245		T: IntoIterator<Item = Protocol<'a>>,
246	{
247		LiteP2pMultiaddr::from_iter(iter.into_iter().map(Into::into)).into()
248	}
249}
250
251impl<'a> From<Protocol<'a>> for Multiaddr {
252	fn from(p: Protocol<'a>) -> Multiaddr {
253		let protocol: LiteP2pProtocol = p.into();
254		let multiaddr: LiteP2pMultiaddr = protocol.into();
255		multiaddr.into()
256	}
257}
258
259/// Easy way for a user to create a `Multiaddr`.
260///
261/// Example:
262///
263/// ```rust
264/// use sc_network_types::build_multiaddr;
265/// let addr = build_multiaddr!(Ip4([127, 0, 0, 1]), Tcp(10500u16));
266/// ```
267///
268/// Each element passed to `multiaddr!` should be a variant of the `Protocol` enum. The
269/// optional parameter is turned into the proper type with the `Into` trait.
270///
271/// For example, `Ip4([127, 0, 0, 1])` works because `Ipv4Addr` implements `From<[u8; 4]>`.
272#[macro_export]
273macro_rules! build_multiaddr {
274    ($($comp:ident $(($param:expr))*),+) => {
275        {
276            use std::iter;
277            let elem = iter::empty::<$crate::multiaddr::Protocol>();
278            $(
279                let elem = {
280                    let cmp = $crate::multiaddr::Protocol::$comp $(( $param.into() ))*;
281                    elem.chain(iter::once(cmp))
282                };
283            )+
284            elem.collect::<$crate::multiaddr::Multiaddr>()
285        }
286    }
287}