Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions zebra-state/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added `ReadRequest::IsTransparentOutputSpent` and `ReadResponse::IsTransparentOutputSpent` to the read state service ([#10235](https://github.com/ZcashFoundation/zebra/pull/10235))
- Added `{ReadRequest, Request}::AnyChainBlock` to the read state service ([#10325](https://github.com/ZcashFoundation/zebra/pull/10325))


## [4.0.0] - 2026-02-05
Expand Down
28 changes: 27 additions & 1 deletion zebra-state/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,17 @@ pub enum Request {
/// [`block::Height`] using `.into()`.
Block(HashOrHeight),

/// Looks up a block by hash in any current chain or by height in the current best chain.
///
/// Returns
///
/// * [`Response::Block(Some(Arc<Block>))`](Response::Block) if the block is in the best chain;
Comment thread
arya2 marked this conversation as resolved.
Outdated
/// * [`Response::Block(None)`](Response::Block) otherwise.
///
/// Note: the [`HashOrHeight`] can be constructed from a [`block::Hash`] or
/// [`block::Height`] using `.into()`.
AnyChainBlock(HashOrHeight),

//// Same as Block, but also returns serialized block size.
////
/// Returns
Expand Down Expand Up @@ -1032,7 +1043,6 @@ impl Request {
match self {
Request::CommitSemanticallyVerifiedBlock(_) => "commit_semantically_verified_block",
Request::CommitCheckpointVerifiedBlock(_) => "commit_checkpoint_verified_block",

Request::AwaitUtxo(_) => "await_utxo",
Request::Depth(_) => "depth",
Request::Tip => "tip",
Expand All @@ -1041,6 +1051,7 @@ impl Request {
Request::AnyChainTransaction(_) => "any_chain_transaction",
Request::UnspentBestChainUtxo { .. } => "unspent_best_chain_utxo",
Request::Block(_) => "block",
Request::AnyChainBlock(_) => "any_chain_block",
Request::BlockAndSize(_) => "block_and_size",
Request::BlockHeader(_) => "block_header",
Request::FindBlockHashes { .. } => "find_block_hashes",
Expand Down Expand Up @@ -1109,6 +1120,17 @@ pub enum ReadRequest {
/// [`block::Height`] using `.into()`.
Block(HashOrHeight),

/// Looks up a block by hash in any current chain or by height in the current best chain.
///
/// Returns
///
/// * [`ReadResponse::Block(Some(Arc<Block>))`](ReadResponse::Block) if the block is in the best chain;
/// * [`ReadResponse::Block(None)`](ReadResponse::Block) otherwise.
///
/// Note: the [`HashOrHeight`] can be constructed from a [`block::Hash`] or
/// [`block::Height`] using `.into()`.
AnyChainBlock(HashOrHeight),

//// Same as Block, but also returns serialized block size.
////
/// Returns
Expand Down Expand Up @@ -1393,6 +1415,7 @@ impl ReadRequest {
ReadRequest::BlockInfo(_) => "block_info",
ReadRequest::Depth(_) => "depth",
ReadRequest::Block(_) => "block",
ReadRequest::AnyChainBlock(_) => "any_chain_block",
ReadRequest::BlockAndSize(_) => "block_and_size",
ReadRequest::BlockHeader(_) => "block_header",
ReadRequest::Transaction(_) => "transaction",
Expand Down Expand Up @@ -1452,6 +1475,9 @@ impl TryFrom<Request> for ReadRequest {
Request::BestChainBlockHash(hash) => Ok(ReadRequest::BestChainBlockHash(hash)),

Request::Block(hash_or_height) => Ok(ReadRequest::Block(hash_or_height)),
Request::AnyChainBlock(hash_or_height) => {
Ok(ReadRequest::AnyChainBlock(hash_or_height))
}
Request::BlockAndSize(hash_or_height) => Ok(ReadRequest::BlockAndSize(hash_or_height)),
Request::BlockHeader(hash_or_height) => Ok(ReadRequest::BlockHeader(hash_or_height)),
Request::Transaction(tx_hash) => Ok(ReadRequest::Transaction(tx_hash)),
Expand Down
25 changes: 25 additions & 0 deletions zebra-state/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,7 @@ impl Service<Request> for StateService {
| Request::AnyChainTransaction(_)
| Request::UnspentBestChainUtxo(_)
| Request::Block(_)
| Request::AnyChainBlock(_)
| Request::BlockAndSize(_)
| Request::BlockHeader(_)
| Request::FindBlockHashes { .. }
Expand Down Expand Up @@ -1484,6 +1485,30 @@ impl Service<ReadRequest> for ReadStateService {
.wait_for_panics()
}

ReadRequest::AnyChainBlock(hash_or_height) => {
let state = self.clone();

tokio::task::spawn_blocking(move || {
span.in_scope(move || {
let block = state.non_finalized_state_receiver.with_watch_data(
|non_finalized_state| {
read::any_chain_block(
non_finalized_state,
&state.db,
hash_or_height,
)
},
);

// The work is done in the future.
timer.finish(module_path!(), line!(), "ReadRequest::AnyChainBlock");

Ok(ReadResponse::Block(block))
})
})
.wait_for_panics()
}

// Used by the get_block (raw) RPC and the StateService.
ReadRequest::BlockAndSize(hash_or_height) => {
let state = self.clone();
Expand Down
5 changes: 3 additions & 2 deletions zebra-state/src/service/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ pub use address::{
utxo::{address_utxos, AddressUtxos},
};
pub use block::{
any_transaction, any_utxo, block, block_and_size, block_header, block_info, mined_transaction,
transaction_hashes_for_any_block, transaction_hashes_for_block, unspent_utxo,
any_chain_block, any_transaction, any_utxo, block, block_and_size, block_header, block_info,
mined_transaction, transaction_hashes_for_any_block, transaction_hashes_for_block,
unspent_utxo,
};

#[cfg(feature = "indexer")]
Expand Down
22 changes: 22 additions & 0 deletions zebra-state/src/service/read/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,28 @@ use crate::{
#[cfg(feature = "indexer")]
use crate::request::Spend;

/// Returns the [`Block`] with [`block::Hash`] or
/// [`Height`], if it exists in the non-finalized state or finalized `db`.
///
/// Checks all non-finalized chain for block hashes or the best chain for heights.
Comment thread
arya2 marked this conversation as resolved.
Outdated
pub fn any_chain_block(
non_finalized: NonFinalizedState,
db: &ZebraDb,
hash_or_height: HashOrHeight,
) -> Option<Arc<Block>> {
let unchecked_best_chain = if let HashOrHeight::Hash(hash) = hash_or_height {
if let Some(block) = non_finalized.any_block_by_hash(hash) {
return Some(block);
}

None
} else {
non_finalized.best_chain()
};

block(unchecked_best_chain, db, hash_or_height)
}

/// Returns the [`Block`] with [`block::Hash`] or
/// [`Height`], if it exists in the non-finalized `chain` or finalized `db`.
pub fn block<C>(chain: Option<C>, db: &ZebraDb, hash_or_height: HashOrHeight) -> Option<Arc<Block>>
Expand Down
Loading