Skip to main content

frame_decode/methods/extrinsic_encoder/
transaction_extensions.rs

1// Copyright (C) 2022-2026 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the frame-decode crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::transaction_extension::{TransactionExtension, TransactionExtensionError};
17use alloc::borrow::ToOwned;
18use alloc::string::String;
19use alloc::vec::Vec;
20use scale_type_resolver::TypeResolver;
21
22/// This trait can be implemented for anything which represents a set of transaction extensions.
23/// It's implemented by default for tuples of items which implement [`TransactionExtension`].
24pub trait TransactionExtensions<Resolver: TypeResolver> {
25    /// Is a given transaction extension contained within this set?
26    fn contains_extension(&self, name: &str) -> bool;
27
28    /// This will be called given the name of each transaction extension we
29    /// wish to obtain the encoded bytes to. Implementations are expected to
30    /// write the bytes that should be included in the **transaction** to the given [`Vec`],
31    /// or return an error if no such bytes can be written.
32    fn encode_extension_value_to(
33        &self,
34        name: &str,
35        type_id: Resolver::TypeId,
36        type_resolver: &Resolver,
37        out: &mut Vec<u8>,
38    ) -> Result<(), TransactionExtensionsError>;
39
40    /// This will be called given the name of each transaction extension we
41    /// wish to obtain the encoded bytes to. Implementations are expected to
42    /// write the bytes that should be included in the **signer payload value
43    /// section** to the given [`Vec`], or return an error if no such bytes can be
44    /// written.
45    ///
46    /// This defaults to calling [`Self::encode_extension_value_to`] if not implemented.
47    /// In most cases this is fine, but for V5 extrinsics we can optionally provide
48    /// the signature inside a transaction extension, and so that transaction would be
49    /// unable to encode anything for the signer payload.
50    fn encode_extension_value_for_signer_payload_to(
51        &self,
52        name: &str,
53        type_id: Resolver::TypeId,
54        type_resolver: &Resolver,
55        out: &mut Vec<u8>,
56    ) -> Result<(), TransactionExtensionsError> {
57        self.encode_extension_value_to(name, type_id, type_resolver, out)
58    }
59
60    /// This will be called given the name of each transaction extension we
61    /// wish to obtain the encoded bytes to. Implementations are expected to
62    /// write the bytes that should be included in the **signer payload implicit**
63    /// to the given [`Vec`], or return an error if no such bytes can be written.
64    fn encode_extension_implicit_to(
65        &self,
66        name: &str,
67        type_id: Resolver::TypeId,
68        type_resolver: &Resolver,
69        out: &mut Vec<u8>,
70    ) -> Result<(), TransactionExtensionsError>;
71}
72
73/// This error will be returned if any of the methods in [`TransactionExtensions`] fail.
74#[derive(Debug, thiserror::Error)]
75pub enum TransactionExtensionsError {
76    /// The requested transaction extension could not be found.
77    #[error("Cannot encode transaction extension '{0}': This extension could not be found")]
78    NotFound(String),
79    /// An error occurred while encoding the transaction extension.
80    #[error("Cannot encode transaction extension '{extension_name}': {error}")]
81    Other {
82        /// The name of the extension that failed to encode.
83        extension_name: String,
84        /// The underlying error.
85        error: TransactionExtensionError,
86    },
87}
88
89// Empty tuples impl `TransactionExtensions`: if called they emit a not found error.
90impl<Resolver: TypeResolver> TransactionExtensions<Resolver> for () {
91    fn contains_extension(&self, _name: &str) -> bool {
92        false
93    }
94
95    fn encode_extension_value_to(
96        &self,
97        name: &str,
98        _type_id: <Resolver as TypeResolver>::TypeId,
99        _type_resolver: &Resolver,
100        _out: &mut Vec<u8>,
101    ) -> Result<(), TransactionExtensionsError> {
102        Err(TransactionExtensionsError::NotFound(name.to_owned()))
103    }
104
105    fn encode_extension_implicit_to(
106        &self,
107        name: &str,
108        _type_id: <Resolver as TypeResolver>::TypeId,
109        _type_resolver: &Resolver,
110        _out: &mut Vec<u8>,
111    ) -> Result<(), TransactionExtensionsError> {
112        Err(TransactionExtensionsError::NotFound(name.to_owned()))
113    }
114}
115
116// Non-empty tuples impl `TransactionExtensions`: for each extension we do a linear
117// search through the tuple items to find it and call the appropriate encode method.
118macro_rules! impl_tuples {
119    ($($ident:ident $index:tt),*) => {
120        impl <Resolver: TypeResolver $(,$ident)*> TransactionExtensions<Resolver> for ($($ident,)*)
121        where
122            $($ident: TransactionExtension<Resolver>,)*
123        {
124            fn contains_extension(&self, name: &str) -> bool {
125                $(
126                    if $ident::NAME == name {
127                        return true
128                    }
129                )*
130                false
131            }
132
133            fn encode_extension_value_to(
134                &self,
135                name: &str,
136                type_id: <Resolver as TypeResolver>::TypeId,
137                type_resolver: &Resolver,
138                out: &mut Vec<u8>
139            ) -> Result<(), TransactionExtensionsError> {
140                let len = out.len();
141
142                $(
143                    if $ident::NAME == name {
144                        return self.$index.encode_value_to(type_id, type_resolver, out)
145                            .map_err(|e| {
146                                // Protection: if we are returning an error then
147                                // no bytes should have been encoded to the given
148                                // Vec. Ensure that this is true:
149                                out.truncate(len);
150                                TransactionExtensionsError::Other {
151                                    extension_name: name.to_owned(),
152                                    error: e,
153                                }
154                            });
155                    }
156                )*
157
158                Err(TransactionExtensionsError::NotFound(name.to_owned()))
159            }
160
161            fn encode_extension_value_for_signer_payload_to(
162                &self,
163                name: &str,
164                type_id: <Resolver as TypeResolver>::TypeId,
165                type_resolver: &Resolver,
166                out: &mut Vec<u8>
167            ) -> Result<(), TransactionExtensionsError> {
168                let len = out.len();
169
170                $(
171                    if $ident::NAME == name {
172                        return self.$index.encode_value_for_signer_payload_to(type_id, type_resolver, out)
173                            .map_err(|e| {
174                                // Protection: if we are returning an error then
175                                // no bytes should have been encoded to the given
176                                // Vec. Ensure that this is true:
177                                out.truncate(len);
178                                TransactionExtensionsError::Other {
179                                    extension_name: name.to_owned(),
180                                    error: e,
181                                }
182                            });
183                    }
184                )*
185
186                Err(TransactionExtensionsError::NotFound(name.to_owned()))
187            }
188
189            fn encode_extension_implicit_to(
190                &self,
191                name: &str,
192                type_id: <Resolver as TypeResolver>::TypeId,
193                type_resolver: &Resolver,
194                out: &mut Vec<u8>
195            ) -> Result<(), TransactionExtensionsError> {
196                let len = out.len();
197
198                $(
199                    if $ident::NAME == name {
200                        return self.$index.encode_implicit_to(type_id, type_resolver, out)
201                            .map_err(|e| {
202                                // Protection: if we are returning an error then
203                                // no bytes should have been encoded to the given
204                                // Vec. Ensure that this is true:
205                                out.truncate(len);
206                                TransactionExtensionsError::Other {
207                                    extension_name: name.to_owned(),
208                                    error: e,
209                                }
210                            });
211                    }
212                )*
213
214                Err(TransactionExtensionsError::NotFound(name.to_owned()))
215            }
216        }
217    }
218}
219
220#[rustfmt::skip]
221const _: () = {
222    impl_tuples!(A 0);
223    impl_tuples!(A 0, B 1);
224    impl_tuples!(A 0, B 1, C 2);
225    impl_tuples!(A 0, B 1, C 2, D 3);
226    impl_tuples!(A 0, B 1, C 2, D 3, E 4);
227    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5);
228    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
229    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
230    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8);
231    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9);
232    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10);
233    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11);
234    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12);
235    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13);
236    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14);
237    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15);
238    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16);
239    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17);
240    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17, S 18);
241    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17, S 18, T 19);
242    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17, S 18, T 19, U 20);
243    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17, S 18, T 19, U 20, V 21);
244    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17, S 18, T 19, U 20, V 21, W 22);
245    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17, S 18, T 19, U 20, V 21, W 22, X 23);
246    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17, S 18, T 19, U 20, V 21, W 22, X 23, Y 24);
247    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15, Q 16, R 17, S 18, T 19, U 20, V 21, W 22, X 23, Y 24, Z 25);
248};