frame_benchmarking_cli/overhead/
remark_builder.rs1use 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
32pub struct DynamicRemarkBuilder<C: Config> {
35 offline_client: OfflineClient<C>,
36}
37
38impl<C: Config> DynamicRemarkBuilder<C> {
39 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 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 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 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}