Conversation
`connector::get_blockhash` was returning `zebra_rpc::methods::GetBlockHash` (the deprecated alias for `GetBlockHashResponse`), which does not implement `ResponseToError` and therefore failed the `send_request` bound. Return the local `response::GetBlockHash` wrapper instead, matching the existing `get_best_blockhash`. `FetchServiceSubscriber::get_blockhash` now returns `GetBlockHashResponse` so the impl matches the `ZcashIndexer` trait signature; the stray local `GetBlockHash` import introduced during the dev merge is removed. Also adds the missing doc comments on the new `block_hash` module, `BlockSelector` enum, `connector::get_blockhash`, and the trait method; drops the dead `TryIntoHeight` import in `indexer.rs`; and silences the unused `serialized_block` binding in the `StateService` stub. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`zebra_rpc::methods::GetBlockHash` is a `#[deprecated]` re-export of `GetBlockHashResponse`. Update every zaino-side usage (the `ZcashIndexer` trait and both impls, the JSON-RPC service trait + handler, the `From` impl target in `zaino-fetch`, and the `fetch_service` integration test) to reference `GetBlockHashResponse` directly. No behavioral change — the two names resolve to the same type. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`BlockSelector` is the input parameter to `getblockhash`, not a response type, but it lived under `jsonrpsee::response::block_hash`. Create a new `jsonrpsee::request` module and relocate the file as `request::block_selector::BlockSelector` so the path reflects the type's role. Update the four importers (`connector.rs`, `backends/fetch.rs`, `backends/state.rs`, `indexer.rs`) accordingly. No behavioral change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`connector::get_blockhash` was returning `RpcRequestError<Infallible>` with a `// TODO: use correct error` note. Replace it with a typed error surface that reflects the RPC's actual failure mode. Add `GetBlockHashError::HeightOutOfRange(String)` in `response.rs`, mapping zcashd's `RPC_INVALID_PARAMETER` (code `-8`, "Block number out of range") via `TryFrom<RpcError>`. Introduce a `pub(crate)` `GetBlockHashByIndex` newtype around `GetBlockHash` whose `ResponseToError::RpcError = GetBlockHashError`; the connector deserializes into it internally and returns `GetBlockHash` to callers. `get_best_blockhash` keeps its `Infallible` error type — `GetBlockHash`'s own `ResponseToError` impl is untouched, so each method's error surface now matches its real behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two narrow `#[cfg(test)] mod` blocks in `response.rs`, each placed next
to the item it exercises:
- `get_block_hash_by_index` confirms the `#[serde(transparent)]` newtype
deserializes the same hex JSON as the inner `GetBlockHash`, pinning
the transparent wrapper contract.
- `get_block_hash_error` confirms `TryFrom<RpcError>` maps code `-8` to
`HeightOutOfRange` and passes every other code through unchanged as
`Err(original)`, pinning the error-discrimination branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `ZcashIndexer` trait and both backend impls already had `get_blockhash`, but `ZcashIndexerRpcServer` in `zaino-serve` only declared `getbestblockhash` — external JSON-RPC clients had no way to reach the endpoint. Add the `#[method(name = "getblockhash")]` trait declaration and the matching impl, delegating to `ZcashIndexer::get_blockhash` with the same error-mapping shape as its `getbestblockhash` sibling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… backends
Three new integration tests exercising the `getblockhash` endpoint:
- `fetch_service::{zcashd,zebrad}::get::blockhash` — happy path via
`FetchService`, verifying both `BlockSelector::Height(n)` (non-tip)
and `BlockSelector::Tip` against `z_get_block` and `get_best_blockhash`
reference values.
- `state_service::zebra::get::blockhash_regtest` — parallel happy-path
exercising the same two selectors through `StateService`.
- `state_service::zebra::get::blockhash_out_of_range_returns_err` —
regression asserting that an out-of-range height must surface as
`Err(…)` rather than panicking. Fails red today via a `.unwrap()` in
`StateService::get_blockhash`; turns green once the downstream fix
for that stub lands.
Also ships `tools/scripts/test-getblockhash.sh` — runs exactly the
new tests plus one `wallet_to_validator::zcashd::connect_to_node_get_info`
control via `makers container-test --manifest-path
integration-tests/Cargo.toml -E '…'`.
Two prerequisite fixups were required before the `integration-tests`
workspace would even compile:
- Phantom pin `core2 = "=0.3.3"` in `integration-tests/Cargo.toml`.
`zcash_protocol ^0.7.2` transitively requires `core2 ^0.3`, all
`0.3.x` versions are yanked, and the root `Cargo.lock` (which already
pins 0.3.3) isn't shared with the integration-tests workspace — so
fresh resolves fail. Tracked in #1043.
- Rebase `zaino-testutils::generate_blocks_and_poll_chain_index` onto
the new async `ChainIndex::snapshot_nonfinalized_state() ->
Result<ChainIndexSnapshot, _>` API and read the tip via
`best_chaintip(&snapshot)`. The `pub(crate) NonfinalizedBlockCacheSnapshot`
shift made the old `.best_tip.height` field access unreachable from
outside `zaino-state`; a friction note in the doc comment points
readers at #1043 and #1044 for the broader cleanup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| &self, | ||
| block_index: BlockSelector, | ||
| ) -> Result<GetBlockHashResponse, Self::Error> { | ||
| Ok(self.fetcher.get_blockhash(block_index).await?.into()) |
There was a problem hiding this comment.
Now we are migrating FetchService and StateService away from using direct access to the underlying data fetch mechanisms (#1062, #1065) we should implement the new RPC methods in this way to avoid creating new tech debt.
The following methods are available in the ChainIndex and should provide all functionality required for this new RPC:
zaino/packages/zaino-state/src/chain_index.rs
Line 202 in e777b2c
zaino/packages/zaino-state/src/chain_index.rs
Line 368 in e777b2c
NOTE: These methods can be accessed using self.indexer, eg:
let snapshot = self.indexer
.snapshot_nonfinalized_state()
.await
.map_err( ... )?;
let hash = self.indexer
.get_block_hash(
&snapshot,
Height(REQUESTED_HEIGHT),
)
.await
.map_err( ... )?;
| } | ||
| } | ||
|
|
||
| async fn get_blockhash( |
There was a problem hiding this comment.
Similar to fetch.rs.
The current aim is to have the exact same implementations in both FetchService and StateService (apart from error types / propagation), so that when all methods have been moved to ChainIndex / BlockChainSource the two current IndexerService implementations can be merged, simplifying zaino's architecture.
Motivation
#201.
Solution
Implement
getblockhash.Specifications & References
https://zcash.github.io/rpc/getblockhash.html
https://github.com/zcash/zcash/blob/16ac743764a513e41dafb2cd79c2417c5bb41e81/src/rpc/blockchain.cpp#L646
PR Checklist