Coverage Report

Created: 2024-05-16 12:16

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