/__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 | | } |