bp_runtime/extensions.rs
1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Bridges Common is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
16
17//! Primitives that may be used for creating signed extensions for indirect runtimes.
18
19use codec::{Compact, Decode, DecodeWithMemTracking, Encode};
20use impl_trait_for_tuples::impl_for_tuples;
21use scale_info::{StaticTypeInfo, TypeInfo};
22use sp_runtime::{
23 impl_tx_ext_default,
24 traits::{Dispatchable, TransactionExtension},
25 transaction_validity::TransactionValidityError,
26};
27use sp_std::{fmt::Debug, marker::PhantomData};
28
29/// Trait that describes some properties of a `TransactionExtension` that are needed in order to
30/// send a transaction to the chain.
31pub trait TransactionExtensionSchema:
32 Encode + Decode + DecodeWithMemTracking + Debug + Eq + Clone + StaticTypeInfo
33{
34 /// A type of the data encoded as part of the transaction.
35 type Payload: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo;
36 /// Parameters which are part of the payload used to produce transaction signature,
37 /// but don't end up in the transaction itself (i.e. inherent part of the runtime).
38 type Implicit: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo;
39}
40
41impl TransactionExtensionSchema for () {
42 type Payload = ();
43 type Implicit = ();
44}
45
46/// An implementation of `TransactionExtensionSchema` using generic params.
47#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Debug, PartialEq, Eq, TypeInfo)]
48pub struct GenericTransactionExtensionSchema<P, S>(PhantomData<(P, S)>);
49
50impl<P, S> TransactionExtensionSchema for GenericTransactionExtensionSchema<P, S>
51where
52 P: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo,
53 S: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo,
54{
55 type Payload = P;
56 type Implicit = S;
57}
58
59/// The `TransactionExtensionSchema` for `frame_system::CheckNonZeroSender`.
60pub type CheckNonZeroSender = GenericTransactionExtensionSchema<(), ()>;
61
62/// The `TransactionExtensionSchema` for `frame_system::CheckSpecVersion`.
63pub type CheckSpecVersion = GenericTransactionExtensionSchema<(), u32>;
64
65/// The `TransactionExtensionSchema` for `frame_system::CheckTxVersion`.
66pub type CheckTxVersion = GenericTransactionExtensionSchema<(), u32>;
67
68/// The `TransactionExtensionSchema` for `frame_system::CheckGenesis`.
69pub type CheckGenesis<Hash> = GenericTransactionExtensionSchema<(), Hash>;
70
71/// The `TransactionExtensionSchema` for `frame_system::CheckEra`.
72pub type CheckEra<Hash> = GenericTransactionExtensionSchema<sp_runtime::generic::Era, Hash>;
73
74/// The `TransactionExtensionSchema` for `frame_system::CheckNonce`.
75pub type CheckNonce<TxNonce> = GenericTransactionExtensionSchema<Compact<TxNonce>, ()>;
76
77/// The `TransactionExtensionSchema` for `frame_system::CheckWeight`.
78pub type CheckWeight = GenericTransactionExtensionSchema<(), ()>;
79
80/// The `TransactionExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`.
81pub type ChargeTransactionPayment<Balance> =
82 GenericTransactionExtensionSchema<Compact<Balance>, ()>;
83
84/// The `TransactionExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`.
85pub type PrevalidateAttests = GenericTransactionExtensionSchema<(), ()>;
86
87/// The `TransactionExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`.
88pub type BridgeRejectObsoleteHeadersAndMessages = GenericTransactionExtensionSchema<(), ()>;
89
90/// The `TransactionExtensionSchema` for `RefundBridgedParachainMessages`.
91/// This schema is dedicated for `RefundBridgedParachainMessages` signed extension as
92/// wildcard/placeholder, which relies on the scale encoding for `()` or `((), ())`, or `((), (),
93/// ())` is the same. So runtime can contains any kind of tuple:
94/// `(BridgeRefundBridgeHubRococoMessages)`
95/// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWestendMessages)`
96/// `(BridgeRefundParachainMessages1, ..., BridgeRefundParachainMessagesN)`
97pub type RefundBridgedParachainMessagesSchema = GenericTransactionExtensionSchema<(), ()>;
98
99#[impl_for_tuples(1, 12)]
100impl TransactionExtensionSchema for Tuple {
101 for_tuples!( type Payload = ( #( Tuple::Payload ),* ); );
102 for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); );
103}
104
105/// A simplified version of signed extensions meant for producing signed transactions
106/// and signed payloads in the client code.
107#[derive(Encode, Decode, DecodeWithMemTracking, Debug, PartialEq, Eq, Clone, TypeInfo)]
108pub struct GenericTransactionExtension<S: TransactionExtensionSchema> {
109 /// A payload that is included in the transaction.
110 pub payload: S::Payload,
111 #[codec(skip)]
112 // It may be set to `None` if extensions are decoded. We are never reconstructing transactions
113 // (and it makes no sense to do that) => decoded version of `TransactionExtensions` is only
114 // used to read fields of the `payload`. And when resigning transaction, we're reconstructing
115 // `TransactionExtensions` from scratch.
116 implicit: Option<S::Implicit>,
117}
118
119impl<S: TransactionExtensionSchema> GenericTransactionExtension<S> {
120 /// Create new `GenericTransactionExtension` object.
121 pub fn new(payload: S::Payload, implicit: Option<S::Implicit>) -> Self {
122 Self { payload, implicit }
123 }
124}
125
126impl<S, C> TransactionExtension<C> for GenericTransactionExtension<S>
127where
128 C: Dispatchable,
129 S: TransactionExtensionSchema,
130 S::Payload: DecodeWithMemTracking + Send + Sync,
131 S::Implicit: Send + Sync,
132{
133 const IDENTIFIER: &'static str = "Not needed.";
134 type Implicit = S::Implicit;
135
136 fn implicit(&self) -> Result<Self::Implicit, TransactionValidityError> {
137 // we shall not ever see this error in relay, because we are never signing decoded
138 // transactions. Instead we're constructing and signing new transactions. So the error code
139 // is kinda random here
140 self.implicit
141 .clone()
142 .ok_or(frame_support::unsigned::TransactionValidityError::Unknown(
143 frame_support::unsigned::UnknownTransaction::Custom(0xFF),
144 ))
145 }
146 type Pre = ();
147 type Val = ();
148
149 impl_tx_ext_default!(C; weight validate prepare);
150}