Merge #901: bitcoind: error when trying to rescan past prune height

a3731fa0045c1319d2d0973e1246bd62744ede42 bitcoind: error when trying to rescan past prune height (Antoine Poinsot)

Pull request description:

  Fixes #693.

ACKs for top commit:
  darosior:
    ACK a3731fa0045c1319d2d0973e1246bd62744ede42 -- tested locally, we now need to display the error in the GUI though (#900)

Tree-SHA512: 5c4fd4e2bc6b66f25ab46aa57b240b24b5b630fab250ce11dc8ae22de266a0384a6e65190eee41d2c5beab8aca43ab80b16685396baa16614a8fa988765d77b2
This commit is contained in:
Antoine Poinsot 2024-01-04 18:28:58 +01:00
commit 15b1f0c789
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304

View File

@ -58,6 +58,7 @@ pub enum BitcoindError {
InvalidVersion(u64),
NetworkMismatch(String /*config*/, String /*bitcoind*/),
StartRescan,
RescanPastPruneHeight,
}
impl BitcoindError {
@ -145,6 +146,12 @@ impl std::fmt::Display for BitcoindError {
"Error while triggering the rescan for the bitcoind watchonly wallet."
)
}
BitcoindError::RescanPastPruneHeight => {
write!(
f,
"Trying to rescan the block chain past the prune block height."
)
}
}
}
}
@ -1040,6 +1047,28 @@ impl BitcoinD {
true
}
// Make sure the bitcoind has enough blocks to rescan up to this timestamp.
fn check_prune_height(&self, timestamp: u32) -> Result<(), BitcoindError> {
let chain_info = self.block_chain_info();
let first_block_height = if let Some(h) = chain_info.get("pruneheight") {
h
} else {
// The node isn't pruned
return Ok(());
};
let prune_height: i32 = first_block_height
.as_i64()
.expect("Height must be an integer")
.try_into()
.expect("Height must fit in a i32");
if let Some(tip) = self.tip_before_timestamp(timestamp) {
if tip.height >= prune_height {
return Ok(());
}
}
Err(BitcoindError::RescanPastPruneHeight)
}
pub fn start_rescan(
&self,
desc: &LianaDescriptor,
@ -1073,6 +1102,11 @@ impl BitcoinD {
})
.collect();
// Have we pruned the blocks necessary to rescan down to this timestamp?
// This check is necessary racy since bitcoind may prune these blocks in-between the check
// here and the import below.
self.check_prune_height(timestamp)?;
// Since we don't wait for a response (which would make us block for the entire duration of
// the rescan), we can't know for sure whether it was started successfully. So what we do
// here is retrying a few times (since the noreply_request disables our generalistic retry