From b922aa75f76e2502e5fe5326b52d1fe761951107 Mon Sep 17 00:00:00 2001 From: Uncle Stretch Date: Wed, 22 Jan 2025 15:32:58 +0300 Subject: [PATCH] naive implementation of sending multiple transactions Signed-off-by: Uncle Stretch --- src/action.rs | 1 + src/casper.rs | 10 +++++----- src/components/wallet/accounts.rs | 21 +++++++++++++++++---- src/network/mod.rs | 25 +++++++++++++++++++++++++ src/network/predefined_txs.rs | 20 ++++++++++++++++++-- 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/action.rs b/src/action.rs index 27fcd4d..66754ee 100644 --- a/src/action.rs +++ b/src/action.rs @@ -28,6 +28,7 @@ pub enum Action { UsedAccount(String), NewAccount(String), NewAddressBookRecord(String, String), + SetSender(String, Option), ClosePopup, diff --git a/src/casper.rs b/src/casper.rs index 5d9f682..2447517 100644 --- a/src/casper.rs +++ b/src/casper.rs @@ -2,7 +2,7 @@ use subxt::{ Config, blocks::Block, client::OnlineClient, - config::{DefaultExtrinsicParams, SubstrateConfig}, + config::{DefaultExtrinsicParamsBuilder, DefaultExtrinsicParams, SubstrateConfig}, }; /// Default set of commonly used type by Casper nodes. @@ -26,9 +26,9 @@ pub type CasperAccountId = subxt::utils::AccountId32; pub type CasperBlock = Block>; /// A struct representing the signed extra and additional parameters required to construct a -/// transaction for a polkadot node. +/// transaction for a casper node. pub type CasperExtrinsicParams = DefaultExtrinsicParams; -///// A builder which leads to [`CasperExtrinsicParams`] being constructed. This is what we provide -///// to methods like `sign_and_submit()`. -//pub type CasperExtrinsicParamsBuilder = DefaultExtrinsicParamsBuilder; +/// A builder which leads to [`CasperExtrinsicParams`] being constructed. This is what we provide +/// to methods like `sign_and_submit()`. +pub type CasperExtrinsicParamsBuilder = DefaultExtrinsicParamsBuilder; diff --git a/src/components/wallet/accounts.rs b/src/components/wallet/accounts.rs index 6c123b7..475d1d4 100644 --- a/src/components/wallet/accounts.rs +++ b/src/components/wallet/accounts.rs @@ -75,13 +75,25 @@ impl Accounts { } } - fn set_used_account(&mut self, index: usize) { - if let Some(action_tx) = &self.action_tx { - let _ = action_tx.send(Action::UsedAccount( - self.wallet_keys[index].seed.clone())); + fn set_sender_nonce(&mut self, index: usize) { + if let Some(network_tx) = &self.network_tx { + let used_seed = self.wallet_keys[index].seed.clone(); + let account_id = self.wallet_keys[index].account_id; + let used_nonce = self.balances + .get(&account_id) + .map(|info| info.nonce); + let _ = network_tx.send(Action::SetSender(used_seed, used_nonce)); } } + fn set_used_account(&mut self, index: usize) { + let used_seed = self.wallet_keys[index].seed.clone(); + if let Some(action_tx) = &self.action_tx { + let _ = action_tx.send(Action::UsedAccount(used_seed.clone())); + } + self.set_sender_nonce(index); + } + fn log_event(&mut self, message: String, level: ActionLevel) { if let Some(action_tx) = &self.action_tx { let _ = action_tx.send(Action::WalletLog(message, level)); @@ -419,6 +431,7 @@ impl Component for Accounts { if let Some(index) = self.table_state.selected() { if self.wallet_keys[index].account_id == account_id { self.set_balance_active(index); + self.set_sender_nonce(index); } } } diff --git a/src/network/mod.rs b/src/network/mod.rs index 8e76bdb..2c283d2 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -33,6 +33,7 @@ pub struct Network { stash_to_watch: Option<[u8; 32]>, accounts_to_watch: std::collections::HashSet<[u8; 32]>, transactions_to_watch: Vec>>, + senders: std::collections::HashMap, } impl Network { @@ -50,6 +51,7 @@ impl Network { stash_to_watch: None, accounts_to_watch: Default::default(), transactions_to_watch: Default::default(), + senders: Default::default(), } } @@ -60,6 +62,21 @@ impl Network { } } + fn store_sender_nonce(&mut self, seed: &str, maybe_nonce: Option) { + if let Some(current_nonce) = maybe_nonce { + self.senders + .entry(seed.to_string()) + .and_modify(|stored_nonce| { + if *stored_nonce < current_nonce { + *stored_nonce = current_nonce; + } + }) + .or_insert(current_nonce); + } else { + let _ = self.senders.remove(seed); + } + } + pub async fn handle_network_event(&mut self, io_event: Action) -> Result<()> { match io_event { Action::NewBestHash(hash) => { @@ -141,6 +158,11 @@ impl Network { Action::GetNominatorsNumber => predefined_calls::get_nominators_number(&self.action_tx, &self.online_client_api).await, Action::GetInflation => predefined_calls::get_inflation(&self.action_tx, &self.online_client_api).await, + Action::SetSender(seed, maybe_nonce) => { + self.store_sender_nonce(&seed, maybe_nonce); + Ok(()) + } + Action::GetValidatorLedger(stash) => { self.store_stash_if_possible(stash); predefined_calls::get_validators_ledger(&self.action_tx, &self.online_client_api, &stash).await @@ -183,6 +205,8 @@ impl Network { } } Action::TransferBalance(sender, receiver, amount) => { + let maybe_nonce = self.senders.get_mut(&sender); + let sender: [u8; 32] = hex::decode(sender) .expect("stored seed is valid hex string; qed") .as_slice() @@ -195,6 +219,7 @@ impl Network { &sender, &receiver, &amount, + maybe_nonce, ).await { self.transactions_to_watch.push(tx_progress); } diff --git a/src/network/predefined_txs.rs b/src/network/predefined_txs.rs index 18187ca..5b59d97 100644 --- a/src/network/predefined_txs.rs +++ b/src/network/predefined_txs.rs @@ -6,7 +6,12 @@ use subxt::{ }; use tokio::sync::mpsc::UnboundedSender; -use crate::{action::Action, casper::CasperConfig, casper_network, types::ActionLevel}; +use crate::{ + action::Action, + types::ActionLevel, + casper::{CasperExtrinsicParamsBuilder, CasperConfig}, + casper_network, +}; pub async fn transfer_balance( action_tx: &UnboundedSender, @@ -14,6 +19,7 @@ pub async fn transfer_balance( sender: &[u8; 32], receiver: &[u8; 32], amount: &u128, + mut maybe_nonce: Option<&mut u32>, ) -> Result>> { let receiver_id = subxt::utils::MultiAddress::Id( subxt::utils::AccountId32::from(*receiver) @@ -23,12 +29,22 @@ pub async fn transfer_balance( .balances() .transfer_allow_death(receiver_id, *amount); + let tx_params = match maybe_nonce { + Some(ref mut nonce) => { + **nonce = nonce.saturating_add(1); + CasperExtrinsicParamsBuilder::new() + .nonce(nonce.saturating_sub(1) as u64) + .build() + }, + None => CasperExtrinsicParamsBuilder::new().build(), + }; + let pair = Pair::from_seed(sender); let signer = PairSigner::::new(pair); match api .tx() - .sign_and_submit_then_watch_default(&transfer_tx, &signer) + .sign_and_submit_then_watch(&transfer_tx, &signer, tx_params) .await { Ok(tx_progress) => { action_tx.send(Action::WalletLog(