bitcoin: interface to get the common block in our and the backend's chains
This will be used to get the common ancestor in the chain upon detecting a block chain reorganization.
This commit is contained in:
parent
efe2cf634d
commit
cce227f80f
@ -651,6 +651,34 @@ impl BitcoinD {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_block_stats(&self, blockhash: bitcoin::BlockHash) -> BlockStats {
|
||||
let res = self.make_node_request(
|
||||
"getblockheader",
|
||||
¶ms!(Json::String(blockhash.to_string()),),
|
||||
);
|
||||
let confirmations = res
|
||||
.get("confirmations")
|
||||
.and_then(Json::as_i64)
|
||||
.expect("Invalid confirmations in `getblockheader` response: not an i64")
|
||||
as i32;
|
||||
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");
|
||||
let height = res
|
||||
.get("height")
|
||||
.and_then(Json::as_i64)
|
||||
.expect("Invalid height in `getblockheader` response: not an u32")
|
||||
as i32;
|
||||
BlockStats {
|
||||
confirmations,
|
||||
previous_blockhash,
|
||||
height,
|
||||
blockhash,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Bitcoind uses a guess for the value of verificationprogress. It will eventually get to
|
||||
// be 1, and we want to be less conservative.
|
||||
@ -779,3 +807,11 @@ impl From<Json> for GetTxRes {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BlockStats {
|
||||
pub confirmations: i32,
|
||||
pub previous_blockhash: bitcoin::BlockHash,
|
||||
pub blockhash: bitcoin::BlockHash,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
@ -52,6 +52,9 @@ pub trait BitcoinInterface: Send {
|
||||
&self,
|
||||
outpoints: &[(bitcoin::OutPoint, bitcoin::Txid)],
|
||||
) -> Vec<(bitcoin::OutPoint, bitcoin::Txid, u32)>;
|
||||
|
||||
/// Get the common ancestor between the Bitcoin backend's tip and the given tip.
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> BlockChainTip;
|
||||
}
|
||||
|
||||
impl BitcoinInterface for d::BitcoinD {
|
||||
@ -207,6 +210,21 @@ impl BitcoinInterface for d::BitcoinD {
|
||||
|
||||
spent
|
||||
}
|
||||
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> 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);
|
||||
ancestor = BlockChainTip {
|
||||
hash: stats.blockhash,
|
||||
height: stats.height,
|
||||
};
|
||||
}
|
||||
|
||||
ancestor
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: do we need to repeat the entire trait implemenation? Isn't there a nicer way?
|
||||
@ -251,6 +269,10 @@ impl BitcoinInterface for sync::Arc<sync::Mutex<dyn BitcoinInterface + 'static>>
|
||||
) -> Vec<(bitcoin::OutPoint, bitcoin::Txid, u32)> {
|
||||
self.lock().unwrap().spent_coins(outpoints)
|
||||
}
|
||||
|
||||
fn common_ancestor(&self, tip: &BlockChainTip) -> BlockChainTip {
|
||||
self.lock().unwrap().common_ancestor(tip)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: We could avoid this type (and all the conversions entailing allocations) if bitcoind
|
||||
|
||||
@ -62,6 +62,10 @@ impl BitcoinInterface for DummyBitcoind {
|
||||
) -> Vec<(bitcoin::OutPoint, bitcoin::Txid, u32)> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn common_ancestor(&self, _: &BlockChainTip) -> BlockChainTip {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyDb {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user