diff --git a/zebra-rpc/src/methods.rs b/zebra-rpc/src/methods.rs index 1f39640e2ef..bf8281fb64b 100644 --- a/zebra-rpc/src/methods.rs +++ b/zebra-rpc/src/methods.rs @@ -360,7 +360,7 @@ where + Sync + 'static, State::Future: Send, - Tip: ChainTip + Send + Sync + 'static, + Tip: ChainTip + Clone + Send + Sync + 'static, { fn get_info(&self) -> Result { let response = GetInfo { @@ -869,18 +869,16 @@ where request: GetAddressTxIdsRequest, ) -> BoxFuture>> { let mut state = self.state.clone(); + let latest_chain_tip = self.latest_chain_tip.clone(); + let start = Height(request.start); let end = Height(request.end); - let chain_height = self.latest_chain_tip.best_tip_height().ok_or(Error { - code: ErrorCode::ServerError(0), - message: "No blocks in state".to_string(), - data: None, - }); - async move { + let chain_height = best_chain_tip_height(&latest_chain_tip)?; + // height range checks - check_height_range(start, end, chain_height?)?; + check_height_range(start, end, chain_height)?; let valid_addresses = AddressStrings { addresses: request.addresses, @@ -994,6 +992,19 @@ where } } +/// Returns the best chain tip height of `latest_chain_tip`, +/// or an RPC error if there are no blocks in the state. +pub fn best_chain_tip_height(latest_chain_tip: &Tip) -> Result +where + Tip: ChainTip + Clone + Send + Sync + 'static, +{ + latest_chain_tip.best_tip_height().ok_or(Error { + code: ErrorCode::ServerError(0), + message: "No blocks in state".to_string(), + data: None, + }) +} + /// Response to a `getinfo` RPC request. /// /// See the notes for the [`Rpc::get_info` method]. diff --git a/zebra-rpc/src/methods/get_block_template_rpcs.rs b/zebra-rpc/src/methods/get_block_template_rpcs.rs index ae9c004e885..f6d33feb25a 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs.rs @@ -18,6 +18,7 @@ use zebra_consensus::{BlockError, VerifyBlockError, VerifyChainError, VerifyChec use zebra_node_services::mempool; use crate::methods::{ + best_chain_tip_height, get_block_template_rpcs::types::{ default_roots::DefaultRoots, get_block_template::GetBlockTemplate, hex_data::HexData, submit_block, transaction::TransactionTemplate, @@ -197,7 +198,7 @@ where + Sync + 'static, >::Future: Send, - Tip: ChainTip + Send + Sync + 'static, + Tip: ChainTip + Clone + Send + Sync + 'static, ChainVerifier: Service, Response = block::Hash, Error = zebra_consensus::BoxError> + Clone + Send @@ -206,27 +207,15 @@ where >>::Future: Send, { fn get_block_count(&self) -> Result { - self.latest_chain_tip - .best_tip_height() - .map(|height| height.0) - .ok_or(Error { - code: ErrorCode::ServerError(0), - message: "No blocks in state".to_string(), - data: None, - }) + best_chain_tip_height(&self.latest_chain_tip).map(|height| height.0) } fn get_block_hash(&self, index: i32) -> BoxFuture> { let mut state = self.state.clone(); - - let maybe_tip_height = self.latest_chain_tip.best_tip_height(); + let latest_chain_tip = self.latest_chain_tip.clone(); async move { - let tip_height = maybe_tip_height.ok_or(Error { - code: ErrorCode::ServerError(0), - message: "No blocks in state".to_string(), - data: None, - })?; + let tip_height = best_chain_tip_height(&latest_chain_tip)?; let height = get_height_from_int(index, tip_height)?; @@ -256,9 +245,12 @@ where fn get_block_template(&self) -> BoxFuture> { let mempool = self.mempool.clone(); + let latest_chain_tip = self.latest_chain_tip.clone(); // Since this is a very large RPC, we use separate functions for each group of fields. async move { + let _tip_height = best_chain_tip_height(&latest_chain_tip)?; + // TODO: put this in a separate get_mempool_transactions() function let request = mempool::Request::FullTransactions; let response = mempool.oneshot(request).await.map_err(|error| Error {