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    /// Does the named transaction extension authorize the transaction
29    /// (see [`TransactionExtension::is_authorization_extension`])? This should
30    /// return `false` for any extension not contained within this set.
31    fn is_authorization_extension(&self, _name: &str) -> bool {
32        false
33    }
34
35    /// This will be called given the name of each transaction extension we
36    /// wish to obtain the encoded bytes to. Implementations are expected to
37    /// write the bytes that should be included in the **transaction** to the given [`Vec`],
38    /// or return an error if no such bytes can be written.
39    fn encode_extension_value_to(
40        &self,
41        name: &str,
42        type_id: Resolver::TypeId,
43        type_resolver: &Resolver,
44        out: &mut Vec<u8>,
45    ) -> Result<(), TransactionExtensionsError>;
46
47    /// This will be called given the name of each transaction extension we
48    /// wish to obtain the encoded bytes to. Implementations are expected to
49    /// write the bytes that should be included in the **signer payload implicit**
50    /// to the given [`Vec`], or return an error if no such bytes can be written.
51    fn encode_extension_implicit_to(
52        &self,
53        name: &str,
54        type_id: Resolver::TypeId,
55        type_resolver: &Resolver,
56        out: &mut Vec<u8>,
57    ) -> Result<(), TransactionExtensionsError>;
58}
59
60/// This error will be returned if any of the methods in [`TransactionExtensions`] fail.
61#[derive(Debug, thiserror::Error)]
62pub enum TransactionExtensionsError {
63    /// The requested transaction extension could not be found.
64    #[error("Cannot encode transaction extension '{0}': This extension could not be found")]
65    NotFound(String),
66    /// An error occurred while encoding the transaction extension.
67    #[error("Cannot encode transaction extension '{extension_name}': {error}")]
68    Other {
69        /// The name of the extension that failed to encode.
70        extension_name: String,
71        /// The underlying error.
72        error: TransactionExtensionError,
73    },
74}
75
76// Empty tuples impl `TransactionExtensions`: if called they emit a not found error.
77impl<Resolver: TypeResolver> TransactionExtensions<Resolver> for () {
78    fn contains_extension(&self, _name: &str) -> bool {
79        false
80    }
81
82    fn encode_extension_value_to(
83        &self,
84        name: &str,
85        _type_id: <Resolver as TypeResolver>::TypeId,
86        _type_resolver: &Resolver,
87        _out: &mut Vec<u8>,
88    ) -> Result<(), TransactionExtensionsError> {
89        Err(TransactionExtensionsError::NotFound(name.to_owned()))
90    }
91
92    fn encode_extension_implicit_to(
93        &self,
94        name: &str,
95        _type_id: <Resolver as TypeResolver>::TypeId,
96        _type_resolver: &Resolver,
97        _out: &mut Vec<u8>,
98    ) -> Result<(), TransactionExtensionsError> {
99        Err(TransactionExtensionsError::NotFound(name.to_owned()))
100    }
101}
102
103// Non-empty tuples impl `TransactionExtensions`: for each extension we do a linear
104// search through the tuple items to find it and call the appropriate encode method.
105macro_rules! impl_tuples {
106    ($($ident:ident $index:tt),*) => {
107        impl <Resolver: TypeResolver $(,$ident)*> TransactionExtensions<Resolver> for ($($ident,)*)
108        where
109            $($ident: TransactionExtension<Resolver>,)*
110        {
111            fn contains_extension(&self, name: &str) -> bool {
112                $(
113                    if $ident::NAME == name {
114                        return true
115                    }
116                )*
117                false
118            }
119
120            fn is_authorization_extension(&self, name: &str) -> bool {
121                $(
122                    if $ident::NAME == name {
123                        return self.$index.is_authorization_extension()
124                    }
125                )*
126                false
127            }
128
129            fn encode_extension_value_to(
130                &self,
131                name: &str,
132                type_id: <Resolver as TypeResolver>::TypeId,
133                type_resolver: &Resolver,
134                out: &mut Vec<u8>
135            ) -> Result<(), TransactionExtensionsError> {
136                let len = out.len();
137
138                $(
139                    if $ident::NAME == name {
140                        return self.$index.encode_value_to(type_id, type_resolver, out)
141                            .map_err(|e| {
142                                // Protection: if we are returning an error then
143                                // no bytes should have been encoded to the given
144                                // Vec. Ensure that this is true:
145                                out.truncate(len);
146                                TransactionExtensionsError::Other {
147                                    extension_name: name.to_owned(),
148                                    error: e,
149                                }
150                            });
151                    }
152                )*
153
154                Err(TransactionExtensionsError::NotFound(name.to_owned()))
155            }
156
157            fn encode_extension_implicit_to(
158                &self,
159                name: &str,
160                type_id: <Resolver as TypeResolver>::TypeId,
161                type_resolver: &Resolver,
162                out: &mut Vec<u8>
163            ) -> Result<(), TransactionExtensionsError> {
164                let len = out.len();
165
166                $(
167                    if $ident::NAME == name {
168                        return self.$index.encode_implicit_to(type_id, type_resolver, out)
169                            .map_err(|e| {
170                                // Protection: if we are returning an error then
171                                // no bytes should have been encoded to the given
172                                // Vec. Ensure that this is true:
173                                out.truncate(len);
174                                TransactionExtensionsError::Other {
175                                    extension_name: name.to_owned(),
176                                    error: e,
177                                }
178                            });
179                    }
180                )*
181
182                Err(TransactionExtensionsError::NotFound(name.to_owned()))
183            }
184        }
185    }
186}
187
188#[rustfmt::skip]
189const _: () = {
190    impl_tuples!(A 0);
191    impl_tuples!(A 0, B 1);
192    impl_tuples!(A 0, B 1, C 2);
193    impl_tuples!(A 0, B 1, C 2, D 3);
194    impl_tuples!(A 0, B 1, C 2, D 3, E 4);
195    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5);
196    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
197    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
198    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8);
199    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9);
200    impl_tuples!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10);
201    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);
202    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);
203    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);
204    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);
205    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);
206    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);
207    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);
208    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);
209    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);
210    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);
211    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);
212    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);
213    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);
214    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);
215    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);
216};