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