Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,30 @@ impl Requester {
rx.await.map_err(|_| ClientError::RecvError)
}

/// Look up a header by block hash in the locally synced header chain. Unlike
/// [`Self::get_header`], this method returns the header even when the block
/// has been demoted from the chain of most work by a reorg, so callers that
/// receive a [`BlockHash`] from an [`Event`](crate::Event) (e.g. an
/// [`IndexedFilter`](crate::IndexedFilter)) can always resolve the exact
/// header the event referred to.
///
/// Returns `None` if the hash is not known to the local header chain.
///
/// # Errors
///
/// If the node has stopped running.
pub async fn get_header_by_hash(
&self,
hash: BlockHash,
) -> Result<Option<IndexedHeader>, ClientError> {
let (tx, rx) = tokio::sync::oneshot::channel::<Option<IndexedHeader>>();
let request = ClientRequest::new(hash, tx);
self.ntx
.send(ClientMessage::GetHeaderByHash(request))
.map_err(|_| ClientError::SendError)?;
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 chain of most work.
///
Expand Down
3 changes: 3 additions & 0 deletions src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ pub(crate) enum ClientMessage {
GetPeerInfo(ClientRequest<(), Vec<(AddrV2, ServiceFlags)>>),
/// Look up a header at a specific height in the chain of most work.
GetHeader(ClientRequest<u32, Option<IndexedHeader>>),
/// Look up a header by its block hash. Returns headers for stale/reorganized
/// branches as well as the canonical chain.
GetHeaderByHash(ClientRequest<BlockHash, Option<IndexedHeader>>),
/// Look up the height of a block hash in the chain of most work.
HeightOfHash(ClientRequest<BlockHash, Option<u32>>),
/// Send an empty message to see if the node is running.
Expand Down
16 changes: 16 additions & 0 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,22 @@ impl Node {
self.dialog.send_warning(Warning::ChannelDropped);
};
}
ClientMessage::GetHeaderByHash(request) => {
let (hash, oneshot) = request.into_values();
let indexed = self
.chain
.header_chain
.header_at_hash(hash)
.and_then(|header| {
self.chain
.header_chain
.height_of_hash(hash)
.map(|height| IndexedHeader::new(height, header))
});
if oneshot.send(indexed).is_err() {
self.dialog.send_warning(Warning::ChannelDropped);
};
}
ClientMessage::NoOp => (),
}
}
Expand Down
Loading