bitcoin: make get_block_stats fallible
The call to getblockheader may fail, for instance when bitcoind is rolling forward its blocks after a crash. It's a pretty edgy case but instead of crashing restart over and over again.
This commit is contained in:
parent
869779dd94
commit
663fbd2c28
@ -957,11 +957,17 @@ impl BitcoinD {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_block_stats(&self, blockhash: bitcoin::BlockHash) -> BlockStats {
|
||||
let res = self.make_node_request(
|
||||
pub fn get_block_stats(&self, blockhash: bitcoin::BlockHash) -> Option<BlockStats> {
|
||||
let res = match self.make_fallible_node_request(
|
||||
"getblockheader",
|
||||
¶ms!(Json::String(blockhash.to_string()),),
|
||||
);
|
||||
) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
log::warn!("Error when fetching block header {}: {}", &blockhash, e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let confirmations = res
|
||||
.get("confirmations")
|
||||
.and_then(Json::as_i64)
|
||||
@ -989,14 +995,14 @@ impl BitcoinD {
|
||||
.and_then(Json::as_u64)
|
||||
.expect("Invalid median timestamp in `getblockheader` response: not an u64")
|
||||
as u32;
|
||||
BlockStats {
|
||||
Some(BlockStats {
|
||||
confirmations,
|
||||
previous_blockhash,
|
||||
height,
|
||||
blockhash,
|
||||
time,
|
||||
median_time_past,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn broadcast_tx(&self, tx: &bitcoin::Transaction) -> Result<(), BitcoindError> {
|
||||
|
||||
@ -28,15 +28,15 @@ pub fn block_before_date<Fh, Fs>(
|
||||
) -> Option<BlockChainTip>
|
||||
where
|
||||
Fh: FnMut(i32) -> Option<bitcoin::BlockHash>,
|
||||
Fs: FnMut(bitcoin::BlockHash) -> BlockStats,
|
||||
Fs: FnMut(bitcoin::BlockHash) -> Option<BlockStats>,
|
||||
{
|
||||
log::debug!("Looking for the first block before {}", target_timestamp);
|
||||
|
||||
let mut start_height = 0;
|
||||
let mut end_height = chain_tip.height;
|
||||
|
||||
let genesis_stats = get_stats(get_hash(0).expect("Genesis hash"));
|
||||
let tip_stats = get_stats(chain_tip.hash);
|
||||
let genesis_stats = get_stats(get_hash(0).expect("Genesis hash"))?;
|
||||
let tip_stats = get_stats(chain_tip.hash)?;
|
||||
if !(genesis_stats.time..tip_stats.time).contains(&target_timestamp) {
|
||||
return None;
|
||||
}
|
||||
@ -47,7 +47,7 @@ where
|
||||
let current_height = start_height + delta.checked_div(2).unwrap();
|
||||
// We want the last block with a timestamp below, not the first with a higher one.
|
||||
let next_height = current_height.checked_add(1).unwrap();
|
||||
let next_stats = get_stats(get_hash(next_height)?);
|
||||
let next_stats = get_stats(get_hash(next_height)?)?;
|
||||
log::debug!("Current next block: {:?}", next_stats);
|
||||
|
||||
if target_timestamp > next_stats.time {
|
||||
@ -85,13 +85,18 @@ mod tests {
|
||||
}
|
||||
|
||||
// Inefficient dummy implementation of BitcoinD's self.get_block_stats
|
||||
fn get_stats(chain: &[(BlockChainTip, BlockStats)], hash: bitcoin::BlockHash) -> BlockStats {
|
||||
chain
|
||||
.iter()
|
||||
.find(|(tip, _)| tip.hash == hash)
|
||||
.unwrap()
|
||||
.1
|
||||
.clone()
|
||||
fn get_stats(
|
||||
chain: &[(BlockChainTip, BlockStats)],
|
||||
hash: bitcoin::BlockHash,
|
||||
) -> Option<BlockStats> {
|
||||
Some(
|
||||
chain
|
||||
.iter()
|
||||
.find(|(tip, _)| tip.hash == hash)
|
||||
.unwrap()
|
||||
.1
|
||||
.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! bh {
|
||||
|
||||
@ -272,11 +272,11 @@ impl BitcoinInterface for d::BitcoinD {
|
||||
}
|
||||
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> Option<BlockChainTip> {
|
||||
let mut stats = self.get_block_stats(tip.hash);
|
||||
let mut stats = self.get_block_stats(tip.hash)?;
|
||||
let mut ancestor = *tip;
|
||||
|
||||
while stats.confirmations == -1 {
|
||||
stats = self.get_block_stats(stats.previous_blockhash?);
|
||||
stats = self.get_block_stats(stats.previous_blockhash?)?;
|
||||
ancestor = BlockChainTip {
|
||||
hash: stats.blockhash,
|
||||
height: stats.height,
|
||||
@ -318,7 +318,7 @@ impl BitcoinInterface for d::BitcoinD {
|
||||
|
||||
fn tip_time(&self) -> Option<u32> {
|
||||
let tip = self.chain_tip();
|
||||
Some(self.get_block_stats(tip.hash).time)
|
||||
Some(self.get_block_stats(tip.hash)?.time)
|
||||
}
|
||||
|
||||
fn wallet_transaction(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user