refactor(rpc): use ChainTip for get_best_block_hash (#3864)
* Use ChainTip for get_best_block_hash RPC * Use ReadStateService and LatestChainTip in tests * Mark Request::Tip as out of scope for ReadStateService
This commit is contained in:
parent
bf1f7aa973
commit
93c681fd6e
|
@ -96,7 +96,7 @@ pub trait Rpc {
|
|||
///
|
||||
/// zcashd reference: [`getbestblockhash`](https://zcash.github.io/rpc/getbestblockhash.html)
|
||||
#[rpc(name = "getbestblockhash")]
|
||||
fn get_best_block_hash(&self) -> BoxFuture<Result<GetBestBlockHash>>;
|
||||
fn get_best_block_hash(&self) -> Result<GetBestBlockHash>;
|
||||
|
||||
/// Returns all transaction ids in the memory pool, as a JSON array.
|
||||
///
|
||||
|
@ -126,7 +126,6 @@ where
|
|||
state: State,
|
||||
|
||||
/// Allows efficient access to the best tip of the blockchain.
|
||||
#[allow(dead_code)]
|
||||
latest_chain_tip: Tip,
|
||||
|
||||
/// The configured network for this RPC service.
|
||||
|
@ -282,32 +281,15 @@ where
|
|||
.boxed()
|
||||
}
|
||||
|
||||
fn get_best_block_hash(&self) -> BoxFuture<Result<GetBestBlockHash>> {
|
||||
let mut state = self.state.clone();
|
||||
|
||||
async move {
|
||||
let request = zebra_state::Request::Tip;
|
||||
let response = state
|
||||
.ready()
|
||||
.and_then(|service| service.call(request))
|
||||
.await
|
||||
.map_err(|error| Error {
|
||||
code: ErrorCode::ServerError(0),
|
||||
message: error.to_string(),
|
||||
data: None,
|
||||
})?;
|
||||
|
||||
match response {
|
||||
zebra_state::Response::Tip(Some((_height, hash))) => Ok(GetBestBlockHash(hash)),
|
||||
zebra_state::Response::Tip(None) => Err(Error {
|
||||
code: ErrorCode::ServerError(0),
|
||||
message: "No blocks in state".to_string(),
|
||||
data: None,
|
||||
}),
|
||||
_ => unreachable!("unmatched response to a tip request"),
|
||||
}
|
||||
}
|
||||
.boxed()
|
||||
fn get_best_block_hash(&self) -> Result<GetBestBlockHash> {
|
||||
self.latest_chain_tip
|
||||
.best_tip_hash()
|
||||
.map(GetBestBlockHash)
|
||||
.ok_or(Error {
|
||||
code: ErrorCode::ServerError(0),
|
||||
message: "No blocks in state".to_string(),
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_raw_mempool(&self) -> BoxFuture<Result<Vec<String>>> {
|
||||
|
|
|
@ -5,9 +5,7 @@ use std::sync::Arc;
|
|||
use tower::buffer::Buffer;
|
||||
|
||||
use zebra_chain::{
|
||||
block::Block,
|
||||
chain_tip::NoChainTip,
|
||||
parameters::Network::{self, *},
|
||||
block::Block, chain_tip::NoChainTip, parameters::Network::*,
|
||||
serialization::ZcashDeserializeInto,
|
||||
};
|
||||
use zebra_network::constants::USER_AGENT;
|
||||
|
@ -61,14 +59,15 @@ async fn rpc_getblock() {
|
|||
|
||||
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
||||
// Create a populated state service
|
||||
let state = zebra_state::populated_state(blocks.clone(), Network::Mainnet).await;
|
||||
let (_state, read_state, latest_chain_tip, _chain_tip_change) =
|
||||
zebra_state::populated_state(blocks.clone(), Mainnet).await;
|
||||
|
||||
// Init RPC
|
||||
let rpc = RpcImpl::new(
|
||||
"RPC test",
|
||||
Buffer::new(mempool.clone(), 1),
|
||||
state,
|
||||
NoChainTip,
|
||||
read_state,
|
||||
latest_chain_tip,
|
||||
Mainnet,
|
||||
);
|
||||
|
||||
|
@ -131,21 +130,21 @@ async fn rpc_getbestblockhash() {
|
|||
// Get a mempool handle
|
||||
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
||||
// Create a populated state service, the tip will be in `NUMBER_OF_BLOCKS`.
|
||||
let state = zebra_state::populated_state(blocks.clone(), Network::Mainnet).await;
|
||||
let (_state, read_state, latest_chain_tip, _chain_tip_change) =
|
||||
zebra_state::populated_state(blocks.clone(), Mainnet).await;
|
||||
|
||||
// Init RPC
|
||||
let rpc = RpcImpl::new(
|
||||
"RPC test",
|
||||
Buffer::new(mempool.clone(), 1),
|
||||
state,
|
||||
NoChainTip,
|
||||
read_state,
|
||||
latest_chain_tip,
|
||||
Mainnet,
|
||||
);
|
||||
|
||||
// Get the tip hash using RPC method `get_best_block_hash`
|
||||
let get_best_block_hash = rpc
|
||||
.get_best_block_hash()
|
||||
.await
|
||||
.expect("We should have a GetBestBlockHash struct");
|
||||
let response_hash = get_best_block_hash.0;
|
||||
|
||||
|
|
|
@ -859,12 +859,6 @@ impl Service<Request> for ReadStateService {
|
|||
.boxed()
|
||||
}
|
||||
|
||||
// Used by get_best_block_hash & get_blockchain_info (#3143) RPCs.
|
||||
//
|
||||
// These RPC methods could use the ChainTip struct instead,
|
||||
// if that's easier or more consistent.
|
||||
Request::Tip => unimplemented!("ReadStateService doesn't Tip yet"),
|
||||
|
||||
// TODO: implement for lightwalletd as part of these tickets
|
||||
|
||||
// get_raw_transaction (#3145)
|
||||
|
@ -885,6 +879,9 @@ impl Service<Request> for ReadStateService {
|
|||
// Out of Scope
|
||||
// TODO: delete when splitting the Request enum
|
||||
|
||||
// Use ChainTip instead.
|
||||
Request::Tip => unreachable!("ReadStateService doesn't need to Tip"),
|
||||
|
||||
// These requests don't need better performance at the moment.
|
||||
Request::FindBlockHashes {
|
||||
known_blocks: _,
|
||||
|
|
|
@ -20,7 +20,9 @@ use zebra_chain::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
arbitrary::Prepare, init_test, service::check, BoxError, PreparedBlock, Request, Response,
|
||||
arbitrary::Prepare,
|
||||
service::{check, ReadStateService, StateService},
|
||||
BoxError, ChainTipChange, Config, LatestChainTip, PreparedBlock, Request, Response,
|
||||
};
|
||||
|
||||
pub use zebra_chain::block::arbitrary::MAX_PARTIAL_CHAIN_BLOCKS;
|
||||
|
@ -166,16 +168,27 @@ impl Strategy for PreparedChain {
|
|||
}
|
||||
}
|
||||
|
||||
/// Initialize a state service with blocks.
|
||||
/// Initialize a state service with blocks, and return:
|
||||
/// - a read-write [`StateService`]
|
||||
/// - a read-only [`ReadStateService`]
|
||||
/// - a [`LatestChainTip`]
|
||||
/// - a [`ChainTipChange`] tracker
|
||||
pub async fn populated_state(
|
||||
blocks: impl IntoIterator<Item = Arc<Block>>,
|
||||
network: Network,
|
||||
) -> Buffer<BoxService<Request, Response, BoxError>, Request> {
|
||||
) -> (
|
||||
Buffer<BoxService<Request, Response, BoxError>, Request>,
|
||||
ReadStateService,
|
||||
LatestChainTip,
|
||||
ChainTipChange,
|
||||
) {
|
||||
let requests = blocks
|
||||
.into_iter()
|
||||
.map(|block| Request::CommitFinalizedBlock(block.into()));
|
||||
|
||||
let mut state = init_test(network);
|
||||
let (state, read_state, latest_chain_tip, chain_tip_change) =
|
||||
StateService::new(Config::ephemeral(), network);
|
||||
let mut state = Buffer::new(BoxService::new(state), 1);
|
||||
|
||||
let mut responses = FuturesUnordered::new();
|
||||
|
||||
|
@ -188,5 +201,5 @@ pub async fn populated_state(
|
|||
rsp.expect("blocks should commit just fine");
|
||||
}
|
||||
|
||||
state
|
||||
(state, read_state, latest_chain_tip, chain_tip_change)
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ async fn test_populated_state_responds_correctly(
|
|||
|
||||
#[tokio::main]
|
||||
async fn populate_and_check(blocks: Vec<Arc<Block>>) -> Result<()> {
|
||||
let state = populated_state(blocks, Network::Mainnet).await;
|
||||
let (state, _, _, _) = populated_state(blocks, Network::Mainnet).await;
|
||||
test_populated_state_responds_correctly(state).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue