Returns block times from the getblock RPC when used with verbosity = 1 (it's already included with verbosity = 0 but this makes it easier to use).
This commit is contained in:
parent
49fca309cf
commit
4aa00fa0a5
|
@ -789,11 +789,38 @@ where
|
|||
let request = zebra_state::ReadRequest::TransactionIdsForBlock(hash.into());
|
||||
let tx_ids_response_fut = state.clone().oneshot(request);
|
||||
|
||||
// Sapling trees
|
||||
//
|
||||
// # Concurrency
|
||||
//
|
||||
// We look up by block hash so the hash, transaction IDs, block header, and confirmations
|
||||
// are consistent.
|
||||
let request = zebra_state::ReadRequest::SaplingTree(hash.into());
|
||||
let sapling_tree_response_fut = state.clone().oneshot(request);
|
||||
|
||||
// Orchard trees
|
||||
//
|
||||
// # Concurrency
|
||||
//
|
||||
// We look up by block hash so the hash, transaction IDs, block header, and confirmations
|
||||
// are consistent.
|
||||
let request = zebra_state::ReadRequest::OrchardTree(hash.into());
|
||||
let orchard_tree_response_fut = state.clone().oneshot(request);
|
||||
|
||||
// Block header
|
||||
//
|
||||
// # Concurrency
|
||||
//
|
||||
// We look up by block hash so the hash, transaction IDs, block header, and confirmations
|
||||
// are consistent.
|
||||
let request = zebra_state::ReadRequest::BlockHeader(hash.into());
|
||||
let block_header_response_fut = state.clone().oneshot(request);
|
||||
|
||||
// Get block confirmations from the block height index
|
||||
//
|
||||
// # Concurrency
|
||||
//
|
||||
// We look up by block hash so the hash, transaction IDs, and confirmations
|
||||
// We look up by block hash so the hash, transaction IDs, block header, and confirmations
|
||||
// are consistent.
|
||||
//
|
||||
// All possible responses are valid, even if a block is added to the chain, or
|
||||
|
@ -807,34 +834,17 @@ where
|
|||
let request = zebra_state::ReadRequest::Depth(hash);
|
||||
let depth_response_fut = state.clone().oneshot(request);
|
||||
|
||||
// Sapling trees
|
||||
//
|
||||
// # Concurrency
|
||||
//
|
||||
// We look up by block hash so the hash, transaction IDs, and confirmations
|
||||
// are consistent.
|
||||
let request = zebra_state::ReadRequest::SaplingTree(hash.into());
|
||||
let sapling_tree_response_fut = state.clone().oneshot(request);
|
||||
|
||||
// Orchard trees
|
||||
//
|
||||
// # Concurrency
|
||||
//
|
||||
// We look up by block hash so the hash, transaction IDs, and confirmations
|
||||
// are consistent.
|
||||
let request = zebra_state::ReadRequest::OrchardTree(hash.into());
|
||||
let orchard_tree_response_fut = state.clone().oneshot(request);
|
||||
|
||||
let mut futs = FuturesOrdered::new();
|
||||
futs.push_back(tx_ids_response_fut);
|
||||
futs.push_back(sapling_tree_response_fut);
|
||||
futs.push_back(orchard_tree_response_fut);
|
||||
futs.push_back(block_header_response_fut);
|
||||
futs.push_back(depth_response_fut);
|
||||
|
||||
let tx_ids_response = futs
|
||||
.next()
|
||||
.await
|
||||
.expect("should have 4 items in futs")
|
||||
.expect("should have 5 items in futs")
|
||||
.map_err(|error| Error {
|
||||
code: ErrorCode::ServerError(0),
|
||||
message: error.to_string(),
|
||||
|
@ -844,7 +854,7 @@ where
|
|||
let sapling_tree_response = futs
|
||||
.next()
|
||||
.await
|
||||
.expect("should have 3 items in futs")
|
||||
.expect("should have 4 items in futs")
|
||||
.map_err(|error| Error {
|
||||
code: ErrorCode::ServerError(0),
|
||||
message: error.to_string(),
|
||||
|
@ -852,6 +862,16 @@ where
|
|||
})?;
|
||||
|
||||
let orchard_tree_response = futs
|
||||
.next()
|
||||
.await
|
||||
.expect("should have 3 items in futs")
|
||||
.map_err(|error| Error {
|
||||
code: ErrorCode::ServerError(0),
|
||||
message: error.to_string(),
|
||||
data: None,
|
||||
})?;
|
||||
|
||||
let block_header_response = futs
|
||||
.next()
|
||||
.await
|
||||
.expect("should have 2 items in futs")
|
||||
|
@ -889,14 +909,6 @@ where
|
|||
_ => unreachable!("unmatched response to a SaplingTree request"),
|
||||
};
|
||||
|
||||
let confirmations = match depth_response {
|
||||
// Confirmations are one more than the depth.
|
||||
// Depth is limited by height, so it will never overflow an i64.
|
||||
zebra_state::ReadResponse::Depth(Some(depth)) => i64::from(depth) + 1,
|
||||
zebra_state::ReadResponse::Depth(None) => NOT_IN_BEST_CHAIN_CONFIRMATIONS,
|
||||
_ => unreachable!("unmatched response to a depth request"),
|
||||
};
|
||||
|
||||
// TODO: look up the height if we only have a hash,
|
||||
// this needs a new state request for the height -> hash index
|
||||
let height = hash_or_height.height();
|
||||
|
@ -907,6 +919,21 @@ where
|
|||
_ => unreachable!("unmatched response to a OrchardTree request"),
|
||||
};
|
||||
|
||||
let block_header = match block_header_response {
|
||||
zebra_state::ReadResponse::BlockHeader(header) => header,
|
||||
_ => unreachable!("unmatched response to a BlockHeader request"),
|
||||
};
|
||||
|
||||
let time = block_header.map(|header| header.time.timestamp());
|
||||
|
||||
let confirmations = match depth_response {
|
||||
// Confirmations are one more than the depth.
|
||||
// Depth is limited by height, so it will never overflow an i64.
|
||||
zebra_state::ReadResponse::Depth(Some(depth)) => i64::from(depth) + 1,
|
||||
zebra_state::ReadResponse::Depth(None) => NOT_IN_BEST_CHAIN_CONFIRMATIONS,
|
||||
_ => unreachable!("unmatched response to a depth request"),
|
||||
};
|
||||
|
||||
let sapling = SaplingTrees {
|
||||
size: sapling_note_commitment_tree_count,
|
||||
};
|
||||
|
@ -921,6 +948,7 @@ where
|
|||
hash: GetBlockHash(hash),
|
||||
confirmations,
|
||||
height,
|
||||
time,
|
||||
tx,
|
||||
trees,
|
||||
})
|
||||
|
@ -1639,6 +1667,10 @@ pub enum GetBlock {
|
|||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
height: Option<Height>,
|
||||
|
||||
/// The height of the requested block.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
time: Option<i64>,
|
||||
|
||||
/// List of transaction IDs in block order, hex-encoded.
|
||||
//
|
||||
// TODO: use a typed Vec<transaction::Hash> here
|
||||
|
@ -1655,6 +1687,7 @@ impl Default for GetBlock {
|
|||
hash: GetBlockHash::default(),
|
||||
confirmations: 0,
|
||||
height: None,
|
||||
time: None,
|
||||
tx: Vec::new(),
|
||||
trees: GetBlockTrees::default(),
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ expression: block
|
|||
{
|
||||
"hash": "0007bc227e1c57a4a70e237cad00e7b7ce565155ab49166bc57397a26d339283",
|
||||
"confirmations": 10,
|
||||
"time": 1477671596,
|
||||
"tx": [
|
||||
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
||||
],
|
||||
|
|
|
@ -5,6 +5,7 @@ expression: block
|
|||
{
|
||||
"hash": "025579869bcf52a989337342f5f57a84f3a28b968f7d6a8307902b065a668d23",
|
||||
"confirmations": 10,
|
||||
"time": 1477674473,
|
||||
"tx": [
|
||||
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
||||
],
|
||||
|
|
|
@ -5,6 +5,7 @@ expression: block
|
|||
{
|
||||
"hash": "0007bc227e1c57a4a70e237cad00e7b7ce565155ab49166bc57397a26d339283",
|
||||
"confirmations": 10,
|
||||
"time": 1477671596,
|
||||
"tx": [
|
||||
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
||||
],
|
||||
|
|
|
@ -5,6 +5,7 @@ expression: block
|
|||
{
|
||||
"hash": "025579869bcf52a989337342f5f57a84f3a28b968f7d6a8307902b065a668d23",
|
||||
"confirmations": 10,
|
||||
"time": 1477674473,
|
||||
"tx": [
|
||||
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
||||
],
|
||||
|
|
|
@ -6,6 +6,7 @@ expression: block
|
|||
"hash": "0007bc227e1c57a4a70e237cad00e7b7ce565155ab49166bc57397a26d339283",
|
||||
"confirmations": 10,
|
||||
"height": 1,
|
||||
"time": 1477671596,
|
||||
"tx": [
|
||||
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
||||
],
|
||||
|
|
|
@ -6,6 +6,7 @@ expression: block
|
|||
"hash": "025579869bcf52a989337342f5f57a84f3a28b968f7d6a8307902b065a668d23",
|
||||
"confirmations": 10,
|
||||
"height": 1,
|
||||
"time": 1477674473,
|
||||
"tx": [
|
||||
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
||||
],
|
||||
|
|
|
@ -6,6 +6,7 @@ expression: block
|
|||
"hash": "0007bc227e1c57a4a70e237cad00e7b7ce565155ab49166bc57397a26d339283",
|
||||
"confirmations": 10,
|
||||
"height": 1,
|
||||
"time": 1477671596,
|
||||
"tx": [
|
||||
"851bf6fbf7a976327817c738c489d7fa657752445430922d94c983c0b9ed4609"
|
||||
],
|
||||
|
|
|
@ -6,6 +6,7 @@ expression: block
|
|||
"hash": "025579869bcf52a989337342f5f57a84f3a28b968f7d6a8307902b065a668d23",
|
||||
"confirmations": 10,
|
||||
"height": 1,
|
||||
"time": 1477674473,
|
||||
"tx": [
|
||||
"f37e9f691fffb635de0999491d906ee85ba40cd36dae9f6e5911a8277d7c5f75"
|
||||
],
|
||||
|
|
|
@ -140,6 +140,7 @@ async fn rpc_getblock() {
|
|||
hash: GetBlockHash(block.hash()),
|
||||
confirmations: (blocks.len() - i).try_into().expect("valid i64"),
|
||||
height: Some(Height(i.try_into().expect("valid u32"))),
|
||||
time: Some(block.header.time.timestamp()),
|
||||
tx: block
|
||||
.transactions
|
||||
.iter()
|
||||
|
@ -163,6 +164,7 @@ async fn rpc_getblock() {
|
|||
hash: GetBlockHash(block.hash()),
|
||||
confirmations: (blocks.len() - i).try_into().expect("valid i64"),
|
||||
height: None,
|
||||
time: Some(block.header.time.timestamp()),
|
||||
tx: block
|
||||
.transactions
|
||||
.iter()
|
||||
|
@ -186,6 +188,7 @@ async fn rpc_getblock() {
|
|||
hash: GetBlockHash(block.hash()),
|
||||
confirmations: (blocks.len() - i).try_into().expect("valid i64"),
|
||||
height: Some(Height(i.try_into().expect("valid u32"))),
|
||||
time: Some(block.header.time.timestamp()),
|
||||
tx: block
|
||||
.transactions
|
||||
.iter()
|
||||
|
@ -209,6 +212,7 @@ async fn rpc_getblock() {
|
|||
hash: GetBlockHash(block.hash()),
|
||||
confirmations: (blocks.len() - i).try_into().expect("valid i64"),
|
||||
height: None,
|
||||
time: Some(block.header.time.timestamp()),
|
||||
tx: block
|
||||
.transactions
|
||||
.iter()
|
||||
|
|
|
@ -614,6 +614,16 @@ pub enum Request {
|
|||
/// [`block::Height`] using `.into()`.
|
||||
Block(HashOrHeight),
|
||||
|
||||
/// Looks up a block header by hash or height in the current best chain.
|
||||
///
|
||||
/// Returns
|
||||
///
|
||||
/// [`Response::BlockHeader(block::Header)`](Response::BlockHeader).
|
||||
///
|
||||
/// Note: the [`HashOrHeight`] can be constructed from a [`block::Hash`] or
|
||||
/// [`block::Height`] using `.into()`.
|
||||
BlockHeader(HashOrHeight),
|
||||
|
||||
/// Request a UTXO identified by the given [`OutPoint`](transparent::OutPoint),
|
||||
/// waiting until it becomes available if it is unknown.
|
||||
///
|
||||
|
@ -725,6 +735,7 @@ impl Request {
|
|||
Request::Transaction(_) => "transaction",
|
||||
Request::UnspentBestChainUtxo { .. } => "unspent_best_chain_utxo",
|
||||
Request::Block(_) => "block",
|
||||
Request::BlockHeader(_) => "block_header",
|
||||
Request::FindBlockHashes { .. } => "find_block_hashes",
|
||||
Request::FindBlockHeaders { .. } => "find_block_headers",
|
||||
Request::CheckBestChainTipNullifiersAndAnchors(_) => {
|
||||
|
@ -776,6 +787,16 @@ pub enum ReadRequest {
|
|||
/// [`block::Height`] using `.into()`.
|
||||
Block(HashOrHeight),
|
||||
|
||||
/// Looks up a block header by hash or height in the current best chain.
|
||||
///
|
||||
/// Returns
|
||||
///
|
||||
/// [`Response::BlockHeader(block::Header)`](Response::BlockHeader).
|
||||
///
|
||||
/// Note: the [`HashOrHeight`] can be constructed from a [`block::Hash`] or
|
||||
/// [`block::Height`] using `.into()`.
|
||||
BlockHeader(HashOrHeight),
|
||||
|
||||
/// Looks up a transaction by hash in the current best chain.
|
||||
///
|
||||
/// Returns
|
||||
|
@ -999,6 +1020,7 @@ impl ReadRequest {
|
|||
ReadRequest::Tip => "tip",
|
||||
ReadRequest::Depth(_) => "depth",
|
||||
ReadRequest::Block(_) => "block",
|
||||
ReadRequest::BlockHeader(_) => "block_header",
|
||||
ReadRequest::Transaction(_) => "transaction",
|
||||
ReadRequest::TransactionIdsForBlock(_) => "transaction_ids_for_block",
|
||||
ReadRequest::UnspentBestChainUtxo { .. } => "unspent_best_chain_utxo",
|
||||
|
@ -1052,6 +1074,7 @@ impl TryFrom<Request> for ReadRequest {
|
|||
Request::BestChainBlockHash(hash) => Ok(ReadRequest::BestChainBlockHash(hash)),
|
||||
|
||||
Request::Block(hash_or_height) => Ok(ReadRequest::Block(hash_or_height)),
|
||||
Request::BlockHeader(hash_or_height) => Ok(ReadRequest::BlockHeader(hash_or_height)),
|
||||
Request::Transaction(tx_hash) => Ok(ReadRequest::Transaction(tx_hash)),
|
||||
Request::UnspentBestChainUtxo(outpoint) => {
|
||||
Ok(ReadRequest::UnspentBestChainUtxo(outpoint))
|
||||
|
|
|
@ -50,6 +50,9 @@ pub enum Response {
|
|||
/// Response to [`Request::Block`] with the specified block.
|
||||
Block(Option<Arc<Block>>),
|
||||
|
||||
/// The response to a `BlockHeader` request.
|
||||
BlockHeader(Option<Arc<block::Header>>),
|
||||
|
||||
/// The response to a `AwaitUtxo` request, from any non-finalized chains, finalized chain,
|
||||
/// pending unverified blocks, or blocks received after the request was sent.
|
||||
Utxo(transparent::Utxo),
|
||||
|
@ -131,6 +134,9 @@ pub enum ReadResponse {
|
|||
/// Response to [`ReadRequest::Block`] with the specified block.
|
||||
Block(Option<Arc<Block>>),
|
||||
|
||||
/// The response to a `BlockHeader` request.
|
||||
BlockHeader(Option<Arc<block::Header>>),
|
||||
|
||||
/// Response to [`ReadRequest::Transaction`] with the specified transaction.
|
||||
Transaction(Option<MinedTx>),
|
||||
|
||||
|
@ -265,6 +271,7 @@ impl TryFrom<ReadResponse> for Response {
|
|||
ReadResponse::BlockHash(hash) => Ok(Response::BlockHash(hash)),
|
||||
|
||||
ReadResponse::Block(block) => Ok(Response::Block(block)),
|
||||
ReadResponse::BlockHeader(header) => Ok(Response::BlockHeader(header)),
|
||||
ReadResponse::Transaction(tx_info) => {
|
||||
Ok(Response::Transaction(tx_info.map(|tx_info| tx_info.tx)))
|
||||
}
|
||||
|
|
|
@ -1120,6 +1120,7 @@ impl Service<Request> for StateService {
|
|||
| Request::Transaction(_)
|
||||
| Request::UnspentBestChainUtxo(_)
|
||||
| Request::Block(_)
|
||||
| Request::BlockHeader(_)
|
||||
| Request::FindBlockHashes { .. }
|
||||
| Request::FindBlockHeaders { .. }
|
||||
| Request::CheckBestChainTipNullifiersAndAnchors(_) => {
|
||||
|
@ -1288,6 +1289,31 @@ impl Service<ReadRequest> for ReadStateService {
|
|||
.wait_for_panics()
|
||||
}
|
||||
|
||||
// Used by the get_block (verbose) RPC and the StateService.
|
||||
ReadRequest::BlockHeader(hash_or_height) => {
|
||||
let state = self.clone();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
span.in_scope(move || {
|
||||
let header = state.non_finalized_state_receiver.with_watch_data(
|
||||
|non_finalized_state| {
|
||||
read::block_header(
|
||||
non_finalized_state.best_chain(),
|
||||
&state.db,
|
||||
hash_or_height,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
// The work is done in the future.
|
||||
timer.finish(module_path!(), line!(), "ReadRequest::Block");
|
||||
|
||||
Ok(ReadResponse::BlockHeader(header))
|
||||
})
|
||||
})
|
||||
.wait_for_panics()
|
||||
}
|
||||
|
||||
// For the get_raw_transaction RPC and the StateService.
|
||||
ReadRequest::Transaction(hash) => {
|
||||
let state = self.clone();
|
||||
|
|
Loading…
Reference in New Issue