From 84043f187d79ca4ba6bb42f48264466a57d91611 Mon Sep 17 00:00:00 2001 From: Hugo Trentesaux <hugo@trentesaux.fr> Date: Wed, 31 May 2023 08:58:16 +0200 Subject: [PATCH] refac WIP add tracking progress WIP refac progress tracking WIP generic runtime wip needing runtime name wip refac smith cert --- Cargo.toml | 8 ++ src/cache.rs | 5 +- src/commands/collective.rs | 15 +-- src/commands/expire.rs | 23 ++-- src/commands/identity.rs | 39 ++++--- src/commands/net_test.rs | 11 +- src/commands/oneshot.rs | 30 ++--- src/commands/revocation.rs | 6 +- src/commands/smith.rs | 57 +++------- src/commands/sudo.rs | 4 +- src/commands/transfer.rs | 13 ++- src/keys.rs | 3 +- src/main.rs | 224 +++++++++++++++++++++++++++---------- 13 files changed, 272 insertions(+), 166 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fce1a3e..06ab6f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,11 @@ serde_json = "1.0.94" sp-core = { git = "https://github.com/duniter/substrate", branch = "duniter-substrate-v0.9.32" } subxt = { git = "https://github.com/duniter/subxt.git", branch = "duniter-substrate-v0.9.32" } tokio = { version = "1.26.0", features = ["macros"] } + +# allows to build gcli with different predefined networks +[features] +default = ["dev"] # default feature is "dev" +dev = [] +gdev = [] +gtest = [] +g1 = [] diff --git a/src/cache.rs b/src/cache.rs index b77206d..643f7a4 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,4 +1,5 @@ -use crate::{gdev, indexer::*, Client}; +use crate::indexer::*; +use crate::*; use anyhow::{anyhow, Result}; use std::collections::{hash_map, HashMap}; @@ -31,7 +32,7 @@ impl<'a> IdentityCache<'a> { .client .storage() .fetch( - &gdev::storage().identity().identities(identity_id), + &runtime::storage().identity().identities(identity_id), Some(parent_hash), ) .await? diff --git a/src/commands/collective.rs b/src/commands/collective.rs index 70dd364..a63b55b 100644 --- a/src/commands/collective.rs +++ b/src/commands/collective.rs @@ -1,4 +1,5 @@ -use crate::{gdev, indexer::*, Args, Client}; +use crate::indexer::*; +use crate::*; use anyhow::Result; use sp_core::{sr25519::Pair, H256}; @@ -7,7 +8,7 @@ use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; pub async fn technical_committee_members(client: Client, args: &Args) -> Result<()> { let parent_hash = client .storage() - .fetch(&gdev::storage().system().parent_hash(), None) + .fetch(&runtime::storage().system().parent_hash(), None) .await? .unwrap(); @@ -27,7 +28,7 @@ pub async fn technical_committee_members(client: Client, args: &Args) -> Result< for account_id in client .storage() .fetch( - &gdev::storage().technical_committee().members(), + &runtime::storage().technical_committee().members(), Some(parent_hash), ) .await? @@ -45,7 +46,7 @@ pub async fn technical_committee_members(client: Client, args: &Args) -> Result< client .storage() .fetch( - &gdev::storage().identity().identity_index_of(&account_id), + &runtime::storage().identity().identity_index_of(&account_id), Some(parent_hash), ) .await @@ -66,14 +67,14 @@ pub async fn technical_committee_members(client: Client, args: &Args) -> Result< pub async fn technical_committee_proposals(client: Client) -> Result<()> { let parent_hash = client .storage() - .fetch(&gdev::storage().system().parent_hash(), None) + .fetch(&runtime::storage().system().parent_hash(), None) .await? .unwrap(); let mut proposals_iter = client .storage() .iter( - gdev::storage() + runtime::storage() .technical_committee() .proposal_of(H256::default()), 10, @@ -99,7 +100,7 @@ pub async fn technical_committee_vote( client .tx() .sign_and_submit_then_watch( - &gdev::tx() + &runtime::tx() .technical_committee() .vote(proposal_hash, proposal_index, vote), &PairSigner::new(pair), diff --git a/src/commands/expire.rs b/src/commands/expire.rs index a23a530..f749f89 100644 --- a/src/commands/expire.rs +++ b/src/commands/expire.rs @@ -1,4 +1,5 @@ -use crate::{cache, gdev, indexer::*, Args, Client}; +use crate::indexer::*; +use crate::*; use anyhow::Result; use futures::join; @@ -16,11 +17,11 @@ pub async fn monitor_expirations( let parent_hash = client .storage() - .fetch(&gdev::storage().system().parent_hash(), None) + .fetch(&runtime::storage().system().parent_hash(), None) .await? .unwrap(); - let addr_current_block = gdev::storage().system().number(); - let addr_current_session = gdev::storage().session().current_index(); + let addr_current_block = runtime::storage().system().number(); + let addr_current_session = runtime::storage().session().current_index(); let (current_block, current_session) = join!( client .storage() @@ -51,7 +52,7 @@ pub async fn monitor_expirations( let mut must_rotate_keys_before_iter = client .storage() .iter( - gdev::storage() + runtime::storage() .authority_members() .must_rotate_keys_before(0), 10, @@ -85,7 +86,7 @@ pub async fn monitor_expirations( let mut basic_certs_iter = client .storage() .iter( - gdev::storage().cert().storage_certs_removable_on(0), + runtime::storage().cert().storage_certs_removable_on(0), 10, Some(parent_hash), ) @@ -101,7 +102,9 @@ pub async fn monitor_expirations( let mut smith_certs_iter = client .storage() .iter( - gdev::storage().smith_cert().storage_certs_removable_on(0), + runtime::storage() + .smith_cert() + .storage_certs_removable_on(0), 10, Some(parent_hash), ) @@ -143,7 +146,7 @@ pub async fn monitor_expirations( let mut basic_membership_iter = client .storage() .iter( - gdev::storage().membership().memberships_expire_on(0), + runtime::storage().membership().memberships_expire_on(0), 10, Some(parent_hash), ) @@ -162,7 +165,9 @@ pub async fn monitor_expirations( let mut smith_membership_iter = client .storage() .iter( - gdev::storage().smith_membership().memberships_expire_on(0), + runtime::storage() + .smith_membership() + .memberships_expire_on(0), 10, Some(parent_hash), ) diff --git a/src/commands/identity.rs b/src/commands/identity.rs index e5ee3ca..71562d9 100644 --- a/src/commands/identity.rs +++ b/src/commands/identity.rs @@ -1,7 +1,8 @@ -use crate::{gdev, indexer::*, Args, Client}; +use crate::indexer::*; +use crate::*; -use crate::gdev::runtime_types::common_runtime::entities::IdtyData; -use crate::gdev::runtime_types::pallet_identity::types::*; +use crate::runtime::runtime_types::common_runtime::entities::IdtyData; +use crate::runtime::runtime_types::pallet_identity::types::*; use anyhow::{anyhow, Result}; use sp_core::{crypto::AccountId32, sr25519::Pair}; use std::str::FromStr; @@ -84,7 +85,7 @@ pub async fn get_idty_index_by_account_id( Ok(client .storage() .fetch( - &gdev::storage().identity().identity_index_of(account_id), + &runtime::storage().identity().identity_index_of(account_id), None, ) .await?) @@ -96,32 +97,36 @@ pub async fn get_identity_by_index( ) -> Result<Option<IdtyValue<u32, AccountId32, IdtyData>>> { Ok(client .storage() - .fetch(&gdev::storage().identity().identities(idty_index), None) + .fetch(&runtime::storage().identity().identities(idty_index), None) .await?) } -pub async fn create_identity(pair: Pair, client: Client, target: AccountId32) -> Result<()> { - client +pub async fn create_identity( + pair: Pair, + client: Client, + target: AccountId32, +) -> Result<TxProgress, subxt::Error> { + Ok(client .tx() .sign_and_submit_then_watch( - &gdev::tx().identity().create_identity(target), + &runtime::tx().identity().create_identity(target), &PairSigner::new(pair), BaseExtrinsicParamsBuilder::new(), ) - .await?; - - Ok(()) + .await?) } -pub async fn confirm_identity(pair: Pair, client: Client, name: String) -> Result<()> { - client +pub async fn confirm_identity( + pair: Pair, + client: Client, + name: String, +) -> Result<TxProgress, subxt::Error> { + Ok(client .tx() .sign_and_submit_then_watch( - &gdev::tx().identity().confirm_identity(name), + &runtime::tx().identity().confirm_identity(name), &PairSigner::new(pair), BaseExtrinsicParamsBuilder::new(), ) - .await?; - - Ok(()) + .await?) } diff --git a/src/commands/net_test.rs b/src/commands/net_test.rs index ab2dff3..9a2c73b 100644 --- a/src/commands/net_test.rs +++ b/src/commands/net_test.rs @@ -1,4 +1,4 @@ -use crate::{gdev, Client, GdevConfig}; +use crate::*; use anyhow::{anyhow, Result}; use sp_core::{crypto::AccountId32, sr25519::Pair, DeriveJunction, Pair as _}; @@ -36,7 +36,7 @@ pub async fn repart( if let Some(pair_i_account) = client .storage() .fetch( - &gdev::storage().system().account(&pair_i.public().into()), + &runtime::storage().system().account(&pair_i.public().into()), None, ) .await? @@ -50,8 +50,7 @@ pub async fn repart( pub async fn spam_roll(pair: Pair, client: Client, actual_repart: usize) -> Result<()> { let mut nonce = 0; - let mut pairs = - Vec::<(PairSigner<GdevConfig, Pair>, AccountId32)>::with_capacity(actual_repart); + let mut pairs = Vec::<(PairSigner<Runtime, Pair>, AccountId32)>::with_capacity(actual_repart); for i in 0..actual_repart { let pair_i = pair .derive(std::iter::once(DeriveJunction::hard::<u32>(i as u32)), None) @@ -68,7 +67,7 @@ pub async fn spam_roll(pair: Pair, client: Client, actual_repart: usize) -> Resu let watcher = client .tx() .create_signed_with_nonce( - &gdev::tx().balances().transfer(MultiAddress::Id(dest), 1), + &runtime::tx().balances().transfer(MultiAddress::Id(dest), 1), &pairs[i].0, nonce, BaseExtrinsicParamsBuilder::new(), @@ -83,7 +82,7 @@ pub async fn spam_roll(pair: Pair, client: Client, actual_repart: usize) -> Resu let watcher = client .tx() .sign_and_submit_then_watch( - &gdev::tx().balances().transfer(MultiAddress::Id(dest), 1), + &runtime::tx().balances().transfer(MultiAddress::Id(dest), 1), &pairs[actual_repart - 1].0, BaseExtrinsicParamsBuilder::new(), ) diff --git a/src/commands/oneshot.rs b/src/commands/oneshot.rs index 9933693..c6d4fb9 100644 --- a/src/commands/oneshot.rs +++ b/src/commands/oneshot.rs @@ -1,4 +1,4 @@ -use crate::{gdev, Client}; +use crate::*; use anyhow::Result; use sp_core::{crypto::AccountId32, sr25519::Pair}; @@ -13,7 +13,7 @@ pub async fn create_oneshot_account( client .tx() .sign_and_submit_then_watch( - &gdev::tx() + &runtime::tx() .oneshot_account() .create_oneshot_account(dest.into(), balance), &PairSigner::new(pair), @@ -32,20 +32,22 @@ pub async fn consume_oneshot_account( ) -> Result<()> { let number = client .storage() - .fetch(&gdev::storage().system().number(), None) + .fetch(&runtime::storage().system().number(), None) .await? .unwrap(); client .tx() .sign_and_submit_then_watch( - &gdev::tx().oneshot_account().consume_oneshot_account( + &runtime::tx().oneshot_account().consume_oneshot_account( number, if dest_oneshot { - gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( + runtime::runtime_types::pallet_oneshot_account::types::Account::Oneshot( dest.into(), ) } else { - gdev::runtime_types::pallet_oneshot_account::types::Account::Normal(dest.into()) + runtime::runtime_types::pallet_oneshot_account::types::Account::Normal( + dest.into(), + ) }, ), &PairSigner::new(pair), @@ -67,31 +69,31 @@ pub async fn consume_oneshot_account_with_remaining( ) -> Result<()> { let number = client .storage() - .fetch(&gdev::storage().system().number(), None) + .fetch(&runtime::storage().system().number(), None) .await? .unwrap(); client .tx() .sign_and_submit_then_watch( - &gdev::tx() + &runtime::tx() .oneshot_account() .consume_oneshot_account_with_remaining( number, if dest_oneshot { - gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( + runtime::runtime_types::pallet_oneshot_account::types::Account::Oneshot( dest.into(), ) } else { - gdev::runtime_types::pallet_oneshot_account::types::Account::Normal( + runtime::runtime_types::pallet_oneshot_account::types::Account::Normal( dest.into(), ) }, if remaining_to_oneshot { - gdev::runtime_types::pallet_oneshot_account::types::Account::Oneshot( + runtime::runtime_types::pallet_oneshot_account::types::Account::Oneshot( remaining_to.into(), ) } else { - gdev::runtime_types::pallet_oneshot_account::types::Account::Normal( + runtime::runtime_types::pallet_oneshot_account::types::Account::Normal( remaining_to.into(), ) }, @@ -111,7 +113,9 @@ pub async fn oneshot_account_balance(client: Client, account: AccountId32) -> Re client .storage() .fetch( - &gdev::storage().oneshot_account().oneshot_accounts(&account), + &runtime::storage() + .oneshot_account() + .oneshot_accounts(&account), None ) .await? diff --git a/src/commands/revocation.rs b/src/commands/revocation.rs index b20ef0c..a03dd9c 100644 --- a/src/commands/revocation.rs +++ b/src/commands/revocation.rs @@ -1,4 +1,4 @@ -use crate::{gdev, Client}; +use crate::*; use anyhow::Result; use futures::join; @@ -6,8 +6,8 @@ use sp_core::{sr25519::Pair, Encode, Pair as _}; pub async fn gen_revoc_doc(api: &Client, pair: &Pair) -> Result<()> { let account_id: sp_core::crypto::AccountId32 = pair.public().into(); - let addr_idty_index = gdev::storage().identity().identity_index_of(&account_id); - let addr_block_hash = gdev::storage().system().block_hash(0); + let addr_idty_index = runtime::storage().identity().identity_index_of(&account_id); + let addr_block_hash = runtime::storage().system().block_hash(0); let (idty_index, genesis_hash) = join!( api.storage().fetch(&addr_idty_index, None,), api.storage().fetch(&addr_block_hash, None) diff --git a/src/commands/smith.rs b/src/commands/smith.rs index ca8928f..3bc83d3 100644 --- a/src/commands/smith.rs +++ b/src/commands/smith.rs @@ -22,7 +22,7 @@ pub async fn set_session_keys(pair: Pair, client: Client, session_keys: SessionK client .tx() .sign_and_submit_then_watch( - &gdev::tx() + &runtime::tx() .authority_members() .set_session_keys(session_keys), &PairSigner::new(pair), @@ -42,7 +42,7 @@ pub async fn go_online(pair: Pair, client: Client) -> Result<()> { if client .storage() .fetch( - &gdev::storage() + &runtime::storage() .session() .next_keys(AccountId32::from(pair.public())), None, @@ -56,7 +56,7 @@ pub async fn go_online(pair: Pair, client: Client) -> Result<()> { client .tx() .sign_and_submit_then_watch( - &gdev::tx().authority_members().go_online(), + &runtime::tx().authority_members().go_online(), &PairSigner::new(pair), BaseExtrinsicParamsBuilder::new(), ) @@ -69,7 +69,7 @@ pub async fn go_offline(pair: Pair, client: Client) -> Result<()> { client .tx() .sign_and_submit_then_watch( - &gdev::tx().authority_members().go_offline(), + &runtime::tx().authority_members().go_offline(), &PairSigner::new(pair), BaseExtrinsicParamsBuilder::new(), ) @@ -81,7 +81,7 @@ pub async fn go_offline(pair: Pair, client: Client) -> Result<()> { pub async fn online(client: Client, args: &Args) -> Result<()> { let parent_hash = client .storage() - .fetch(&gdev::storage().system().parent_hash(), None) + .fetch(&runtime::storage().system().parent_hash(), None) .await? .unwrap(); @@ -104,7 +104,7 @@ pub async fn online(client: Client, args: &Args) -> Result<()> { let online_authorities = client .storage() .fetch( - &gdev::storage().authority_members().online_authorities(), + &runtime::storage().authority_members().online_authorities(), Some(parent_hash), ) .await? @@ -124,7 +124,9 @@ pub async fn online(client: Client, args: &Args) -> Result<()> { let incoming_authorities = client .storage() .fetch( - &gdev::storage().authority_members().incoming_authorities(), + &runtime::storage() + .authority_members() + .incoming_authorities(), Some(parent_hash), ) .await? @@ -144,7 +146,9 @@ pub async fn online(client: Client, args: &Args) -> Result<()> { let outgoing_authorities = client .storage() .fetch( - &gdev::storage().authority_members().outgoing_authorities(), + &runtime::storage() + .authority_members() + .outgoing_authorities(), Some(parent_hash), ) .await? @@ -164,41 +168,12 @@ pub async fn online(client: Client, args: &Args) -> Result<()> { Ok(()) } -/// emit a new smith cert from signer's identity to target identity -pub async fn emit_cert(args: Args, receiver: u32) -> Result<()> { - // issuer key - let pair = get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(); - - // connect to client - let client = Client::from_url(&args.url).await.unwrap(); - - // get issuer index - let issuer = commands::identity::get_idty_index_by_account_id( - client.clone(), - &AccountId32::from(pair.public()), - ) - .await? - .ok_or(anyhow!("can not certify if not member"))?; - - // submit and track certification - cert(client, pair, issuer, receiver).await?; - - Ok(()) -} - /// submit a certification and track progress -async fn cert(client: Client, pair: Pair, issuer: u32, receiver: u32) -> Result<()> { +pub async fn cert(client: Client, pair: Pair, issuer: u32, receiver: u32) -> Result<()> { let mut progress = client .tx() .sign_and_submit_then_watch( - &gdev::tx().smith_cert().add_cert(issuer, receiver), + &runtime::tx().smith_cert().add_cert(issuer, receiver), &PairSigner::new(pair), BaseExtrinsicParamsBuilder::new(), ) @@ -222,8 +197,8 @@ async fn cert(client: Client, pair: Pair, issuer: u32, receiver: u32) -> Result< // get the block events and return if ExtrinsicFailed let events = in_block.wait_for_success().await?; // look for the expected event - let new_cert_event = events.find_first::<gdev::smith_cert::events::NewCert>()?; - let renew_cert_event = events.find_first::<gdev::smith_cert::events::RenewedCert>()?; + let new_cert_event = events.find_first::<runtime::smith_cert::events::NewCert>()?; + let renew_cert_event = events.find_first::<runtime::smith_cert::events::RenewedCert>()?; if let Some(event) = new_cert_event { println!("{event:?}"); diff --git a/src/commands/sudo.rs b/src/commands/sudo.rs index 7987a08..728708f 100644 --- a/src/commands/sudo.rs +++ b/src/commands/sudo.rs @@ -1,4 +1,4 @@ -use crate::{gdev, Client}; +use crate::*; use anyhow::Result; use sp_core::{crypto::AccountId32, sr25519::Pair}; @@ -8,7 +8,7 @@ pub async fn set_key(pair: Pair, client: Client, new_key: AccountId32) -> Result client .tx() .sign_and_submit_then_watch( - &gdev::tx().sudo().set_key(new_key.into()), + &runtime::tx().sudo().set_key(new_key.into()), &PairSigner::new(pair), BaseExtrinsicParamsBuilder::new(), ) diff --git a/src/commands/transfer.rs b/src/commands/transfer.rs index 857dbde..b3cefa6 100644 --- a/src/commands/transfer.rs +++ b/src/commands/transfer.rs @@ -1,11 +1,12 @@ -use crate::{gdev, Client}; +use crate::*; use anyhow::Result; use sp_core::{crypto::AccountId32, sr25519::Pair}; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; -type Call = gdev::runtime_types::gdev_runtime::RuntimeCall; -type BalancesCall = gdev::runtime_types::pallet_balances::pallet::Call; +#[cfg(any(feature = "dev", feature = "gdev"))] // find how to get runtime calls +type Call = runtime::runtime_types::gdev_runtime::RuntimeCall; +type BalancesCall = runtime::runtime_types::pallet_balances::pallet::Call; pub async fn transfer( pair: Pair, @@ -18,7 +19,7 @@ pub async fn transfer( client .tx() .sign_and_submit_then_watch( - &gdev::tx().balances().transfer(dest.into(), balance), + &runtime::tx().balances().transfer(dest.into(), balance), &PairSigner::new(pair), BaseExtrinsicParamsBuilder::new(), ) @@ -27,7 +28,7 @@ pub async fn transfer( client .tx() .sign_and_submit_then_watch( - &gdev::tx() + &runtime::tx() .balances() .transfer_keep_alive(dest.into(), balance), &PairSigner::new(pair), @@ -60,7 +61,7 @@ pub async fn transfer_multiple( client .tx() .sign_and_submit_then_watch( - &gdev::tx().utility().batch(transactions), + &runtime::tx().utility().batch(transactions), &PairSigner::new(pair.clone()), BaseExtrinsicParamsBuilder::new(), ) diff --git a/src/keys.rs b/src/keys.rs index 5940d29..fa75289 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -14,11 +14,12 @@ pub enum NeededKeys { Secret, } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] pub enum SecretFormat { /// Raw 32B seed Seed, /// Substrate secret key or BIP39 mnemonic (optionally followed by derivation path) + #[default] Substrate, } diff --git a/src/main.rs b/src/main.rs index f251d64..00dfb47 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,25 +3,28 @@ mod commands; mod indexer; mod keys; -use keys::*; - -use anyhow::Result; use clap::Parser; use codec::Encode; +use keys::*; +use sp_core::sr25519::Pair; use sp_core::H256; +#[cfg(feature = "dev")] #[subxt::subxt(runtime_metadata_path = "res/metadata.scale")] -pub mod gdev {} +pub mod runtime {} -pub type Client = subxt::OnlineClient<GdevConfig>; +pub type Client = subxt::OnlineClient<Runtime>; +pub type AccountId = subxt::ext::sp_runtime::AccountId32; +pub type TxInBlock = subxt::tx::TxInBlock<Runtime, Client>; +pub type TxProgress = subxt::tx::TxProgress<Runtime, Client>; -pub enum GdevConfig {} -impl subxt::config::Config for GdevConfig { +pub enum Runtime {} +impl subxt::config::Config for Runtime { type Index = u32; type BlockNumber = u32; type Hash = sp_core::H256; type Hashing = subxt::ext::sp_runtime::traits::BlakeTwo256; - type AccountId = subxt::ext::sp_runtime::AccountId32; + type AccountId = AccountId; type Address = subxt::ext::sp_runtime::MultiAddress<Self::AccountId, u32>; type Header = subxt::ext::sp_runtime::generic::Header< Self::BlockNumber, @@ -49,7 +52,7 @@ impl From<u64> for Tip { } } -#[derive(Parser, Debug)] +#[derive(Clone, Parser, Debug, Default)] #[clap(author, version, about, long_about = None)] pub struct Args { #[clap(subcommand)] @@ -76,20 +79,144 @@ pub struct Args { url: String, } -#[derive(Debug, clap::Subcommand)] +/// Data of current command +/// can also include fetched information +#[derive(Default)] +pub struct Data { + pub args: Args, + pub client: Option<Client>, + pub address: Option<AccountId>, + pub keypair: Option<Pair>, + pub idty_index: Option<u32>, +} + +// implement helper functions for Data +impl Data { + /// constructor + pub fn new(args: Args) -> Self { + Self { + args, + ..Default::default() + } + } + // --- getters --- + // the "unwrap" should not fail if data is well prepared + pub fn client(&self) -> Client { + self.client.clone().unwrap() + } + pub fn address(&self) -> AccountId { + self.address.clone().unwrap() + } + pub fn keypair(&self) -> Pair { + self.keypair.clone().unwrap() + } + pub fn idty_index(&self) -> u32 { + self.idty_index.clone().unwrap() + } + // --- mutators --- + /// force an address if needed + pub fn build_address(mut self) -> Self { + self.address = Some( + get_keys( + self.args.secret_format, + &self.args.address, + &self.args.secret, + NeededKeys::Public, + ) + .expect("needed") + .0 + .expect("needed"), + ); + self + } + /// force a keypair if needed + pub fn build_keypair(mut self) -> Self { + let (address, keypair) = get_keys( + self.args.secret_format, + &self.args.address, + &self.args.secret, + NeededKeys::Secret, + ) + .expect("needed"); + self.address = address; + self.keypair = keypair; + self + } + /// build a client from url + // TODO get client from a pre-defined list + pub async fn build_client(mut self) -> Self { + self.client = Some(Client::from_url(&self.args.url).await.expect("needed")); + self + } + /// get issuer index + /// needs address and client first + pub async fn fetch_idty_index(mut self) -> Result<Self, anyhow::Error> { + self.idty_index = Some( + commands::identity::get_idty_index_by_account_id( + self.client().clone(), + &self.address(), + ) + .await? + .ok_or(anyhow::anyhow!("needs to be member to use this command"))?, + ); + Ok(self) + } +} + +/// track progress of transaction on the network +/// until it is in block with success or failure +pub async fn track_progress(progress: TxProgress) -> anyhow::Result<()> { + println!("submitted transaction to network, waiting 6 seconds..."); + // wait for in block + let tx = progress.wait_for_in_block().await?; + // print result + println!("{:?}", tx.wait_for_success().await?); + // return empty + Ok(()) +} + +/// custom error type intended to provide more convenient error message to user +#[derive(Debug)] +pub enum GcliError { + /// error coming from subxt + Subxt(subxt::Error), + /// error coming from anyhow + Anyhow(anyhow::Error), +} +impl std::fmt::Display for GcliError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} +impl std::error::Error for GcliError {} +impl From<subxt::Error> for GcliError { + fn from(e: subxt::Error) -> GcliError { + GcliError::Subxt(e) + } +} +impl From<anyhow::Error> for GcliError { + fn from(e: anyhow::Error) -> GcliError { + GcliError::Anyhow(e) + } +} + +#[derive(Clone, Debug, clap::Subcommand, Default)] pub enum Subcommand { - /// Confirm an identity - /// - /// To be called by the certified not-yet-member account, to become member. - ConfirmIdentity { - name: String, - }, + // TODO flodef + #[default] + GetBalance, /// Create and certify an identity /// /// Caller must be member, and the target account must exist. CreateIdentity { target: sp_core::crypto::AccountId32, }, + /// Confirm an identity + /// + /// To be called by the certified not-yet-member account, to become member. + ConfirmIdentity { + name: String, + }, CreateOneshot { balance: u64, dest: sp_core::crypto::AccountId32, @@ -189,54 +316,25 @@ pub enum Subcommand { } #[tokio::main(flavor = "current_thread")] -async fn main() -> Result<()> { +async fn main() -> Result<(), GcliError> { env_logger::init(); let args = Args::parse(); - - /*if let Some(account_id) = &account_id { - println!("Account address: {account_id}"); - }*/ - - /*if let Some(account_id) = &account_id { - let account = client - .storage() - .fetch(&gdev::storage().system().account(account_id), None) - .await? - .expect("Cannot fetch account"); - logs::info!("Account free balance: {}", account.data.free); - }*/ + let mut data = Data::new(args.clone()); match args.subcommand { - Subcommand::ConfirmIdentity { name } => { - commands::identity::confirm_identity( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - name, - ) - .await? - } + Subcommand::GetBalance => {} Subcommand::CreateIdentity { target } => { - commands::identity::create_identity( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - target, - ) - .await? + data = data.build_client().await.build_keypair(); + let progress = + commands::identity::create_identity(data.keypair(), data.client(), target).await?; + track_progress(progress).await? + } + Subcommand::ConfirmIdentity { name } => { + data = data.build_client().await.build_keypair(); + let progress = + commands::identity::confirm_identity(data.keypair(), data.client(), name).await?; + track_progress(progress).await? } Subcommand::CreateOneshot { balance, dest } => { commands::oneshot::create_oneshot_account( @@ -419,7 +517,15 @@ async fn main() -> Result<()> { ) .await? } - Subcommand::SmithCert { to } => commands::smith::emit_cert(args, to).await?, + Subcommand::SmithCert { to } => { + data = data + .build_client() + .await + .build_keypair() + .fetch_idty_index() + .await?; + commands::smith::cert(data.client(), data.keypair(), data.idty_index(), to).await? + } Subcommand::TechMembers => { commands::collective::technical_committee_members( Client::from_url(&args.url).await.unwrap(), -- GitLab