Changeset View
Changeset View
Standalone View
Standalone View
chronik/chronik-indexer/src/query/util.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. | ||||
use std::collections::{hash_map::Entry, BTreeMap, HashMap}; | use std::{ | ||||
collections::{hash_map::Entry, BTreeMap, HashMap}, | |||||
str::FromStr, | |||||
}; | |||||
use abc_rust_error::Result; | use abc_rust_error::{Report, Result}; | ||||
use bitcoinsuite_core::{ | use bitcoinsuite_core::{ | ||||
block::BlockHash, | |||||
ser::BitcoinSer, | ser::BitcoinSer, | ||||
tx::{OutPoint, SpentBy, Tx, TxId}, | tx::{OutPoint, SpentBy, Tx, TxId}, | ||||
}; | }; | ||||
use chronik_db::io::{DbBlock, SpentByEntry, SpentByReader, TxNum, TxReader}; | use chronik_db::io::{ | ||||
BlockHeight, DbBlock, SpentByEntry, SpentByReader, TxNum, TxReader, | |||||
}; | |||||
use chronik_proto::proto; | use chronik_proto::proto; | ||||
use thiserror::Error; | use thiserror::Error; | ||||
use crate::avalanche::Avalanche; | use crate::avalanche::Avalanche; | ||||
/// Errors indicating something went wrong with reading txs. | /// Errors indicating something went wrong with reading txs. | ||||
#[derive(Debug, Error, PartialEq)] | #[derive(Debug, Error, PartialEq)] | ||||
pub enum QueryUtilError { | pub enum QueryUtilError { | ||||
/// DB contains a spent-by entry whose referenced tx_num cannot be found. | /// DB contains a spent-by entry whose referenced tx_num cannot be found. | ||||
#[error( | #[error( | ||||
"500: Inconsistent DB: tx_num = {tx_num} has spent entry {entry:?} in \ | "500: Inconsistent DB: tx_num = {tx_num} has spent entry {entry:?} in \ | ||||
the DB, but the tx cannot be not found in the index" | the DB, but the tx cannot be not found in the index" | ||||
)] | )] | ||||
SpendingTxNotFound { | SpendingTxNotFound { | ||||
/// Which tx has an output spent by an unknown tx. | /// Which tx has an output spent by an unknown tx. | ||||
tx_num: TxNum, | tx_num: TxNum, | ||||
/// The offending entry in the DB that references an unknown tx. | /// The offending entry in the DB that references an unknown tx. | ||||
entry: SpentByEntry, | entry: SpentByEntry, | ||||
}, | }, | ||||
/// Query is neither a hex hash nor an integer string | |||||
#[error("400: Not a hash or height: {0}")] | |||||
NotHashOrHeight(String), | |||||
} | } | ||||
use self::QueryUtilError::*; | use self::QueryUtilError::*; | ||||
/// Make a [`proto::Tx`]. | /// Make a [`proto::Tx`]. | ||||
pub(crate) fn make_tx_proto( | pub(crate) fn make_tx_proto( | ||||
tx: &Tx, | tx: &Tx, | ||||
outputs_spent: &OutputsSpent<'_>, | outputs_spent: &OutputsSpent<'_>, | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
fn make_spent_by_proto(spent_by: &SpentBy) -> proto::SpentBy { | fn make_spent_by_proto(spent_by: &SpentBy) -> proto::SpentBy { | ||||
proto::SpentBy { | proto::SpentBy { | ||||
txid: spent_by.txid.to_vec(), | txid: spent_by.txid.to_vec(), | ||||
input_idx: spent_by.input_idx, | input_idx: spent_by.input_idx, | ||||
} | } | ||||
} | } | ||||
pub(crate) enum HashOrHeight { | |||||
Hash(BlockHash), | |||||
Height(BlockHeight), | |||||
} | |||||
impl FromStr for HashOrHeight { | |||||
type Err = Report; | |||||
fn from_str(hash_or_height: &str) -> Result<Self> { | |||||
if let Ok(hash) = hash_or_height.parse::<BlockHash>() { | |||||
Ok(HashOrHeight::Hash(hash)) | |||||
} else { | |||||
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.to_string()).into() | |||||
); | |||||
} | |||||
}; | |||||
Ok(HashOrHeight::Height(height)) | |||||
} | |||||
} | |||||
} | |||||
/// Helper struct for querying which tx outputs have been spent by DB or mempool | /// Helper struct for querying which tx outputs have been spent by DB or mempool | ||||
/// txs. | /// txs. | ||||
pub(crate) struct OutputsSpent<'a> { | pub(crate) struct OutputsSpent<'a> { | ||||
spent_by_mempool: Option<&'a BTreeMap<u32, SpentBy>>, | spent_by_mempool: Option<&'a BTreeMap<u32, SpentBy>>, | ||||
spent_by_blocks: Vec<SpentByEntry>, | spent_by_blocks: Vec<SpentByEntry>, | ||||
txid_by_num: HashMap<TxNum, TxId>, | txid_by_num: HashMap<TxNum, TxId>, | ||||
} | } | ||||
▲ Show 20 Lines • Show All 58 Lines • Show Last 20 Lines |