Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/network/codec/storage_call_proof.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
use crate::util::protobuf;
19
20
use alloc::{borrow::Cow, vec::Vec};
21
22
/// Description of a storage proof request that can be sent to a peer.
23
#[derive(Debug, Clone, PartialEq, Eq)]
24
pub struct StorageProofRequestConfig<TKeysIter> {
25
    /// Hash of the block to request the storage of.
26
    pub block_hash: [u8; 32],
27
    /// List of storage keys to query.
28
    pub keys: TKeysIter,
29
}
30
31
// See https://github.com/paritytech/substrate/blob/c8653447fc8ef8d95a92fe164c96dffb37919e85/client/network/sync/src/schema/api.v1.proto
32
// for protocol definition.
33
34
/// Builds the bytes corresponding to a storage proof request.
35
0
pub fn build_storage_proof_request<'a>(
36
0
    config: StorageProofRequestConfig<impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + 'a>,
37
0
) -> impl Iterator<Item = impl AsRef<[u8]> + 'a> + 'a {
38
0
    protobuf::message_tag_encode(
39
0
        2,
40
0
        protobuf::bytes_tag_encode(2, config.block_hash)
41
0
            .map(either::Left)
42
0
            .chain(
43
0
                config
44
0
                    .keys
45
0
                    .flat_map(|key| protobuf::bytes_tag_encode(3, key))
Unexecuted instantiation: _RNCINvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proof27build_storage_proof_requestppE0Ba_
Unexecuted instantiation: _RNCINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof27build_storage_proof_requestINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1A_9into_iter8IntoIterB1x_EE0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof27build_storage_proof_requestppE0Ba_
Unexecuted instantiation: _RNCINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof27build_storage_proof_requestINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1A_9into_iter8IntoIterB1x_EE0CsiUjFBJteJ7x_17smoldot_full_node
46
0
                    .map(either::Right),
47
0
            ),
48
0
    )
49
0
}
Unexecuted instantiation: _RINvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proof27build_storage_proof_requestppEB8_
Unexecuted instantiation: _RINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof27build_storage_proof_requestINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1y_9into_iter8IntoIterB1v_EECsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof27build_storage_proof_requestppEB8_
Unexecuted instantiation: _RINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof27build_storage_proof_requestINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1y_9into_iter8IntoIterB1v_EECsiUjFBJteJ7x_17smoldot_full_node
50
51
/// Description of a call proof request that can be sent to a peer.
52
#[derive(Debug, Clone, PartialEq, Eq)]
53
pub struct CallProofRequestConfig<'a, I> {
54
    /// Hash of the block to request the storage of.
55
    pub block_hash: [u8; 32],
56
    /// Name of the runtime function to call.
57
    pub method: Cow<'a, str>,
58
    /// Iterator to buffers of bytes to be concatenated then passed as input to the call. The
59
    /// semantics of these bytes depend on which method is being called.
60
    pub parameter_vectored: I,
61
}
62
63
// See https://github.com/paritytech/substrate/blob/c8653447fc8ef8d95a92fe164c96dffb37919e85/client/network/light/src/schema/light.v1.proto
64
// for protocol definition.
65
66
/// Builds the bytes corresponding to a call proof request.
67
0
pub fn build_call_proof_request<'a>(
68
0
    config: CallProofRequestConfig<'a, impl Iterator<Item = impl AsRef<[u8]> + 'a> + 'a>,
69
0
) -> impl Iterator<Item = impl AsRef<[u8]> + 'a> + 'a {
70
0
    // TODO: don't allocate here
71
0
    let parameter = config
72
0
        .parameter_vectored
73
0
        .fold(Vec::with_capacity(512), |mut a, b| {
74
0
            a.extend_from_slice(b.as_ref());
75
0
            a
76
0
        });
Unexecuted instantiation: _RNCINvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proof24build_call_proof_requestppE0Ba_
Unexecuted instantiation: _RNCINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof24build_call_proof_requestINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1x_9into_iter8IntoIterB1u_EE0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof24build_call_proof_requestppE0Ba_
Unexecuted instantiation: _RNCINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof24build_call_proof_requestINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1x_9into_iter8IntoIterB1u_EE0CsiUjFBJteJ7x_17smoldot_full_node
77
0
78
0
    protobuf::message_tag_encode(
79
0
        1,
80
0
        protobuf::bytes_tag_encode(2, config.block_hash)
81
0
            .map(either::Left)
82
0
            .chain(
83
0
                protobuf::string_tag_encode(3, config.method)
84
0
                    .map(either::Left)
85
0
                    .map(either::Right),
86
0
            )
87
0
            .chain(
88
0
                protobuf::bytes_tag_encode(4, parameter)
89
0
                    .map(either::Right)
90
0
                    .map(either::Right),
91
0
            ),
92
0
    )
93
0
}
Unexecuted instantiation: _RINvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proof24build_call_proof_requestppEB8_
Unexecuted instantiation: _RINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof24build_call_proof_requestINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1v_9into_iter8IntoIterB1s_EECsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof24build_call_proof_requestppEB8_
Unexecuted instantiation: _RINvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof24build_call_proof_requestINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1v_9into_iter8IntoIterB1s_EECsiUjFBJteJ7x_17smoldot_full_node
94
95
/// Decodes a response to a storage proof request or a call proof request.
96
///
97
/// On success, returns a SCALE-encoded Merkle proof, or `None` if the remote couldn't answer
98
/// the request.
99
0
pub fn decode_storage_or_call_proof_response(
100
0
    ty: StorageOrCallProof,
101
0
    response_bytes: &[u8],
102
0
) -> Result<Option<&[u8]>, DecodeStorageCallProofResponseError> {
103
0
    let field_num = match ty {
104
0
        StorageOrCallProof::CallProof => 1,
105
0
        StorageOrCallProof::StorageProof => 2,
106
    };
107
108
    // TODO: while the `proof` field is correctly optional, the `response` field isn't supposed to be optional; make it `#[required]` again once https://github.com/paritytech/substrate/pull/12732 has been merged and released
109
110
0
    let mut parser = nom::combinator::all_consuming::<_, _, nom::error::Error<&[u8]>, _>(
111
0
        nom::combinator::complete(protobuf::message_decode! {
112
0
            #[optional] response = field_num => protobuf::message_tag_decode(protobuf::message_decode!{
113
0
                #[optional] proof = 2 => protobuf::bytes_tag_decode
Unexecuted instantiation: _RNCNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proof37decode_storage_or_call_proof_responses_00Bb_
Unexecuted instantiation: _RNCNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof37decode_storage_or_call_proof_responses_00Bb_
114
0
            }),
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proof37decode_storage_or_call_proof_responses_0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof37decode_storage_or_call_proof_responses_0B9_
115
0
        }),
116
0
    );
117
118
0
    let proof = match nom::Finish::finish(parser(response_bytes)) {
119
0
        Ok((_, out)) => out.response.and_then(|r| r.proof),
Unexecuted instantiation: _RNCNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proof37decode_storage_or_call_proof_response0B9_
Unexecuted instantiation: _RNCNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof37decode_storage_or_call_proof_response0B9_
120
0
        Err(_) => return Err(DecodeStorageCallProofResponseError::ProtobufDecode),
121
    };
122
123
0
    Ok(proof)
124
0
}
Unexecuted instantiation: _RNvNtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proof37decode_storage_or_call_proof_response
Unexecuted instantiation: _RNvNtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proof37decode_storage_or_call_proof_response
125
126
/// Error potentially returned by [`decode_storage_or_call_proof_response`].
127
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXs9_NtNtNtCsN16ciHI6Qf_7smoldot7network5codec18storage_call_proofNtB5_35DecodeStorageCallProofResponseErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs9_NtNtNtCseuYC0Zibziv_7smoldot7network5codec18storage_call_proofNtB5_35DecodeStorageCallProofResponseErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
128
pub enum DecodeStorageCallProofResponseError {
129
    /// Error while decoding the Protobuf encoding.
130
    ProtobufDecode,
131
    /// Response isn't a response to a storage proof request.
132
    BadResponseTy,
133
    /// Failed to decode response as a storage proof.
134
    ProofDecodeError,
135
}
136
137
/// Passed as parameter to [`decode_storage_or_call_proof_response`] to indicate what kind of
138
/// request the response corresponds to.
139
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
140
pub enum StorageOrCallProof {
141
    StorageProof,
142
    CallProof,
143
}