From 8b2da794735bb7563cf29d3bbc7952c5d433d856 Mon Sep 17 00:00:00 2001 From: Hugo Trentesaux <hugo@trentesaux.fr> Date: Wed, 7 Jun 2023 15:11:04 +0200 Subject: [PATCH] move account commands to subcommand --- README.md | 8 ++-- doc/example.md | 4 +- src/cache.rs | 3 +- src/commands/account.rs | 64 ++++++++++++++++++++++++++++++ src/commands/collective.rs | 1 - src/commands/expire.rs | 3 +- src/commands/identity.rs | 13 +++---- src/commands/net_test.rs | 18 ++++----- src/commands/smith.rs | 1 - src/commands/sudo.rs | 9 +---- src/commands/transfer.rs | 28 +++++++------- src/keys.rs | 20 +++++----- src/main.rs | 79 +++----------------------------------- 13 files changed, 112 insertions(+), 139 deletions(-) diff --git a/README.md b/README.md index d888442..8b08205 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,11 @@ If using a different runtime, update the metadata for the client to compile: Send 10 ÄžD from Alice to Ferdie: - cargo run -- --url ws://localhost:9944 --secret //Alice transfer 1000 5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL + cargo run -- --url ws://localhost:9944 --secret //Alice account transfer 1000 5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL List certifications and session keys that will expire within one month: - cargo run -- --url wss://gdev.p2p.legal:443/ws expire --blocks 432000 + cargo run -- --url wss://gdev.p2p.legal:443/ws smith expire --blocks 432000 For more examples see [in the example file](./doc/example.md). @@ -55,8 +55,8 @@ Now the command `duniter-rpc` will open an SSH session and a bridge to your RPC When your node is ready to forge blocks, rotate keys and go online: ```bash -gcli --secret "my secret phrase" update-keys -gcli --secret "my secret phrase" go-online +gcli --secret "my secret phrase" smith update-keys +gcli --secret "my secret phrase" smith go-online ``` ### Keys diff --git a/doc/example.md b/doc/example.md index d66db76..5a1816a 100644 --- a/doc/example.md +++ b/doc/example.md @@ -42,11 +42,9 @@ gcli --network gdev config save # get duniter current block gcli current-block # get balance of test1 account -gcli --address 5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa balance +gcli --address 5FeggKqw2AbnGZF9Y9WPM2QTgzENS3Hit94Ewgmzdg5a3LNa account balance # get information about test1 identity (needs indexer) 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 ``` ## Indexer commands diff --git a/src/cache.rs b/src/cache.rs index 36d8c72..bec5bae 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,7 +1,6 @@ use crate::indexer::*; use crate::*; -use anyhow::{anyhow, Result}; use std::collections::{hash_map, HashMap}; pub struct IdentityCache { @@ -23,7 +22,7 @@ impl IdentityCache { &mut self, identity_id: u32, parent_hash: sp_core::H256, - ) -> Result<String> { + ) -> anyhow::Result<String> { Ok(match self.identities.entry(identity_id) { hash_map::Entry::Occupied(entry) => entry.get().clone(), hash_map::Entry::Vacant(entry) => entry diff --git a/src/commands/account.rs b/src/commands/account.rs index 101e088..0d5add6 100644 --- a/src/commands/account.rs +++ b/src/commands/account.rs @@ -1,5 +1,69 @@ use crate::*; +/// define account subcommands +#[derive(Clone, Default, Debug, clap::Parser)] +pub enum Subcommand { + /// Fetch account balance + #[default] + Balance, + /// Transfer some currency to an account + Transfer { + /// Amount to transfer + amount: u64, + /// Destination address + dest: AccountId, + /// Prevent from going below account existential deposit + #[clap(short = 'k', long = "keep-alive")] + keep_alive: bool, + }, + /// Transfer the same amount for each space-separated address. + /// If an address appears mutiple times, it will get multiple times the same amount + TransferMultiple { + /// Amount given to each destination address + amount: u64, + /// List of target addresses + dests: Vec<AccountId>, + }, +} + +/// handle account 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::Balance => { + data = data + .build_address() + .fetch_system_properties() + .await?; + commands::account::get_balance(data).await? + } + Subcommand::Transfer { + amount, + dest, + keep_alive, + } => { + data = data.build_client().await?; + commands::transfer::transfer( + &data, + amount, + dest, + keep_alive, + ) + .await?; + } + Subcommand::TransferMultiple { amount, dests } => { + data = data.build_client().await?; + commands::transfer::transfer_multiple(&data, + amount, + dests, + ) + .await?; + } + }; + + Ok(()) +} + /// get balance pub async fn get_balance(data: Data) -> Result<(), anyhow::Error> { let account_id = data.address(); diff --git a/src/commands/collective.rs b/src/commands/collective.rs index 698be58..92c8da4 100644 --- a/src/commands/collective.rs +++ b/src/commands/collective.rs @@ -1,7 +1,6 @@ use crate::*; use anyhow::Result; -use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; /// define technical committee subcommands #[derive(Clone, Default, Debug, clap::Parser)] diff --git a/src/commands/expire.rs b/src/commands/expire.rs index 96004ed..7fe2518 100644 --- a/src/commands/expire.rs +++ b/src/commands/expire.rs @@ -1,10 +1,9 @@ use crate::*; -use anyhow::Result; use futures::join; use std::collections::BTreeMap; -pub async fn monitor_expirations(data: &Data, blocks: u32, sessions: u32) -> Result<()> { +pub async fn monitor_expirations(data: &Data, blocks: u32, sessions: u32) -> anyhow::Result<()> { let client = data.client(); let indexer = data.indexer.clone(); diff --git a/src/commands/identity.rs b/src/commands/identity.rs index 32b5fc8..81a08ba 100644 --- a/src/commands/identity.rs +++ b/src/commands/identity.rs @@ -5,7 +5,6 @@ use crate::runtime::runtime_types::common_runtime::entities::IdtyData; use crate::runtime::runtime_types::pallet_identity::types::*; use crate::runtime::runtime_types::sp_core::sr25519::Signature; use crate::runtime::runtime_types::sp_runtime::MultiSignature; -use sp_core::{crypto::AccountId32, sr25519::Pair}; use std::str::FromStr; /// define identity subcommands @@ -84,7 +83,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<( /// get identity pub async fn get_identity( data: &Data, - mut account_id: Option<AccountId32>, + mut account_id: Option<AccountId>, mut identity_id: Option<u32>, mut username: Option<String>, ) -> Result<(), anyhow::Error> { @@ -107,7 +106,7 @@ pub async fn get_identity( ))?; if let Some(pubkey) = indexer.pubkey_by_username(username).await? { // convert string to accountid - let fetched_account_id = AccountId32::from_str(&pubkey).map_err(|e| anyhow!(e))?; + let fetched_account_id = AccountId::from_str(&pubkey).map_err(|e| anyhow!(e))?; // in the future, also ask indexer the identity index identity_id = get_idty_index_by_account_id(client, &fetched_account_id).await?; account_id = Some(fetched_account_id); @@ -127,7 +126,7 @@ pub async fn get_identity( "Account id: {}", account_id .as_ref() - .map_or(String::new(), AccountId32::to_string) + .map_or(String::new(), AccountId::to_string) ); println!( "Identity id: {}", @@ -145,7 +144,7 @@ pub async fn get_identity( /// get identity index by account id pub async fn get_idty_index_by_account_id( client: &Client, - account_id: &AccountId32, + account_id: &AccountId, ) -> Result<Option<u32>, anyhow::Error> { Ok(client .storage() @@ -160,7 +159,7 @@ pub async fn get_idty_index_by_account_id( pub async fn get_identity_by_index( client: &Client, idty_index: u32, -) -> Result<Option<IdtyValue<u32, AccountId32, IdtyData>>, anyhow::Error> { +) -> Result<Option<IdtyValue<u32, AccountId, IdtyData>>, anyhow::Error> { Ok(client .storage() .fetch(&runtime::storage().identity().identities(idty_index), None) @@ -171,7 +170,7 @@ pub async fn get_identity_by_index( pub async fn create_identity( pair: Pair, client: &Client, - target: AccountId32, + target: AccountId, ) -> Result<(), subxt::Error> { let progress = client .tx() diff --git a/src/commands/net_test.rs b/src/commands/net_test.rs index 228469c..e1c3c38 100644 --- a/src/commands/net_test.rs +++ b/src/commands/net_test.rs @@ -1,18 +1,14 @@ use crate::*; -use anyhow::{anyhow, Result}; -use sp_core::{crypto::AccountId32, sr25519::Pair, DeriveJunction, Pair as _}; -use subxt::{ - ext::sp_runtime::MultiAddress, - tx::{BaseExtrinsicParamsBuilder, PairSigner}, -}; +use sp_core::DeriveJunction; +use subxt::ext::sp_runtime::MultiAddress; pub async fn repart( pair: Pair, client: &Client, target: u32, actual_repart: Option<u32>, -) -> Result<()> { +) -> anyhow::Result<()> { let mut pairs = Vec::new(); for i in actual_repart.unwrap_or_default()..target { let pair_i = pair @@ -48,9 +44,9 @@ pub async fn repart( Ok(()) } -pub async fn spam_roll(pair: Pair, client: &Client, actual_repart: usize) -> Result<()> { +pub async fn spam_roll(pair: Pair, client: &Client, actual_repart: usize) -> anyhow::Result<()> { let mut nonce = 0; - let mut pairs = Vec::<(PairSigner<Runtime, Pair>, AccountId32)>::with_capacity(actual_repart); + let mut pairs = Vec::<(PairSigner<Runtime, Pair>, AccountId)>::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) @@ -63,7 +59,7 @@ pub async fn spam_roll(pair: Pair, client: &Client, actual_repart: usize) -> Res loop { let mut watchers = Vec::with_capacity(actual_repart); for i in 0..(actual_repart - 1) { - let dest: AccountId32 = pairs[i + 1].1.clone(); + let dest: AccountId = pairs[i + 1].1.clone(); let watcher = client .tx() .create_signed_with_nonce( @@ -78,7 +74,7 @@ pub async fn spam_roll(pair: Pair, client: &Client, actual_repart: usize) -> Res log::info!("send 1 cent from //{} to //{}", i, i + 1); watchers.push(watcher); } - let dest: AccountId32 = pairs[0].1.clone(); + let dest: AccountId = pairs[0].1.clone(); let watcher = client .tx() .sign_and_submit_then_watch( diff --git a/src/commands/smith.rs b/src/commands/smith.rs index a05f677..49670f1 100644 --- a/src/commands/smith.rs +++ b/src/commands/smith.rs @@ -1,7 +1,6 @@ use crate::*; use std::ops::Deref; -use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; type SessionKeys = [u8; 128]; diff --git a/src/commands/sudo.rs b/src/commands/sudo.rs index 301ce6c..7182fdf 100644 --- a/src/commands/sudo.rs +++ b/src/commands/sudo.rs @@ -1,14 +1,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, - new_key: AccountId32, -) -> Result<(), subxt::Error> { +pub async fn set_key(pair: Pair, client: &Client, new_key: AccountId) -> Result<(), subxt::Error> { let progress = client .tx() .sign_and_submit_then_watch( diff --git a/src/commands/transfer.rs b/src/commands/transfer.rs index c0ebc08..ca6ab53 100644 --- a/src/commands/transfer.rs +++ b/src/commands/transfer.rs @@ -1,36 +1,33 @@ use crate::*; -use sp_core::{crypto::AccountId32, sr25519::Pair}; -use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; - #[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; +/// transfer balance to target pub async fn transfer( - pair: Pair, - client: &Client, + data: &Data, balance: u64, - dest: AccountId32, + dest: AccountId, keep_alive: bool, ) -> Result<(), subxt::Error> { let progress = if keep_alive { - client + data.client() .tx() .sign_and_submit_then_watch( &runtime::tx().balances().transfer(dest.into(), balance), - &PairSigner::new(pair), + &PairSigner::new(data.keypair()), BaseExtrinsicParamsBuilder::new(), ) .await? } else { - client + data.client() .tx() .sign_and_submit_then_watch( &runtime::tx() .balances() .transfer_keep_alive(dest.into(), balance), - &PairSigner::new(pair), + &PairSigner::new(data.keypair()), BaseExtrinsicParamsBuilder::new(), ) .await? @@ -44,11 +41,11 @@ pub async fn transfer( Ok(()) } +/// transfer balance to multiple target pub async fn transfer_multiple( - pair: Pair, - client: &Client, + data: &Data, amount: u64, - dests: Vec<AccountId32>, + dests: Vec<AccountId>, ) -> Result<(), subxt::Error> { // build the list of transactions from the destination accounts let transactions: Vec<Call> = dests @@ -62,11 +59,12 @@ pub async fn transfer_multiple( .collect(); // wrap these calls in a batch call - let progress = client + let progress = data + .client() .tx() .sign_and_submit_then_watch( &runtime::tx().utility().batch(transactions), - &PairSigner::new(pair.clone()), + &PairSigner::new(data.keypair()), BaseExtrinsicParamsBuilder::new(), ) .await?; diff --git a/src/keys.rs b/src/keys.rs index fa75289..8df0eba 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -1,9 +1,7 @@ -use anyhow::{anyhow, Result}; +use crate::*; + use clap::builder::OsStr; -use sp_core::{ - crypto::{AccountId32, Pair as _, Ss58Codec}, - sr25519::Pair, -}; +use sp_core::crypto::Ss58Codec; use std::str::FromStr; #[allow(dead_code)] @@ -50,7 +48,7 @@ impl From<SecretFormat> for OsStr { } } -pub fn pair_from_str(secret_format: SecretFormat, secret: &str) -> Result<Pair> { +pub fn pair_from_str(secret_format: SecretFormat, secret: &str) -> anyhow::Result<Pair> { match secret_format { SecretFormat::Seed => { let mut seed = [0; 32]; @@ -81,12 +79,12 @@ pub fn get_keys( address: &Option<String>, secret: &Option<String>, needed_keys: NeededKeys, -) -> Result<(Option<AccountId32>, Option<Pair>)> { +) -> anyhow::Result<(Option<AccountId>, Option<Pair>)> { // Get from args let mut account_id = match (address, secret) { (Some(address), Some(secret)) => { let pair = pair_from_str(secret_format, secret)?; - let address = AccountId32::from_string(address) + let address = AccountId::from_string(address) .map_err(|_| anyhow!("Invalid address {}", address))?; assert_eq!( address, @@ -99,9 +97,9 @@ pub fn get_keys( let pair = pair_from_str(secret_format, secret)?; return Ok((Some(pair.public().into()), Some(pair))); } - (Some(address), None) => Some( - AccountId32::from_str(address).map_err(|_| anyhow!("Invalid address {}", address))?, - ), + (Some(address), None) => { + Some(AccountId::from_str(address).map_err(|_| anyhow!("Invalid address {}", address))?) + } (None, None) => None, }; diff --git a/src/main.rs b/src/main.rs index 410f2a6..6074dc4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -157,11 +157,6 @@ impl From<anyhow::Error> for GcliError { #[derive(Clone, Debug, clap::Subcommand, Default)] pub enum Subcommand { - /// Fetch account balance - #[default] - Balance, - /// Show address corresponding to given arguments - ShowAddress, #[clap(hide = true)] Repart { // Number of transactions per block to target @@ -174,27 +169,14 @@ pub enum Subcommand { SpamRoll { actual_repart: usize, }, - Transfer { - /// Amount to transfer - amount: u64, - /// Destination address - dest: AccountId, - /// Prevent from going below account existential deposit - #[clap(short = 'k', long = "keep-alive")] - keep_alive: bool, - }, - /// Transfer the same amount for each space-separated address. - /// If an address appears mutiple times, it will get multiple times the same amount - TransferMultiple { - /// Amount given to each destination address - amount: u64, - /// List of target addresses - dests: Vec<AccountId>, - }, /// Get information about runtime RuntimeInfo, + #[default] /// Check current block CurrentBlock, + /// Account subcommands + #[clap(subcommand)] + Account(commands::account::Subcommand), /// Identity subcommands #[clap(subcommand)] Identity(commands::identity::Subcommand), @@ -228,19 +210,6 @@ async fn main() -> Result<(), GcliError> { let mut data = Data::new(args.clone()); match args.subcommand { - Subcommand::Balance => { - data = data - .build_address() - .build_client() - .await? - .fetch_system_properties() - .await?; - commands::account::get_balance(data).await? - } - Subcommand::ShowAddress => { - data = data.build_address(); - println!("address is: {}", data.address()); - } Subcommand::Repart { target, actual_repart, @@ -277,45 +246,6 @@ async fn main() -> Result<(), GcliError> { ) .await? } - Subcommand::Transfer { - amount, - dest, - keep_alive, - } => { - data = data.build_client().await?; - commands::transfer::transfer( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - data.client(), - amount, - dest, - keep_alive, - ) - .await?; - } - Subcommand::TransferMultiple { amount, dests } => { - data = data.build_client().await?; - commands::transfer::transfer_multiple( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - data.client(), - amount, - dests, - ) - .await?; - } Subcommand::RuntimeInfo => { data = data.build_client().await?.fetch_system_properties().await?; commands::runtime::runtime_info(data).await; @@ -332,6 +262,7 @@ async fn main() -> Result<(), GcliError> { .unwrap() ); } + Subcommand::Account(subcommand) => commands::account::handle_command(data, subcommand).await?, Subcommand::Identity(subcommand) => commands::identity::handle_command(data, subcommand).await?, Subcommand::Smith(subcommand) => commands::smith::handle_command(data, subcommand).await?, Subcommand::Tech(subcommand) => commands::collective::handle_command(data, subcommand).await?, -- GitLab