diff --git a/src/client.rs b/src/client.rs
index 4bf37165..d1fcd4c3 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -221,6 +221,21 @@ impl Requester {
rx.await.map_err(|_| ClientError::RecvError)
}
+ /// Look up the height of a block hash in the locally synced chain of most work.
+ /// Returns `None` if the hash is not in the header chain.
+ ///
+ /// # Errors
+ ///
+ /// If the node has stopped running.
+ pub async fn height_of_hash(&self, hash: BlockHash) -> Result, ClientError> {
+ let (tx, rx) = tokio::sync::oneshot::channel:: >();
+ let request = ClientRequest::new(hash, tx);
+ self.ntx
+ .send(ClientMessage::HeightOfHash(request))
+ .map_err(|_| ClientError::SendError)?;
+ rx.await.map_err(|_| ClientError::RecvError)
+ }
+
/// Check if the node is running.
pub fn is_running(&self) -> bool {
self.ntx.send(ClientMessage::NoOp).is_ok()
diff --git a/src/messages.rs b/src/messages.rs
index 7021c859..3f5caa31 100644
--- a/src/messages.rs
+++ b/src/messages.rs
@@ -153,6 +153,8 @@ pub(crate) enum ClientMessage {
GetBroadcastMinFeeRate(ClientRequest<(), FeeRate>),
/// Get info on connections
GetPeerInfo(ClientRequest<(), Vec<(AddrV2, ServiceFlags)>>),
+ /// Look up the height of a block hash in the chain of most work.
+ HeightOfHash(ClientRequest>),
/// Send an empty message to see if the node is running.
NoOp,
}
diff --git a/src/node.rs b/src/node.rs
index 94bd4293..493a2995 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -268,6 +268,14 @@ impl Node {
self.dialog.send_warning(Warning::ChannelDropped);
};
}
+ ClientMessage::HeightOfHash(request) => {
+ let (hash, oneshot) = request.into_values();
+ let height =
+ self.chain.header_chain.height_of_hash(hash);
+ if oneshot.send(height).is_err() {
+ self.dialog.send_warning(Warning::ChannelDropped);
+ };
+ }
ClientMessage::NoOp => (),
}
}
diff --git a/tests/core.rs b/tests/core.rs
index 5d62e984..5f5ba30b 100644
--- a/tests/core.rs
+++ b/tests/core.rs
@@ -253,6 +253,14 @@ async fn various_client_methods() {
let peers = requester.peer_info().await.unwrap();
assert_eq!(peers.len(), 1);
assert!(requester.is_running());
+ // height_of_hash for the chain tip should return the tip height
+ let tip_height = requester.height_of_hash(cp.hash).await.unwrap();
+ assert!(tip_height.is_some());
+ assert_eq!(tip_height.unwrap(), cp.height);
+ // height_of_hash for an unknown hash should return None
+ let fake_hash: BlockHash = bitcoin::hashes::Hash::all_zeros();
+ let unknown = requester.height_of_hash(fake_hash).await.unwrap();
+ assert!(unknown.is_none());
requester.shutdown().unwrap();
rpc.stop().unwrap();
}