diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 9eac7182..35135675 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -7,7 +7,7 @@ use std::{ time::Instant, }; -use futures::future::{FutureExt, TryFutureExt}; +use futures::future::FutureExt; use memory_state::{NonFinalizedState, QueuedBlocks}; use tokio::sync::broadcast; use tower::{util::BoxService, Service}; @@ -213,26 +213,24 @@ impl Service for StateService { } Request::Depth(hash) => { // todo: handle in memory and sled - self.sled.depth(hash).map_ok(Response::Depth).boxed() + let rsp = self.sled.depth(hash).map(Response::Depth); + async move { rsp }.boxed() } Request::Tip => { // todo: handle in memory and sled - self.sled.tip().map_ok(Response::Tip).boxed() + let rsp = self.sled.tip().map(Response::Tip); + async move { rsp }.boxed() } Request::BlockLocator => { // todo: handle in memory and sled - self.sled - .block_locator() - .map_ok(Response::BlockLocator) - .boxed() + let rsp = self.sled.block_locator().map(Response::BlockLocator); + async move { rsp }.boxed() } Request::Transaction(_) => unimplemented!(), Request::Block(hash_or_height) => { //todo: handle in memory and sled - self.sled - .block(hash_or_height) - .map_ok(Response::Block) - .boxed() + let rsp = self.sled.block(hash_or_height).map(Response::Block); + async move { rsp }.boxed() } Request::AwaitUtxo(outpoint) => { let fut = self.pending_utxos.queue(outpoint); diff --git a/zebra-state/src/sled_state.rs b/zebra-state/src/sled_state.rs index 1fe23ed1..7c4cb2ea 100644 --- a/zebra-state/src/sled_state.rs +++ b/zebra-state/src/sled_state.rs @@ -1,6 +1,6 @@ //! The primary implementation of the `zebra_state::Service` built upon sled -use std::{collections::HashMap, convert::TryInto, future::Future, sync::Arc}; +use std::{collections::HashMap, convert::TryInto, sync::Arc}; use tracing::trace; use zebra_chain::{ @@ -158,7 +158,7 @@ impl FinalizedState { /// Returns the hash of the current finalized tip block. pub fn finalized_tip_hash(&self) -> block::Hash { - read_tip(&self.hash_by_height) + self.tip() .expect("inability to look up tip is unrecoverable") .map(|(_, hash)| hash) // if the state is empty, return the genesis previous block hash @@ -167,7 +167,7 @@ impl FinalizedState { /// Returns the height of the current finalized tip block. pub fn finalized_tip_height(&self) -> Option { - read_tip(&self.hash_by_height) + self.tip() .expect("inability to look up tip is unrecoverable") .map(|(height, _)| height) } @@ -239,78 +239,60 @@ impl FinalizedState { } // TODO: this impl works only during checkpointing, it needs to be rewritten - pub fn block_locator(&self) -> impl Future, BoxError>> { - let hash_by_height = self.hash_by_height.clone(); + pub fn block_locator(&self) -> Result, BoxError> { + let (tip_height, _) = match self.tip()? { + Some(height) => height, + None => return Ok(Vec::new()), + }; - let tip = self.tip(); - - async move { - let (tip_height, _) = match tip.await? { - Some(height) => height, - None => return Ok(Vec::new()), - }; - - let heights = crate::util::block_locator_heights(tip_height); - let mut hashes = Vec::with_capacity(heights.len()); - for height in heights { - if let Some(bytes) = hash_by_height.get(&height.0.to_be_bytes())? { - let hash = block::Hash(bytes.as_ref().try_into().unwrap()); - hashes.push(hash) - } + let heights = crate::util::block_locator_heights(tip_height); + let mut hashes = Vec::with_capacity(heights.len()); + for height in heights { + if let Some(bytes) = self.hash_by_height.get(&height.0.to_be_bytes())? { + let hash = block::Hash(bytes.as_ref().try_into().unwrap()); + hashes.push(hash) } - Ok(hashes) } + Ok(hashes) } - pub fn tip( - &self, - ) -> impl Future, BoxError>> { - let hash_by_height = self.hash_by_height.clone(); - async move { read_tip(&hash_by_height) } + pub fn tip(&self) -> Result, BoxError> { + Ok(self.hash_by_height.iter().rev().next().transpose()?.map( + |(height_bytes, hash_bytes)| { + let height = block::Height(u32::from_be_bytes( + height_bytes.as_ref().try_into().unwrap(), + )); + let hash = block::Hash(hash_bytes.as_ref().try_into().unwrap()); + (height, hash) + }, + )) } - pub fn depth(&self, hash: block::Hash) -> impl Future, BoxError>> { - let height_by_hash = self.height_by_hash.clone(); + pub fn depth(&self, hash: block::Hash) -> Result, BoxError> { + let height = match self.height_by_hash.get(&hash.0)? { + Some(bytes) => block::Height(u32::from_be_bytes(bytes.as_ref().try_into().unwrap())), + None => return Ok(None), + }; - // TODO: this impl works only during checkpointing, it needs to be rewritten - let tip = self.tip(); + let (tip_height, _) = self.tip()?.expect("tip must exist"); - async move { - let height = match height_by_hash.get(&hash.0)? { + Ok(Some(tip_height.0 - height.0)) + } + + pub fn block(&self, hash_or_height: HashOrHeight) -> Result>, BoxError> { + let height = match hash_or_height { + HashOrHeight::Height(height) => height, + HashOrHeight::Hash(hash) => match self.height_by_hash.get(&hash.0)? { Some(bytes) => { block::Height(u32::from_be_bytes(bytes.as_ref().try_into().unwrap())) } None => return Ok(None), - }; + }, + }; - let (tip_height, _) = tip.await?.expect("tip must exist"); - - Ok(Some(tip_height.0 - height.0)) - } - } - - pub fn block( - &self, - hash_or_height: HashOrHeight, - ) -> impl Future>, BoxError>> { - let height_by_hash = self.height_by_hash.clone(); - let block_by_height = self.block_by_height.clone(); - - async move { - let height = match hash_or_height { - HashOrHeight::Height(height) => height, - HashOrHeight::Hash(hash) => match height_by_hash.get(&hash.0)? { - Some(bytes) => { - block::Height(u32::from_be_bytes(bytes.as_ref().try_into().unwrap())) - } - None => return Ok(None), - }, - }; - - match block_by_height.get(&height.0.to_be_bytes())? { - Some(bytes) => Ok(Some(Arc::::zcash_deserialize(bytes.as_ref())?)), - None => Ok(None), - } + match self.block_by_height.get(&height.0.to_be_bytes())? { + Some(bytes) => Ok(Some(Arc::::zcash_deserialize(bytes.as_ref())?)), + None => Ok(None), } } @@ -323,19 +305,3 @@ impl FinalizedState { self.utxo_by_outpoint.zs_get(outpoint) } } - -// Split into a helper function to be called synchronously or asynchronously. -fn read_tip(hash_by_height: &sled::Tree) -> Result, BoxError> { - Ok(hash_by_height - .iter() - .rev() - .next() - .transpose()? - .map(|(height_bytes, hash_bytes)| { - let height = block::Height(u32::from_be_bytes( - height_bytes.as_ref().try_into().unwrap(), - )); - let hash = block::Hash(hash_bytes.as_ref().try_into().unwrap()); - (height, hash) - })) -}