Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/network/codec.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
//! Encoding and decoding of messages of the protocols used by Polkadot/Substrate.
19
20
// TODO: expand docs
21
22
use alloc::{borrow::Cow, string::String};
23
use core::{fmt, iter};
24
25
// Implementation note: each protocol goes into a different sub-module whose content is
26
// re-exported here.
27
28
mod block_announces;
29
mod block_request;
30
mod grandpa;
31
mod grandpa_warp_sync;
32
mod identify;
33
mod kademlia;
34
mod state_request;
35
mod storage_call_proof;
36
37
pub use self::block_announces::*;
38
pub use self::block_request::*;
39
pub use self::grandpa::*;
40
pub use self::grandpa_warp_sync::*;
41
pub use self::identify::*;
42
pub use self::kademlia::*;
43
pub use self::state_request::*;
44
pub use self::storage_call_proof::*;
45
46
/// Name of a protocol that is part of the Substrate/Polkadot networking.
47
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
48
pub enum ProtocolName<'a> {
49
    Identify,
50
    Ping,
51
    BlockAnnounces {
52
        genesis_hash: [u8; 32],
53
        fork_id: Option<&'a str>,
54
    },
55
    Transactions {
56
        genesis_hash: [u8; 32],
57
        fork_id: Option<&'a str>,
58
    },
59
    Grandpa {
60
        genesis_hash: [u8; 32],
61
        fork_id: Option<&'a str>,
62
    },
63
    Sync {
64
        genesis_hash: [u8; 32],
65
        fork_id: Option<&'a str>,
66
    },
67
    Light {
68
        genesis_hash: [u8; 32],
69
        fork_id: Option<&'a str>,
70
    },
71
    Kad {
72
        genesis_hash: [u8; 32],
73
        fork_id: Option<&'a str>,
74
    },
75
    SyncWarp {
76
        genesis_hash: [u8; 32],
77
        fork_id: Option<&'a str>,
78
    },
79
    State {
80
        genesis_hash: [u8; 32],
81
        fork_id: Option<&'a str>,
82
    },
83
}
84
85
impl<'a> fmt::Debug for ProtocolName<'a> {
86
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87
0
        fmt::Display::fmt(self, f)
88
0
    }
Unexecuted instantiation: _RNvXNtNtCsN16ciHI6Qf_7smoldot7network5codecNtB2_12ProtocolNameNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXNtNtCseuYC0Zibziv_7smoldot7network5codecNtB2_12ProtocolNameNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt
89
}
90
91
impl<'a> fmt::Display for ProtocolName<'a> {
92
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93
0
        for chunk in encode_protocol_name(*self) {
94
0
            f.write_str(chunk.as_ref())?;
95
        }
96
0
        Ok(())
97
0
    }
Unexecuted instantiation: _RNvXs_NtNtCsN16ciHI6Qf_7smoldot7network5codecNtB4_12ProtocolNameNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs_NtNtCseuYC0Zibziv_7smoldot7network5codecNtB4_12ProtocolNameNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
98
}
99
100
/// Turns a [`ProtocolName`] into its string version. Returns a list of objects that, when
101
/// concatenated together, forms the string version of the [`ProtocolName`].
102
0
pub fn encode_protocol_name(
103
0
    protocol: ProtocolName<'_>,
104
0
) -> impl Iterator<Item = impl AsRef<str> + '_> + '_ {
105
0
    let (genesis_hash, fork_id, base_protocol_name) = match protocol {
106
0
        ProtocolName::Identify => return either::Left(iter::once(Cow::Borrowed("/ipfs/id/1.0.0"))),
107
0
        ProtocolName::Ping => return either::Left(iter::once(Cow::Borrowed("/ipfs/ping/1.0.0"))),
108
        ProtocolName::BlockAnnounces {
109
0
            genesis_hash,
110
0
            fork_id,
111
0
        } => (genesis_hash, fork_id, "block-announces/1"),
112
        ProtocolName::Transactions {
113
0
            genesis_hash,
114
0
            fork_id,
115
0
        } => (genesis_hash, fork_id, "transactions/1"),
116
        ProtocolName::Grandpa {
117
0
            genesis_hash,
118
0
            fork_id,
119
0
        } => (genesis_hash, fork_id, "grandpa/1"),
120
        ProtocolName::Sync {
121
0
            genesis_hash,
122
0
            fork_id,
123
0
        } => (genesis_hash, fork_id, "sync/2"),
124
        ProtocolName::Light {
125
0
            genesis_hash,
126
0
            fork_id,
127
0
        } => (genesis_hash, fork_id, "light/2"),
128
        ProtocolName::Kad {
129
0
            genesis_hash,
130
0
            fork_id,
131
0
        } => (genesis_hash, fork_id, "kad"),
132
        ProtocolName::SyncWarp {
133
0
            genesis_hash,
134
0
            fork_id,
135
0
        } => (genesis_hash, fork_id, "sync/warp"),
136
        ProtocolName::State {
137
0
            genesis_hash,
138
0
            fork_id,
139
0
        } => (genesis_hash, fork_id, "state/2"),
140
    };
141
142
0
    let genesis_hash = hex::encode(genesis_hash);
143
144
0
    if let Some(fork_id) = fork_id {
145
0
        either::Right(either::Right(
146
0
            [
147
0
                Cow::Borrowed("/"),
148
0
                Cow::Owned(genesis_hash),
149
0
                Cow::Borrowed("/"),
150
0
                Cow::Borrowed(fork_id),
151
0
                Cow::Borrowed("/"),
152
0
                Cow::Borrowed(base_protocol_name),
153
0
            ]
154
0
            .into_iter(),
155
0
        ))
156
    } else {
157
0
        either::Right(either::Left(
158
0
            [
159
0
                Cow::Borrowed("/"),
160
0
                Cow::Owned(genesis_hash),
161
0
                Cow::Borrowed("/"),
162
0
                Cow::Borrowed(base_protocol_name),
163
0
            ]
164
0
            .into_iter(),
165
0
        ))
166
    }
167
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot7network5codec20encode_protocol_name
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot7network5codec20encode_protocol_name
168
169
/// Turns a [`ProtocolName`] into a string.
170
0
pub fn encode_protocol_name_string(protocol: ProtocolName<'_>) -> String {
171
0
    encode_protocol_name(protocol).fold(String::with_capacity(128), |mut a, b| {
172
0
        a.push_str(b.as_ref());
173
0
        a
174
0
    })
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec27encode_protocol_name_string0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec27encode_protocol_name_string0B7_
175
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot7network5codec27encode_protocol_name_string
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot7network5codec27encode_protocol_name_string
176
177
/// Decodes a protocol name into its components.
178
///
179
/// Returns an error if the protocol name isn't recognized.
180
0
pub fn decode_protocol_name(name: &str) -> Result<ProtocolName, ()> {
181
0
    nom::combinator::all_consuming(nom::branch::alt((
182
0
        nom::combinator::map(nom::bytes::complete::tag("/ipfs/id/1.0.0"), |_| {
183
0
            ProtocolName::Identify
184
0
        }),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec20decode_protocol_name0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec20decode_protocol_name0B7_
185
0
        nom::combinator::map(nom::bytes::complete::tag("/ipfs/ping/1.0.0"), |_| {
186
0
            ProtocolName::Ping
187
0
        }),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec20decode_protocol_names_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec20decode_protocol_names_0B7_
188
0
        nom::combinator::map(
189
0
            nom::sequence::tuple((
190
0
                nom::bytes::complete::tag("/"),
191
0
                genesis_hash,
192
0
                nom::bytes::complete::tag("/"),
193
0
                protocol_ty,
194
0
            )),
195
0
            |(_, genesis_hash, _, protocol_ty)| {
196
0
                protocol_ty_to_real_protocol(protocol_ty, genesis_hash, None)
197
0
            },
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec20decode_protocol_names0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec20decode_protocol_names0_0B7_
198
0
        ),
199
0
        nom::combinator::map(
200
0
            nom::sequence::tuple((
201
0
                nom::bytes::complete::tag("/"),
202
0
                genesis_hash,
203
0
                nom::bytes::complete::tag("/"),
204
0
                nom::bytes::complete::take_until("/"),
205
0
                nom::bytes::complete::tag("/"),
206
0
                protocol_ty,
207
0
            )),
208
0
            |(_, genesis_hash, _, fork_id, _, protocol_ty)| {
209
0
                protocol_ty_to_real_protocol(protocol_ty, genesis_hash, Some(fork_id))
210
0
            },
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec20decode_protocol_names1_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec20decode_protocol_names1_0B7_
211
0
        ),
212
0
    )))(name)
213
0
    .map(|(_, parse_result)| parse_result)
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec20decode_protocol_names2_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec20decode_protocol_names2_0B7_
214
0
    .map_err(|_| ())
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec20decode_protocol_names3_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec20decode_protocol_names3_0B7_
215
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot7network5codec20decode_protocol_name
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot7network5codec20decode_protocol_name
216
217
0
fn genesis_hash(name: &str) -> nom::IResult<&str, [u8; 32]> {
218
0
    nom::combinator::map_opt(nom::bytes::complete::take(64u32), |hash| {
219
0
        hex::decode(hash)
220
0
            .ok()
221
0
            .map(|hash| <[u8; 32]>::try_from(hash).unwrap_or_else(|_| unreachable!()))
Unexecuted instantiation: _RNCNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec12genesis_hash00B9_
Unexecuted instantiation: _RNCNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec12genesis_hash00B9_
Unexecuted instantiation: _RNCNCNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec12genesis_hash000Bb_
Unexecuted instantiation: _RNCNCNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec12genesis_hash000Bb_
222
0
    })(name)
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec12genesis_hash0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec12genesis_hash0B7_
223
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot7network5codec12genesis_hash
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot7network5codec12genesis_hash
224
225
enum ProtocolTy {
226
    BlockAnnounces,
227
    Transactions,
228
    Grandpa,
229
    Sync,
230
    Light,
231
    Kad,
232
    SyncWarp,
233
    State,
234
}
235
236
0
fn protocol_ty(name: &str) -> nom::IResult<&str, ProtocolTy> {
237
0
    nom::branch::alt((
238
0
        nom::combinator::map(nom::bytes::complete::tag("block-announces/1"), |_| {
239
0
            ProtocolTy::BlockAnnounces
240
0
        }),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_ty0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_ty0B7_
241
0
        nom::combinator::map(nom::bytes::complete::tag("transactions/1"), |_| {
242
0
            ProtocolTy::Transactions
243
0
        }),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_tys_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_tys_0B7_
244
0
        nom::combinator::map(nom::bytes::complete::tag("grandpa/1"), |_| {
245
0
            ProtocolTy::Grandpa
246
0
        }),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_tys0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_tys0_0B7_
247
0
        nom::combinator::map(nom::bytes::complete::tag("sync/2"), |_| ProtocolTy::Sync),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_tys1_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_tys1_0B7_
248
0
        nom::combinator::map(nom::bytes::complete::tag("light/2"), |_| ProtocolTy::Light),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_tys2_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_tys2_0B7_
249
0
        nom::combinator::map(nom::bytes::complete::tag("kad"), |_| ProtocolTy::Kad),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_tys3_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_tys3_0B7_
250
0
        nom::combinator::map(nom::bytes::complete::tag("sync/warp"), |_| {
251
0
            ProtocolTy::SyncWarp
252
0
        }),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_tys4_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_tys4_0B7_
253
0
        nom::combinator::map(nom::bytes::complete::tag("state/2"), |_| ProtocolTy::State),
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_tys5_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_tys5_0B7_
254
0
    ))(name)
255
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot7network5codec11protocol_ty
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot7network5codec11protocol_ty
256
257
0
fn protocol_ty_to_real_protocol(
258
0
    ty: ProtocolTy,
259
0
    genesis_hash: [u8; 32],
260
0
    fork_id: Option<&str>,
261
0
) -> ProtocolName {
262
0
    match ty {
263
0
        ProtocolTy::BlockAnnounces => ProtocolName::BlockAnnounces {
264
0
            genesis_hash,
265
0
            fork_id,
266
0
        },
267
0
        ProtocolTy::Transactions => ProtocolName::Transactions {
268
0
            genesis_hash,
269
0
            fork_id,
270
0
        },
271
0
        ProtocolTy::Grandpa => ProtocolName::Grandpa {
272
0
            genesis_hash,
273
0
            fork_id,
274
0
        },
275
0
        ProtocolTy::Sync => ProtocolName::Sync {
276
0
            genesis_hash,
277
0
            fork_id,
278
0
        },
279
0
        ProtocolTy::Light => ProtocolName::Light {
280
0
            genesis_hash,
281
0
            fork_id,
282
0
        },
283
0
        ProtocolTy::Kad => ProtocolName::Kad {
284
0
            genesis_hash,
285
0
            fork_id,
286
0
        },
287
0
        ProtocolTy::SyncWarp => ProtocolName::SyncWarp {
288
0
            genesis_hash,
289
0
            fork_id,
290
0
        },
291
0
        ProtocolTy::State => ProtocolName::State {
292
0
            genesis_hash,
293
0
            fork_id,
294
0
        },
295
    }
296
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot7network5codec28protocol_ty_to_real_protocol
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot7network5codec28protocol_ty_to_real_protocol
297
298
// TODO: tests for the protocol names