Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions base_layer/wallet/src/storage/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ pub trait WalletBackend: Send + Sync + Clone {
exclude_recovered: bool,
) -> Result<(), WalletStorageError>;

/// Apply a sparse storage schedule to scanned blocks, keeping all recent blocks
/// and progressively sparser checkpoints for older blocks. Blocks containing
/// recovered outputs are always preserved.
fn apply_sparse_scanned_blocks_schedule(&self, tip_height: u64) -> Result<(), WalletStorageError>;

/// Change the passphrase used to encrypt the database
fn change_passphrase(&self, existing: &SafePassword, new: &SafePassword) -> Result<(), WalletStorageError>;

Expand Down Expand Up @@ -337,6 +342,11 @@ where T: WalletBackend + 'static
Ok(())
}

pub fn apply_sparse_scanned_blocks_schedule(&self, tip_height: u64) -> Result<(), WalletStorageError> {
self.db.apply_sparse_scanned_blocks_schedule(tip_height)?;
Ok(())
}

pub fn get_all_burn_proofs(&self) -> Result<Vec<DbBurnProof>, WalletStorageError> {
self.db.fetch_burn_proofs()
}
Expand Down
36 changes: 36 additions & 0 deletions base_layer/wallet/src/storage/sqlite_db/scanned_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,42 @@ impl ScannedBlockSql {
query.execute(conn)?;
Ok(())
}

/// Apply a sparse storage schedule to scanned blocks, keeping:
/// - All blocks within `tip - 720` to `tip`
/// - Every 100th block from `tip - 10,000` to `tip - 720`
/// - Every 1,000th block from `tip - 100,000` to `tip - 10,000`
/// - Every 5,000th block from genesis to `tip - 100,000`
/// Blocks containing recovered outputs (num_outputs > 0) are always preserved.
pub fn apply_sparse_schedule(tip_height: u64, conn: &mut SqliteConnection) -> Result<(), WalletStorageError> {
let blocks = Self::index(conn)?;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is going to be expensive, we should not read the entire table into memory to do this, write a sql query to do this.

for block in blocks {
let height = block.height as u64;
if let Some(outputs) = block.num_outputs {
if outputs > 0 {
continue;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The logic to preserve blocks with recovered outputs (num_outputs > 0) is currently non-functional because the num_outputs field is never populated. The ScannedBlock domain model (defined in service.rs) does not include this field, and the From<ScannedBlock> for ScannedBlockSql implementation explicitly sets it to None. Consequently, all blocks will be pruned according to the sparse schedule regardless of whether they contain recovered outputs, which contradicts the PR description. The ScannedBlock struct and the scanner task need to be updated to track and store the number of recovered outputs per block.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is correct, its an unsed field this logic can be removed.

if !Self::should_keep_at_height(height, tip_height) {
diesel::delete(scanned_blocks::table.filter(scanned_blocks::height.eq(block.height))).execute(conn)?;
}
}
Ok(())
}

/// Determine whether a block at `height` should be kept given the current `tip`.
fn should_keep_at_height(height: u64, tip: u64) -> bool {
let depth = tip.saturating_sub(height);
if depth <= 720 {
true
} else if depth <= 10_000 {
height % 100 == 0
} else if depth <= 100_000 {
height % 1_000 == 0
} else {
height % 5_000 == 0
}
}
}

impl From<ScannedBlock> for ScannedBlockSql {
Expand Down
5 changes: 5 additions & 0 deletions base_layer/wallet/src/storage/sqlite_db/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,11 @@ impl WalletBackend for WalletSqliteDatabase {
ScannedBlockSql::clear_before_height(height, exclude_recovered, &mut conn)
}

fn apply_sparse_scanned_blocks_schedule(&self, tip_height: u64) -> Result<(), WalletStorageError> {
let mut conn = self.database_connection.get_pooled_connection()?;
ScannedBlockSql::apply_sparse_schedule(tip_height, &mut conn)
}

fn change_passphrase(&self, existing: &SafePassword, new: &SafePassword) -> Result<(), WalletStorageError> {
let mut conn = self.database_connection.get_pooled_connection()?;

Expand Down
2 changes: 1 addition & 1 deletion base_layer/wallet/src/utxo_scanner_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use crate::{

pub const LOG_TARGET: &str = "wallet::utxo_scanning";

// Cache 1 days worth of headers.
// Keep all blocks within the most recent window (approximately 1 day of blocks).
pub const SCANNED_BLOCK_CACHE_SIZE: u64 = 720;

pub struct UtxoScannerService<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use crate::{
utxo_scanner_service::{
RECOVERY_KEY,
handle::UtxoScannerEvent,
service::{SCANNED_BLOCK_CACHE_SIZE, ScannedBlock, UtxoScannerResources},
service::{ScannedBlock, UtxoScannerResources},
uxto_scanner_service_builder::UtxoScannerMode,
},
};
Expand Down Expand Up @@ -576,10 +576,9 @@ where
}
// We need to update the last one
if let Some(scanned_block) = prev_scanned_block.clone() {
self.resources.db.clear_scanned_blocks_before_height(
scanned_block.height.saturating_sub(SCANNED_BLOCK_CACHE_SIZE),
true,
)?;
self.resources
.db
.apply_sparse_scanned_blocks_schedule(scanned_block.height)?;
if last_saved_hash != Some(scanned_block.header_hash) {
self.resources.db.save_scanned_block(scanned_block)?;
}
Expand Down