Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/libp2p/multihash.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
//! A multihash is a small data structure containing a code (an integer) and data. The format of
19
//! the data depends on the code.
20
//!
21
//! See <https://github.com/multiformats/multihash>
22
23
use alloc::vec::Vec;
24
use core::fmt;
25
26
use crate::util;
27
28
/// A multihash made of a code and a slice of data.
29
///
30
/// This type contains a generic parameter `T` that stores the multihash itself, for example
31
/// `Vec<u8>` or `&[u8]`.
32
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
33
pub struct Multihash<T = Vec<u8>>(T);
34
35
impl<T: AsRef<[u8]>> Multihash<T> {
36
    /// Returns the code stored in this multihash.
37
2
    pub fn hash_algorithm_code(&self) -> u32 {
38
2
        decode(&self.0.as_ref()).unwrap().0
39
2
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE19hash_algorithm_codeB6_
Line
Count
Source
37
2
    pub fn hash_algorithm_code(&self) -> u32 {
38
2
        decode(&self.0.as_ref()).unwrap().0
39
2
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE19hash_algorithm_codeCsih6EgvAwZF2_13smoldot_light
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE19hash_algorithm_codeB6_
40
41
    /// Returns the data stored in this multihash.
42
2
    pub fn data(&self) -> &[u8] {
43
2
        decode(&self.0.as_ref()).unwrap().1
44
2
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE4dataB6_
Line
Count
Source
42
2
    pub fn data(&self) -> &[u8] {
43
2
        decode(&self.0.as_ref()).unwrap().1
44
2
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE4dataB6_
45
46
    /// Checks whether `input` is a valid multihash.
47
11
    pub fn from_bytes(input: T) -> Result<Self, (FromBytesError, T)> {
48
11
        if let Err(
err0
) = decode(input.as_ref()) {
49
0
            return Err((err, input));
50
11
        }
51
11
52
11
        Ok(Multihash(input))
53
11
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashINtNtCsdZExvAaxgia_5alloc6borrow3CowShEE10from_bytesB6_
Line
Count
Source
47
3
    pub fn from_bytes(input: T) -> Result<Self, (FromBytesError, T)> {
48
3
        if let Err(
err0
) = decode(input.as_ref()) {
49
0
            return Err((err, input));
50
3
        }
51
3
52
3
        Ok(Multihash(input))
53
3
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE10from_bytesB6_
Line
Count
Source
47
2
    pub fn from_bytes(input: T) -> Result<Self, (FromBytesError, T)> {
48
2
        if let Err(
err0
) = decode(input.as_ref()) {
49
0
            return Err((err, input));
50
2
        }
51
2
52
2
        Ok(Multihash(input))
53
2
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesB6_
Line
Count
Source
47
6
    pub fn from_bytes(input: T) -> Result<Self, (FromBytesError, T)> {
48
6
        if let Err(
err0
) = decode(input.as_ref()) {
49
0
            return Err((err, input));
50
6
        }
51
6
52
6
        Ok(Multihash(input))
53
6
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsih6EgvAwZF2_13smoldot_light
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashINtNtCsdZExvAaxgia_5alloc6borrow3CowShEE10from_bytesB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRINtNtCsdZExvAaxgia_5alloc3vec3VechEE10from_bytesB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCscDgN54JpMGG_6author
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10from_bytesCsibGXYHQB8Ea_25json_rpc_general_requests
54
55
    /// Destroys the [`Multihash`] and returns the underlying buffer.
56
176
    pub fn into_bytes(self) -> T {
57
176
        self.0
58
176
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashNtB2_9Multihash10into_bytesB6_
Line
Count
Source
56
28
    pub fn into_bytes(self) -> T {
57
28
        self.0
58
28
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesB6_
Line
Count
Source
56
2
    pub fn into_bytes(self) -> T {
57
2
        self.0
58
2
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesCsDDUKWWCHAU_18smoldot_light_wasm
_RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashNtB2_9Multihash10into_bytesB6_
Line
Count
Source
56
146
    pub fn into_bytes(self) -> T {
57
146
        self.0
58
146
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesCsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesCscDgN54JpMGG_6author
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB2_9MultihashRShE10into_bytesCsibGXYHQB8Ea_25json_rpc_general_requests
59
}
60
61
impl<'a> Multihash<&'a [u8]> {
62
    /// Returns the data stored in this multihash.
63
0
    pub fn data_ref(&self) -> &'a [u8] {
64
0
        decode(&self.0.as_ref()).unwrap().1
65
0
    }
Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB4_9MultihashRShE8data_ref
Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB4_9MultihashRShE8data_ref
66
67
    /// Checks whether `input` is a valid multihash.
68
    ///
69
    /// Contrary to [`Multihash::from_bytes`], doesn't return an error if the slice is too long
70
    /// but returns the remainder.
71
0
    pub fn from_bytes_partial(
72
0
        input: &'a [u8],
73
0
    ) -> Result<(Multihash<&'a [u8]>, &'a [u8]), FromBytesError> {
74
0
        match multihash::<nom::error::Error<&[u8]>>(input) {
75
0
            Ok((rest, _)) => Ok((Multihash(&input.as_ref()[..rest.len()]), rest)),
76
0
            Err(_) => Err(FromBytesError::DecodeError),
77
        }
78
0
    }
Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB4_9MultihashRShE18from_bytes_partial
Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB4_9MultihashRShE18from_bytes_partial
79
}
80
81
impl Multihash<Vec<u8>> {
82
    /// Builds a multihash from the "identity" hash algorithm code and the provided data.
83
    ///
84
    /// Calling [`Multihash::data`] on the returned value will always yield back the same data
85
    /// as was passed as parameter.
86
174
    pub fn identity<'a>(data: &'a [u8]) -> Self {
87
174
        let mut out = Vec::with_capacity(data.len() + 8);
88
174
        out.extend(util::leb128::encode(0u32));
89
174
        out.extend(util::leb128::encode_usize(data.len()));
90
174
        out.extend_from_slice(data);
91
174
        Multihash(out)
92
174
    }
_RNvMs0_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashNtB5_9Multihash8identity
Line
Count
Source
86
28
    pub fn identity<'a>(data: &'a [u8]) -> Self {
87
28
        let mut out = Vec::with_capacity(data.len() + 8);
88
28
        out.extend(util::leb128::encode(0u32));
89
28
        out.extend(util::leb128::encode_usize(data.len()));
90
28
        out.extend_from_slice(data);
91
28
        Multihash(out)
92
28
    }
_RNvMs0_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashNtB5_9Multihash8identity
Line
Count
Source
86
146
    pub fn identity<'a>(data: &'a [u8]) -> Self {
87
146
        let mut out = Vec::with_capacity(data.len() + 8);
88
146
        out.extend(util::leb128::encode(0u32));
89
146
        out.extend(util::leb128::encode_usize(data.len()));
90
146
        out.extend_from_slice(data);
91
146
        Multihash(out)
92
146
    }
93
}
94
95
impl<T> AsRef<T> for Multihash<T> {
96
4
    fn as_ref(&self) -> &T {
97
4
        &self.0
98
4
    }
_RNvXs1_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB5_9MultihashINtNtCsdZExvAaxgia_5alloc6borrow3CowShEEINtNtCsaYZPK01V26L_4core7convert5AsRefB11_E6as_refB9_
Line
Count
Source
96
3
    fn as_ref(&self) -> &T {
97
3
        &self.0
98
3
    }
_RNvXs1_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB11_E6as_refB9_
Line
Count
Source
96
1
    fn as_ref(&self) -> &T {
97
1
        &self.0
98
1
    }
Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashINtNtCsdZExvAaxgia_5alloc6borrow3CowShEEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refB9_
Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashNtB5_9MultihashINtNtCsaYZPK01V26L_4core7convert5AsRefINtNtCsdZExvAaxgia_5alloc3vec3VechEE6as_refB9_
Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCscDgN54JpMGG_6author
Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashINtB5_9MultihashRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB12_E6as_refCsibGXYHQB8Ea_25json_rpc_general_requests
99
}
100
101
/// Error when turning bytes into a [`Multihash`].
102
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXsc_NtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashNtB5_14FromBytesErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsc_NtNtCseuYC0Zibziv_7smoldot6libp2p9multihashNtB5_14FromBytesErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
103
pub enum FromBytesError {
104
    /// The multihash is invalid.
105
    DecodeError,
106
}
107
108
impl<T: AsRef<[u8]>> fmt::Debug for Multihash<T> {
109
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110
0
        fmt::Display::fmt(self, f)
111
0
    }
Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashs2_0pEINtB5_9MultihashpENtNtCsaYZPK01V26L_4core3fmt5Debug3fmtB9_
Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot6libp2p9multihashs2_0pEINtB5_9MultihashpENtNtCsaYZPK01V26L_4core3fmt5Debug3fmtB9_
112
}
113
114
impl<T: AsRef<[u8]>> fmt::Display for Multihash<T> {
115
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116
0
        let base58 = bs58::encode(self.0.as_ref()).into_string();
117
0
        write!(f, "{base58}")
118
0
    }
Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot6libp2p9multihashs3_0pEINtB5_9MultihashpENtNtCsaYZPK01V26L_4core3fmt7Display3fmtB9_
Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot6libp2p9multihashs3_0pEINtB5_9MultihashpENtNtCsaYZPK01V26L_4core3fmt7Display3fmtB9_
119
}
120
121
15
fn decode<'a>(bytes: &'a [u8]) -> Result<(u32, &'a [u8]), FromBytesError> {
122
15
    match nom::combinator::all_consuming(multihash::<nom::error::Error<&[u8]>>)(bytes) {
123
15
        Ok((_rest, multihash)) => {
124
15
            debug_assert!(_rest.is_empty());
125
15
            Ok(multihash)
126
        }
127
0
        Err(_) => Err(FromBytesError::DecodeError),
128
    }
129
15
}
_RNvNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihash6decode
Line
Count
Source
121
15
fn decode<'a>(bytes: &'a [u8]) -> Result<(u32, &'a [u8]), FromBytesError> {
122
15
    match nom::combinator::all_consuming(multihash::<nom::error::Error<&[u8]>>)(bytes) {
123
15
        Ok((_rest, multihash)) => {
124
15
            debug_assert!(_rest.is_empty());
125
15
            Ok(multihash)
126
        }
127
0
        Err(_) => Err(FromBytesError::DecodeError),
128
    }
129
15
}
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6libp2p9multihash6decode
130
131
15
fn multihash<'a, E: nom::error::ParseError<&'a [u8]>>(
132
15
    bytes: &'a [u8],
133
15
) -> nom::IResult<&'a [u8], (u32, &'a [u8]), E> {
134
15
    nom::sequence::tuple((
135
15
        nom::combinator::map_opt(crate::util::leb128::nom_leb128_usize, |c| {
136
15
            u32::try_from(c).ok()
137
15
        }),
_RNCINvNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihash9multihashINtNtCs6ga8gEqbpRc_3nom5error5ErrorRShEE0B8_
Line
Count
Source
135
15
        nom::combinator::map_opt(crate::util::leb128::nom_leb128_usize, |c| {
136
15
            u32::try_from(c).ok()
137
15
        }),
Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6libp2p9multihash9multihashINtNtCs6ga8gEqbpRc_3nom5error5ErrorRShEE0B8_
138
15
        nom::multi::length_data(crate::util::leb128::nom_leb128_usize),
139
15
    ))(bytes)
140
15
}
_RINvNtNtCsN16ciHI6Qf_7smoldot6libp2p9multihash9multihashINtNtCs6ga8gEqbpRc_3nom5error5ErrorRShEEB6_
Line
Count
Source
131
15
fn multihash<'a, E: nom::error::ParseError<&'a [u8]>>(
132
15
    bytes: &'a [u8],
133
15
) -> nom::IResult<&'a [u8], (u32, &'a [u8]), E> {
134
15
    nom::sequence::tuple((
135
15
        nom::combinator::map_opt(crate::util::leb128::nom_leb128_usize, |c| {
136
            u32::try_from(c).ok()
137
15
        }),
138
15
        nom::multi::length_data(crate::util::leb128::nom_leb128_usize),
139
15
    ))(bytes)
140
15
}
Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6libp2p9multihash9multihashINtNtCs6ga8gEqbpRc_3nom5error5ErrorRShEEB6_