substrate_relay_helper/cli/
chain_schema.rs1use clap::Parser;
20use relay_substrate_client::{AccountKeyPairOf, ChainWithTransactions};
21use strum::{EnumString, VariantNames};
22
23use relay_substrate_client::{ChainRuntimeVersion, ChainWithRuntimeVersion, SimpleRuntimeVersion};
24
25use crate::TransactionParams;
26
27#[doc = "Runtime version params."]
28#[derive(Debug, PartialEq, Eq, Clone, Copy, Parser, EnumString, VariantNames)]
29pub enum RuntimeVersionType {
30 Auto,
32 Custom,
34 Bundle,
36}
37
38#[macro_export]
40macro_rules! declare_chain_runtime_version_params_cli_schema {
41 ($chain:ident, $chain_prefix:ident) => {
42 bp_runtime::paste::item! {
43 #[doc = $chain " runtime version params."]
44 #[derive(Debug, PartialEq, Eq, Clone, Copy, Parser)]
45 pub struct [<$chain RuntimeVersionParams>] {
46 #[doc = "The type of runtime version for chain " $chain]
47 #[arg(long, default_value = "Bundle")]
48 pub [<$chain_prefix _version_mode>]: RuntimeVersionType,
49 #[doc = "The custom sepc_version for chain " $chain]
50 #[arg(long)]
51 pub [<$chain_prefix _spec_version>]: Option<u32>,
52 #[doc = "The custom transaction_version for chain " $chain]
53 #[arg(long)]
54 pub [<$chain_prefix _transaction_version>]: Option<u32>,
55 }
56
57 impl [<$chain RuntimeVersionParams>] {
58 pub fn into_runtime_version(
60 self,
61 bundle_runtime_version: Option<SimpleRuntimeVersion>,
62 ) -> anyhow::Result<ChainRuntimeVersion> {
63 Ok(match self.[<$chain_prefix _version_mode>] {
64 RuntimeVersionType::Auto => ChainRuntimeVersion::Auto,
65 RuntimeVersionType::Custom => {
66 let custom_spec_version = self.[<$chain_prefix _spec_version>]
67 .ok_or_else(|| anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?;
68 let custom_transaction_version = self.[<$chain_prefix _transaction_version>]
69 .ok_or_else(|| anyhow::Error::msg(format!("The {}-transaction-version is required when choose custom mode", stringify!($chain_prefix))))?;
70 ChainRuntimeVersion::Custom(
71 SimpleRuntimeVersion {
72 spec_version: custom_spec_version,
73 transaction_version: custom_transaction_version
74 }
75 )
76 },
77 RuntimeVersionType::Bundle => match bundle_runtime_version {
78 Some(runtime_version) => ChainRuntimeVersion::Custom(runtime_version),
79 None => {
80 return Err(anyhow::format_err!("Cannot use bundled runtime version of {}: it is not known to the relay", stringify!($chain_prefix)));
81 }
82 },
83 })
84 }
85 }
86 }
87 };
88}
89
90#[macro_export]
92macro_rules! declare_chain_connection_params_cli_schema {
93 ($chain:ident, $chain_prefix:ident) => {
94 bp_runtime::paste::item! {
95 #[doc = $chain " connection params."]
99 #[derive(Debug, PartialEq, Eq, Clone, Parser)]
100 pub struct [<$chain ConnectionParams>] {
101 #[doc = "WS endpoint of " $chain ": full URI."]
102 #[arg(long)]
103 pub [<$chain_prefix _uri>]: String,
104 #[doc = "Custom runtime version"]
105 #[command(flatten)]
106 pub [<$chain_prefix _runtime_version>]: [<$chain RuntimeVersionParams>],
107 }
108
109 impl [<$chain ConnectionParams>] {
110 #[allow(dead_code)]
112 pub async fn into_client<Chain: ChainWithRuntimeVersion>(
113 self,
114 ) -> anyhow::Result<$crate::cli::DefaultClient<Chain>> {
115 let chain_runtime_version = self
116 .[<$chain_prefix _runtime_version>]
117 .into_runtime_version(Chain::RUNTIME_VERSION)?;
118 Ok(relay_substrate_client::new(relay_substrate_client::ConnectionParams {
119 uri: self.[<$chain_prefix _uri>],
120 chain_runtime_version,
121 })
122 .await
123 )
124 }
125 }
126 }
127 };
128}
129
130#[macro_export]
132macro_rules! declare_chain_signing_params_cli_schema {
133 ($chain:ident, $chain_prefix:ident) => {
134 bp_runtime::paste::item! {
135 #[doc = $chain " signing params."]
136 #[derive(Debug, PartialEq, Eq, Clone, Parser)]
137 pub struct [<$chain SigningParams>] {
138 #[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."]
139 #[arg(long)]
140 pub [<$chain_prefix _signer>]: Option<String>,
141 #[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."]
142 #[arg(long)]
143 pub [<$chain_prefix _signer_password>]: Option<String>,
144
145 #[doc = "Path to the file, that contains SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer option."]
146 #[arg(long)]
147 pub [<$chain_prefix _signer_file>]: Option<std::path::PathBuf>,
148 #[doc = "Path to the file, that password for the SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer_password option."]
149 #[arg(long)]
150 pub [<$chain_prefix _signer_password_file>]: Option<std::path::PathBuf>,
151
152 #[doc = "Transactions mortality period, in blocks. MUST be a power of two in [4; 65536] range. MAY NOT be larger than `BlockHashCount` parameter of the chain system module."]
153 #[arg(long)]
154 pub [<$chain_prefix _transactions_mortality>]: Option<u32>,
155 }
156
157 impl [<$chain SigningParams>] {
158 #[allow(dead_code)]
160 pub fn transactions_mortality(&self) -> anyhow::Result<Option<u32>> {
161 self.[<$chain_prefix _transactions_mortality>]
162 .map(|transactions_mortality| {
163 if !(4..=65536).contains(&transactions_mortality)
164 || !transactions_mortality.is_power_of_two()
165 {
166 Err(anyhow::format_err!(
167 "Transactions mortality {} is not a power of two in a [4; 65536] range",
168 transactions_mortality,
169 ))
170 } else {
171 Ok(transactions_mortality)
172 }
173 })
174 .transpose()
175 }
176
177 #[allow(dead_code)]
179 pub fn to_keypair<Chain: ChainWithTransactions>(&self) -> anyhow::Result<AccountKeyPairOf<Chain>> {
180 let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) {
181 (Some(suri), _) => suri.to_owned(),
182 (None, Some(suri_file)) => std::fs::read_to_string(suri_file)
183 .map_err(|err| anyhow::format_err!(
184 "Failed to read SURI from file {:?}: {}",
185 suri_file,
186 err,
187 ))?,
188 (None, None) => return Err(anyhow::format_err!(
189 "One of options must be specified: '{}' or '{}'",
190 stringify!([<$chain_prefix _signer>]),
191 stringify!([<$chain_prefix _signer_file>]),
192 )),
193 };
194
195 let suri_password = match (
196 self.[<$chain_prefix _signer_password>].as_ref(),
197 self.[<$chain_prefix _signer_password_file>].as_ref(),
198 ) {
199 (Some(suri_password), _) => Some(suri_password.to_owned()),
200 (None, Some(suri_password_file)) => std::fs::read_to_string(suri_password_file)
201 .map(Some)
202 .map_err(|err| anyhow::format_err!(
203 "Failed to read SURI password from file {:?}: {}",
204 suri_password_file,
205 err,
206 ))?,
207 _ => None,
208 };
209
210 use sp_core::crypto::Pair;
211
212 AccountKeyPairOf::<Chain>::from_string(
213 &suri,
214 suri_password.as_deref()
215 ).map_err(|e| anyhow::format_err!("{:?}", e))
216 }
217
218 #[allow(dead_code)]
220 pub fn transaction_params<Chain: ChainWithTransactions>(
221 &self,
222 ) -> anyhow::Result<TransactionParams<AccountKeyPairOf<Chain>>> {
223 Ok(TransactionParams {
224 mortality: self.transactions_mortality()?,
225 signer: self.to_keypair::<Chain>()?,
226 })
227 }
228 }
229 }
230 };
231}
232
233#[macro_export]
236macro_rules! declare_chain_cli_schema {
237 ($chain:ident, $chain_prefix:ident) => {
238 $crate::declare_chain_runtime_version_params_cli_schema!($chain, $chain_prefix);
239 $crate::declare_chain_connection_params_cli_schema!($chain, $chain_prefix);
240 $crate::declare_chain_signing_params_cli_schema!($chain, $chain_prefix);
241 };
242}
243
244declare_chain_cli_schema!(Source, source);
245declare_chain_cli_schema!(Target, target);