Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/network/codec/block_announces.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
use crate::header;
19
20
use alloc::vec;
21
use nom::Finish as _;
22
23
/// Decoded handshake sent or received when opening a block announces notifications substream.
24
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
25
pub struct BlockAnnouncesHandshakeRef<'a> {
26
    /// Role a node reports playing on the network.
27
    pub role: Role,
28
29
    /// Height of the best block according to this node.
30
    pub best_number: u64,
31
32
    /// Hash of the best block according to this node.
33
    pub best_hash: &'a [u8; 32],
34
35
    /// Hash of the genesis block according to this node.
36
    ///
37
    /// > **Note**: This should be compared to the locally known genesis block hash, to make sure
38
    /// >           that both nodes are on the same chain.
39
    pub genesis_hash: &'a [u8; 32],
40
}
41
42
/// Role a node reports playing on the network.
43
///
44
/// This role can be seen more or less as a priority level. The role a node reports cannot be
45
/// trusted but is used as a hint. For example, Grandpa votes can be broadcasted with a higher
46
/// priority to the nodes that report themselves as authorities.
47
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
48
pub enum Role {
49
    /// Authorities author blocks and participate in the consensus.
50
    ///
51
    /// This role is non-binding, and is used only as a hint to prioritize some nodes over others.
52
    Authority,
53
54
    /// Full nodes store the state of the chain. They are part of the infrastructure of the chain
55
    /// in the sense that light nodes benefit from having a lot of full nodes to connect to.
56
    ///
57
    /// This role is non-binding, and is used only as a hint to prioritize some nodes over others.
58
    Full,
59
60
    /// Light nodes are the lowest priority nodes.
61
    Light,
62
}
63
64
impl Role {
65
    /// Returns the SCALE encoding of this enum. Always guaranteed to be one byte.
66
0
    pub fn scale_encoding(&self) -> [u8; 1] {
67
0
        match *self {
68
0
            Role::Full => [0b1],
69
0
            Role::Light => [0b10],
70
0
            Role::Authority => [0b100],
71
        }
72
0
    }
Unexecuted instantiation: _RNvMNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announcesNtB2_4Role14scale_encoding
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announcesNtB2_4Role14scale_encoding
73
}
74
75
/// Decoded block announcement notification.
76
#[derive(Debug)]
77
pub struct BlockAnnounceRef<'a> {
78
    /// SCALE-encoded header in the announce.
79
    ///
80
    /// > **Note**: Due to the way block announces are encoded, the header is always guaranteed to
81
    /// >           decode correctly. However this shouldn't be relied upon.
82
    pub scale_encoded_header: &'a [u8],
83
84
    /// True if the block is the new best block of the announcer.
85
    pub is_best: bool,
86
    // TODO: missing a `Vec<u8>` field that SCALE-decodes into this type: https://github.com/paritytech/polkadot/blob/fff4635925c12c80717a524367687fcc304bcb13/node%2Fprimitives%2Fsrc%2Flib.rs#L87
87
}
88
89
/// Turns a block announcement into its SCALE-encoding ready to be sent over the wire.
90
///
91
/// This function returns an iterator of buffers. The encoded message consists in the
92
/// concatenation of the buffers.
93
0
pub fn encode_block_announce(
94
0
    announce: BlockAnnounceRef<'_>,
95
0
) -> impl Iterator<Item = impl AsRef<[u8]> + '_> + '_ {
96
0
    let is_best = if announce.is_best { [1u8] } else { [0u8] };
97
98
0
    [
99
0
        either::Left(announce.scale_encoded_header),
100
0
        either::Right(is_best),
101
0
        either::Right([0u8]),
102
0
    ]
103
0
    .into_iter()
104
0
}
Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces21encode_block_announce
Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces21encode_block_announce
105
106
/// Decodes a block announcement.
107
0
pub fn decode_block_announce(
108
0
    bytes: &[u8],
109
0
    block_number_bytes: usize,
110
0
) -> Result<BlockAnnounceRef, DecodeBlockAnnounceError> {
111
0
    let result: Result<_, nom::error::Error<_>> =
112
0
        nom::combinator::all_consuming(nom::combinator::complete(nom::combinator::map(
113
0
            nom::sequence::tuple((
114
0
                nom::combinator::recognize(|enc_hdr| {
115
0
                    match header::decode_partial(enc_hdr, block_number_bytes) {
116
0
                        Ok((hdr, rest)) => Ok((rest, hdr)),
117
0
                        Err(_) => Err(nom::Err::Failure(nom::error::make_error(
118
0
                            enc_hdr,
119
0
                            nom::error::ErrorKind::Verify,
120
0
                        ))),
121
                    }
122
0
                }),
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces21decode_block_announce0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces21decode_block_announce0B9_
123
0
                nom::branch::alt((
124
0
                    nom::combinator::map(nom::bytes::streaming::tag(&[0]), |_| false),
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces21decode_block_announces_0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces21decode_block_announces_0B9_
125
0
                    nom::combinator::map(nom::bytes::streaming::tag(&[1]), |_| true),
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces21decode_block_announces0_0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces21decode_block_announces0_0B9_
126
0
                )),
127
0
                crate::util::nom_bytes_decode,
128
0
            )),
129
0
            |(scale_encoded_header, is_best, _)| BlockAnnounceRef {
130
0
                scale_encoded_header,
131
0
                is_best,
132
0
            },
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces21decode_block_announces1_0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces21decode_block_announces1_0B9_
133
0
        )))(bytes)
134
0
        .finish();
135
0
136
0
    match result {
137
0
        Ok((_, ann)) => Ok(ann),
138
0
        Err(err) => Err(DecodeBlockAnnounceError(err.code)),
139
    }
140
0
}
Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces21decode_block_announce
Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces21decode_block_announce
141
142
/// Error potentially returned by [`decode_block_announces_handshake`].
143
0
#[derive(Debug, derive_more::Display)]
Unexecuted instantiation: _RNvXse_NtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announcesNtB5_24DecodeBlockAnnounceErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXse_NtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announcesNtB5_24DecodeBlockAnnounceErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
144
#[display(fmt = "Failed to decode a block announcement")]
145
pub struct DecodeBlockAnnounceError(nom::error::ErrorKind);
146
147
/// Turns a block announces handshake into its SCALE-encoding ready to be sent over the wire.
148
///
149
/// This function returns an iterator of buffers. The encoded message consists in the
150
/// concatenation of the buffers.
151
0
pub fn encode_block_announces_handshake(
152
0
    handshake: BlockAnnouncesHandshakeRef<'_>,
153
0
    block_number_bytes: usize,
154
0
) -> impl Iterator<Item = impl AsRef<[u8]> + '_> + '_ {
155
0
    let mut header = vec![0; 1 + block_number_bytes];
156
0
    header[0] = handshake.role.scale_encoding()[0];
157
0
    // TODO: what to do if the best number doesn't fit in the given size? right now we just wrap around
158
0
    header[1..].copy_from_slice(&handshake.best_number.to_le_bytes()[..block_number_bytes]);
159
0
160
0
    [
161
0
        either::Left(header),
162
0
        either::Right(handshake.best_hash),
163
0
        either::Right(handshake.genesis_hash),
164
0
    ]
165
0
    .into_iter()
166
0
}
Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces32encode_block_announces_handshake
Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces32encode_block_announces_handshake
167
168
/// Decodes a SCALE-encoded block announces handshake.
169
0
pub fn decode_block_announces_handshake(
170
0
    expected_block_number_bytes: usize,
171
0
    handshake: &[u8],
172
0
) -> Result<BlockAnnouncesHandshakeRef, BlockAnnouncesHandshakeDecodeError> {
173
0
    let result: Result<_, nom::error::Error<_>> =
174
0
        nom::combinator::all_consuming(nom::combinator::complete(nom::combinator::map(
175
0
            nom::sequence::tuple((
176
0
                nom::branch::alt((
177
0
                    nom::combinator::map(nom::bytes::streaming::tag(&[0b1]), |_| Role::Full),
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces32decode_block_announces_handshake0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces32decode_block_announces_handshake0B9_
178
0
                    nom::combinator::map(nom::bytes::streaming::tag(&[0b10]), |_| Role::Light),
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces32decode_block_announces_handshakes_0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces32decode_block_announces_handshakes_0B9_
179
0
                    nom::combinator::map(nom::bytes::streaming::tag(&[0b100]), |_| Role::Authority),
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces32decode_block_announces_handshakes0_0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces32decode_block_announces_handshakes0_0B9_
180
0
                )),
181
0
                crate::util::nom_varsize_number_decode_u64(expected_block_number_bytes),
182
0
                nom::bytes::streaming::take(32u32),
183
0
                nom::bytes::streaming::take(32u32),
184
0
            )),
185
0
            |(role, best_number, best_hash, genesis_hash)| BlockAnnouncesHandshakeRef {
186
0
                role,
187
0
                best_number,
188
0
                best_hash: TryFrom::try_from(best_hash).unwrap(),
189
0
                genesis_hash: TryFrom::try_from(genesis_hash).unwrap(),
190
0
            },
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces32decode_block_announces_handshakes1_0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces32decode_block_announces_handshakes1_0B9_
191
0
        )))(handshake)
192
0
        .finish();
193
0
194
0
    match result {
195
0
        Ok((_, hs)) => Ok(hs),
196
0
        Err(err) => Err(BlockAnnouncesHandshakeDecodeError(err.code)),
197
    }
198
0
}
Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announces32decode_block_announces_handshake
Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announces32decode_block_announces_handshake
199
200
/// Error potentially returned by [`decode_block_announces_handshake`].
201
0
#[derive(Debug, Clone, derive_more::Display)]
Unexecuted instantiation: _RNvXsh_NtNtNtCsN16ciHI6Qf_7smoldot7network5codec15block_announcesNtB5_34BlockAnnouncesHandshakeDecodeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsh_NtNtNtCseuYC0Zibziv_7smoldot7network5codec15block_announcesNtB5_34BlockAnnouncesHandshakeDecodeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
202
#[display(fmt = "Failed to decode a block announces handshake")]
203
pub struct BlockAnnouncesHandshakeDecodeError(nom::error::ErrorKind);