/__w/smoldot/smoldot/repo/lib/src/verify/body_only.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 | | //! Verifying a block body. This operation is also called executing a block. |
19 | | //! |
20 | | //! In order to execute a block, one must perform two runtime calls, to |
21 | | //! [`CHECK_INHERENTS_FUNCTION_NAME`] and to [`EXECUTE_BLOCK_FUNCTION_NAME`] (in that order). |
22 | | //! |
23 | | //! The parameter to pass for these runtime calls can be determined using |
24 | | //! [`check_inherents_parameter`] and [`execute_block_parameter`]. When execution succeeds, |
25 | | //! the output of the runtime call must be checked using [`check_check_inherents_output`] |
26 | | //! and [`check_execute_block_output`]. |
27 | | //! The storage changes must be preserved between the two calls. |
28 | | //! |
29 | | //! Any error during the execution or the output verification means that the block is invalid. |
30 | | |
31 | | use crate::{header, util, verify::inherents}; |
32 | | |
33 | | use alloc::vec::Vec; |
34 | | use core::{iter, time::Duration}; |
35 | | |
36 | | pub const EXECUTE_BLOCK_FUNCTION_NAME: &'static str = "Core_execute_block"; |
37 | | |
38 | | /// Returns a list of buffers that, when concatenated together, forms the parameter to pass to |
39 | | /// the `Core_execute_block` function in order to verify the inherents of a block. |
40 | 0 | pub fn execute_block_parameter<'a>( |
41 | 0 | block_header: &'a [u8], |
42 | 0 | block_number_bytes: usize, |
43 | 0 | block_body: impl ExactSizeIterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a, |
44 | 0 | ) -> Result< |
45 | 0 | impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a, |
46 | 0 | ExecuteBlockParameterError, |
47 | 0 | > { |
48 | | // Consensus engines add a seal at the end of the digest logs. This seal is guaranteed to |
49 | | // be the last item. We need to remove it before we can verify the unsealed header. |
50 | 0 | let mut unsealed_header = match header::decode(block_header, block_number_bytes) { |
51 | 0 | Ok(h) => h, |
52 | 0 | Err(err) => return Err(ExecuteBlockParameterError::InvalidHeader(err)), |
53 | | }; |
54 | 0 | let _seal_log = unsealed_header.digest.pop_seal(); |
55 | 0 |
|
56 | 0 | let encoded_body_len = util::encode_scale_compact_usize(block_body.len()); |
57 | 0 | Ok(unsealed_header |
58 | 0 | .scale_encoding(block_number_bytes) |
59 | 0 | .map(|b| either::Right(either::Left(b))) Unexecuted instantiation: _RNCINvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only23execute_block_parameterppE0B8_ Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only23execute_block_parameterppE0B8_ Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only23execute_block_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1b_EE0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only23execute_block_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1b_EE0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only23execute_block_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1b_EE0CsibGXYHQB8Ea_25json_rpc_general_requests |
60 | 0 | .chain(iter::once(either::Right(either::Right(encoded_body_len)))) |
61 | 0 | .chain(block_body.map(either::Left))) |
62 | 0 | } Unexecuted instantiation: _RINvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only23execute_block_parameterppEB6_ Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only23execute_block_parameterppEB6_ Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only23execute_block_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB19_EECsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only23execute_block_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB19_EECscDgN54JpMGG_6author Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only23execute_block_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB19_EECsibGXYHQB8Ea_25json_rpc_general_requests |
63 | | |
64 | | /// Error potentially returned by [`execute_block_parameter`]. |
65 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs_NtNtCsN16ciHI6Qf_7smoldot6verify9body_onlyNtB4_26ExecuteBlockParameterErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs_NtNtCseuYC0Zibziv_7smoldot6verify9body_onlyNtB4_26ExecuteBlockParameterErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
66 | | pub enum ExecuteBlockParameterError { |
67 | | /// Header provided as parameter is invalid. |
68 | | InvalidHeader(header::Error), |
69 | | } |
70 | | |
71 | | /// Checks the output of the `Core_execute_block` runtime call. |
72 | 0 | pub fn check_execute_block_output(output: &[u8]) -> Result<(), ExecuteBlockOutputError> { |
73 | 0 | if !output.is_empty() { |
74 | 0 | return Err(ExecuteBlockOutputError::NotEmpty); |
75 | 0 | } |
76 | 0 |
|
77 | 0 | Ok(()) |
78 | 0 | } Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only26check_execute_block_output Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6verify9body_only26check_execute_block_output |
79 | | |
80 | | /// Error potentially returned by [`check_execute_block_output`]. |
81 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs1_NtNtCsN16ciHI6Qf_7smoldot6verify9body_onlyNtB5_23ExecuteBlockOutputErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs1_NtNtCseuYC0Zibziv_7smoldot6verify9body_onlyNtB5_23ExecuteBlockOutputErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
82 | | pub enum ExecuteBlockOutputError { |
83 | | /// The output is not empty. |
84 | | NotEmpty, |
85 | | } |
86 | | |
87 | | pub const CHECK_INHERENTS_FUNCTION_NAME: &'static str = "BlockBuilder_check_inherents"; |
88 | | |
89 | | /// Returns a list of buffers that, when concatenated together, forms the parameter to pass to |
90 | | /// the `BlockBuilder_check_inherents` function in order to verify the inherents of a block. |
91 | 0 | pub fn check_inherents_parameter<'a>( |
92 | 0 | block_header: &'a [u8], |
93 | 0 | block_number_bytes: usize, |
94 | 0 | block_body: impl ExactSizeIterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a, |
95 | 0 | now_from_unix_epoch: Duration, |
96 | 0 | ) -> Result< |
97 | 0 | impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a, |
98 | 0 | ExecuteBlockParameterError, |
99 | 0 | > { |
100 | | // The first parameter of `BlockBuilder_check_inherents` is identical to the one of |
101 | | // `Core_execute_block`. |
102 | 0 | let execute_block_parameter = |
103 | 0 | execute_block_parameter(block_header, block_number_bytes, block_body)?; |
104 | | |
105 | | // The second parameter of `BlockBuilder_check_inherents` is a SCALE-encoded list of |
106 | | // tuples containing an "inherent identifier" (`[u8; 8]`) and a value (`Vec<u8>`). |
107 | 0 | let inherent_data = inherents::InherentData { |
108 | 0 | timestamp: u64::try_from(now_from_unix_epoch.as_millis()).unwrap_or(u64::MAX), |
109 | 0 | }; |
110 | 0 | let list = inherent_data.into_raw_list(); |
111 | 0 | let len = util::encode_scale_compact_usize(list.len()); |
112 | 0 | let encoded_list = list.flat_map(|(id, value)| { |
113 | 0 | let value_len = util::encode_scale_compact_usize(value.as_ref().len()); |
114 | 0 | let value_and_len = iter::once(value_len) |
115 | 0 | .map(either::Left) |
116 | 0 | .chain(iter::once(value).map(either::Right)); |
117 | 0 | iter::once(id) |
118 | 0 | .map(either::Left) |
119 | 0 | .chain(value_and_len.map(either::Right)) |
120 | 0 | }); Unexecuted instantiation: _RNCINvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only25check_inherents_parameterppE0B8_ Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterppE0B8_ Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1d_EE0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1d_EE0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1d_EE0CsibGXYHQB8Ea_25json_rpc_general_requests |
121 | 0 |
|
122 | 0 | Ok([ |
123 | 0 | either::Left(execute_block_parameter.map(either::Left)), |
124 | 0 | either::Right(either::Left(iter::once(either::Right(either::Left(len))))), |
125 | 0 | either::Right(either::Right( |
126 | 0 | encoded_list.map(either::Right).map(either::Right), |
127 | 0 | )), |
128 | 0 | ] |
129 | 0 | .into_iter() |
130 | 0 | .flat_map(|i| i)) Unexecuted instantiation: _RNCINvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only25check_inherents_parameterppEs_0B8_ Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterppEs_0B8_ Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1d_EEs_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1d_EEs_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1d_EEs_0CsibGXYHQB8Ea_25json_rpc_general_requests |
131 | 0 | } Unexecuted instantiation: _RINvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only25check_inherents_parameterppEB6_ Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterppEB6_ Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1b_EECsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1b_EECscDgN54JpMGG_6author Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot6verify9body_only25check_inherents_parameterRINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtCsaYZPK01V26L_4core5slice4iter4IterB1b_EECsibGXYHQB8Ea_25json_rpc_general_requests |
132 | | |
133 | | /// Checks the output of the `BlockBuilder_check_inherents` runtime call. |
134 | 0 | pub fn check_check_inherents_output(output: &[u8]) -> Result<(), InherentsOutputError> { |
135 | 0 | // The format of the output of `check_inherents` consists of two booleans and a list of |
136 | 0 | // errors. |
137 | 0 | // We don't care about the value of the two booleans, and they are ignored during the parsing. |
138 | 0 | // Because we don't pass as parameter the `auraslot` or `babeslot`, errors will be generated |
139 | 0 | // on older runtimes that expect these values. For this reason, errors concerning `auraslot` |
140 | 0 | // and `babeslot` are ignored. |
141 | 0 | let parser = nom::sequence::preceded( |
142 | 0 | nom::sequence::tuple((crate::util::nom_bool_decode, crate::util::nom_bool_decode)), |
143 | 0 | nom::combinator::flat_map(crate::util::nom_scale_compact_usize, |num_elems| { |
144 | 0 | nom::multi::fold_many_m_n( |
145 | 0 | num_elems, |
146 | 0 | num_elems, |
147 | 0 | nom::sequence::tuple(( |
148 | 0 | nom::combinator::map(nom::bytes::streaming::take(8u8), |b| { |
149 | 0 | <[u8; 8]>::try_from(b).unwrap() |
150 | 0 | }), Unexecuted instantiation: _RNCNCNvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only28check_check_inherents_output00B9_ Unexecuted instantiation: _RNCNCNvNtNtCseuYC0Zibziv_7smoldot6verify9body_only28check_check_inherents_output00B9_ |
151 | 0 | crate::util::nom_bytes_decode, |
152 | 0 | )), |
153 | 0 | Vec::new, |
154 | 0 | |mut errors, (module, error)| { |
155 | 0 | if module != *b"auraslot" && module != *b"babeslot" { |
156 | 0 | errors.push((module, error.to_vec())); |
157 | 0 | } |
158 | 0 | errors |
159 | 0 | }, Unexecuted instantiation: _RNCNCNvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only28check_check_inherents_output0s_0B9_ Unexecuted instantiation: _RNCNCNvNtNtCseuYC0Zibziv_7smoldot6verify9body_only28check_check_inherents_output0s_0B9_ |
160 | 0 | ) |
161 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only28check_check_inherents_output0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6verify9body_only28check_check_inherents_output0B7_ |
162 | 0 | ); |
163 | 0 |
|
164 | 0 | match nom::combinator::all_consuming::<_, _, nom::error::Error<&[u8]>, _>(parser)(output) { |
165 | 0 | Err(_err) => Err(InherentsOutputError::ParseFailure), |
166 | 0 | Ok((_, errors)) => { |
167 | 0 | if errors.is_empty() { |
168 | 0 | Ok(()) |
169 | | } else { |
170 | 0 | Err(InherentsOutputError::Error { errors }) |
171 | | } |
172 | | } |
173 | | } |
174 | 0 | } Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot6verify9body_only28check_check_inherents_output Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6verify9body_only28check_check_inherents_output |
175 | | |
176 | | /// Error potentially returned by [`check_check_inherents_output`]. |
177 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs3_NtNtCsN16ciHI6Qf_7smoldot6verify9body_onlyNtB5_20InherentsOutputErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs3_NtNtCseuYC0Zibziv_7smoldot6verify9body_onlyNtB5_20InherentsOutputErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
178 | | pub enum InherentsOutputError { |
179 | | /// Runtime has returned some errors. |
180 | | #[display(fmt = "Runtime has returned some errors when verifying inherents: {errors:?}")] |
181 | | Error { |
182 | | /// List of errors produced by the runtime. |
183 | | /// |
184 | | /// The first element of each tuple is an identifier of the module that produced the |
185 | | /// error, while the second element is a SCALE-encoded piece of data. |
186 | | /// |
187 | | /// Due to the fact that errors are not supposed to happen, and that the format of errors |
188 | | /// has changed depending on runtime versions, no utility is provided to decode them. |
189 | | errors: Vec<([u8; 8], Vec<u8>)>, |
190 | | }, |
191 | | /// Failed to parse the output. |
192 | | ParseFailure, |
193 | | } |