bitcoind: handle missing previousblockhash from getblockheader
It seems that internally bitcoind might temporarily not have a pprev pointer for a block. This will result in the optional "previousblockhash" field to be null and would previously make us crash. Handle that gracefully.
This commit is contained in:
parent
9fa4b95847
commit
80803c78a4
@ -679,12 +679,14 @@ impl BitcoinD {
|
||||
let previous_blockhash = res
|
||||
.get("previousblockhash")
|
||||
.and_then(Json::as_str)
|
||||
.and_then(|s| bitcoin::BlockHash::from_str(s).ok())
|
||||
.expect("Invalid previousblockhash in `getblockheader` response");
|
||||
.map(|s| {
|
||||
bitcoin::BlockHash::from_str(s)
|
||||
.expect("Invalid previousblockhash in `getblockheader` response")
|
||||
});
|
||||
let height = res
|
||||
.get("height")
|
||||
.and_then(Json::as_i64)
|
||||
.expect("Invalid height in `getblockheader` response: not an u32")
|
||||
.expect("Invalid height in `getblockheader` response: not an i64")
|
||||
as i32;
|
||||
BlockStats {
|
||||
confirmations,
|
||||
@ -848,7 +850,7 @@ impl From<Json> for GetTxRes {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BlockStats {
|
||||
pub confirmations: i32,
|
||||
pub previous_blockhash: bitcoin::BlockHash,
|
||||
pub previous_blockhash: Option<bitcoin::BlockHash>,
|
||||
pub blockhash: bitcoin::BlockHash,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ pub trait BitcoinInterface: Send {
|
||||
) -> Vec<(bitcoin::OutPoint, bitcoin::Txid, i32, u32)>;
|
||||
|
||||
/// Get the common ancestor between the Bitcoin backend's tip and the given tip.
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> BlockChainTip;
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> Option<BlockChainTip>;
|
||||
|
||||
/// Broadcast this transaction to the Bitcoin P2P network
|
||||
fn broadcast_tx(&self, tx: &bitcoin::Transaction) -> Result<(), BitcoinError>;
|
||||
@ -260,19 +260,19 @@ impl BitcoinInterface for d::BitcoinD {
|
||||
spent
|
||||
}
|
||||
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> BlockChainTip {
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> Option<BlockChainTip> {
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
ancestor
|
||||
Some(ancestor)
|
||||
}
|
||||
|
||||
fn broadcast_tx(&self, tx: &bitcoin::Transaction) -> Result<(), BitcoinError> {
|
||||
@ -335,7 +335,7 @@ impl BitcoinInterface for sync::Arc<sync::Mutex<dyn BitcoinInterface + 'static>>
|
||||
self.lock().unwrap().spent_coins(outpoints)
|
||||
}
|
||||
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> BlockChainTip {
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> Option<BlockChainTip> {
|
||||
self.lock().unwrap().common_ancestor(tip)
|
||||
}
|
||||
|
||||
|
||||
@ -150,13 +150,20 @@ fn new_tip(bit: &impl BitcoinInterface, current_tip: &BlockChainTip) -> TipUpdat
|
||||
// block chain re-organisation. Find the common ancestor between our current chain and
|
||||
// the new chain and return that. The caller will take care of rewinding our state.
|
||||
log::info!("Block chain reorganization detected. Looking for common ancestor.");
|
||||
let common_ancestor = bit.common_ancestor(current_tip);
|
||||
log::info!(
|
||||
"Common ancestor found: '{}'. Starting rescan from there. Old tip was '{}'.",
|
||||
common_ancestor,
|
||||
current_tip
|
||||
);
|
||||
TipUpdate::Reorged(common_ancestor)
|
||||
if let Some(common_ancestor) = bit.common_ancestor(current_tip) {
|
||||
log::info!(
|
||||
"Common ancestor found: '{}'. Starting rescan from there. Old tip was '{}'.",
|
||||
common_ancestor,
|
||||
current_tip
|
||||
);
|
||||
TipUpdate::Reorged(common_ancestor)
|
||||
} else {
|
||||
log::error!(
|
||||
"Failed to get common ancestor for tip '{}'. Starting over.",
|
||||
current_tip
|
||||
);
|
||||
new_tip(bit, current_tip)
|
||||
}
|
||||
}
|
||||
|
||||
fn updates(
|
||||
|
||||
@ -67,7 +67,7 @@ impl BitcoinInterface for DummyBitcoind {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn common_ancestor(&self, _: &BlockChainTip) -> BlockChainTip {
|
||||
fn common_ancestor(&self, _: &BlockChainTip) -> Option<BlockChainTip> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user