Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/chain/blocks_tree/verify.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
//! Extension module containing the API and implementation of everything related to verifying
19
//! blocks.
20
21
use crate::{chain::chain_information, header, verify};
22
23
use super::{
24
    fmt, Arc, BestScore, Block, BlockConsensus, BlockFinality, Duration, Finality,
25
    FinalizedConsensus, NonFinalizedTree, Vec,
26
};
27
28
impl<T> NonFinalizedTree<T> {
29
    /// Verifies the given block header.
30
    ///
31
    /// The verification is performed in the context of the chain. In particular, the
32
    /// verification will fail if the parent block isn't already in the chain.
33
    ///
34
    /// If the verification succeeds, an [`VerifiedHeader`] object might be returned which can be
35
    /// used to then insert the block in the chain using
36
    /// [`NonFinalizedTree::insert_verified_header`].
37
    ///
38
    /// Must be passed the current UNIX time in order to verify that the block doesn't pretend to
39
    /// come from the future.
40
4
    pub fn verify_header(
41
4
        &self,
42
4
        scale_encoded_header: Vec<u8>,
43
4
        now_from_unix_epoch: Duration,
44
4
    ) -> Result<HeaderVerifySuccess, HeaderVerifyError> {
45
4
        let decoded_header = match header::decode(&scale_encoded_header, self.block_number_bytes) {
46
4
            Ok(h) => h,
47
0
            Err(err) => return Err(HeaderVerifyError::InvalidHeader(err)),
48
        };
49
50
4
        let hash = header::hash_from_scale_encoded_header(&scale_encoded_header);
51
4
52
4
        // Check for duplicates.
53
4
        if self.blocks_by_hash.contains_key(&hash) {
54
0
            return Ok(HeaderVerifySuccess::Duplicate);
55
4
        }
56
57
        // Try to find the parent block in the tree of known blocks.
58
        // `Some` with an index of the parent within the tree of unfinalized blocks.
59
        // `None` means that the parent is the finalized block.
60
4
        let parent_tree_index = {
61
4
            if *decoded_header.parent_hash == self.finalized_block_hash {
62
2
                None
63
            } else {
64
2
                match self.blocks_by_hash.get(decoded_header.parent_hash) {
65
2
                    Some(parent) => Some(*parent),
66
                    None => {
67
0
                        let parent_hash = *decoded_header.parent_hash;
68
0
                        return Err(HeaderVerifyError::BadParent { parent_hash });
69
                    }
70
                }
71
            }
72
        };
73
74
        // Some consensus-specific information must be fetched from the tree of ancestry. The
75
        // information is found either in the parent block, or in the finalized block.
76
4
        let (parent_consensus, parent_best_score, parent_finality) =
77
4
            if let Some(
parent_tree_index2
) = parent_tree_index {
78
2
                let parent = self.blocks.get(parent_tree_index).unwrap();
79
2
                (
80
2
                    Some(parent.consensus.clone()),
81
2
                    parent.best_score,
82
2
                    parent.finality.clone(),
83
2
                )
84
            } else {
85
2
                let consensus = match &self.finalized_consensus {
86
0
                    FinalizedConsensus::Unknown => None,
87
                    FinalizedConsensus::Aura {
88
0
                        authorities_list, ..
89
0
                    } => Some(BlockConsensus::Aura {
90
0
                        authorities_list: authorities_list.clone(),
91
0
                    }),
92
                    FinalizedConsensus::Babe {
93
2
                        block_epoch_information,
94
2
                        next_epoch_transition,
95
2
                        ..
96
2
                    } => Some(BlockConsensus::Babe {
97
2
                        current_epoch: block_epoch_information.clone(),
98
2
                        next_epoch: next_epoch_transition.clone(),
99
2
                    }),
100
                };
101
102
2
                let finality = match self.finality {
103
0
                    Finality::Outsourced => BlockFinality::Outsourced,
104
                    Finality::Grandpa {
105
2
                        after_finalized_block_authorities_set_id,
106
2
                        ref finalized_scheduled_change,
107
2
                        ref finalized_triggered_authorities,
108
2
                    } => {
109
2
                        debug_assert!(finalized_scheduled_change
110
2
                            .as_ref()
111
2
                            .map(|(n, _)| 
*n >= decoded_header.number0
)
Unexecuted instantiation: _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers5_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers5_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers5_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers5_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers5_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers5_0CsibGXYHQB8Ea_25json_rpc_general_requests
112
2
                            .unwrap_or(true));
113
2
                        BlockFinality::Grandpa {
114
2
                            prev_auth_change_trigger_number: None,
115
2
                            triggers_change: false,
116
2
                            scheduled_change: finalized_scheduled_change.clone(),
117
2
                            after_block_authorities_set_id:
118
2
                                after_finalized_block_authorities_set_id,
119
2
                            triggered_authorities: finalized_triggered_authorities.clone(),
120
2
                        }
121
                    }
122
                };
123
124
2
                (consensus, self.finalized_best_score, finality)
125
            };
126
127
4
        let parent_block_header = if let Some(
parent_tree_index2
) = parent_tree_index {
128
2
            &self
129
2
                .blocks
130
2
                .get(parent_tree_index)
131
2
                .unwrap_or_else(|| 
unreachable!()0
)
Unexecuted instantiation: _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_header0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_header0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_header0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_header0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_header0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_header0CsibGXYHQB8Ea_25json_rpc_general_requests
132
2
                .header
133
        } else {
134
2
            &self.finalized_block_header
135
        };
136
137
4
        let header_verify_result = {
138
4
            let consensus_config = match (&self.finalized_consensus, &parent_consensus) {
139
                (
140
0
                    FinalizedConsensus::Aura { slot_duration, .. },
141
0
                    Some(BlockConsensus::Aura { authorities_list }),
142
0
                ) => verify::header_only::ConfigConsensus::Aura {
143
0
                    current_authorities: header::AuraAuthoritiesIter::from_slice(authorities_list),
144
0
                    now_from_unix_epoch,
145
0
                    slot_duration: *slot_duration,
146
0
                },
147
                (
148
                    FinalizedConsensus::Babe {
149
4
                        slots_per_epoch, ..
150
4
                    },
151
4
                    Some(BlockConsensus::Babe {
152
4
                        current_epoch,
153
4
                        next_epoch,
154
4
                    }),
155
4
                ) => verify::header_only::ConfigConsensus::Babe {
156
4
                    parent_block_epoch: current_epoch.as_ref().map(|v| 
(&**v).into()2
),
_RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers_0Ba_
Line
Count
Source
156
2
                    parent_block_epoch: current_epoch.as_ref().map(|v| (&**v).into()),
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers_0CsibGXYHQB8Ea_25json_rpc_general_requests
157
4
                    parent_block_next_epoch: (&**next_epoch).into(),
158
4
                    slots_per_epoch: *slots_per_epoch,
159
4
                    now_from_unix_epoch,
160
4
                },
161
                (FinalizedConsensus::Unknown, None) => {
162
0
                    return Err(HeaderVerifyError::UnknownConsensusEngine)
163
                }
164
                _ => {
165
0
                    return Err(HeaderVerifyError::ConsensusMismatch);
166
                }
167
            };
168
169
            match verify::header_only::verify(verify::header_only::Config {
170
4
                consensus: consensus_config,
171
4
                finality: match &parent_finality {
172
0
                    BlockFinality::Outsourced => verify::header_only::ConfigFinality::Outsourced,
173
4
                    BlockFinality::Grandpa { .. } => verify::header_only::ConfigFinality::Grandpa,
174
                },
175
4
                allow_unknown_consensus_engines: self.allow_unknown_consensus_engines,
176
4
                block_header: decoded_header.clone(),
177
4
                block_number_bytes: self.block_number_bytes,
178
4
                parent_block_header: {
179
4
                    // All headers inserted in `self` are necessarily valid, and thus this
180
4
                    // `unwrap()` can't panic.
181
4
                    header::decode(parent_block_header, self.block_number_bytes)
182
4
                        .unwrap_or_else(|_| 
unreachable!()0
)
Unexecuted instantiation: _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers0_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers0_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers0_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers0_0CsibGXYHQB8Ea_25json_rpc_general_requests
183
                },
184
            }) {
185
4
                Ok(s) => s,
186
0
                Err(err) => {
187
0
                    // The code in this module is meant to ensure that the chain is in an
188
0
                    // appropriate state, therefore `is_invalid_chain_configuration` being `true`
189
0
                    // would indicate a bug in the code somewhere.
190
0
                    // We use a `debug_assert` rather than `assert` in order to avoid crashing,
191
0
                    // as treating the header as invalid is an appropriate way to handle a bug
192
0
                    // here.
193
0
                    debug_assert!(!err.is_invalid_chain_configuration());
194
0
                    return Err(HeaderVerifyError::VerificationFailed(err));
195
                }
196
            }
197
        };
198
199
        // Updated consensus information for the block being verified.
200
4
        let (best_score_num_primary_slots, best_score_num_secondary_slots, consensus_update) =
201
            match (
202
4
                header_verify_result,
203
4
                &parent_consensus,
204
4
                self.finalized_consensus.clone(),
205
4
                parent_tree_index.map(|idx| 
self.blocks.get(idx).unwrap().consensus.clone()2
),
_RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers1_0Ba_
Line
Count
Source
205
2
                parent_tree_index.map(|idx| self.blocks.get(idx).unwrap().consensus.clone()),
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers1_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers1_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers1_0CsibGXYHQB8Ea_25json_rpc_general_requests
206
            ) {
207
                // No Aura epoch transition. Just a regular block.
208
                (
209
                    verify::header_only::Success::Aura {
210
                        authorities_change: None,
211
                    },
212
                    Some(BlockConsensus::Aura {
213
0
                        authorities_list: parent_authorities,
214
0
                    }),
215
0
                    FinalizedConsensus::Aura { .. },
216
0
                    _,
217
0
                ) => (
218
0
                    parent_best_score.num_primary_slots + 1,
219
0
                    parent_best_score.num_secondary_slots,
220
0
                    BlockConsensus::Aura {
221
0
                        authorities_list: parent_authorities.clone(),
222
0
                    },
223
0
                ),
224
225
                // Aura epoch transition.
226
                (
227
                    verify::header_only::Success::Aura {
228
0
                        authorities_change: Some(new_authorities_list),
229
0
                    },
230
0
                    Some(BlockConsensus::Aura { .. }),
231
0
                    FinalizedConsensus::Aura { .. },
232
0
                    _,
233
0
                ) => (
234
0
                    parent_best_score.num_primary_slots + 1,
235
0
                    parent_best_score.num_secondary_slots,
236
0
                    BlockConsensus::Aura {
237
0
                        authorities_list: Arc::new(new_authorities_list),
238
0
                    },
239
0
                ),
240
241
                // No Babe epoch transition. Just a regular block.
242
                (
243
                    verify::header_only::Success::Babe {
244
                        epoch_transition_target: None,
245
2
                        is_primary_slot,
246
2
                        ..
247
2
                    },
248
2
                    Some(BlockConsensus::Babe { .. }),
249
2
                    FinalizedConsensus::Babe { .. },
250
2
                    Some(BlockConsensus::Babe {
251
2
                        current_epoch,
252
2
                        next_epoch,
253
                    }),
254
                )
255
                | (
256
                    verify::header_only::Success::Babe {
257
                        epoch_transition_target: None,
258
0
                        is_primary_slot,
259
0
                        ..
260
0
                    },
261
0
                    Some(BlockConsensus::Babe { .. }),
262
0
                    FinalizedConsensus::Babe {
263
0
                        block_epoch_information: current_epoch,
264
0
                        next_epoch_transition: next_epoch,
265
                        ..
266
                    },
267
                    None,
268
                ) => (
269
2
                    parent_best_score.num_primary_slots + if is_primary_slot { 
11
} else {
01
},
270
2
                    parent_best_score.num_secondary_slots + if is_primary_slot { 
01
} else {
11
},
271
2
                    BlockConsensus::Babe {
272
2
                        current_epoch,
273
2
                        next_epoch,
274
2
                    },
275
                ),
276
277
                // Babe epoch transition.
278
                (
279
                    verify::header_only::Success::Babe {
280
0
                        epoch_transition_target: Some(epoch_transition_target),
281
0
                        is_primary_slot,
282
0
                        ..
283
0
                    },
284
0
                    Some(BlockConsensus::Babe { .. }),
285
0
                    FinalizedConsensus::Babe { .. },
286
0
                    Some(BlockConsensus::Babe {
287
0
                        next_epoch: next_epoch_transition,
288
                        ..
289
                    }),
290
                )
291
                | (
292
                    verify::header_only::Success::Babe {
293
0
                        epoch_transition_target: Some(epoch_transition_target),
294
0
                        is_primary_slot,
295
0
                        ..
296
0
                    },
297
0
                    Some(BlockConsensus::Babe { .. }),
298
0
                    FinalizedConsensus::Babe {
299
0
                        next_epoch_transition,
300
                        ..
301
                    },
302
                    None,
303
2
                ) if next_epoch_transition.start_slot_number.is_some(
)0
=> (
304
0
                    parent_best_score.num_primary_slots + if is_primary_slot { 1 } else { 0 },
305
0
                    parent_best_score.num_secondary_slots + if is_primary_slot { 0 } else { 1 },
306
0
                    BlockConsensus::Babe {
307
0
                        current_epoch: Some(next_epoch_transition),
308
0
                        next_epoch: Arc::new(epoch_transition_target),
309
0
                    },
310
                ),
311
312
                // Babe epoch transition to first epoch.
313
                // Should only ever happen when the verified block is block 1.
314
                (
315
                    verify::header_only::Success::Babe {
316
0
                        epoch_transition_target: Some(epoch_transition_target),
317
0
                        slot_number,
318
0
                        is_primary_slot,
319
0
                        ..
320
0
                    },
321
0
                    Some(BlockConsensus::Babe { .. }),
322
0
                    FinalizedConsensus::Babe { .. },
323
0
                    Some(BlockConsensus::Babe { next_epoch, .. }),
324
                )
325
                | (
326
                    verify::header_only::Success::Babe {
327
2
                        epoch_transition_target: Some(epoch_transition_target),
328
2
                        slot_number,
329
2
                        is_primary_slot,
330
2
                        ..
331
2
                    },
332
2
                    Some(BlockConsensus::Babe { .. }),
333
2
                    FinalizedConsensus::Babe {
334
2
                        next_epoch_transition: next_epoch,
335
                        ..
336
                    },
337
                    None,
338
                ) => {
339
2
                    debug_assert_eq!(decoded_header.number, 1);
340
                    (
341
2
                        parent_best_score.num_primary_slots + if is_primary_slot { 
11
} else {
01
},
342
2
                        parent_best_score.num_secondary_slots + if is_primary_slot { 
01
} else {
11
},
343
2
                        BlockConsensus::Babe {
344
2
                            current_epoch: Some(Arc::new(
345
2
                                chain_information::BabeEpochInformation {
346
2
                                    start_slot_number: Some(slot_number),
347
2
                                    allowed_slots: next_epoch.allowed_slots,
348
2
                                    epoch_index: next_epoch.epoch_index,
349
2
                                    authorities: next_epoch.authorities.clone(),
350
2
                                    c: next_epoch.c,
351
2
                                    randomness: next_epoch.randomness,
352
2
                                },
353
2
                            )),
354
2
                            next_epoch: Arc::new(epoch_transition_target),
355
2
                        },
356
                    )
357
                }
358
359
                // Any mismatch between consensus algorithms should have been detected by the
360
                // block verification.
361
0
                _ => unreachable!(),
362
            };
363
364
        // Updated finality information for the block being verified.
365
4
        let finality_update = match &parent_finality {
366
0
            BlockFinality::Outsourced => BlockFinality::Outsourced,
367
            BlockFinality::Grandpa {
368
4
                prev_auth_change_trigger_number: parent_prev_auth_change_trigger_number,
369
4
                after_block_authorities_set_id: parent_after_block_authorities_set_id,
370
4
                scheduled_change: parent_scheduled_change,
371
4
                triggered_authorities: parent_triggered_authorities,
372
4
                triggers_change: parent_triggers_change,
373
4
                ..
374
4
            } => {
375
4
                let mut triggered_authorities = parent_triggered_authorities.clone();
376
4
                let mut triggers_change = false;
377
4
                let mut scheduled_change = parent_scheduled_change.clone();
378
379
                // Check whether the verified block schedules a change of authorities.
380
10
                for 
grandpa_digest_item0
in
decoded_header.digest.logs().filter_map(4
|d| match d {
381
0
                    header::DigestItemRef::GrandpaConsensus(gp) => Some(gp),
382
10
                    _ => None,
383
10
                }
)4
{
_RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers2_0Ba_
Line
Count
Source
380
10
                for grandpa_digest_item in decoded_header.digest.logs().filter_map(|d| match d {
381
0
                    header::DigestItemRef::GrandpaConsensus(gp) => Some(gp),
382
10
                    _ => None,
383
10
                }) {
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers2_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers2_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers2_0CsibGXYHQB8Ea_25json_rpc_general_requests
384
                    // TODO: implement items other than ScheduledChange
385
                    // TODO: when it comes to forced change, they take precedence over scheduled changes but only sheduled changes within the same block
386
0
                    if let header::GrandpaConsensusLogRef::ScheduledChange(change) =
387
0
                        grandpa_digest_item
388
                    {
389
0
                        let trigger_block_height =
390
0
                            decoded_header.number.checked_add(change.delay).unwrap();
391
0
392
0
                        // It is forbidden to schedule a change while a change is already
393
0
                        // scheduled, otherwise the block is invalid. This is verified during
394
0
                        // the block verification.
395
0
                        match scheduled_change {
396
0
                            Some(_) => {
397
0
                                // Ignore any new change if a change is already in progress.
398
0
                                // Matches the behaviour here: <https://github.com/paritytech/substrate/blob/a357c29ebabb075235977edd5e3901c66575f995/client/finality-grandpa/src/authorities.rs#L479>
399
0
                            }
400
0
                            None => {
401
0
                                scheduled_change = Some((
402
0
                                    trigger_block_height,
403
0
                                    change.next_authorities.map(|a| a.into()).collect(),
Unexecuted instantiation: _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers3_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers3_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers3_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers3_0CsibGXYHQB8Ea_25json_rpc_general_requests
404
0
                                ));
405
0
                            }
406
                        }
407
0
                    }
408
                }
409
410
                // If the newly-verified block is one where Grandpa scheduled change are
411
                // triggered, we need update the field values.
412
                // Note that this is checked after we have potentially fetched `scheduled_change`
413
                // from the block.
414
4
                if let Some((
trigger_height, new_list0
)) = &scheduled_change {
415
0
                    if *trigger_height == decoded_header.number {
416
0
                        triggers_change = true;
417
0
                        triggered_authorities = new_list.clone();
418
0
                        scheduled_change = None;
419
0
                    }
420
4
                }
421
422
                // Some sanity checks.
423
4
                debug_assert!(scheduled_change
424
4
                    .as_ref()
425
4
                    .map(|(n, _)| 
*n > decoded_header.number0
)
Unexecuted instantiation: _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers6_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers6_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers6_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers6_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers6_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers6_0CsibGXYHQB8Ea_25json_rpc_general_requests
426
4
                    .unwrap_or(true));
427
4
                debug_assert!(parent_prev_auth_change_trigger_number
428
4
                    .as_ref()
429
4
                    .map(|n| 
*n < decoded_header.number0
)
Unexecuted instantiation: _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers7_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers7_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers7_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers7_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers7_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers7_0CsibGXYHQB8Ea_25json_rpc_general_requests
430
4
                    .unwrap_or(true));
431
432
                BlockFinality::Grandpa {
433
4
                    prev_auth_change_trigger_number: if *parent_triggers_change {
434
0
                        Some(decoded_header.number - 1)
435
                    } else {
436
4
                        *parent_prev_auth_change_trigger_number
437
                    },
438
4
                    triggered_authorities,
439
4
                    scheduled_change,
440
4
                    triggers_change,
441
4
                    after_block_authorities_set_id: if triggers_change {
442
0
                        *parent_after_block_authorities_set_id + 1
443
                    } else {
444
4
                        *parent_after_block_authorities_set_id
445
                    },
446
                }
447
            }
448
        };
449
450
        // Determine whether this block would be the new best.
451
4
        let is_new_best = {
452
4
            let current_best_score = self
453
4
                .blocks_by_best_score
454
4
                .last_key_value()
455
4
                .map(|(s, _)| 
s2
)
_RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeuE13verify_headers4_0Ba_
Line
Count
Source
455
2
                .map(|(s, _)| s)
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headers4_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreepE13verify_headers4_0Ba_
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers4_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers4_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB6_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headers4_0CsibGXYHQB8Ea_25json_rpc_general_requests
456
4
                .unwrap_or(&self.finalized_best_score);
457
4
458
4
            let new_block_best_score = BestScore {
459
4
                num_primary_slots: best_score_num_primary_slots,
460
4
                num_secondary_slots: best_score_num_secondary_slots,
461
4
                insertion_counter: self.blocks_insertion_counter,
462
4
            };
463
4
464
4
            debug_assert_ne!(new_block_best_score, *current_best_score);
465
4
            new_block_best_score > *current_best_score
466
4
        };
467
4
468
4
        Ok(HeaderVerifySuccess::Verified {
469
4
            verified_header: VerifiedHeader {
470
4
                number: decoded_header.number,
471
4
                scale_encoded_header,
472
4
                consensus_update,
473
4
                finality_update,
474
4
                best_score_num_primary_slots,
475
4
                best_score_num_secondary_slots,
476
4
                hash,
477
4
            },
478
4
            is_new_best,
479
4
        })
480
4
    }
_RNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeuE13verify_headerB8_
Line
Count
Source
40
4
    pub fn verify_header(
41
4
        &self,
42
4
        scale_encoded_header: Vec<u8>,
43
4
        now_from_unix_epoch: Duration,
44
4
    ) -> Result<HeaderVerifySuccess, HeaderVerifyError> {
45
4
        let decoded_header = match header::decode(&scale_encoded_header, self.block_number_bytes) {
46
4
            Ok(h) => h,
47
0
            Err(err) => return Err(HeaderVerifyError::InvalidHeader(err)),
48
        };
49
50
4
        let hash = header::hash_from_scale_encoded_header(&scale_encoded_header);
51
4
52
4
        // Check for duplicates.
53
4
        if self.blocks_by_hash.contains_key(&hash) {
54
0
            return Ok(HeaderVerifySuccess::Duplicate);
55
4
        }
56
57
        // Try to find the parent block in the tree of known blocks.
58
        // `Some` with an index of the parent within the tree of unfinalized blocks.
59
        // `None` means that the parent is the finalized block.
60
4
        let parent_tree_index = {
61
4
            if *decoded_header.parent_hash == self.finalized_block_hash {
62
2
                None
63
            } else {
64
2
                match self.blocks_by_hash.get(decoded_header.parent_hash) {
65
2
                    Some(parent) => Some(*parent),
66
                    None => {
67
0
                        let parent_hash = *decoded_header.parent_hash;
68
0
                        return Err(HeaderVerifyError::BadParent { parent_hash });
69
                    }
70
                }
71
            }
72
        };
73
74
        // Some consensus-specific information must be fetched from the tree of ancestry. The
75
        // information is found either in the parent block, or in the finalized block.
76
4
        let (parent_consensus, parent_best_score, parent_finality) =
77
4
            if let Some(
parent_tree_index2
) = parent_tree_index {
78
2
                let parent = self.blocks.get(parent_tree_index).unwrap();
79
2
                (
80
2
                    Some(parent.consensus.clone()),
81
2
                    parent.best_score,
82
2
                    parent.finality.clone(),
83
2
                )
84
            } else {
85
2
                let consensus = match &self.finalized_consensus {
86
0
                    FinalizedConsensus::Unknown => None,
87
                    FinalizedConsensus::Aura {
88
0
                        authorities_list, ..
89
0
                    } => Some(BlockConsensus::Aura {
90
0
                        authorities_list: authorities_list.clone(),
91
0
                    }),
92
                    FinalizedConsensus::Babe {
93
2
                        block_epoch_information,
94
2
                        next_epoch_transition,
95
2
                        ..
96
2
                    } => Some(BlockConsensus::Babe {
97
2
                        current_epoch: block_epoch_information.clone(),
98
2
                        next_epoch: next_epoch_transition.clone(),
99
2
                    }),
100
                };
101
102
2
                let finality = match self.finality {
103
0
                    Finality::Outsourced => BlockFinality::Outsourced,
104
                    Finality::Grandpa {
105
2
                        after_finalized_block_authorities_set_id,
106
2
                        ref finalized_scheduled_change,
107
2
                        ref finalized_triggered_authorities,
108
2
                    } => {
109
2
                        debug_assert!(finalized_scheduled_change
110
2
                            .as_ref()
111
2
                            .map(|(n, _)| *n >= decoded_header.number)
112
2
                            .unwrap_or(true));
113
2
                        BlockFinality::Grandpa {
114
2
                            prev_auth_change_trigger_number: None,
115
2
                            triggers_change: false,
116
2
                            scheduled_change: finalized_scheduled_change.clone(),
117
2
                            after_block_authorities_set_id:
118
2
                                after_finalized_block_authorities_set_id,
119
2
                            triggered_authorities: finalized_triggered_authorities.clone(),
120
2
                        }
121
                    }
122
                };
123
124
2
                (consensus, self.finalized_best_score, finality)
125
            };
126
127
4
        let parent_block_header = if let Some(
parent_tree_index2
) = parent_tree_index {
128
2
            &self
129
2
                .blocks
130
2
                .get(parent_tree_index)
131
2
                .unwrap_or_else(|| unreachable!())
132
2
                .header
133
        } else {
134
2
            &self.finalized_block_header
135
        };
136
137
4
        let header_verify_result = {
138
4
            let consensus_config = match (&self.finalized_consensus, &parent_consensus) {
139
                (
140
0
                    FinalizedConsensus::Aura { slot_duration, .. },
141
0
                    Some(BlockConsensus::Aura { authorities_list }),
142
0
                ) => verify::header_only::ConfigConsensus::Aura {
143
0
                    current_authorities: header::AuraAuthoritiesIter::from_slice(authorities_list),
144
0
                    now_from_unix_epoch,
145
0
                    slot_duration: *slot_duration,
146
0
                },
147
                (
148
                    FinalizedConsensus::Babe {
149
4
                        slots_per_epoch, ..
150
4
                    },
151
4
                    Some(BlockConsensus::Babe {
152
4
                        current_epoch,
153
4
                        next_epoch,
154
4
                    }),
155
4
                ) => verify::header_only::ConfigConsensus::Babe {
156
4
                    parent_block_epoch: current_epoch.as_ref().map(|v| (&**v).into()),
157
4
                    parent_block_next_epoch: (&**next_epoch).into(),
158
4
                    slots_per_epoch: *slots_per_epoch,
159
4
                    now_from_unix_epoch,
160
4
                },
161
                (FinalizedConsensus::Unknown, None) => {
162
0
                    return Err(HeaderVerifyError::UnknownConsensusEngine)
163
                }
164
                _ => {
165
0
                    return Err(HeaderVerifyError::ConsensusMismatch);
166
                }
167
            };
168
169
            match verify::header_only::verify(verify::header_only::Config {
170
4
                consensus: consensus_config,
171
4
                finality: match &parent_finality {
172
0
                    BlockFinality::Outsourced => verify::header_only::ConfigFinality::Outsourced,
173
4
                    BlockFinality::Grandpa { .. } => verify::header_only::ConfigFinality::Grandpa,
174
                },
175
4
                allow_unknown_consensus_engines: self.allow_unknown_consensus_engines,
176
4
                block_header: decoded_header.clone(),
177
4
                block_number_bytes: self.block_number_bytes,
178
4
                parent_block_header: {
179
4
                    // All headers inserted in `self` are necessarily valid, and thus this
180
4
                    // `unwrap()` can't panic.
181
4
                    header::decode(parent_block_header, self.block_number_bytes)
182
4
                        .unwrap_or_else(|_| unreachable!())
183
                },
184
            }) {
185
4
                Ok(s) => s,
186
0
                Err(err) => {
187
0
                    // The code in this module is meant to ensure that the chain is in an
188
0
                    // appropriate state, therefore `is_invalid_chain_configuration` being `true`
189
0
                    // would indicate a bug in the code somewhere.
190
0
                    // We use a `debug_assert` rather than `assert` in order to avoid crashing,
191
0
                    // as treating the header as invalid is an appropriate way to handle a bug
192
0
                    // here.
193
0
                    debug_assert!(!err.is_invalid_chain_configuration());
194
0
                    return Err(HeaderVerifyError::VerificationFailed(err));
195
                }
196
            }
197
        };
198
199
        // Updated consensus information for the block being verified.
200
4
        let (best_score_num_primary_slots, best_score_num_secondary_slots, consensus_update) =
201
            match (
202
4
                header_verify_result,
203
4
                &parent_consensus,
204
4
                self.finalized_consensus.clone(),
205
4
                parent_tree_index.map(|idx| self.blocks.get(idx).unwrap().consensus.clone()),
206
            ) {
207
                // No Aura epoch transition. Just a regular block.
208
                (
209
                    verify::header_only::Success::Aura {
210
                        authorities_change: None,
211
                    },
212
                    Some(BlockConsensus::Aura {
213
0
                        authorities_list: parent_authorities,
214
0
                    }),
215
0
                    FinalizedConsensus::Aura { .. },
216
0
                    _,
217
0
                ) => (
218
0
                    parent_best_score.num_primary_slots + 1,
219
0
                    parent_best_score.num_secondary_slots,
220
0
                    BlockConsensus::Aura {
221
0
                        authorities_list: parent_authorities.clone(),
222
0
                    },
223
0
                ),
224
225
                // Aura epoch transition.
226
                (
227
                    verify::header_only::Success::Aura {
228
0
                        authorities_change: Some(new_authorities_list),
229
0
                    },
230
0
                    Some(BlockConsensus::Aura { .. }),
231
0
                    FinalizedConsensus::Aura { .. },
232
0
                    _,
233
0
                ) => (
234
0
                    parent_best_score.num_primary_slots + 1,
235
0
                    parent_best_score.num_secondary_slots,
236
0
                    BlockConsensus::Aura {
237
0
                        authorities_list: Arc::new(new_authorities_list),
238
0
                    },
239
0
                ),
240
241
                // No Babe epoch transition. Just a regular block.
242
                (
243
                    verify::header_only::Success::Babe {
244
                        epoch_transition_target: None,
245
2
                        is_primary_slot,
246
2
                        ..
247
2
                    },
248
2
                    Some(BlockConsensus::Babe { .. }),
249
2
                    FinalizedConsensus::Babe { .. },
250
2
                    Some(BlockConsensus::Babe {
251
2
                        current_epoch,
252
2
                        next_epoch,
253
                    }),
254
                )
255
                | (
256
                    verify::header_only::Success::Babe {
257
                        epoch_transition_target: None,
258
0
                        is_primary_slot,
259
0
                        ..
260
0
                    },
261
0
                    Some(BlockConsensus::Babe { .. }),
262
0
                    FinalizedConsensus::Babe {
263
0
                        block_epoch_information: current_epoch,
264
0
                        next_epoch_transition: next_epoch,
265
                        ..
266
                    },
267
                    None,
268
                ) => (
269
2
                    parent_best_score.num_primary_slots + if is_primary_slot { 
11
} else {
01
},
270
2
                    parent_best_score.num_secondary_slots + if is_primary_slot { 
01
} else {
11
},
271
2
                    BlockConsensus::Babe {
272
2
                        current_epoch,
273
2
                        next_epoch,
274
2
                    },
275
                ),
276
277
                // Babe epoch transition.
278
                (
279
                    verify::header_only::Success::Babe {
280
0
                        epoch_transition_target: Some(epoch_transition_target),
281
0
                        is_primary_slot,
282
0
                        ..
283
0
                    },
284
0
                    Some(BlockConsensus::Babe { .. }),
285
0
                    FinalizedConsensus::Babe { .. },
286
0
                    Some(BlockConsensus::Babe {
287
0
                        next_epoch: next_epoch_transition,
288
                        ..
289
                    }),
290
                )
291
                | (
292
                    verify::header_only::Success::Babe {
293
0
                        epoch_transition_target: Some(epoch_transition_target),
294
0
                        is_primary_slot,
295
0
                        ..
296
0
                    },
297
0
                    Some(BlockConsensus::Babe { .. }),
298
0
                    FinalizedConsensus::Babe {
299
0
                        next_epoch_transition,
300
                        ..
301
                    },
302
                    None,
303
2
                ) if next_epoch_transition.start_slot_number.is_some(
)0
=> (
304
0
                    parent_best_score.num_primary_slots + if is_primary_slot { 1 } else { 0 },
305
0
                    parent_best_score.num_secondary_slots + if is_primary_slot { 0 } else { 1 },
306
0
                    BlockConsensus::Babe {
307
0
                        current_epoch: Some(next_epoch_transition),
308
0
                        next_epoch: Arc::new(epoch_transition_target),
309
0
                    },
310
                ),
311
312
                // Babe epoch transition to first epoch.
313
                // Should only ever happen when the verified block is block 1.
314
                (
315
                    verify::header_only::Success::Babe {
316
0
                        epoch_transition_target: Some(epoch_transition_target),
317
0
                        slot_number,
318
0
                        is_primary_slot,
319
0
                        ..
320
0
                    },
321
0
                    Some(BlockConsensus::Babe { .. }),
322
0
                    FinalizedConsensus::Babe { .. },
323
0
                    Some(BlockConsensus::Babe { next_epoch, .. }),
324
                )
325
                | (
326
                    verify::header_only::Success::Babe {
327
2
                        epoch_transition_target: Some(epoch_transition_target),
328
2
                        slot_number,
329
2
                        is_primary_slot,
330
2
                        ..
331
2
                    },
332
2
                    Some(BlockConsensus::Babe { .. }),
333
2
                    FinalizedConsensus::Babe {
334
2
                        next_epoch_transition: next_epoch,
335
                        ..
336
                    },
337
                    None,
338
                ) => {
339
2
                    debug_assert_eq!(decoded_header.number, 1);
340
                    (
341
2
                        parent_best_score.num_primary_slots + if is_primary_slot { 
11
} else {
01
},
342
2
                        parent_best_score.num_secondary_slots + if is_primary_slot { 
01
} else {
11
},
343
2
                        BlockConsensus::Babe {
344
2
                            current_epoch: Some(Arc::new(
345
2
                                chain_information::BabeEpochInformation {
346
2
                                    start_slot_number: Some(slot_number),
347
2
                                    allowed_slots: next_epoch.allowed_slots,
348
2
                                    epoch_index: next_epoch.epoch_index,
349
2
                                    authorities: next_epoch.authorities.clone(),
350
2
                                    c: next_epoch.c,
351
2
                                    randomness: next_epoch.randomness,
352
2
                                },
353
2
                            )),
354
2
                            next_epoch: Arc::new(epoch_transition_target),
355
2
                        },
356
                    )
357
                }
358
359
                // Any mismatch between consensus algorithms should have been detected by the
360
                // block verification.
361
0
                _ => unreachable!(),
362
            };
363
364
        // Updated finality information for the block being verified.
365
4
        let finality_update = match &parent_finality {
366
0
            BlockFinality::Outsourced => BlockFinality::Outsourced,
367
            BlockFinality::Grandpa {
368
4
                prev_auth_change_trigger_number: parent_prev_auth_change_trigger_number,
369
4
                after_block_authorities_set_id: parent_after_block_authorities_set_id,
370
4
                scheduled_change: parent_scheduled_change,
371
4
                triggered_authorities: parent_triggered_authorities,
372
4
                triggers_change: parent_triggers_change,
373
4
                ..
374
4
            } => {
375
4
                let mut triggered_authorities = parent_triggered_authorities.clone();
376
4
                let mut triggers_change = false;
377
4
                let mut scheduled_change = parent_scheduled_change.clone();
378
379
                // Check whether the verified block schedules a change of authorities.
380
4
                for 
grandpa_digest_item0
in decoded_header.digest.logs().filter_map(|d| match d {
381
                    header::DigestItemRef::GrandpaConsensus(gp) => Some(gp),
382
                    _ => None,
383
4
                }) {
384
                    // TODO: implement items other than ScheduledChange
385
                    // TODO: when it comes to forced change, they take precedence over scheduled changes but only sheduled changes within the same block
386
0
                    if let header::GrandpaConsensusLogRef::ScheduledChange(change) =
387
0
                        grandpa_digest_item
388
                    {
389
0
                        let trigger_block_height =
390
0
                            decoded_header.number.checked_add(change.delay).unwrap();
391
0
392
0
                        // It is forbidden to schedule a change while a change is already
393
0
                        // scheduled, otherwise the block is invalid. This is verified during
394
0
                        // the block verification.
395
0
                        match scheduled_change {
396
0
                            Some(_) => {
397
0
                                // Ignore any new change if a change is already in progress.
398
0
                                // Matches the behaviour here: <https://github.com/paritytech/substrate/blob/a357c29ebabb075235977edd5e3901c66575f995/client/finality-grandpa/src/authorities.rs#L479>
399
0
                            }
400
0
                            None => {
401
0
                                scheduled_change = Some((
402
0
                                    trigger_block_height,
403
0
                                    change.next_authorities.map(|a| a.into()).collect(),
404
0
                                ));
405
0
                            }
406
                        }
407
0
                    }
408
                }
409
410
                // If the newly-verified block is one where Grandpa scheduled change are
411
                // triggered, we need update the field values.
412
                // Note that this is checked after we have potentially fetched `scheduled_change`
413
                // from the block.
414
4
                if let Some((
trigger_height, new_list0
)) = &scheduled_change {
415
0
                    if *trigger_height == decoded_header.number {
416
0
                        triggers_change = true;
417
0
                        triggered_authorities = new_list.clone();
418
0
                        scheduled_change = None;
419
0
                    }
420
4
                }
421
422
                // Some sanity checks.
423
4
                debug_assert!(scheduled_change
424
4
                    .as_ref()
425
4
                    .map(|(n, _)| *n > decoded_header.number)
426
4
                    .unwrap_or(true));
427
4
                debug_assert!(parent_prev_auth_change_trigger_number
428
4
                    .as_ref()
429
4
                    .map(|n| *n < decoded_header.number)
430
4
                    .unwrap_or(true));
431
432
                BlockFinality::Grandpa {
433
4
                    prev_auth_change_trigger_number: if *parent_triggers_change {
434
0
                        Some(decoded_header.number - 1)
435
                    } else {
436
4
                        *parent_prev_auth_change_trigger_number
437
                    },
438
4
                    triggered_authorities,
439
4
                    scheduled_change,
440
4
                    triggers_change,
441
4
                    after_block_authorities_set_id: if triggers_change {
442
0
                        *parent_after_block_authorities_set_id + 1
443
                    } else {
444
4
                        *parent_after_block_authorities_set_id
445
                    },
446
                }
447
            }
448
        };
449
450
        // Determine whether this block would be the new best.
451
4
        let is_new_best = {
452
4
            let current_best_score = self
453
4
                .blocks_by_best_score
454
4
                .last_key_value()
455
4
                .map(|(s, _)| s)
456
4
                .unwrap_or(&self.finalized_best_score);
457
4
458
4
            let new_block_best_score = BestScore {
459
4
                num_primary_slots: best_score_num_primary_slots,
460
4
                num_secondary_slots: best_score_num_secondary_slots,
461
4
                insertion_counter: self.blocks_insertion_counter,
462
4
            };
463
4
464
4
            debug_assert_ne!(new_block_best_score, *current_best_score);
465
4
            new_block_best_score > *current_best_score
466
4
        };
467
4
468
4
        Ok(HeaderVerifySuccess::Verified {
469
4
            verified_header: VerifiedHeader {
470
4
                number: decoded_header.number,
471
4
                scale_encoded_header,
472
4
                consensus_update,
473
4
                finality_update,
474
4
                best_score_num_primary_slots,
475
4
                best_score_num_secondary_slots,
476
4
                hash,
477
4
            },
478
4
            is_new_best,
479
4
        })
480
4
    }
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE13verify_headerCsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreepE13verify_headerB8_
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headerCsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headerCscDgN54JpMGG_6author
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE13verify_headerCsibGXYHQB8Ea_25json_rpc_general_requests
481
482
    /// Insert a header that has already been verified to be valid.
483
    ///
484
    /// # Panic
485
    ///
486
    /// Panics if the parent of the block isn't in the tree. The presence of the parent is verified
487
    /// when the block is verified, so this can only happen if you remove the parent after having
488
    /// verified the block but before calling this function.
489
    ///
490
4
    pub fn insert_verified_header(&mut self, verified_header: VerifiedHeader, user_data: T) {
491
        // Try to find the parent block in the tree of known blocks.
492
        // `Some` with an index of the parent within the tree of unfinalized blocks.
493
        // `None` means that the parent is the finalized block.
494
4
        let parent_tree_index = {
495
4
            let decoded_header = header::decode(
496
4
                &verified_header.scale_encoded_header,
497
4
                self.block_number_bytes,
498
4
            )
499
4
            .unwrap();
500
4
501
4
            if *decoded_header.parent_hash == self.finalized_block_hash {
502
2
                None
503
            } else {
504
2
                Some(*self.blocks_by_hash.get(decoded_header.parent_hash).unwrap())
505
            }
506
        };
507
508
4
        let best_score = BestScore {
509
4
            num_primary_slots: verified_header.best_score_num_primary_slots,
510
4
            num_secondary_slots: verified_header.best_score_num_secondary_slots,
511
4
            insertion_counter: self.blocks_insertion_counter,
512
4
        };
513
514
4
        let prev_auth_change_trigger_number_if_trigger = if let BlockFinality::Grandpa {
515
0
            prev_auth_change_trigger_number,
516
            triggers_change: true,
517
            ..
518
4
        } = verified_header.finality_update
519
        {
520
0
            Some(prev_auth_change_trigger_number)
521
        } else {
522
4
            None
523
        };
524
525
4
        let new_node_index = self.blocks.insert(
526
4
            parent_tree_index,
527
4
            Block {
528
4
                header: verified_header.scale_encoded_header,
529
4
                hash: verified_header.hash,
530
4
                number: verified_header.number,
531
4
                consensus: verified_header.consensus_update,
532
4
                finality: verified_header.finality_update,
533
4
                best_score,
534
4
                user_data,
535
4
            },
536
4
        );
537
4
538
4
        let _prev_value = self
539
4
            .blocks_by_hash
540
4
            .insert(verified_header.hash, new_node_index);
541
4
        // A bug here would be serious enough that it is worth being an `assert!`
542
4
        assert!(_prev_value.is_none());
543
544
4
        self.blocks_by_best_score.insert(best_score, new_node_index);
545
546
4
        if let Some(
prev_auth_change_trigger_number0
) = prev_auth_change_trigger_number_if_trigger {
547
0
            self.blocks_trigger_gp_change
548
0
                .insert((prev_auth_change_trigger_number, new_node_index));
549
4
        }
550
551
        // An overflow here would break the logic of the module. It is better to panic than to
552
        // continue running.
553
4
        self.blocks_insertion_counter = self.blocks_insertion_counter.checked_add(1).unwrap();
554
4
    }
_RNvMNtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeuE22insert_verified_headerB8_
Line
Count
Source
490
4
    pub fn insert_verified_header(&mut self, verified_header: VerifiedHeader, user_data: T) {
491
        // Try to find the parent block in the tree of known blocks.
492
        // `Some` with an index of the parent within the tree of unfinalized blocks.
493
        // `None` means that the parent is the finalized block.
494
4
        let parent_tree_index = {
495
4
            let decoded_header = header::decode(
496
4
                &verified_header.scale_encoded_header,
497
4
                self.block_number_bytes,
498
4
            )
499
4
            .unwrap();
500
4
501
4
            if *decoded_header.parent_hash == self.finalized_block_hash {
502
2
                None
503
            } else {
504
2
                Some(*self.blocks_by_hash.get(decoded_header.parent_hash).unwrap())
505
            }
506
        };
507
508
4
        let best_score = BestScore {
509
4
            num_primary_slots: verified_header.best_score_num_primary_slots,
510
4
            num_secondary_slots: verified_header.best_score_num_secondary_slots,
511
4
            insertion_counter: self.blocks_insertion_counter,
512
4
        };
513
514
4
        let prev_auth_change_trigger_number_if_trigger = if let BlockFinality::Grandpa {
515
0
            prev_auth_change_trigger_number,
516
            triggers_change: true,
517
            ..
518
4
        } = verified_header.finality_update
519
        {
520
0
            Some(prev_auth_change_trigger_number)
521
        } else {
522
4
            None
523
        };
524
525
4
        let new_node_index = self.blocks.insert(
526
4
            parent_tree_index,
527
4
            Block {
528
4
                header: verified_header.scale_encoded_header,
529
4
                hash: verified_header.hash,
530
4
                number: verified_header.number,
531
4
                consensus: verified_header.consensus_update,
532
4
                finality: verified_header.finality_update,
533
4
                best_score,
534
4
                user_data,
535
4
            },
536
4
        );
537
4
538
4
        let _prev_value = self
539
4
            .blocks_by_hash
540
4
            .insert(verified_header.hash, new_node_index);
541
4
        // A bug here would be serious enough that it is worth being an `assert!`
542
4
        assert!(_prev_value.is_none());
543
544
4
        self.blocks_by_best_score.insert(best_score, new_node_index);
545
546
4
        if let Some(
prev_auth_change_trigger_number0
) = prev_auth_change_trigger_number_if_trigger {
547
0
            self.blocks_trigger_gp_change
548
0
                .insert((prev_auth_change_trigger_number, new_node_index));
549
4
        }
550
551
        // An overflow here would break the logic of the module. It is better to panic than to
552
        // continue running.
553
4
        self.blocks_insertion_counter = self.blocks_insertion_counter.checked_add(1).unwrap();
554
4
    }
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionuEE22insert_verified_headerCsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreepE22insert_verified_headerB8_
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE22insert_verified_headerCsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE22insert_verified_headerCscDgN54JpMGG_6author
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyINtB4_16NonFinalizedTreeINtNtCsaYZPK01V26L_4core6option6OptionNtNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service17NonFinalizedBlockEE22insert_verified_headerCsibGXYHQB8Ea_25json_rpc_general_requests
555
}
556
557
/// Successfully-verified block header that can be inserted into the chain.
558
pub struct VerifiedHeader {
559
    scale_encoded_header: Vec<u8>,
560
    consensus_update: BlockConsensus,
561
    finality_update: BlockFinality,
562
    best_score_num_primary_slots: u64,
563
    best_score_num_secondary_slots: u64,
564
    hash: [u8; 32],
565
    number: u64,
566
}
567
568
impl VerifiedHeader {
569
    /// Returns the block header.
570
0
    pub fn scale_encoded_header(&self) -> &[u8] {
571
0
        &self.scale_encoded_header
572
0
    }
Unexecuted instantiation: _RNvMs_NtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyNtB4_14VerifiedHeader20scale_encoded_header
Unexecuted instantiation: _RNvMs_NtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyNtB4_14VerifiedHeader20scale_encoded_header
573
574
    /// Returns the block header.
575
0
    pub fn into_scale_encoded_header(self) -> Vec<u8> {
576
0
        self.scale_encoded_header
577
0
    }
Unexecuted instantiation: _RNvMs_NtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyNtB4_14VerifiedHeader25into_scale_encoded_header
Unexecuted instantiation: _RNvMs_NtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyNtB4_14VerifiedHeader25into_scale_encoded_header
578
}
579
580
impl fmt::Debug for VerifiedHeader {
581
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
582
0
        f.debug_tuple("VerifiedHeader")
583
0
            .field(&hex::encode(&self.scale_encoded_header))
584
0
            .finish()
585
0
    }
Unexecuted instantiation: _RNvXs0_NtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyNtB5_14VerifiedHeaderNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs0_NtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyNtB5_14VerifiedHeaderNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt
586
}
587
588
/// See [`NonFinalizedTree::verify_header`].
589
#[derive(Debug)]
590
pub enum HeaderVerifySuccess {
591
    /// Block is already known.
592
    Duplicate,
593
    /// Block wasn't known and has been successfully verified.
594
    Verified {
595
        /// Header that has been verified. Can be passed to
596
        /// [`NonFinalizedTree::insert_verified_header`].
597
        verified_header: VerifiedHeader,
598
        /// True if the verified block will become the new "best" block after being inserted.
599
        is_new_best: bool,
600
    },
601
}
602
603
/// Error that can happen when verifying a block header.
604
// TODO: some of these errors are redundant with verify::header_only::Error
605
0
#[derive(Debug, derive_more::Display)]
Unexecuted instantiation: _RNvXs3_NtNtNtCsN16ciHI6Qf_7smoldot5chain11blocks_tree6verifyNtB5_17HeaderVerifyErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs3_NtNtNtCseuYC0Zibziv_7smoldot5chain11blocks_tree6verifyNtB5_17HeaderVerifyErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
606
pub enum HeaderVerifyError {
607
    /// Error while decoding the header.
608
    #[display(fmt = "Error while decoding the header: {_0}")]
609
    InvalidHeader(header::Error),
610
    /// Block can't be verified as it uses an unknown consensus engine.
611
    UnknownConsensusEngine,
612
    /// Block uses a different consensus than the rest of the chain.
613
    ConsensusMismatch,
614
    /// The parent of the block isn't known.
615
    #[display(fmt = "The parent of the block isn't known.")]
616
    BadParent {
617
        /// Hash of the parent block in question.
618
        parent_hash: [u8; 32],
619
    },
620
    /// The block verification has failed. The block is invalid and should be thrown away.
621
    #[display(fmt = "{_0}")]
622
    VerificationFailed(verify::header_only::Error),
623
}