Merge branch 'full_scan_fix' into grim

This commit is contained in:
ardocrat
2026-05-13 17:27:15 +03:00
2 changed files with 101 additions and 96 deletions
+21 -18
View File
@@ -14,6 +14,7 @@
//! Generic implementation of owner API functions
use std::cmp;
use uuid::Uuid;
use crate::api_impl::foreign::finalize_tx as foreign_finalize;
@@ -974,26 +975,30 @@ where
w.w2n_client().get_chain_tip()?
};
let start_height = match start_height {
Some(h) => h,
None => 1,
};
let start_height = start_height.unwrap_or_else(|| 1);
let mut info = scan::scan(
// Scan every 10k heights to save data between batches in case of interruption.
let mut total_pmmr_range = None;
for h in (start_height..tip.0).step_by(10001) {
let (mut info, range) = scan::scan(
wallet_inst.clone(),
keychain_mask,
delete_unconfirmed,
None,
h,
cmp::min(tip.0, h + 10000),
start_height,
tip.0,
total_pmmr_range,
status_send_channel,
)?;
info.hash = tip.1;
info.hash = tip.1.clone();
total_pmmr_range = Some(range);
wallet_lock!(wallet_inst, w);
let mut batch = w.batch(keychain_mask)?;
batch.save_last_scanned_block(info)?;
batch.commit()?;
}
Ok(())
}
@@ -1135,25 +1140,23 @@ where
}
}
let start_pmmr_index = if last_scanned_block.start_pmmr_index == 0 {
None
} else {
Some(last_scanned_block.start_pmmr_index)
};
let mut info = scan::scan(
// Scan every 10k heights to save data between batches in case of interruption.
let mut total_pmmr_range = None;
for h in (start_height..tip.0).step_by(10001) {
let (mut info, range) = scan::scan(
wallet_inst.clone(),
keychain_mask,
false,
start_pmmr_index,
h,
cmp::min(tip.0, h + 10000),
start_height,
tip.0,
total_pmmr_range,
status_send_channel,
)?;
info.hash = tip.1.clone();
total_pmmr_range = Some(range);
info.hash = tip.1;
{
wallet_lock!(wallet_inst, w);
let mut batch = w.batch(keychain_mask)?;
batch.save_last_scanned_block(info)?;
+55 -53
View File
@@ -226,40 +226,33 @@ where
Ok(vw)
}
fn collect_chain_outputs<'a, L, C, K>(
wallet_inst: &Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
keychain_mask: &Option<&SecretKey>,
fn collect_chain_outputs<'a, C, K>(
keychain: &K,
client: C,
start_height: u64,
batch_start_index: u64,
batch_end_index: u64,
start_index: u64,
end_index: Option<u64>,
end_index: u64,
status_send_channel: &Option<Sender<StatusMessage>>,
) -> Result<(Vec<OutputResult>, u64), Error>
) -> Result<(Vec<OutputResult>, u64, u8), Error>
where
L: WalletLCProvider<'a, C, K>,
C: NodeClient + 'a,
K: Keychain + 'a,
{
let batch_size = 1000;
let start_index_stat = start_index;
let mut start_index = start_index;
let mut start_index = batch_start_index;
let mut result_vec: Vec<OutputResult> = vec![];
let last_retrieved_return_index;
debug!(
"collect_chain_outputs: start_index {}, end_index {}",
start_index,
end_index.unwrap_or(0)
);
let mut perc_complete;
loop {
let (highest_index, last_retrieved_index, outputs) =
client.get_outputs_by_pmmr_index(start_index, end_index, batch_size)?;
client.get_outputs_by_pmmr_index(start_index, Some(batch_end_index), batch_size)?;
let range = highest_index as f64 - start_index_stat as f64;
let range = end_index as f64 - start_index_stat as f64;
let progress = last_retrieved_index as f64 - start_index_stat as f64;
let perc_complete = cmp::min(((progress / range) * 100.0) as u8, 99);
perc_complete = cmp::min(((progress / range) * 100.0) as u8, 99);
let msg = format!(
"Checking {} outputs, up to index {}. (Highest index: {})",
@@ -278,20 +271,10 @@ where
perc_complete,
)?);
// Save last scanned block info to continue from same index in case of interruption.
{
wallet_lock!(wallet_inst, w);
let mut batch = w.batch(*keychain_mask)?;
batch.save_last_scanned_block(ScannedBlockInfo {
height: start_height,
hash: "".to_string(),
start_pmmr_index: start_index,
last_pmmr_index: last_retrieved_index,
})?;
batch.commit()?;
debug!("collect_chain_outputs: save_last_scanned_block: start_index {}, last_pmmr_index {}", start_index, last_retrieved_index);
}
debug!(
"collect_chain_outputs: start_index {}, last_pmmr_index {}",
start_index, last_retrieved_index
);
if highest_index <= last_retrieved_index {
last_retrieved_return_index = last_retrieved_index;
@@ -299,7 +282,7 @@ where
}
start_index = last_retrieved_index + 1;
}
Ok((result_vec, last_retrieved_return_index))
Ok((result_vec, last_retrieved_return_index, perc_complete))
}
///
@@ -484,11 +467,13 @@ pub fn scan<'a, L, C, K>(
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
keychain_mask: Option<&SecretKey>,
delete_unconfirmed: bool,
start_pmmr_index: Option<u64>,
batch_start_height: u64,
batch_end_height: u64,
start_height: u64,
end_height: u64,
total_pmmr_range: Option<(u64, u64)>,
status_send_channel: &Option<Sender<StatusMessage>>,
) -> Result<ScannedBlockInfo, Error>
) -> Result<(ScannedBlockInfo, (u64, u64)), Error>
where
L: WalletLCProvider<'a, C, K>,
C: NodeClient + 'a,
@@ -496,34 +481,46 @@ where
{
// First, get a definitive list of outputs we own from the chain
if let Some(ref s) = status_send_channel {
if start_height == batch_start_height {
let _ = s.send(StatusMessage::Scanning("Starting UTXO scan".to_owned(), 0));
}
}
let (client, keychain) = {
wallet_lock!(wallet_inst, w);
(w.w2n_client().clone(), w.keychain(keychain_mask)?)
};
// Retrieve the actual PMMR index range we're looking for
let pmmr_range = client.height_range_to_pmmr_indices(start_height, Some(end_height))?;
// Retrieve total PMMR index range we're looking for
let total_pmmr_range = if let Some(total_range) = total_pmmr_range {
total_range
} else {
client.height_range_to_pmmr_indices(start_height, Some(end_height))?
};
let start_pmmr_index = start_pmmr_index.unwrap_or(pmmr_range.0);
let (chain_outs, last_index) = collect_chain_outputs(
&wallet_inst,
&keychain_mask,
// Retrieve current batch PMMR index range
let pmmr_range =
client.height_range_to_pmmr_indices(batch_start_height, Some(batch_end_height))?;
debug!(
"scan: from: {}, to: {}",
batch_start_height, batch_end_height
);
let (chain_outs, last_index, perc_complete) = collect_chain_outputs(
&keychain,
client,
start_height,
start_pmmr_index,
Some(pmmr_range.1),
pmmr_range.0,
pmmr_range.1,
total_pmmr_range.0,
total_pmmr_range.1,
status_send_channel,
)?;
let msg = format!(
"Identified {} wallet_outputs as belonging to this wallet",
chain_outs.len(),
);
if let Some(ref s) = status_send_channel {
let _ = s.send(StatusMessage::Scanning(msg, 99));
let _ = s.send(StatusMessage::Scanning(msg, perc_complete));
}
// Now, get all outputs owned by this wallet (regardless of account)
@@ -561,7 +558,7 @@ where
o.value, o.key_id, m.1.commit,
);
if let Some(ref s) = status_send_channel {
let _ = s.send(StatusMessage::Scanning(msg, 99));
let _ = s.send(StatusMessage::Scanning(msg, perc_complete));
}
o.status = OutputStatus::Unspent;
// any transactions associated with this should be cancelled
@@ -582,7 +579,7 @@ where
m.value, m.key_id, m.commit, m.mmr_index
);
if let Some(ref s) = status_send_channel {
let _ = s.send(StatusMessage::Scanning(msg, 99));
let _ = s.send(StatusMessage::Scanning(msg, perc_complete));
}
restore_missing_output(
wallet_inst.clone(),
@@ -603,7 +600,7 @@ where
o.value, o.key_id, m.1.commit,
);
if let Some(ref s) = status_send_channel {
let _ = s.send(StatusMessage::Scanning(msg, 99));
let _ = s.send(StatusMessage::Scanning(msg, perc_complete));
}
o.status = OutputStatus::Unspent;
cancel_tx_log_entry(wallet_inst.clone(), keychain_mask, &o)?;
@@ -626,7 +623,7 @@ where
o.value, o.key_id, m.commit,
);
if let Some(ref s) = status_send_channel {
let _ = s.send(StatusMessage::Scanning(msg, 99));
let _ = s.send(StatusMessage::Scanning(msg, perc_complete));
}
cancel_tx_log_entry(wallet_inst.clone(), keychain_mask, &o)?;
wallet_lock!(wallet_inst, w);
@@ -647,7 +644,7 @@ where
let label = format!("{}_{}", label_base, acct_index);
let msg = format!("Setting account {} at path {}", label, path);
if let Some(ref s) = status_send_channel {
let _ = s.send(StatusMessage::Scanning(msg, 99));
let _ = s.send(StatusMessage::Scanning(msg, perc_complete));
}
keys::set_acct_path(&mut **w, keychain_mask, &label, path)?;
acct_index += 1;
@@ -662,15 +659,20 @@ where
}
if let Some(ref s) = status_send_channel {
if end_height == batch_end_height {
let _ = s.send(StatusMessage::ScanningComplete(
"Scanning Complete".to_owned(),
));
}
}
Ok(ScannedBlockInfo {
height: end_height,
Ok((
ScannedBlockInfo {
height: batch_end_height,
hash: "".to_owned(),
start_pmmr_index: pmmr_range.0,
last_pmmr_index: last_index,
})
},
total_pmmr_range,
))
}