referrerpolicy=no-referrer-when-downgrade

polkadot_service/
benchmarking.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot 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// Polkadot 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 Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Code related to benchmarking a node.
18
19use polkadot_primitives::AccountId;
20use sc_client_api::UsageProvider;
21use sp_keyring::Sr25519Keyring;
22use sp_runtime::OpaqueExtrinsic;
23
24use crate::*;
25
26macro_rules! identify_chain {
27	(
28		$chain:expr,
29		$nonce:ident,
30		$current_block:ident,
31		$period:ident,
32		$genesis:ident,
33		$signer:ident,
34		$generic_code:expr $(,)*
35	) => {
36		match $chain {
37			Chain::Polkadot => Err("Polkadot runtimes are currently not supported"),
38			Chain::Kusama => Err("Kusama runtimes are currently not supported"),
39			Chain::Rococo => {
40				#[cfg(feature = "rococo-native")]
41				{
42					use rococo_runtime as runtime;
43
44					let call = $generic_code;
45
46					Ok(rococo_sign_call(call, $nonce, $current_block, $period, $genesis, $signer))
47				}
48
49				#[cfg(not(feature = "rococo-native"))]
50				{
51					Err("`rococo-native` feature not enabled")
52				}
53			},
54			Chain::Westend => {
55				#[cfg(feature = "westend-native")]
56				{
57					use westend_runtime as runtime;
58
59					let call = $generic_code;
60
61					Ok(westend_sign_call(call, $nonce, $current_block, $period, $genesis, $signer))
62				}
63
64				#[cfg(not(feature = "westend-native"))]
65				{
66					Err("`westend-native` feature not enabled")
67				}
68			},
69			Chain::Unknown => {
70				let _ = $nonce;
71				let _ = $current_block;
72				let _ = $period;
73				let _ = $genesis;
74				let _ = $signer;
75
76				Err("Unknown chain")
77			},
78		}
79	};
80}
81
82/// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks.
83///
84/// Note: Should only be used for benchmarking.
85pub struct TransferKeepAliveBuilder {
86	client: Arc<FullClient>,
87	dest: AccountId,
88	chain: Chain,
89}
90
91impl TransferKeepAliveBuilder {
92	/// Creates a new [`Self`] from the given client and the arguments for the extrinsics.
93	pub fn new(client: Arc<FullClient>, dest: AccountId, chain: Chain) -> Self {
94		Self { client, dest, chain }
95	}
96}
97
98impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder {
99	fn pallet(&self) -> &str {
100		"balances"
101	}
102
103	fn extrinsic(&self) -> &str {
104		"transfer_keep_alive"
105	}
106
107	fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
108		let signer = Sr25519Keyring::Bob.pair();
109		// We apply the extrinsic directly, so let's take some random period.
110		let period = 128;
111		let genesis = self.client.usage_info().chain.best_hash;
112		let current_block = 0;
113		let _dest = self.dest.clone();
114
115		identify_chain! {
116			self.chain,
117			nonce,
118			current_block,
119			period,
120			genesis,
121			signer,
122			{
123				runtime::RuntimeCall::Balances(runtime::BalancesCall::transfer_keep_alive {
124					dest: _dest.into(),
125					value: runtime::ExistentialDeposit::get(),
126				})
127			},
128		}
129	}
130}
131
132#[cfg(feature = "westend-native")]
133fn westend_sign_call(
134	call: westend_runtime::RuntimeCall,
135	nonce: u32,
136	current_block: u64,
137	period: u64,
138	genesis: sp_core::H256,
139	acc: sp_core::sr25519::Pair,
140) -> OpaqueExtrinsic {
141	use codec::Encode;
142	use sp_core::Pair;
143	use westend_runtime as runtime;
144
145	let tx_ext: runtime::TxExtension = (
146		frame_system::AuthorizeCall::<runtime::Runtime>::new(),
147		frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
148		frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
149		frame_system::CheckTxVersion::<runtime::Runtime>::new(),
150		frame_system::CheckGenesis::<runtime::Runtime>::new(),
151		frame_system::CheckMortality::<runtime::Runtime>::from(sp_runtime::generic::Era::mortal(
152			period,
153			current_block,
154		)),
155		frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
156		frame_system::CheckWeight::<runtime::Runtime>::new(),
157		pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
158		frame_metadata_hash_extension::CheckMetadataHash::<runtime::Runtime>::new(false),
159		frame_system::WeightReclaim::<runtime::Runtime>::new(),
160	)
161		.into();
162
163	let payload = runtime::SignedPayload::from_raw(
164		call.clone(),
165		tx_ext.clone(),
166		(
167			(),
168			(),
169			runtime::VERSION.spec_version,
170			runtime::VERSION.transaction_version,
171			genesis,
172			genesis,
173			(),
174			(),
175			(),
176			None,
177			(),
178		),
179	);
180
181	let signature = payload.using_encoded(|p| acc.sign(p));
182	runtime::UncheckedExtrinsic::new_signed(
183		call,
184		sp_runtime::AccountId32::from(acc.public()).into(),
185		polkadot_core_primitives::Signature::Sr25519(signature),
186		tx_ext,
187	)
188	.into()
189}
190
191#[cfg(feature = "rococo-native")]
192fn rococo_sign_call(
193	call: rococo_runtime::RuntimeCall,
194	nonce: u32,
195	current_block: u64,
196	period: u64,
197	genesis: sp_core::H256,
198	acc: sp_core::sr25519::Pair,
199) -> OpaqueExtrinsic {
200	use codec::Encode;
201	use rococo_runtime as runtime;
202	use sp_core::Pair;
203
204	let tx_ext: runtime::TxExtension = (
205		frame_system::AuthorizeCall::<runtime::Runtime>::new(),
206		frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
207		frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
208		frame_system::CheckTxVersion::<runtime::Runtime>::new(),
209		frame_system::CheckGenesis::<runtime::Runtime>::new(),
210		frame_system::CheckMortality::<runtime::Runtime>::from(sp_runtime::generic::Era::mortal(
211			period,
212			current_block,
213		)),
214		frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
215		frame_system::CheckWeight::<runtime::Runtime>::new(),
216		pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
217		frame_metadata_hash_extension::CheckMetadataHash::<runtime::Runtime>::new(false),
218		frame_system::WeightReclaim::<runtime::Runtime>::new(),
219	)
220		.into();
221
222	let payload = runtime::SignedPayload::from_raw(
223		call.clone(),
224		tx_ext.clone(),
225		(
226			(),
227			(),
228			runtime::VERSION.spec_version,
229			runtime::VERSION.transaction_version,
230			genesis,
231			genesis,
232			(),
233			(),
234			(),
235			None,
236			(),
237		),
238	);
239
240	let signature = payload.using_encoded(|p| acc.sign(p));
241	runtime::UncheckedExtrinsic::new_signed(
242		call,
243		sp_runtime::AccountId32::from(acc.public()).into(),
244		polkadot_core_primitives::Signature::Sr25519(signature),
245		tx_ext,
246	)
247	.into()
248}
249
250/// Generates inherent data for benchmarking Polkadot, Kusama, Westend and Rococo.
251///
252/// Not to be used outside of benchmarking since it returns mocked values.
253pub fn benchmark_inherent_data(
254	header: polkadot_core_primitives::Header,
255) -> std::result::Result<sp_inherents::InherentData, sp_inherents::Error> {
256	use sp_inherents::InherentDataProvider;
257	let mut inherent_data = sp_inherents::InherentData::new();
258
259	// Assume that all runtimes have the `timestamp` pallet.
260	let d = std::time::Duration::from_millis(0);
261	let timestamp = sp_timestamp::InherentDataProvider::new(d.into());
262	futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data))?;
263
264	let para_data = polkadot_primitives::InherentData {
265		bitfields: Vec::new(),
266		backed_candidates: Vec::new(),
267		disputes: Vec::new(),
268		parent_header: header,
269	};
270
271	inherent_data.put_data(polkadot_primitives::PARACHAINS_INHERENT_IDENTIFIER, &para_data)?;
272
273	Ok(inherent_data)
274}