diff --git a/sn_client/src/api.rs b/sn_client/src/api.rs index 6359147e57..0d78dea614 100644 --- a/sn_client/src/api.rs +++ b/sn_client/src/api.rs @@ -945,13 +945,14 @@ impl Client { .await } - /// This is a similar funcation to `get_spend_from_network` to get a spend from network. - /// Just using different `RetryStrategy` to improve the performance during crawling. - pub async fn crawl_spend_from_network(&self, address: SpendAddress) -> Result { + /// Try to peek a spend by just fetching one copy of it. + /// Useful to help decide whether a re-put is necessary, or a spend exists already + /// (client side verification). + pub async fn peek_a_spend(&self, address: SpendAddress) -> Result { self.try_fetch_spend_from_network( address, GetRecordCfg { - get_quorum: Quorum::Majority, + get_quorum: Quorum::One, retry_strategy: None, target_record: None, expected_holders: Default::default(), @@ -960,21 +961,26 @@ impl Client { .await } - /// Try to confirm the Genesis spend doesn't present in the network yet. - /// It shall be quick, and any signle returned copy shall consider as error. - pub async fn is_genesis_spend_present(&self) -> bool { - let genesis_addr = SpendAddress::from_unique_pubkey(&GENESIS_SPEND_UNIQUE_KEY); + /// This is a similar funcation to `get_spend_from_network` to get a spend from network. + /// Just using different `RetryStrategy` to improve the performance during crawling. + pub async fn crawl_spend_from_network(&self, address: SpendAddress) -> Result { self.try_fetch_spend_from_network( - genesis_addr, + address, GetRecordCfg { - get_quorum: Quorum::One, + get_quorum: Quorum::Majority, retry_strategy: None, target_record: None, expected_holders: Default::default(), }, ) .await - .is_ok() + } + + /// Try to confirm the Genesis spend doesn't present in the network yet. + /// It shall be quick, and any signle returned copy shall consider as error. + pub async fn is_genesis_spend_present(&self) -> bool { + let genesis_addr = SpendAddress::from_unique_pubkey(&GENESIS_SPEND_UNIQUE_KEY); + self.peek_a_spend(genesis_addr).await.is_ok() } async fn try_fetch_spend_from_network( diff --git a/sn_client/src/uploader/upload.rs b/sn_client/src/uploader/upload.rs index 67bfe06d8e..c3f88d2c80 100644 --- a/sn_client/src/uploader/upload.rs +++ b/sn_client/src/uploader/upload.rs @@ -860,6 +860,10 @@ impl InnerUploader { got_a_previous_force_payment = false; } + let _ = wallet_client + .resend_pending_transaction_blocking_loop() + .await; + let result = match wallet_client.pay_for_records(&cost_map, verify_store).await { Ok((storage_cost, royalty_fees)) => { diff --git a/sn_client/src/wallet.rs b/sn_client/src/wallet.rs index eb9c9f7108..fe8ffc1133 100644 --- a/sn_client/src/wallet.rs +++ b/sn_client/src/wallet.rs @@ -669,6 +669,59 @@ impl WalletClient { } } + /// This is a blocking loop in cas there is pending transaction. + /// It will keeps resending the unconfirmed spend infinitely but explictly. + /// Function will only return on success (all unconfirmed spend uploaded), + /// or user chose to manualy, but safely, terminate the procedure. + pub async fn resend_pending_transaction_blocking_loop(&mut self) -> WalletResult<()> { + if !self.wallet.unconfirmed_spend_requests_exist() { + return Ok(()); + } + // Wallet shall be all clear to progress forward. + while self.wallet.unconfirmed_spend_requests_exist() { + info!("Pre-Unconfirmed transactions dected, sending again after 30 seconds..."); + println!("Pre-Unconfirmed transactions exist, sending again after 30 seconds..."); + println!("It's safe to terminate the work, but do remember to retain the unconfirmed_spend file during wallet update."); + println!("Otherwise, you are in risk to make the wallet corrupted."); + // Longer wait as the network will already in heavy duty situation, + // hence try not to give it further burden with short intervaled re-puts. + sleep(Duration::from_secs(30)).await; + + // Before re-sending, take a peek of un-confirmed spends first + // Helping user having a better view of what's happening. + let unconfirmed_spends_addrs: Vec<_> = self + .wallet + .unconfirmed_spend_requests() + .iter() + .map(|s| SpendAddress::from_unique_pubkey(&s.spend.unique_pubkey)) + .collect(); + for addr in unconfirmed_spends_addrs { + match self.client.peek_a_spend(addr).await { + Ok(_) => { + info!("Unconfirmed Spend {addr:?} is find having at least one copy in the network !"); + println!( + "Unconfirmed Spend {addr:?} is find at least one copy in the network !" + ); + } + Err(err) => { + info!( + "Unconfirmed Spend {addr:?} has no copy in the network yet {err:?} !" + ); + println!( + "Unconfirmed Spend {addr:?} has no copy in the network yet {err:?} !" + ); + } + } + } + + self.resend_pending_transactions(true).await; + } + info!("Wallet is now all cleared, OK to progress further."); + println!("Wallet is now all cleared, OK to progress further."); + println!("DO NOTE TERMINATE THE WORK MANUALLY !"); + Ok(()) + } + /// Try resending failed transactions multiple times until it succeeds or until we reach max attempts. async fn resend_pending_transaction_until_success( &mut self,