use std::{ collections::{btree_map::Entry, BTreeMap, HashMap}, error::Error, sync::Arc, }; use zebra_chain::{ block::{Block, BlockHeaderHash}, types::BlockHeight, }; #[derive(Default)] pub(super) struct BlockIndex { by_hash: HashMap>, by_height: BTreeMap>, } impl BlockIndex { pub(super) fn insert( &mut self, block: impl Into>, ) -> Result> { let block = block.into(); let hash = block.as_ref().into(); let height = block.coinbase_height().unwrap(); match self.by_height.entry(height) { Entry::Vacant(entry) => { let _ = entry.insert(block.clone()); let _ = self.by_hash.insert(hash, block); Ok(hash) } Entry::Occupied(_) => Err("forks in the chain aren't supported yet")?, } } pub(super) fn get(&mut self, query: impl Into) -> Option> { match query.into() { BlockQuery::ByHash(hash) => self.by_hash.get(&hash), BlockQuery::ByHeight(height) => self.by_height.get(&height), } .cloned() } pub(super) fn get_tip(&self) -> Option> { self.by_height .iter() .next_back() .map(|(_key, value)| value.clone()) } } pub(super) enum BlockQuery { ByHash(BlockHeaderHash), ByHeight(BlockHeight), } impl From for BlockQuery { fn from(hash: BlockHeaderHash) -> Self { Self::ByHash(hash) } } impl From for BlockQuery { fn from(height: BlockHeight) -> Self { Self::ByHeight(height) } }