referrerpolicy=no-referrer-when-downgrade

frame_benchmarking_cli/overhead/
remark_builder.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use crate::extrinsic::ExtrinsicBuilder;
19use codec::{Decode, Encode};
20use sc_client_api::UsageProvider;
21use sp_api::{ApiExt, Core, Metadata, ProvideRuntimeApi};
22use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic};
23use std::sync::Arc;
24use subxt::{
25	client::RuntimeVersion as SubxtRuntimeVersion,
26	config::{substrate::SubstrateExtrinsicParamsBuilder, HashFor},
27	Config, OfflineClient, SubstrateConfig,
28};
29
30pub type SubstrateRemarkBuilder = DynamicRemarkBuilder<SubstrateConfig>;
31
32/// Remark builder that can be used to build simple extrinsics for
33/// FRAME-based runtimes.
34pub struct DynamicRemarkBuilder<C: Config> {
35	offline_client: OfflineClient<C>,
36}
37
38impl<C: Config> DynamicRemarkBuilder<C> {
39	/// Initializes a new remark builder from a client.
40	///
41	/// This will first fetch metadata and runtime version from the runtime and then
42	/// construct an offline client that provides the extrinsics.
43	pub fn new_from_client<Client, Block>(client: Arc<Client>) -> sc_cli::Result<Self>
44	where
45		Block: BlockT,
46		Client: UsageProvider<Block> + ProvideRuntimeApi<Block>,
47		Client::Api: Metadata<Block> + Core<Block>,
48	{
49		let genesis = client.usage_info().chain.best_hash;
50		let api = client.runtime_api();
51
52		let Ok(Some(metadata_api_version)) = api.api_version::<dyn Metadata<Block>>(genesis) else {
53			return Err("Unable to fetch metadata runtime API version.".to_string().into());
54		};
55
56		log::debug!("Found metadata API version {}.", metadata_api_version);
57		let opaque_metadata = if metadata_api_version > 1 {
58			let Ok(supported_metadata_versions) = api.metadata_versions(genesis) else {
59				return Err("Unable to fetch metadata versions".to_string().into());
60			};
61
62			let latest = supported_metadata_versions
63				.into_iter()
64				.max()
65				.ok_or("No stable metadata versions supported".to_string())?;
66
67			api.metadata_at_version(genesis, latest)
68				.map_err(|e| format!("Unable to fetch metadata: {:?}", e))?
69				.ok_or("Unable to decode metadata".to_string())?
70		} else {
71			// Fall back to using the non-versioned metadata API.
72			api.metadata(genesis)
73				.map_err(|e| format!("Unable to fetch metadata: {:?}", e))?
74		};
75
76		let version = api.version(genesis).unwrap();
77		let runtime_version = SubxtRuntimeVersion {
78			spec_version: version.spec_version,
79			transaction_version: version.transaction_version,
80		};
81		let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?;
82		let genesis = HashFor::<C>::decode(&mut &genesis.encode()[..])
83			.map_err(|_| "Incompatible hash types?")?;
84
85		Ok(Self { offline_client: OfflineClient::new(genesis, runtime_version, metadata) })
86	}
87}
88
89impl<C: Config> DynamicRemarkBuilder<C> {
90	/// Constructs a new remark builder.
91	pub fn new(
92		metadata: subxt::Metadata,
93		genesis_hash: HashFor<C>,
94		runtime_version: SubxtRuntimeVersion,
95	) -> Self {
96		Self { offline_client: OfflineClient::new(genesis_hash, runtime_version, metadata) }
97	}
98}
99
100impl ExtrinsicBuilder for DynamicRemarkBuilder<SubstrateConfig> {
101	fn pallet(&self) -> &str {
102		"system"
103	}
104
105	fn extrinsic(&self) -> &str {
106		"remark"
107	}
108
109	fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
110		let signer = subxt_signer::sr25519::dev::alice();
111		let dynamic_tx = subxt::dynamic::tx("System", "remark", vec![Vec::<u8>::new()]);
112
113		let params = SubstrateExtrinsicParamsBuilder::new().nonce(nonce.into()).build();
114
115		// Default transaction parameters assume a nonce of 0.
116		let transaction = self
117			.offline_client
118			.tx()
119			.create_partial_offline(&dynamic_tx, params)
120			.unwrap()
121			.sign(&signer);
122		let mut encoded = transaction.into_encoded();
123
124		OpaqueExtrinsic::from_bytes(&mut encoded).map_err(|_| "Unable to construct OpaqueExtrinsic")
125	}
126}