1. feat(state): Use ReadStateService for RPCs (#3847)
* Use the read-only state service for RPCs * Refactor non-finalized block lookup into Chain * Implement the read-only state block request * Drop the Chain watch channel lock before accessing the finalized state
This commit is contained in:
parent
5950083006
commit
5c62dd62cd
|
@ -55,6 +55,7 @@ pub(crate) mod check;
|
|||
mod finalized_state;
|
||||
mod non_finalized_state;
|
||||
mod pending_utxos;
|
||||
mod read;
|
||||
|
||||
#[cfg(any(test, feature = "proptest-impl"))]
|
||||
pub mod arbitrary;
|
||||
|
@ -443,13 +444,10 @@ impl StateService {
|
|||
Some(tip.0 - height.0)
|
||||
}
|
||||
|
||||
/// Return the block identified by either its `height` or `hash` if it exists
|
||||
/// in the current best chain.
|
||||
/// Return the block identified by either its `height` or `hash`,
|
||||
/// if it exists in the current best chain.
|
||||
pub fn best_block(&self, hash_or_height: HashOrHeight) -> Option<Arc<Block>> {
|
||||
self.mem
|
||||
.best_block(hash_or_height)
|
||||
.map(|contextual| contextual.block)
|
||||
.or_else(|| self.disk.db().block(hash_or_height))
|
||||
read::block(self.mem.best_chain(), self.disk.db(), hash_or_height)
|
||||
}
|
||||
|
||||
/// Return the transaction identified by `hash` if it exists in the current
|
||||
|
@ -843,13 +841,23 @@ impl Service<Request> for ReadStateService {
|
|||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
#[instrument(name = "read_state", skip(self, req))]
|
||||
#[instrument(name = "read_state", skip(self))]
|
||||
fn call(&mut self, req: Request) -> Self::Future {
|
||||
match req {
|
||||
// TODO: implement for lightwalletd before using this state in RPC methods
|
||||
|
||||
// Used by get_block RPC.
|
||||
Request::Block(_hash_or_height) => unimplemented!("ReadStateService doesn't Block yet"),
|
||||
Request::Block(hash_or_height) => {
|
||||
let state = self.clone();
|
||||
|
||||
async move {
|
||||
Ok(read::block(
|
||||
state.best_chain_receiver.borrow().clone().as_ref(),
|
||||
&state.db,
|
||||
hash_or_height,
|
||||
))
|
||||
.map(Response::Block)
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
||||
// Used by get_best_block_hash & get_blockchain_info (#3143) RPCs.
|
||||
//
|
||||
|
|
|
@ -17,7 +17,7 @@ use zebra_chain::{
|
|||
use crate::{
|
||||
request::ContextuallyValidBlock,
|
||||
service::{check, finalized_state::ZebraDb},
|
||||
FinalizedBlock, HashOrHeight, PreparedBlock, ValidateContextError,
|
||||
FinalizedBlock, PreparedBlock, ValidateContextError,
|
||||
};
|
||||
|
||||
mod chain;
|
||||
|
@ -304,15 +304,6 @@ impl NonFinalizedState {
|
|||
None
|
||||
}
|
||||
|
||||
/// Returns the [`ContextuallyValidBlock`] at a given height or hash in the best chain.
|
||||
pub fn best_block(&self, hash_or_height: HashOrHeight) -> Option<ContextuallyValidBlock> {
|
||||
let best_chain = self.best_chain()?;
|
||||
let height =
|
||||
hash_or_height.height_or_else(|hash| best_chain.height_by_hash.get(&hash).cloned())?;
|
||||
|
||||
best_chain.blocks.get(&height).map(Clone::clone)
|
||||
}
|
||||
|
||||
/// Returns the hash for a given `block::Height` if it is present in the best chain.
|
||||
pub fn best_hash(&self, height: block::Height) -> Option<block::Hash> {
|
||||
self.best_chain()?
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! Chain that is a part of the non-finalized state.
|
||||
//! [`Chain`] implements a single non-finalized blockchain,
|
||||
//! starting at the finalized tip.
|
||||
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
|
@ -23,7 +24,7 @@ use zebra_chain::{
|
|||
work::difficulty::PartialCumulativeWork,
|
||||
};
|
||||
|
||||
use crate::{service::check, ContextuallyValidBlock, ValidateContextError};
|
||||
use crate::{service::check, ContextuallyValidBlock, HashOrHeight, ValidateContextError};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Chain {
|
||||
|
@ -317,6 +318,14 @@ impl Chain {
|
|||
Ok(Some(forked))
|
||||
}
|
||||
|
||||
/// Returns the [`ContextuallyValidBlock`] at a given height or hash in this chain.
|
||||
pub fn block(&self, hash_or_height: HashOrHeight) -> Option<&ContextuallyValidBlock> {
|
||||
let height =
|
||||
hash_or_height.height_or_else(|hash| self.height_by_hash.get(&hash).cloned())?;
|
||||
|
||||
self.blocks.get(&height)
|
||||
}
|
||||
|
||||
/// Returns the block hash of the tip block.
|
||||
pub fn non_finalized_tip_hash(&self) -> block::Hash {
|
||||
self.blocks
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
//! Shared state reading code.
|
||||
//!
|
||||
//! Used by [`StateService`] and [`ReadStateService`]
|
||||
//! to read from the best [`Chain`] in the [`NonFinalizedState`],
|
||||
//! and the database in the [`FinalizedState`].
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use zebra_chain::block::Block;
|
||||
|
||||
use crate::{
|
||||
service::{finalized_state::ZebraDb, non_finalized_state::Chain},
|
||||
HashOrHeight,
|
||||
};
|
||||
|
||||
/// Return the block identified by either its `height` or `hash` if it exists
|
||||
/// in the non-finalized `chain` or finalized `db`.
|
||||
pub(crate) fn block(
|
||||
chain: Option<&Arc<Chain>>,
|
||||
db: &ZebraDb,
|
||||
hash_or_height: HashOrHeight,
|
||||
) -> Option<Arc<Block>> {
|
||||
chain
|
||||
.and_then(|chain| chain.block(hash_or_height))
|
||||
.map(|contextual| contextual.block.clone())
|
||||
.or_else(|| db.block(hash_or_height))
|
||||
}
|
|
@ -106,7 +106,7 @@ impl StartCmd {
|
|||
info!(?config);
|
||||
|
||||
info!("initializing node state");
|
||||
let (state_service, _read_only_state_service, latest_chain_tip, chain_tip_change) =
|
||||
let (state_service, read_only_state_service, latest_chain_tip, chain_tip_change) =
|
||||
zebra_state::init(config.state.clone(), config.network.network);
|
||||
let state = ServiceBuilder::new()
|
||||
.buffer(Self::state_buffer_bound())
|
||||
|
@ -164,7 +164,7 @@ impl StartCmd {
|
|||
config.rpc,
|
||||
app_version().to_string(),
|
||||
mempool.clone(),
|
||||
state.clone(),
|
||||
read_only_state_service,
|
||||
);
|
||||
|
||||
let setup_data = InboundSetupData {
|
||||
|
|
Loading…
Reference in New Issue