Changeset View
Changeset View
Standalone View
Standalone View
chronik/chronik-indexer/src/query/blocks.rs
// Copyright (c) 2023 The Bitcoin developers | // Copyright (c) 2023 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
//! Module for [`QueryBlocks`], to query blocks. | //! Module for [`QueryBlocks`], to query blocks. | ||||
use abc_rust_error::Result; | use abc_rust_error::Result; | ||||
use bitcoinsuite_core::block::BlockHash; | |||||
use chronik_db::{ | use chronik_db::{ | ||||
db::Db, | db::Db, | ||||
io::{BlockHeight, BlockReader, BlockStats, BlockStatsReader, DbBlock}, | io::{BlockHeight, BlockReader, BlockStats, BlockStatsReader, DbBlock}, | ||||
}; | }; | ||||
use chronik_proto::proto; | use chronik_proto::proto; | ||||
use thiserror::Error; | use thiserror::Error; | ||||
use crate::avalanche::Avalanche; | use crate::{avalanche::Avalanche, query::HashOrHeight}; | ||||
const MAX_BLOCKS_PAGE_SIZE: usize = 500; | const MAX_BLOCKS_PAGE_SIZE: usize = 500; | ||||
/// Struct for querying blocks from the DB. | /// Struct for querying blocks from the DB. | ||||
#[derive(Debug)] | #[derive(Debug)] | ||||
pub struct QueryBlocks<'a> { | pub struct QueryBlocks<'a> { | ||||
/// Db. | /// Db. | ||||
pub db: &'a Db, | pub db: &'a Db, | ||||
/// Avalanche. | /// Avalanche. | ||||
pub avalanche: &'a Avalanche, | pub avalanche: &'a Avalanche, | ||||
} | } | ||||
/// Errors indicating something went wrong with querying blocks. | /// Errors indicating something went wrong with querying blocks. | ||||
#[derive(Debug, Error, PartialEq)] | #[derive(Debug, Error, PartialEq)] | ||||
pub enum QueryBlockError { | pub enum QueryBlockError { | ||||
/// Query is neither a hex hash nor an integer string | |||||
#[error("400: Not a hash or height: {0}")] | |||||
NotHashOrHeight(String), | |||||
/// Block not found in DB | /// Block not found in DB | ||||
#[error("404: Block not found: {0}")] | #[error("404: Block not found: {0}")] | ||||
BlockNotFound(String), | BlockNotFound(String), | ||||
/// Invalid block start height | /// Invalid block start height | ||||
#[error("400: Invalid block start height: {0}")] | #[error("400: Invalid block start height: {0}")] | ||||
InvalidStartHeight(BlockHeight), | InvalidStartHeight(BlockHeight), | ||||
Show All 21 Lines | impl<'a> QueryBlocks<'a> { | ||||
/// `height` may not have any leading zeros, because otherwise it might | /// `height` may not have any leading zeros, because otherwise it might | ||||
/// become ambiguous with a hash. | /// become ambiguous with a hash. | ||||
pub fn by_hash_or_height( | pub fn by_hash_or_height( | ||||
&self, | &self, | ||||
hash_or_height: String, | hash_or_height: String, | ||||
) -> Result<proto::Block> { | ) -> Result<proto::Block> { | ||||
let db_blocks = BlockReader::new(self.db)?; | let db_blocks = BlockReader::new(self.db)?; | ||||
let block_stats_reader = BlockStatsReader::new(self.db)?; | let block_stats_reader = BlockStatsReader::new(self.db)?; | ||||
let db_block = if let Ok(hash) = hash_or_height.parse::<BlockHash>() { | let db_block = match hash_or_height.parse::<HashOrHeight>()? { | ||||
db_blocks.by_hash(&hash)? | HashOrHeight::Hash(hash) => db_blocks.by_hash(&hash)?, | ||||
} else { | HashOrHeight::Height(height) => db_blocks.by_height(height)?, | ||||
let height = match hash_or_height.parse::<BlockHeight>() { | |||||
// disallow leading zeros | |||||
Ok(0) if hash_or_height.len() == 1 => 0, | |||||
Ok(height) if !hash_or_height.starts_with('0') => height, | |||||
_ => return Err(NotHashOrHeight(hash_or_height).into()), | |||||
}; | |||||
db_blocks.by_height(height)? | |||||
}; | }; | ||||
let db_block = db_block.ok_or(BlockNotFound(hash_or_height))?; | let db_block = db_block.ok_or(BlockNotFound(hash_or_height))?; | ||||
let block_stats = block_stats_reader | let block_stats = block_stats_reader | ||||
.by_height(db_block.height)? | .by_height(db_block.height)? | ||||
.ok_or(MissingBlockStats(db_block.height))?; | .ok_or(MissingBlockStats(db_block.height))?; | ||||
Ok(proto::Block { | Ok(proto::Block { | ||||
block_info: Some( | block_info: Some( | ||||
self.make_block_info_proto(&db_block, &block_stats), | self.make_block_info_proto(&db_block, &block_stats), | ||||
▲ Show 20 Lines • Show All 75 Lines • Show Last 20 Lines |