/__w/smoldot/smoldot/repo/lib/src/network/codec/grandpa_warp_sync.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 | | //! The GrandPa warp sync protocol is a request-response protocol. |
19 | | //! |
20 | | //! The request's body consists in a block hash. |
21 | | //! |
22 | | //! The response's body consists in a sequence of so-called *fragments*. Each fragment consists in |
23 | | //! a block header and a GrandPa justification corresponding to this header. The justification |
24 | | //! must be verified. |
25 | | //! |
26 | | //! The fragments only contain blocks higher than the hash of the block passed in the request. |
27 | | //! |
28 | | //! By doing a GrandPa warp sync request, a node is capable of quickly obtaining a proof that a |
29 | | //! certain recent block has been finalized by authorities. |
30 | | //! |
31 | | //! A proof has to be minimum. All the headers in all fragments, except for the last, have to |
32 | | //! contain a change in the set of GrandPa authorities. |
33 | | //! |
34 | | //! The responding node has the possibility to cut proofs that are above a certain threshold. When |
35 | | //! it does so, [`GrandpaWarpSyncResponse::is_finished`] should be set to `false`, so that the |
36 | | //! requester can start additional warp sync requests afterwards. |
37 | | |
38 | | use crate::{finality, header}; |
39 | | |
40 | | use alloc::vec::Vec; |
41 | | |
42 | | // TODO: all the constraints explained here should be checked when decoding the message |
43 | | |
44 | | /// Response to a GrandPa warp sync request. |
45 | | #[derive(Debug)] |
46 | | pub struct GrandpaWarpSyncResponse<'a> { |
47 | | /// List of fragments that consist in the proof. |
48 | | /// |
49 | | /// The fragments must be ordered by ascending block height. |
50 | | pub fragments: Vec<GrandpaWarpSyncResponseFragment<'a>>, |
51 | | |
52 | | /// If `true`, the last fragment corresponds to the highest finalized block known to the |
53 | | /// responder. If `false`, the requested is encouraged to start a follow-up GrandPa warp sync |
54 | | /// request starting at the last block in the fragments. |
55 | | pub is_finished: bool, |
56 | | } |
57 | | |
58 | | /// Response to a GrandPa warp sync request. |
59 | | #[derive(Debug)] |
60 | | pub struct GrandpaWarpSyncResponseFragment<'a> { |
61 | | /// Header of a block in the chain. |
62 | | /// |
63 | | /// Must always contain a change in the list of authorities, except for the last fragment |
64 | | /// if [`GrandpaWarpSyncResponse::is_finished`] is `true`. |
65 | | pub scale_encoded_header: &'a [u8], |
66 | | |
67 | | /// Justification that proves the finality of |
68 | | /// [`GrandpaWarpSyncResponseFragment::scale_encoded_header`]. |
69 | | pub scale_encoded_justification: &'a [u8], |
70 | | } |
71 | | |
72 | | /// Error potentially returned by [`decode_grandpa_warp_sync_response`]. |
73 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs1_NtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_syncNtB5_34DecodeGrandpaWarpSyncResponseErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs1_NtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_syncNtB5_34DecodeGrandpaWarpSyncResponseErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
74 | | #[display(fmt = "Failed to decode response")] |
75 | | pub struct DecodeGrandpaWarpSyncResponseError; |
76 | | |
77 | | /// Decodes a SCALE-encoded GrandPa warp sync response. |
78 | 0 | pub fn decode_grandpa_warp_sync_response( |
79 | 0 | encoded: &[u8], |
80 | 0 | block_number_bytes: usize, |
81 | 0 | ) -> Result<GrandpaWarpSyncResponse, DecodeGrandpaWarpSyncResponseError> { |
82 | 0 | nom::combinator::all_consuming(nom::combinator::map( |
83 | 0 | nom::sequence::tuple(( |
84 | 0 | decode_fragments(block_number_bytes), |
85 | 0 | nom::number::streaming::le_u8, |
86 | 0 | )), |
87 | 0 | |(fragments, is_finished)| GrandpaWarpSyncResponse { |
88 | 0 | fragments, |
89 | 0 | is_finished: is_finished != 0, |
90 | 0 | }, Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync33decode_grandpa_warp_sync_response0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync33decode_grandpa_warp_sync_response0B9_ |
91 | 0 | ))(encoded) |
92 | 0 | .map(|(_, parse_result)| parse_result) Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync33decode_grandpa_warp_sync_responses_0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync33decode_grandpa_warp_sync_responses_0B9_ |
93 | 0 | .map_err(|_| DecodeGrandpaWarpSyncResponseError) Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync33decode_grandpa_warp_sync_responses0_0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync33decode_grandpa_warp_sync_responses0_0B9_ |
94 | 0 | } Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync33decode_grandpa_warp_sync_response Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync33decode_grandpa_warp_sync_response |
95 | | |
96 | 0 | fn decode_fragments<'a>( |
97 | 0 | block_number_bytes: usize, |
98 | 0 | ) -> impl FnMut(&'a [u8]) -> nom::IResult<&[u8], Vec<GrandpaWarpSyncResponseFragment>> { |
99 | 0 | nom::combinator::flat_map(crate::util::nom_scale_compact_usize, move |num_elems| { |
100 | 0 | nom::multi::many_m_n(num_elems, num_elems, decode_fragment(block_number_bytes)) |
101 | 0 | }) Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync16decode_fragments0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync16decode_fragments0B9_ |
102 | 0 | } Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync16decode_fragments Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync16decode_fragments |
103 | | |
104 | 0 | fn decode_fragment<'a>( |
105 | 0 | block_number_bytes: usize, |
106 | 0 | ) -> impl FnMut(&'a [u8]) -> nom::IResult<&[u8], GrandpaWarpSyncResponseFragment> { |
107 | 0 | nom::combinator::map( |
108 | 0 | nom::sequence::tuple(( |
109 | 0 | nom::combinator::recognize(move |s| { |
110 | 0 | header::decode_partial(s, block_number_bytes) |
111 | 0 | .map(|(a, b)| (b, a)) Unexecuted instantiation: _RNCNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync15decode_fragment00Bb_ Unexecuted instantiation: _RNCNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync15decode_fragment00Bb_ |
112 | 0 | .map_err(|_| { |
113 | 0 | nom::Err::Failure(nom::error::make_error(s, nom::error::ErrorKind::Verify)) |
114 | 0 | }) Unexecuted instantiation: _RNCNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync15decode_fragment0s_0Bb_ Unexecuted instantiation: _RNCNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync15decode_fragment0s_0Bb_ |
115 | 0 | }), Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync15decode_fragment0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync15decode_fragment0B9_ |
116 | 0 | nom::combinator::recognize(move |s| { |
117 | 0 | finality::decode::decode_partial_grandpa_justification(s, block_number_bytes) |
118 | 0 | .map(|(a, b)| (b, a)) Unexecuted instantiation: _RNCNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync15decode_fragments_00Bb_ Unexecuted instantiation: _RNCNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync15decode_fragments_00Bb_ |
119 | 0 | .map_err(|_| { |
120 | 0 | nom::Err::Failure(nom::error::make_error(s, nom::error::ErrorKind::Verify)) |
121 | 0 | }) Unexecuted instantiation: _RNCNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync15decode_fragments_0s_0Bb_ Unexecuted instantiation: _RNCNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync15decode_fragments_0s_0Bb_ |
122 | 0 | }), Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync15decode_fragments_0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync15decode_fragments_0B9_ |
123 | 0 | )), |
124 | 0 | move |(scale_encoded_header, scale_encoded_justification)| { |
125 | 0 | GrandpaWarpSyncResponseFragment { |
126 | 0 | scale_encoded_header, |
127 | 0 | scale_encoded_justification, |
128 | 0 | } |
129 | 0 | }, Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync15decode_fragments0_0B9_ Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync15decode_fragments0_0B9_ |
130 | 0 | ) |
131 | 0 | } Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec17grandpa_warp_sync15decode_fragment Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec17grandpa_warp_sync15decode_fragment |