Skip to content

Commit

Permalink
Account resyncing (#931)
Browse files Browse the repository at this point in the history
  • Loading branch information
briancorbin authored Nov 14, 2023
1 parent 316aed6 commit 38b2b37
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE accounts DROP COLUMN resyncing;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE accounts ADD COLUMN resyncing BOOLEAN NOT NULL DEFAULT FALSE;

UPDATE accounts SET next_block_index = 0;
UPDATE accounts SET resyncing = TRUE;
32 changes: 31 additions & 1 deletion full-service/src/db/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use crate::{
};
use base64::engine::{general_purpose::STANDARD as BASE64_ENGINE, Engine};
use bip39::Mnemonic;
use diesel::prelude::*;
use diesel::{
dsl::{exists, select},
prelude::*,
};
use mc_account_keys::{
AccountKey, PublicAddress, RootEntropy, RootIdentity, ViewAccountKey, CHANGE_SUBADDRESS_INDEX,
DEFAULT_SUBADDRESS_INDEX,
Expand Down Expand Up @@ -435,6 +438,10 @@ pub trait AccountModel {
fn get_shared_secret(&self, tx_public_key: &RistrettoPublic) -> Result<RistrettoPublic, WalletDbError>;

fn public_address(&self, index: u64) -> Result<PublicAddress, WalletDbError>;

fn update_resyncing(&self, resyncing: bool, conn: Conn) -> Result<(), WalletDbError>;

fn resync_in_progress(conn: Conn) -> Result<bool, WalletDbError>;
}

impl AccountModel for Account {
Expand Down Expand Up @@ -906,6 +913,24 @@ impl AccountModel for Account {
let account_key = self.account_key()?;
Ok(account_key.subaddress(index))
}

fn update_resyncing(&self, resyncing: bool, conn: Conn) -> Result<(), WalletDbError> {
use crate::db::schema::accounts;

diesel::update(accounts::table.filter(accounts::id.eq(&self.id)))
.set(accounts::resyncing.eq(resyncing))
.execute(conn)?;
Ok(())
}

fn resync_in_progress(conn: Conn) -> Result<bool, WalletDbError> {
use crate::db::schema::accounts;

Ok(
select(exists(accounts::table.filter(accounts::resyncing.eq(true))))
.get_result(conn)?,
)
}
}

#[cfg(test)]
Expand Down Expand Up @@ -969,6 +994,7 @@ mod tests {
fog_enabled: false,
view_only: false,
managed_by_hardware_wallet: false,
resyncing: false,
};
assert_eq!(expected_account, acc);

Expand Down Expand Up @@ -1035,6 +1061,7 @@ mod tests {
fog_enabled: false,
view_only: false,
managed_by_hardware_wallet: false,
resyncing: false,
};
assert_eq!(expected_account_secondary, acc_secondary);

Expand Down Expand Up @@ -1201,6 +1228,7 @@ mod tests {
fog_enabled: true,
view_only: false,
managed_by_hardware_wallet: false,
resyncing: false,
};
assert_eq!(expected_account, acc);
}
Expand Down Expand Up @@ -1258,6 +1286,7 @@ mod tests {
fog_enabled: false,
view_only: true,
managed_by_hardware_wallet: false,
resyncing: false,
};
assert_eq!(expected_account, account);
}
Expand Down Expand Up @@ -1317,6 +1346,7 @@ mod tests {
fog_enabled: true,
view_only: true,
managed_by_hardware_wallet: true,
resyncing: false,
};

// Check to make sure the account in the database is correct
Expand Down
1 change: 1 addition & 0 deletions full-service/src/db/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub struct Account {
/// and is required in order to spend funds and generate key images for this
/// account.
pub managed_by_hardware_wallet: bool,
pub resyncing: bool,
}

/// A structure that can be inserted to create a new entity in the `accounts`
Expand Down
1 change: 1 addition & 0 deletions full-service/src/db/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ diesel::table! {
fog_enabled -> Bool,
view_only -> Bool,
managed_by_hardware_wallet -> Bool,
resyncing -> Bool,
}
}

Expand Down
8 changes: 8 additions & 0 deletions full-service/src/json_rpc/v1/api/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ where
{
global_log::info!("Running command {:?}", command);

if service.resync_in_progress().map_err(format_error)? {
let wallet_status = service.get_wallet_status().map_err(format_error)?;

return Err(format_error(format!(
"Resync in progress, please wait until it is completed to perform API calls... ({}% complete)", wallet_status.percent_synced()
)));
}

let response = match command {
JsonCommandRequest::assign_address_for_account {
account_id,
Expand Down
8 changes: 8 additions & 0 deletions full-service/src/json_rpc/v2/api/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ where
{
global_log::info!("Running command {:?}", command);

if service.resync_in_progress().map_err(format_error)? {
let wallet_status = service.get_wallet_status().map_err(format_error)?;

return Err(format_error(format!(
"Resync in progress, please wait until it is completed to perform API calls... ({}% complete)", wallet_status.percent_synced()
)));
}

let response = match command {
JsonCommandRequest::assign_address_for_account {
account_id,
Expand Down
13 changes: 13 additions & 0 deletions full-service/src/service/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ pub trait AccountService {
&self,
account_id: &AccountID
) -> Result<bool, AccountServiceError>;

fn resync_in_progress(&self) -> Result<bool, AccountServiceError>;
}

#[async_trait]
Expand Down Expand Up @@ -714,6 +716,17 @@ where
Ok(true)
})
}

fn resync_in_progress(&self) -> Result<bool, AccountServiceError> {
let mut pooled_conn = match self.get_pooled_conn() {
Ok(pooled_conn) => Ok(pooled_conn),
Err(WalletDbError::WalletFunctionsDisabled) => return Ok(false),
Err(err) => Err(err),
}?;

let conn = pooled_conn.deref_mut();
Ok(Account::resync_in_progress(conn)?)
}
}

fn get_public_fog_address(
Expand Down
6 changes: 6 additions & 0 deletions full-service/src/service/balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ pub struct WalletStatus {
pub account_map: HashMap<AccountID, Account>,
}

impl WalletStatus {
pub fn percent_synced(&self) -> u64 {
self.min_synced_block_index * 100 / self.local_block_height
}
}

/// Trait defining the ways in which the wallet can interact with and manage
/// balances.
#[rustfmt::skip]
Expand Down
7 changes: 7 additions & 0 deletions full-service/src/service/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,14 @@ pub fn sync_all_accounts(

for account in accounts {
// If there are no new blocks for this account, don't do anything.
//
// If the account is currently resyncing, we need to set it to false
// here.
if account.next_block_index as u64 > num_blocks - 1 {
if account.resyncing {
account.update_resyncing(false, conn)?;
}

continue;
}
sync_account_next_chunk(ledger_db, conn, &account.id, logger)?;
Expand Down

0 comments on commit 38b2b37

Please sign in to comment.