diff --git a/doc/example.md b/doc/example.md index 369d19ba1b0a0a5e2c95d2945fe936e8da31a919..d66db7671b8f1121e6813403626763a780c90331 100644 --- a/doc/example.md +++ b/doc/example.md @@ -42,9 +42,9 @@ gcli --network gdev config save # get duniter current block gcli current-block # get balance of test1 account -gcli --address 5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa get-balance +gcli --address 5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa balance # get information about test1 identity (needs indexer) -gcli identity --username test1 +gcli identity get --username test1 # show address of given secret gcli --secret "pipe paddle ketchup filter life ice feel embody glide quantum ride usage"//2 show-address ``` diff --git a/src/commands/collective.rs b/src/commands/collective.rs index d9645be0ae3b9ec69093548bb6007639188ec916..ed5fb88158b7018f5f25cea8f2c7aa22d55f47c0 100644 --- a/src/commands/collective.rs +++ b/src/commands/collective.rs @@ -4,6 +4,7 @@ use anyhow::Result; use sp_core::{sr25519::Pair, H256}; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; +/// list technical committee members pub async fn technical_committee_members(data: &Data) -> Result<()> { let client = data.client(); let indexer = data.indexer.clone(); @@ -50,6 +51,7 @@ pub async fn technical_committee_members(data: &Data) -> Result<()> { Ok(()) } +/// list technical committee proposals // TODO: // * better formatting (format pubkeys to SS58 and add usernames) // * display proposals indices @@ -79,6 +81,7 @@ pub async fn technical_committee_proposals(client: &Client) -> Result<()> { Ok(()) } +/// submit vote to technical committee pub async fn technical_committee_vote( pair: Pair, client: &Client, diff --git a/src/commands/identity.rs b/src/commands/identity.rs index efa5c4370824da72b0ead6f7f1c9262908f471df..46df5fe11ce9c46c70fb9bfa6d1943d0092e431e 100644 --- a/src/commands/identity.rs +++ b/src/commands/identity.rs @@ -8,6 +8,71 @@ use crate::runtime::runtime_types::sp_runtime::MultiSignature; use sp_core::{crypto::AccountId32, sr25519::Pair}; use std::str::FromStr; +/// define identity subcommands +#[derive(Clone, Default, Debug, clap::Parser)] +pub enum Subcommand { + /// show identity + #[default] + Show, + /// Fetch identity + Get { + #[clap(short = 'a', long = "address")] + account_id: Option<AccountId>, + #[clap(short = 'i', long = "identity")] + identity_id: Option<u32>, + #[clap(short = 'u', long = "username")] + username: Option<String>, + }, + /// Create and certify an identity + /// + /// Caller must be member, and the target account must exist. + Create { target: AccountId }, + /// Confirm an identity + /// + /// To be called by the certified not-yet-member account, to become member. + Confirm { name: String }, + /// Revoke an identity immediately + Revoke, +} + +/// handle identity commands +pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<()> { + let mut data = data.build_client().await?.build_indexer().await?; + match command { + Subcommand::Show => {} + Subcommand::Get { + ref account_id, + identity_id, + ref username, + } => { + commands::identity::get_identity( + &data, + account_id.clone(), + identity_id, + username.clone(), + ) + .await? + } + Subcommand::Create { target } => { + data = data.build_keypair(); + commands::identity::create_identity(data.keypair(), data.client(), target).await?; + } + Subcommand::Confirm { name } => { + data = data.build_keypair(); + commands::identity::confirm_identity(data.keypair(), data.client(), name).await?; + } + Subcommand::Revoke => { + data = data.build_keypair().fetch_idty_index().await?; + commands::identity::revoke_identity(data).await?; + } + }; + + Ok(()) +} + +// ====================== + +/// get identity pub async fn get_identity( data: &Data, mut account_id: Option<AccountId32>, @@ -63,11 +128,12 @@ pub async fn get_identity( if let (Some(indexer), Some(account_id), None) = (&indexer, &account_id, &username) { username = indexer.username_by_pubkey(&account_id.to_string()).await?; } - println!("Username: {}", username.unwrap_or_default()); + println!("Username: {}", username.unwrap_or("<no indexer>".to_string())); Ok(()) } +/// get identity index by account id pub async fn get_idty_index_by_account_id( client: &Client, account_id: &AccountId32, @@ -81,6 +147,7 @@ pub async fn get_idty_index_by_account_id( .await?) } +/// get identityt value by index pub async fn get_identity_by_index( client: &Client, idty_index: u32, @@ -91,6 +158,7 @@ pub async fn get_identity_by_index( .await?) } +/// created identity pub async fn create_identity( pair: Pair, client: &Client, @@ -112,6 +180,7 @@ pub async fn create_identity( Ok(()) } +/// confirm identity pub async fn confirm_identity( pair: Pair, client: &Client, diff --git a/src/commands/sudo.rs b/src/commands/sudo.rs index a0c2d9a81804c9b2fd1b0be67352a0882d669bdf..301ce6cdc98203a0a315938de0cc292903c42bb6 100644 --- a/src/commands/sudo.rs +++ b/src/commands/sudo.rs @@ -3,6 +3,7 @@ use crate::*; use sp_core::{crypto::AccountId32, sr25519::Pair}; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; +/// set sudo key pub async fn set_key( pair: Pair, client: &Client, diff --git a/src/indexer.rs b/src/indexer.rs index ab376b892a0d536d16c6a72896159a1794593186..25473cbc76a79f2854252270b8739cb805eb9c98 100644 --- a/src/indexer.rs +++ b/src/indexer.rs @@ -108,32 +108,22 @@ impl Indexer { } } +/// define indexer subcommands #[derive(Clone, Default, Debug, clap::Parser)] pub enum Subcommand { #[default] - /// Show indexer endpoint - ShowEndpoint, - /// Fetch latest indexed block - LatestBlock, /// Check that indexer and node are on the same network (same genesis hash) Check, + /// Fetch latest indexed block + LatestBlock, } +/// handle indexer commands pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<()> { // build indexer because it is needed for all subcommands let mut data = data.build_indexer().await?; // match subcommand match command { - Subcommand::ShowEndpoint => { - println!("indexer endpoint: {}", data.indexer().gql_url); - } - Subcommand::LatestBlock => { - println!( - "latest block indexed by {} is: {}", - data.cfg.indexer_endpoint, - data.indexer().fetch_latest_block().await? - ); - } Subcommand::Check => { data = data.build_client().await?; if data.genesis_hash == data.indexer_genesis_hash { @@ -153,6 +143,13 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<( ); } } + Subcommand::LatestBlock => { + println!( + "latest block indexed by {} is: {}", + data.cfg.indexer_endpoint, + data.indexer().fetch_latest_block().await? + ); + } }; Ok(()) diff --git a/src/main.rs b/src/main.rs index bb19e550f7e9491572dd34a7e0f3db0949b7dbd4..c9000b25c5472054f801db56100dec652ea2090c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -157,36 +157,13 @@ impl From<anyhow::Error> for GcliError { #[derive(Clone, Debug, clap::Subcommand, Default)] pub enum Subcommand { - /// Fetch account balance TODO also oneshot account + /// Fetch account balance #[default] - GetBalance, + Balance, /// Show address corresponding to given arguments ShowAddress, - /// Fetch identity - Identity { - #[clap(short = 'p', long = "pubkey")] - account_id: Option<AccountId>, - #[clap(short = 'i', long = "identity")] - identity_id: Option<u32>, - #[clap(short = 'u', long = "username")] - username: Option<String>, - }, - /// Create and certify an identity - /// - /// Caller must be member, and the target account must exist. - CreateIdentity { - target: AccountId, - }, - /// Confirm an identity - /// - /// To be called by the certified not-yet-member account, to become member. - ConfirmIdentity { - name: String, - }, /// Generate a revocation document for the provided account GenRevocDoc, - /// Revoke an identity immediately - RevokeIdentity, /// List upcoming expirations that require an action Expire { /// Show certs that expire within less than this number of blocks @@ -255,6 +232,9 @@ pub enum Subcommand { RuntimeInfo, /// Check current block CurrentBlock, + /// Indentity subcommands + #[clap(subcommand)] + Identity(commands::identity::Subcommand), /// Oneshot account subcommands #[clap(subcommand)] Oneshot(commands::oneshot::Subcommand), @@ -279,7 +259,7 @@ async fn main() -> Result<(), GcliError> { let mut data = Data::new(args.clone()); match args.subcommand { - Subcommand::GetBalance => { + Subcommand::Balance => { data = data .build_address() .build_client() @@ -292,41 +272,10 @@ async fn main() -> Result<(), GcliError> { data = data.build_address(); println!("address is: {}", data.address()); } - Subcommand::CreateIdentity { target } => { - data = data.build_client().await?.build_keypair(); - commands::identity::create_identity(data.keypair(), data.client(), target).await?; - } - Subcommand::ConfirmIdentity { name } => { - data = data.build_client().await?.build_keypair(); - commands::identity::confirm_identity(data.keypair(), data.client(), name).await?; - } - Subcommand::RevokeIdentity => { - data = data - .build_client() - .await? - .build_keypair() - .fetch_idty_index() - .await?; - commands::identity::revoke_identity(data).await?; - } Subcommand::Expire { blocks, sessions } => { data = data.build_client().await?; commands::expire::monitor_expirations(&data, blocks, sessions).await? } - Subcommand::Identity { - ref account_id, - identity_id, - ref username, - } => { - data = data.build_client().await?; - commands::identity::get_identity( - &data, - account_id.clone(), - identity_id, - username.clone(), - ) - .await? - } Subcommand::GenRevocDoc => { data = data .build_client() @@ -520,6 +469,7 @@ async fn main() -> Result<(), GcliError> { .unwrap() ); } + Subcommand::Identity(subcommand) => commands::identity::handle_command(data, subcommand).await?, Subcommand::Oneshot(subcommand) => { commands::oneshot::handle_command(data, subcommand).await? }