Skip to content

Commit 4012015

Browse files
authored
remove custom CLI parser functions (#935)
1 parent 59292f9 commit 4012015

File tree

9 files changed

+113
-97
lines changed

9 files changed

+113
-97
lines changed

toolkit/cli/commands/src/address_association_signatures.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,28 @@ use parity_scale_codec::Encode;
77
use serde::Serialize;
88
use serde_json::json;
99
use sidechain_domain::*;
10-
use std::str::FromStr;
1110

1211
/// Generates Ed25519 signatures to associate Cardano stake addresses with Partner Chain addresses.
1312
/// Generic over address type to support different Partner Chain implementations.
1413
#[derive(Clone, Debug, Parser)]
1514
#[command(author, version, about, long_about = None)]
1615
pub struct AddressAssociationSignaturesCmd<
17-
PartnerchainAddress: Clone + Sync + Send + FromStr + 'static,
16+
PartnerchainAddress: Clone + Sync + Send + FromStrStdErr + 'static,
1817
> {
1918
/// Genesis UTXO that identifies the target Partner Chain
2019
#[arg(long)]
2120
pub genesis_utxo: UtxoId,
2221
/// Partner Chain address to be associated with the Cardano stake address
23-
#[arg(long, value_parser=parse_pc_address::<PartnerchainAddress>)]
22+
#[arg(long)]
2423
pub partnerchain_address: PartnerchainAddress,
2524
/// Ed25519 signing key for the Cardano stake address. Its public key will be associated with partnerchain_address.
2625
#[arg(long)]
2726
pub signing_key: StakeSigningKeyParam,
2827
}
2928

30-
/// Parses Partner Chain address from string format.
31-
fn parse_pc_address<T: FromStr>(s: &str) -> Result<T, String> {
32-
T::from_str(s).map_err(|_| "Failed to parse Partner Chain address".to_owned())
33-
}
34-
3529
impl<PartnerchainAddress> AddressAssociationSignaturesCmd<PartnerchainAddress>
3630
where
37-
PartnerchainAddress: Serialize + Clone + Sync + Send + FromStr + Encode + 'static,
31+
PartnerchainAddress: Serialize + Clone + Sync + Send + FromStrStdErr + Encode + 'static,
3832
{
3933
/// Generates signature and outputs JSON to stdout.
4034
pub fn execute(&self) -> anyhow::Result<()> {
@@ -67,6 +61,7 @@ mod test {
6761
use hex::FromHexError;
6862
use hex_literal::hex;
6963
use sidechain_domain::byte_string::ByteString;
64+
use std::str::FromStr;
7065

7166
#[derive(Clone, Encode, Serialize)]
7267
struct AccountId32(pub [u8; 32]);

toolkit/cli/commands/src/block_producer_metadata_signatures.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ use serde::de::DeserializeOwned;
66
use serde_json::{self, json};
77
use sidechain_domain::*;
88
use sp_block_producer_metadata::MetadataSignedMessage;
9-
use std::{io::BufReader, str::FromStr};
9+
use std::io::BufReader;
1010
use time_source::{SystemTimeSource, TimeSource};
1111

1212
/// Generates ECDSA signatures for block producer metadata using cross-chain keys.
1313
#[derive(Clone, Debug, clap::Subcommand)]
1414
#[command(author, version, about, long_about = None)]
15-
pub enum BlockProducerMetadataSignatureCmd<AccountId: FromStr + Clone + Send + Sync + 'static> {
15+
pub enum BlockProducerMetadataSignatureCmd<AccountId: FromStrStdErr + Clone + Send + Sync + 'static>
16+
{
1617
/// Generates signature for the `upsert_metadata` extrinsic
1718
Upsert {
1819
/// Genesis UTXO that uniquely identifies the target Partner Chain
@@ -28,7 +29,7 @@ pub enum BlockProducerMetadataSignatureCmd<AccountId: FromStr + Clone + Send + S
2829
#[arg(long, default_value = "3600")]
2930
ttl: u64,
3031
/// Partner Chain Account that will be used to upsert the metadata and will own it on-chain
31-
#[arg(long, value_parser=parse_partner_chain_accounts::<AccountId>)]
32+
#[arg(long)]
3233
partner_chain_account: AccountId,
3334
},
3435
/// Generates signature for the `delete_metadata` extrinsic
@@ -44,16 +45,12 @@ pub enum BlockProducerMetadataSignatureCmd<AccountId: FromStr + Clone + Send + S
4445
ttl: u64,
4546
/// Partner Chain Account that will be used to delete the metadata.
4647
/// It must be the account that owns it on-chain.
47-
#[arg(long, value_parser=parse_partner_chain_accounts::<AccountId>)]
48+
#[arg(long)]
4849
partner_chain_account: AccountId,
4950
},
5051
}
5152

52-
fn parse_partner_chain_accounts<T: FromStr>(s: &str) -> Result<T, String> {
53-
T::from_str(s).map_err(|_| "Failed to parse Account ID".to_owned())
54-
}
55-
56-
impl<AccountId: Encode + FromStr + Clone + Send + Sync + 'static>
53+
impl<AccountId: Encode + FromStrStdErr + Clone + Send + Sync + 'static>
5754
BlockProducerMetadataSignatureCmd<AccountId>
5855
{
5956
/// Reads metadata file, generates signatures, and outputs JSON to stdout.

toolkit/cli/node-commands/src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub use partner_chains_cli::PartnerChainRuntime;
1616
use partner_chains_smart_contracts_commands::SmartContractsCmd;
1717
use sc_cli::{CliConfiguration, SharedParams, SubstrateCli};
1818
use sc_service::TaskManager;
19-
use sidechain_domain::{McEpochNumber, ScEpochNumber, StakePoolPublicKey};
19+
use sidechain_domain::*;
2020
use sp_api::ProvideRuntimeApi;
2121
use sp_blockchain::HeaderBackend;
2222
use sp_runtime::AccountId32;
@@ -30,7 +30,6 @@ use sp_session_validator_management_query::commands::*;
3030
#[allow(deprecated)]
3131
use sp_sidechain::{GetGenesisUtxo, GetSidechainStatus};
3232
use std::future::Future;
33-
use std::str::FromStr;
3433
use std::sync::Arc;
3534

3635
#[derive(Debug, Clone, Parser)]
@@ -104,7 +103,7 @@ static REGISTRATION_STATUS_AFTER_HELP: once_cell::sync::Lazy<String> = once_cell
104103
/// Entry point for all Partner Chains specific subcommand.
105104
pub enum PartnerChainsSubcommand<
106105
RuntimeBindings: PartnerChainRuntime + Send + Sync,
107-
PartnerchainAddress: Clone + Sync + Send + FromStr + 'static,
106+
PartnerchainAddress: Clone + Sync + Send + FromStrStdErr + 'static,
108107
> {
109108
/// Returns sidechain parameters.
110109
/// Requires --chain parameter that results in loading a properly configured chain spec.
@@ -181,7 +180,7 @@ where
181180
CommitteeMember::AuthorityId: Decode + Encode + AsRef<[u8]> + Send + Sync + 'static,
182181
CommitteeMember::AuthorityKeys: Decode + Encode,
183182
BlockProducerMetadata: DeserializeOwned + Encode + Send + Sync,
184-
PartnerchainAddress: Serialize + Clone + Sync + Send + FromStr + Encode + 'static,
183+
PartnerchainAddress: Serialize + Clone + Sync + Send + FromStrStdErr + Encode + 'static,
185184
{
186185
match cmd {
187186
PartnerChainsSubcommand::SidechainParams(cmd) => {

toolkit/sidechain/domain/src/lib.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,76 @@ pub struct PermissionedCandidateData {
12651265
pub keys: CandidateKeys,
12661266
}
12671267

1268+
/// Parses public keys formatted as PARTNER_CHAINS_KEY:AURA_KEY:GRANDPA_KEY or PARTNER_CHAINS_KEY,KEY_ID_1:KEY_1,...,KEY_ID_N:KEY_N
1269+
#[cfg(feature = "std")]
1270+
impl FromStr for PermissionedCandidateData {
1271+
type Err = alloc::boxed::Box<dyn core::error::Error + Send + Sync>;
1272+
1273+
fn from_str(partner_chain_public_keys: &str) -> Result<Self, Self::Err> {
1274+
fn is_legacy_format(line: &str) -> bool {
1275+
line.contains(':') && !line.contains(',')
1276+
}
1277+
1278+
fn parse_legacy_format(
1279+
line: &str,
1280+
) -> Result<
1281+
PermissionedCandidateData,
1282+
alloc::boxed::Box<dyn core::error::Error + Send + Sync>,
1283+
> {
1284+
let line = line.replace("0x", "");
1285+
if let [sidechain_pub_key, aura_pub_key, grandpa_pub_key] =
1286+
line.split(":").collect::<Vec<_>>()[..]
1287+
{
1288+
Ok(PermissionedCandidateData {
1289+
sidechain_public_key: SidechainPublicKey(
1290+
hex::decode(sidechain_pub_key).map_err(|e| e.to_string())?,
1291+
),
1292+
keys: CandidateKeys(vec![
1293+
AuraPublicKey(hex::decode(aura_pub_key).map_err(|e| e.to_string())?).into(),
1294+
GrandpaPublicKey(hex::decode(grandpa_pub_key).map_err(|e| e.to_string())?)
1295+
.into(),
1296+
]),
1297+
})
1298+
} else {
1299+
Err(format!("Failed to parse partner chain public keys (legacy) from '{line}'")
1300+
.into())
1301+
}
1302+
}
1303+
1304+
fn parse_generic_format(
1305+
line: &str,
1306+
) -> Result<
1307+
PermissionedCandidateData,
1308+
alloc::boxed::Box<dyn core::error::Error + Send + Sync>,
1309+
> {
1310+
let mut columns = line.split(",");
1311+
if let Some(partner_chains_key) = columns.next() {
1312+
let partner_chains_key = SidechainPublicKey(
1313+
hex::decode(partner_chains_key.trim_start_matches("0x"))
1314+
.map_err(|e| e.to_string())?,
1315+
);
1316+
let mut keys = vec![];
1317+
for column in columns {
1318+
let key = CandidateKey::from_str(column)?;
1319+
keys.push(key);
1320+
}
1321+
Ok(PermissionedCandidateData {
1322+
sidechain_public_key: partner_chains_key,
1323+
keys: CandidateKeys(keys),
1324+
})
1325+
} else {
1326+
Err("Failed to parse partner chain public keys (generic) from '{line}'.".into())
1327+
}
1328+
}
1329+
1330+
if is_legacy_format(&partner_chain_public_keys) {
1331+
parse_legacy_format(&partner_chain_public_keys)
1332+
} else {
1333+
parse_generic_format(&partner_chain_public_keys)
1334+
}
1335+
}
1336+
}
1337+
12681338
/// Cardano SPO registration. This is a stripped-down version of [RegistrationData].
12691339
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
12701340
pub struct CandidateRegistration {
@@ -1446,3 +1516,13 @@ pub struct PoolDelegation {
14461516
/// Delegated amount for each delegator of the stake pool
14471517
pub delegators: BTreeMap<DelegatorKey, DelegatorStakeAmount>,
14481518
}
1519+
1520+
/// [FromStr] trait with [FromStr::Err] fixed to a type compatible with `clap`'s `value_parser` macro.
1521+
pub trait FromStrStdErr:
1522+
FromStr<Err: Into<alloc::boxed::Box<(dyn core::error::Error + Send + Sync + 'static)>>>
1523+
{
1524+
}
1525+
impl<T: FromStr<Err: Into<alloc::boxed::Box<(dyn core::error::Error + Send + Sync + 'static)>>>>
1526+
FromStrStdErr for T
1527+
{
1528+
}

toolkit/smart-contracts/commands/src/assemble_tx.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use sidechain_domain::{TransactionCbor, VKeyWitnessCbor};
88
pub struct AssembleAndSubmitCmd {
99
#[clap(flatten)]
1010
common_arguments: crate::CommonArguments,
11-
#[arg(long, value_parser = TransactionCbor::decode_hex)]
11+
#[arg(long)]
1212
/// Hex-encoded transaction CBOR (with or without 0x prefix)
1313
transaction: TransactionCbor,
14-
#[arg(short, long, num_args = 1.., value_delimiter = ' ', value_parser = VKeyWitnessCbor::decode_hex)]
14+
#[arg(short, long, num_args = 1.., value_delimiter = ' ')]
1515
/// Witnesses of the transaction. Each witness is a hex-encoded CBOR (with or without 0x prefix), encoding a 1 element list containing a 2 elements list [[public_key, signature]].
1616
witnesses: Vec<VKeyWitnessCbor>,
1717
}

toolkit/smart-contracts/commands/src/lib.rs

Lines changed: 8 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use partner_chains_cardano_offchain::{
3030
};
3131
use serde::Serialize;
3232
use sidechain_domain::*;
33-
use std::{str::FromStr, time::Duration};
33+
use std::time::Duration;
3434

3535
pub mod assemble_tx;
3636
pub mod d_parameter;
@@ -180,60 +180,10 @@ impl From<GenesisUtxo> for UtxoId {
180180
}
181181
}
182182

183-
/// Parses public keys formatted as PARTNER_CHAINS_KEY:AURA_KEY:GRANDPA_KEY or PARTNER_CHAINS_KEY,KEY_ID_1:KEY_1,...,KEY_ID_N:KEY_N
184-
pub(crate) fn parse_partnerchain_public_keys(
185-
partner_chain_public_keys: &str,
186-
) -> CmdResult<PermissionedCandidateData> {
187-
fn is_legacy_format(line: &str) -> bool {
188-
line.contains(':') && !line.contains(',')
189-
}
190-
191-
fn parse_legacy_format(line: &str) -> CmdResult<PermissionedCandidateData> {
192-
let line = line.replace("0x", "");
193-
if let [sidechain_pub_key, aura_pub_key, grandpa_pub_key] =
194-
line.split(":").collect::<Vec<_>>()[..]
195-
{
196-
Ok(PermissionedCandidateData {
197-
sidechain_public_key: SidechainPublicKey(hex::decode(sidechain_pub_key)?),
198-
keys: CandidateKeys(vec![
199-
AuraPublicKey(hex::decode(aura_pub_key)?).into(),
200-
GrandpaPublicKey(hex::decode(grandpa_pub_key)?).into(),
201-
]),
202-
})
203-
} else {
204-
Err(format!("Failed to parse partner chain public keys (legacy) from '{line}'").into())
205-
}
206-
}
207-
208-
fn parse_generic_format(line: &str) -> CmdResult<PermissionedCandidateData> {
209-
let mut columns = line.split(",");
210-
if let Some(partner_chains_key) = columns.next() {
211-
let partner_chains_key =
212-
SidechainPublicKey(hex::decode(partner_chains_key.trim_start_matches("0x"))?);
213-
let mut keys = vec![];
214-
for column in columns {
215-
let key = CandidateKey::from_str(column)?;
216-
keys.push(key);
217-
}
218-
Ok(PermissionedCandidateData {
219-
sidechain_public_key: partner_chains_key,
220-
keys: CandidateKeys(keys),
221-
})
222-
} else {
223-
Err("Failed to parse partner chain public keys (generic) from '{line}'.".into())
224-
}
225-
}
226-
227-
if is_legacy_format(&partner_chain_public_keys) {
228-
parse_legacy_format(&partner_chain_public_keys)
229-
} else {
230-
parse_generic_format(&partner_chain_public_keys)
231-
}
232-
}
233-
234183
#[cfg(test)]
235184
mod test {
236-
use crate::parse_partnerchain_public_keys;
185+
use std::str::FromStr;
186+
237187
use hex_literal::hex;
238188
use sidechain_domain::{
239189
AuraPublicKey, CandidateKey, CandidateKeys, GrandpaPublicKey, PermissionedCandidateData,
@@ -243,32 +193,32 @@ mod test {
243193
#[test]
244194
fn parse_partnerchain_public_keys_legacy_format_without_0x_prefix() {
245195
let input = "039799ff93d184146deacaa455dade51b13ed16f23cdad11d1ad6af20103391180:e85534c93315d60f808568d1dce5cb9e8ba6ed0b204209c5cc8f3bec56c10b73:cdf3e5b33f53c8b541bbaea383225c45654f24de38c585725f3cff25b2802f55";
246-
assert_eq!(parse_partnerchain_public_keys(input).unwrap(), expected_public_keys())
196+
assert_eq!(PermissionedCandidateData::from_str(input).unwrap(), expected_public_keys())
247197
}
248198

249199
#[test]
250200
fn parse_partnerchain_public_keys_legacy_format_with_0x_prefix() {
251201
let input = "0x039799ff93d184146deacaa455dade51b13ed16f23cdad11d1ad6af20103391180:0xe85534c93315d60f808568d1dce5cb9e8ba6ed0b204209c5cc8f3bec56c10b73:0xcdf3e5b33f53c8b541bbaea383225c45654f24de38c585725f3cff25b2802f55";
252-
assert_eq!(parse_partnerchain_public_keys(input).unwrap(), expected_public_keys())
202+
assert_eq!(PermissionedCandidateData::from_str(input).unwrap(), expected_public_keys())
253203
}
254204

255205
#[test]
256206
fn parse_partnerchain_public_keys_generic_format_without_0x_prefix() {
257207
let input = "039799ff93d184146deacaa455dade51b13ed16f23cdad11d1ad6af20103391180,aura:e85534c93315d60f808568d1dce5cb9e8ba6ed0b204209c5cc8f3bec56c10b73,gran:cdf3e5b33f53c8b541bbaea383225c45654f24de38c585725f3cff25b2802f55";
258-
assert_eq!(parse_partnerchain_public_keys(input).unwrap(), expected_public_keys())
208+
assert_eq!(PermissionedCandidateData::from_str(input).unwrap(), expected_public_keys())
259209
}
260210

261211
#[test]
262212
fn parse_partnerchain_public_keys_generic_format_with_0x_prefix() {
263213
let input = "0x039799ff93d184146deacaa455dade51b13ed16f23cdad11d1ad6af20103391180,aura:0xe85534c93315d60f808568d1dce5cb9e8ba6ed0b204209c5cc8f3bec56c10b73,gran:0xcdf3e5b33f53c8b541bbaea383225c45654f24de38c585725f3cff25b2802f55";
264-
assert_eq!(parse_partnerchain_public_keys(input).unwrap(), expected_public_keys())
214+
assert_eq!(PermissionedCandidateData::from_str(input).unwrap(), expected_public_keys())
265215
}
266216

267217
#[test]
268218
fn key_id_can_contain_0x() {
269219
let input = "0x0102,0xxd:0xffff";
270220
assert_eq!(
271-
parse_partnerchain_public_keys(input).unwrap(),
221+
PermissionedCandidateData::from_str(input).unwrap(),
272222
PermissionedCandidateData {
273223
sidechain_public_key: SidechainPublicKey([1, 2].to_vec()),
274224
keys: CandidateKeys(vec![CandidateKey {

toolkit/smart-contracts/commands/src/permissioned_candidates.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use crate::{GenesisUtxo, PaymentFilePath, option_to_json, parse_partnerchain_public_keys};
1+
use crate::{GenesisUtxo, PaymentFilePath, option_to_json};
22
use partner_chains_cardano_offchain::permissioned_candidates::upsert_permissioned_candidates;
33
use std::fs::read_to_string;
4+
use std::str::FromStr;
45

56
#[derive(Clone, Debug, clap::Parser)]
67
/// Command for upserting the permissioned candidates on the main chain
@@ -10,7 +11,7 @@ pub struct UpsertPermissionedCandidatesCmd {
1011
#[arg(long)]
1112
/// Path to the file containing the permissioned candidates data.
1213
/// Each line represents one permissioned candidate in format PARTNER_CHAINS_KEY,KEY_1_ID:KEY_1_BYTES,...,KEY_N_ID:KEY_N_BYTES.
13-
/// Legacy format of PARTNER_CHAINS_KEY:AURA_PUB_KEY:GRANDPA_PUB_KEY is supported, each line is eqivalent to `PARTNER_CHAINS_KEY,aura:AURA_PUB_KEY,gran:GRANDPA_PUB_KEY`.
14+
/// Legacy format of PARTNER_CHAINS_KEY:AURA_PUB_KEY:GRANDPA_PUB_KEY is supported, each line is equivalent to `PARTNER_CHAINS_KEY,aura:AURA_PUB_KEY,gran:GRANDPA_PUB_KEY`.
1415
permissioned_candidates_file: String,
1516
#[clap(flatten)]
1617
/// Path to the payment key file
@@ -37,9 +38,10 @@ impl UpsertPermissionedCandidatesCmd {
3738
if line.is_empty() {
3839
continue;
3940
}
40-
let permissioned_candidate = parse_partnerchain_public_keys(line).map_err(|e| {
41-
format!("Failed to parse permissioned candidate: '{}', because of {}", line, e)
42-
})?;
41+
let permissioned_candidate =
42+
sidechain_domain::PermissionedCandidateData::from_str(line).map_err(|e| {
43+
format!("Failed to parse permissioned candidate: '{}', because of {}", line, e)
44+
})?;
4345
permissioned_candidates.push(permissioned_candidate);
4446
}
4547

toolkit/smart-contracts/commands/src/register.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use crate::{
2-
GenesisUtxo, PaymentFilePath, option_to_json, parse_partnerchain_public_keys,
3-
transaction_submitted_json,
4-
};
1+
use crate::{GenesisUtxo, PaymentFilePath, option_to_json, transaction_submitted_json};
52
use partner_chains_cardano_offchain::register::{run_deregister, run_register};
63
use sidechain_domain::{
74
AdaBasedStaking, CandidateRegistration, MainchainSignature, PermissionedCandidateData,
@@ -22,11 +19,7 @@ pub struct RegisterCmd {
2219
#[clap(flatten)]
2320
/// Path to the payment key file
2421
payment_key_file: PaymentFilePath,
25-
#[arg(
26-
long,
27-
alias = "sidechain-public-keys",
28-
value_parser = parse_partnerchain_public_keys
29-
)]
22+
#[arg(long, alias = "sidechain-public-keys")]
3023
/// Candidate public keys in format PARTNER_CHAINS_KEY_HEX:AURA_KEY_HEX:GRANDPA_KEY_HEX or PARTNER_CHAINS_KEY_HEX,KEY_ID_1:KEY_1_HEX,...,KEY_ID_N:KEY_N_HEX
3124
partner_chain_public_keys: PermissionedCandidateData,
3225
#[arg(long, alias = "sidechain-signature")]

0 commit comments

Comments
 (0)