avail_rust_core/
extrinsics_params.rs

1// Copyright 2019-2024 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5use crate::types::Era;
6use codec::{Compact, Encode};
7use scale_info::PortableRegistry;
8use subxt_core::{
9	client::ClientState,
10	config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder, Header, transaction_extensions},
11	error::ExtrinsicParamsError,
12};
13
14use crate::types::metadata::AppId;
15
16#[derive(Debug, Clone, Copy, Default)]
17pub struct CheckAppId(pub AppId);
18
19/// Ideally, we would use avail_core::AppId but we cannot define `RefineParams` for it so we need a wrapper. Crazy
20impl<T: Config> transaction_extensions::Params<T> for AppId {}
21impl<T: Config> transaction_extensions::Params<T> for CheckAppId {}
22
23impl ExtrinsicParamsEncoder for CheckAppId {
24	fn encode_value_to(&self, v: &mut Vec<u8>) {
25		Compact::<u32>(self.0.0).encode_to(v);
26	}
27
28	fn encode_implicit_to(&self, _: &mut Vec<u8>) {}
29}
30
31impl<T: Config> subxt_core::config::ExtrinsicParams<T> for CheckAppId {
32	type Params = AppId;
33
34	fn new(_client: &ClientState<T>, id: Self::Params) -> Result<Self, ExtrinsicParamsError> {
35		Ok(CheckAppId(id))
36	}
37}
38
39impl<T: Config> transaction_extensions::TransactionExtension<T> for CheckAppId {
40	type Decoded = Compact<u32>;
41
42	fn matches(identifier: &str, _type_id: u32, _types: &PortableRegistry) -> bool {
43		identifier == "CheckAppId"
44	}
45}
46
47/// Type used only for decoding extrinsic from blocks.
48pub type OnlyCodecExtra = (
49	(),            // CheckNonZeroSender,
50	(),            // CheckSpecVersion<Runtime>,
51	(),            // CheckTxVersion<Runtime>,
52	(),            // CheckGenesis<Runtime>,
53	Era,           // CheckEra<Runtime>,
54	Compact<u32>,  // CheckNonce<Runtime>,
55	(),            // CheckWeight<Runtime>,
56	Compact<u128>, // ChargeTransactionPayment<Runtime>,
57	AppId,         // CheckAppId<Runtime>,
58);
59
60/// The default [`super::ExtrinsicParams`] implementation understands common signed extensions
61/// and how to apply them to a given chain.
62pub type DefaultExtrinsicParams<T> = transaction_extensions::AnyOf<
63	T,
64	(
65		transaction_extensions::CheckSpecVersion,
66		transaction_extensions::CheckTxVersion,
67		transaction_extensions::CheckGenesis<T>,
68		transaction_extensions::CheckMortality<T>,
69		transaction_extensions::CheckNonce,
70		transaction_extensions::ChargeTransactionPayment,
71		CheckAppId,
72	),
73>;
74
75/// A builder that outputs the set of [`super::ExtrinsicParams::Params`] required for
76/// [`DefaultExtrinsicParams`]. This may expose methods that aren't applicable to the current
77/// chain; such values will simply be ignored if so.
78pub struct DefaultExtrinsicParamsBuilder<T: Config> {
79	/// `None` means the tx will be immortal.
80	mortality: Option<Mortality<T::Hash>>,
81	/// `None` means the nonce will be automatically set.
82	nonce: Option<u64>,
83	tip: u128,
84	app_id: AppId,
85}
86
87#[derive(Debug, Clone)]
88struct Mortality<Hash> {
89	/// Block hash that mortality starts from
90	checkpoint_hash: Hash,
91	/// Block number that mortality starts from (must
92	// point to the same block as the hash above)
93	checkpoint_number: u64,
94	/// How many blocks the tx is mortal for
95	period: u64,
96}
97
98impl<T: Config> Default for DefaultExtrinsicParamsBuilder<T> {
99	fn default() -> Self {
100		Self {
101			mortality: None,
102			tip: 0,
103			nonce: None,
104			app_id: AppId::default(),
105		}
106	}
107}
108
109impl<T: Config> DefaultExtrinsicParamsBuilder<T> {
110	/// Configure new extrinsic params. We default to providing no tip
111	/// and using an immortal transaction unless otherwise configured
112	pub fn new() -> Self {
113		Default::default()
114	}
115
116	/// Make the transaction mortal, given a block header that it should be mortal from,
117	/// and the number of blocks (roughly; it'll be rounded to a power of two) that it will
118	/// be mortal for.
119	pub fn mortal(mut self, from_block: &T::Header, for_n_blocks: u64) -> Self {
120		self.mortality = Some(Mortality {
121			checkpoint_hash: from_block.hash(),
122			checkpoint_number: from_block.number().into(),
123			period: for_n_blocks,
124		});
125		self
126	}
127
128	/// Provide a specific nonce for the submitter of the extrinsic
129	pub fn nonce(mut self, nonce: u64) -> Self {
130		self.nonce = Some(nonce);
131		self
132	}
133
134	/// App Id
135	pub fn app_id(mut self, app_id: u32) -> Self {
136		self.app_id = AppId(app_id);
137		self
138	}
139
140	/// Make the transaction mortal, given a block number and block hash (which must both point to
141	/// the same block) that it should be mortal from, and the number of blocks (roughly; it'll be
142	/// rounded to a power of two) that it will be mortal for.
143	///
144	/// Prefer to use [`DefaultExtrinsicParamsBuilder::mortal()`], which ensures that the block hash
145	/// and number align.
146	pub fn mortal_unchecked(mut self, from_block_number: u64, from_block_hash: T::Hash, for_n_blocks: u64) -> Self {
147		self.mortality = Some(Mortality {
148			checkpoint_hash: from_block_hash,
149			checkpoint_number: from_block_number,
150			period: for_n_blocks,
151		});
152		self
153	}
154
155	/// Provide a tip to the block author in the chain's native token.
156	pub fn tip(mut self, tip: u128) -> Self {
157		self.tip = tip;
158		self
159	}
160
161	/// Build the extrinsic parameters.
162	pub fn build(self) -> <DefaultExtrinsicParams<T> as ExtrinsicParams<T>>::Params {
163		let check_mortality_params = if let Some(mortality) = self.mortality {
164			transaction_extensions::CheckMortalityParams::mortal_from_unchecked(
165				mortality.period,
166				mortality.checkpoint_number,
167				mortality.checkpoint_hash,
168			)
169		} else {
170			transaction_extensions::CheckMortalityParams::immortal()
171		};
172
173		let charge_transaction_params = transaction_extensions::ChargeTransactionPaymentParams::tip(self.tip);
174
175		let check_nonce_params = match self.nonce {
176			Some(x) => transaction_extensions::CheckNonceParams::with_nonce(x),
177			None => transaction_extensions::CheckNonceParams::from_chain(),
178		};
179		((), (), (), check_mortality_params, check_nonce_params, charge_transaction_params, self.app_id)
180	}
181}