Skip to content

Commit

Permalink
Resync outputs if a transaction got confirmed (#1937)
Browse files Browse the repository at this point in the history
* Resync outputs if a transaction got confirmed

* Use Thibaults suggestion to have cleaner code

* Changelog

* Update changelog
  • Loading branch information
Thoralf-M authored Mar 10, 2023
1 parent 430ccdc commit aa7d22b
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changes/sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nodejs-binding": patch
---

Resync outputs if a transaction got confirmed between syncing outputs and pending transactions to prevent not having unspent outputs afterwards.
6 changes: 6 additions & 0 deletions wallet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Security -->

## 1.0.0-rc.7 - 2023-XX-XX

### Changed

- Resync outputs if a transaction got confirmed between syncing outputs and pending transactions to prevent not having unspent outputs afterwards;

## 1.0.0-rc.6 - 2023-03-09

### Added
Expand Down
54 changes: 33 additions & 21 deletions wallet/src/account/operations/syncing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,41 @@ impl AccountHandle {
return self.balance().await;
}

let addresses_to_sync = self.get_addresses_to_sync(&options).await?;
self.sync_internal(&options).await?;

// Sync transactions after updating account with outputs, so we can use them to check the transaction
// status
if options.sync_pending_transactions {
let confirmed_tx_with_unknown_output = self.sync_pending_transactions().await?;
// Sync again if we don't know the output yet, to prevent having no unspent outputs after syncing
if confirmed_tx_with_unknown_output {
log::debug!("[SYNC] a transaction for which no output is known got confirmed, syncing outputs again");
self.sync_internal(&options).await?;
}
};

let account_balance = self.balance().await?;
// Update last_synced mutex
let time_now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("time went backwards")
.as_millis();
*last_synced = time_now;
log::debug!("[SYNC] finished syncing in {:.2?}", syc_start_time.elapsed());
Ok(account_balance)
}

async fn sync_internal(&self, options: &SyncOptions) -> crate::Result<()> {
log::debug!("[SYNC] sync_internal");

let addresses_to_sync = self.get_addresses_to_sync(options).await?;
log::debug!("[SYNC] addresses_to_sync {}", addresses_to_sync.len());

let (spent_or_not_synced_output_ids, addresses_with_unspent_outputs, outputs_data): (
Vec<OutputId>,
Vec<AddressWithUnspentOutputs>,
Vec<OutputData>,
) = self.request_outputs_recursively(addresses_to_sync, &options).await?;
) = self.request_outputs_recursively(addresses_to_sync, options).await?;

// Request possible spent outputs
log::debug!("[SYNC] spent_or_not_synced_outputs: {spent_or_not_synced_output_ids:?}");
Expand All @@ -64,8 +91,8 @@ impl AccountHandle {
.try_get_outputs_metadata(spent_or_not_synced_output_ids.clone())
.await?;

// Add the output response to the output ids, the output response is optional, because an output could be pruned
// and then we can't get the metadata
// Add the output response to the output ids, the output response is optional, because an output could be
// pruned and then we can't get the metadata
let mut spent_or_unsynced_output_metadata_map: HashMap<OutputId, Option<OutputMetadataDto>> =
spent_or_not_synced_output_ids.into_iter().map(|o| (o, None)).collect();
for output_metadata_response in spent_or_unsynced_output_metadata_responses {
Expand Down Expand Up @@ -102,24 +129,9 @@ impl AccountHandle {
addresses_with_unspent_outputs,
outputs_data,
spent_or_unsynced_output_metadata_map,
&options,
options,
)
.await?;

// Sync transactions after updating account with outputs, so we can use them to check the transaction status
if options.sync_pending_transactions {
self.sync_pending_transactions().await?;
};

let account_balance = self.balance().await?;
// Update last_synced mutex
let time_now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("time went backwards")
.as_millis();
*last_synced = time_now;
log::debug!("[SYNC] finished syncing in {:.2?}", syc_start_time.elapsed());
Ok(account_balance)
.await
}

// First request all outputs directly related to the ed25519 addresses, then for each nft and alias output we got,
Expand Down
14 changes: 11 additions & 3 deletions wallet/src/account/operations/syncing/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@ use crate::account::{
impl AccountHandle {
/// Sync transactions and reattach them if unconfirmed. Returns the transaction with updated metadata and spent
/// output ids that don't need to be locked anymore
pub(crate) async fn sync_pending_transactions(&self) -> crate::Result<()> {
/// Return true if a transaction got confirmed for which we don't have an output already, based on this outputs will
/// be synced again
pub(crate) async fn sync_pending_transactions(&self) -> crate::Result<bool> {
log::debug!("[SYNC] sync pending transactions");
let account = self.read().await;

// only set to true if a transaction got confirmed for which we don't have an output
// (transaction_output.is_none())
let mut confirmed_unknown_output = false;

if account.pending_transactions.is_empty() {
return Ok(());
return Ok(confirmed_unknown_output);
}

let network_id = self.client.get_network_id().await?;
Expand Down Expand Up @@ -101,6 +107,7 @@ impl AccountHandle {
transaction_id,
metadata.block_id
);
confirmed_unknown_output = true;
updated_transaction_and_outputs(
transaction,
Some(BlockId::from_str(&metadata.block_id)?),
Expand All @@ -116,6 +123,7 @@ impl AccountHandle {
if let Ok(included_block) =
self.client.get_included_block(&transaction.payload.id()).await
{
confirmed_unknown_output = true;
updated_transaction_and_outputs(
transaction,
Some(included_block.id()),
Expand Down Expand Up @@ -208,7 +216,7 @@ impl AccountHandle {
self.update_account_with_transactions(updated_transactions, spent_output_ids, output_ids_to_unlock)
.await?;

Ok(())
Ok(confirmed_unknown_output)
}
}

Expand Down

0 comments on commit aa7d22b

Please sign in to comment.