global: improve errors

This commit is contained in:
nym21
2025-12-16 20:49:19 +01:00
parent 3ca83a2289
commit 1ad8d8a631
36 changed files with 232 additions and 334 deletions

13
Cargo.lock generated
View File

@@ -647,6 +647,7 @@ dependencies = [
"jiff",
"minreq",
"serde_json",
"thiserror 2.0.17",
"tokio",
"vecdb",
]
@@ -4189,7 +4190,9 @@ dependencies = [
[[package]]
name = "rawdb"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abd96eb8d340052584b01120ce302e283b9176b278b5b5944a5f0fc00493f861"
dependencies = [
"libc",
"log",
@@ -5370,7 +5373,9 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23"
[[package]]
name = "vecdb"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "371b5a52a650ac0661a56ceae92e8af88e7930448ae9d3bb29c68a71437dc5d4"
dependencies = [
"ctrlc",
"log",
@@ -5388,7 +5393,9 @@ dependencies = [
[[package]]
name = "vecdb_derive"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f035c1c36fae53aeed226bdda0009292294986ea0ed6a932535cacdbec08d73d"
dependencies = [
"quote",
"syn 2.0.111",

View File

@@ -76,9 +76,9 @@ serde_derive = "1.0.228"
serde_json = { version = "1.0.145", features = ["float_roundtrip"] }
smallvec = "1.15.1"
tokio = { version = "1.48.0", features = ["rt-multi-thread"] }
vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco"] }
vecdb = { version = "0.4.1", features = ["derive", "serde_json", "pco"] }
# vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco"] }
# vecdb = { git = "https://github.com/anydb-rs/anydb", features = ["derive", "serde_json", "pco"] }
# vecdb = { version = "0.4.0", features = ["derive", "serde_json", "pco"] }
[workspace.metadata.release]
shared-version = true

View File

@@ -9,7 +9,7 @@ use std::{
time::{Duration, Instant, SystemTime, UNIX_EPOCH},
};
use brk_error::Result;
use brk_error::{Error, Result};
mod disk;
mod io;
@@ -84,7 +84,7 @@ impl Bencher {
current = current
.parent()
.ok_or("Workspace root not found")?
.ok_or(Error::NotFound("Workspace root not found".into()))?
.to_path_buf();
};
@@ -94,7 +94,7 @@ impl Bencher {
/// Start monitoring disk usage and memory footprint
pub fn start(&mut self) -> Result<()> {
if self.0.monitor_thread.lock().is_some() {
return Err("Bencher already started".into());
return Err(Error::Internal("Bencher already started"));
}
let stop_flag = self.0.stop_flag.clone();
@@ -113,7 +113,7 @@ impl Bencher {
self.0.stop_flag.store(true, Ordering::Relaxed);
if let Some(handle) = self.0.monitor_thread.lock().take() {
handle.join().map_err(|_| "Monitor thread panicked")??;
handle.join().map_err(|_| Error::Internal("Monitor thread panicked"))??;
}
self.0.progression.flush()?;

View File

@@ -218,7 +218,7 @@ Finally, you can run the program with '-h' for help."
self.rpcpassword.clone().unwrap(),
))
} else {
Err(Error::Str("Failed to find correct auth"))
Err(Error::AuthFailed)
}
}

View File

@@ -9,7 +9,7 @@ use brk_iterator::Blocks;
use brk_reader::Reader;
use brk_rpc::{Auth, Client};
use log::{debug, info};
use vecdb::{AnyStoredVec, Exit};
use vecdb::Exit;
pub fn main() -> Result<()> {
// Can't increase main thread's stack size, thus we need to use another thread
@@ -45,15 +45,6 @@ fn run() -> Result<()> {
let mut computer = Computer::forced_import(&outputs_benches_dir, &indexer, Some(fetcher))?;
dbg!(
computer
.indexes
.txinindex_to_txoutindex
.region()
.meta()
.reserved()
);
let mut bencher =
Bencher::from_cargo_env(env!("CARGO_PKG_NAME"), &outputs_dir.join("computed"))?;
bencher.start()?;

View File

@@ -5,7 +5,7 @@ use brk_error::Result;
use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_types::TxIndex;
use vecdb::{AnyStoredVec, Exit, GenericStoredVec};
use vecdb::{Exit, GenericStoredVec};
pub fn main() -> Result<()> {
// Can't increase main thread's stack size, thus we need to use another thread
@@ -61,18 +61,7 @@ fn run() -> Result<()> {
.txindex_to_output_count
.read_once(txindex)?;
dbg!(output_count);
let _ = dbg!(
computer
.indexes
.txinindex_to_txoutindex
.read_once(first_txinindex)
);
let _ = dbg!(
computer
.indexes
.txinindex_to_txoutindex
.read_once(first_txinindex + 1)
);
let _ = dbg!(computer.chain.txinindex_to_value.read_once(first_txinindex));
let _ = dbg!(
computer
@@ -98,13 +87,6 @@ fn run() -> Result<()> {
let _ = dbg!(computer.chain.txindex_to_input_value.read_once(txindex));
let _ = dbg!(computer.chain.txindex_to_output_value.read_once(txindex));
// dbg!(computer.indexes.txindex_to_txindex.ge(txindex));
dbg!(
computer
.indexes
.txinindex_to_txoutindex
.region()
.meta()
.len()
);
Ok(())
}

View File

@@ -853,19 +853,33 @@ impl Vecs {
compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v2, TxVersion::TWO)?;
compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v3, TxVersion::THREE)?;
// ---
// TxInIndex
// ---
let txindex_to_first_txoutindex = &indexer.vecs.tx.txindex_to_first_txoutindex;
let txindex_to_first_txoutindex_reader = txindex_to_first_txoutindex.create_reader();
let txoutindex_to_value = &indexer.vecs.txout.txoutindex_to_value;
let txoutindex_to_value_reader = indexer.vecs.txout.txoutindex_to_value.create_reader();
self.txinindex_to_value.compute_transform(
starting_indexes.txinindex,
&indexes.txinindex_to_txoutindex,
|(txinindex, txoutindex, ..)| {
let value = if txoutindex == TxOutIndex::COINBASE {
Sats::MAX
&indexer.vecs.txin.txinindex_to_outpoint,
|(txinindex, outpoint, ..)| {
if unlikely(outpoint.is_coinbase()) {
return (txinindex, Sats::MAX);
}
let txoutindex = txindex_to_first_txoutindex
.read_unwrap(outpoint.txindex(), &txindex_to_first_txoutindex_reader)
+ outpoint.vout();
let value = if unlikely(txoutindex == TxOutIndex::COINBASE) {
unreachable!()
} else {
txoutindex_to_value
.unchecked_read(txoutindex, &txoutindex_to_value_reader)
.unwrap()
};
(txinindex, value)
},
exit,

View File

@@ -159,7 +159,7 @@ where
/// Compute percentiles from sorted values (assumes values is already sorted)
fn compute_percentiles_from_sorted(&mut self, index: usize, values: &[T]) -> Result<()> {
if let Some(max) = self.max.as_mut() {
max.truncate_push_at(index, *values.last().ok_or(Error::Str("expect some"))?)?;
max.truncate_push_at(index, *values.last().ok_or(Error::Internal("Empty values for percentiles"))?)?;
}
if let Some(pct90) = self.pct90.as_mut() {
pct90.truncate_push_at(index, get_percentile(values, 0.90))?;

View File

@@ -13,8 +13,8 @@ use brk_types::{
YearIndex,
};
use vecdb::{
Database, EagerVec, Exit, GenericStoredVec, ImportableVec, IterableCloneableVec, LazyVecFrom1,
PAGE_SIZE, PcoVec, TypedVecIterator, unlikely,
Database, EagerVec, Exit, ImportableVec, IterableCloneableVec, LazyVecFrom1, PAGE_SIZE, PcoVec,
TypedVecIterator,
};
const VERSION: Version = Version::ZERO;
@@ -83,7 +83,6 @@ pub struct Vecs {
pub txindex_to_output_count: EagerVec<PcoVec<TxIndex, StoredU64>>,
pub txindex_to_txindex: LazyVecFrom1<TxIndex, TxIndex, TxIndex, Txid>,
pub txinindex_to_txinindex: LazyVecFrom1<TxInIndex, TxInIndex, TxInIndex, OutPoint>,
pub txinindex_to_txoutindex: EagerVec<PcoVec<TxInIndex, TxOutIndex>>,
pub txoutindex_to_txoutindex: LazyVecFrom1<TxOutIndex, TxOutIndex, TxOutIndex, Sats>,
pub unknownoutputindex_to_unknownoutputindex:
LazyVecFrom1<UnknownOutputIndex, UnknownOutputIndex, UnknownOutputIndex, TxIndex>,
@@ -121,7 +120,6 @@ impl Vecs {
}
let this = Self {
txinindex_to_txoutindex: eager!("txoutindex"),
txoutindex_to_txoutindex: lazy!("txoutindex", indexer.vecs.txout.txoutindex_to_value),
txinindex_to_txinindex: lazy!("txinindex", indexer.vecs.txin.txinindex_to_outpoint),
p2pk33addressindex_to_p2pk33addressindex: lazy!(
@@ -247,27 +245,6 @@ impl Vecs {
starting_indexes: brk_indexer::Indexes,
exit: &Exit,
) -> Result<Indexes> {
// ---
// TxInIndex
// ---
let txindex_to_first_txoutindex = &indexer.vecs.tx.txindex_to_first_txoutindex;
let txindex_to_first_txoutindex_reader = txindex_to_first_txoutindex.create_reader();
self.txinindex_to_txoutindex.compute_transform(
starting_indexes.txinindex,
&indexer.vecs.txin.txinindex_to_outpoint,
|(txinindex, outpoint, ..)| {
if unlikely(outpoint.is_coinbase()) {
return (txinindex, TxOutIndex::COINBASE);
}
let txoutindex = txindex_to_first_txoutindex
.read_unwrap(outpoint.txindex(), &txindex_to_first_txoutindex_reader)
+ outpoint.vout();
(txinindex, txoutindex)
},
exit,
)?;
// ---
// TxIndex
// ---

View File

@@ -821,7 +821,7 @@ impl Vecs {
Ok(prev_height.incremented())
} else {
Err(Error::Str("Unset"))
Err(Error::Internal("No previous height to import state from"))
}
}

View File

@@ -37,7 +37,7 @@ impl PriceToAmount {
let (&height, path) = files
.range(..=height)
.next_back()
.ok_or(Error::Str("Not found"))?;
.ok_or(Error::NotFound("No price state found at or before height".into()))?;
self.state = Some(State::deserialize(&fs::read(path)?)?);
Ok(height)
}

View File

@@ -15,5 +15,6 @@ fjall = { workspace = true }
jiff = { workspace = true }
minreq = { workspace = true }
serde_json = { workspace = true }
thiserror = "2.0"
tokio = { workspace = true }
vecdb = { workspace = true }

View File

@@ -1,210 +1,130 @@
#![doc = include_str!("../README.md")]
use std::{
fmt::{self, Debug, Display},
io, result, time,
};
use std::{io, result, time};
use thiserror::Error;
pub type Result<T, E = Error> = result::Result<T, E>;
#[derive(Debug)]
#[derive(Debug, Error)]
pub enum Error {
IO(io::Error),
BitcoinRPC(bitcoincore_rpc::Error),
Jiff(jiff::Error),
Fjall(fjall::Error),
VecDB(vecdb::Error),
RawDB(vecdb::RawDBError),
Minreq(minreq::Error),
SystemTimeError(time::SystemTimeError),
BitcoinConsensusEncode(bitcoin::consensus::encode::Error),
BitcoinBip34Error(bitcoin::block::Bip34Error),
BitcoinHexError(bitcoin::consensus::encode::FromHexError),
BitcoinFromScriptError(bitcoin::address::FromScriptError),
BitcoinHexToArrayError(bitcoin::hex::HexToArrayError),
SerdeJSON(serde_json::Error),
TokioJoin(tokio::task::JoinError),
ZeroCopyError,
Vecs(vecdb::Error),
#[error(transparent)]
IO(#[from] io::Error),
#[error(transparent)]
BitcoinRPC(#[from] bitcoincore_rpc::Error),
#[error(transparent)]
Jiff(#[from] jiff::Error),
#[error(transparent)]
Fjall(#[from] fjall::Error),
#[error(transparent)]
VecDB(#[from] vecdb::Error),
#[error(transparent)]
RawDB(#[from] vecdb::RawDBError),
#[error(transparent)]
Minreq(#[from] minreq::Error),
#[error(transparent)]
SystemTimeError(#[from] time::SystemTimeError),
#[error(transparent)]
BitcoinConsensusEncode(#[from] bitcoin::consensus::encode::Error),
#[error(transparent)]
BitcoinBip34Error(#[from] bitcoin::block::Bip34Error),
#[error(transparent)]
BitcoinHexError(#[from] bitcoin::consensus::encode::FromHexError),
#[error(transparent)]
BitcoinFromScriptError(#[from] bitcoin::address::FromScriptError),
#[error(transparent)]
BitcoinHexToArrayError(#[from] bitcoin::hex::HexToArrayError),
#[error(transparent)]
SerdeJSON(#[from] serde_json::Error),
#[error(transparent)]
TokioJoin(#[from] tokio::task::JoinError),
#[error("ZeroCopy error")]
ZeroCopyError,
#[error("Wrong length, expected: {expected}, received: {received}")]
WrongLength { expected: usize, received: usize },
#[error("Wrong address type")]
WrongAddressType,
#[error("Date cannot be indexed, must be 2009-01-03, 2009-01-09 or greater")]
UnindexableDate,
#[error("Quick cache error")]
QuickCacheError,
#[error("The provided address appears to be invalid")]
InvalidAddress,
#[error("Invalid network")]
InvalidNetwork,
#[error("The provided TXID appears to be invalid")]
InvalidTxid,
#[error("Mempool data is not available")]
MempoolNotAvailable,
#[error("Address not found in the blockchain (no transaction history)")]
UnknownAddress,
#[error("Failed to find the TXID in the blockchain")]
UnknownTxid,
#[error("Unsupported type ({0})")]
UnsupportedType(String),
Str(&'static str),
String(String),
// Generic errors with context
#[error("{0}")]
NotFound(String),
#[error("{0}")]
OutOfRange(String),
#[error("Parse error: {0}")]
Parse(String),
#[error("Internal error: {0}")]
Internal(&'static str),
#[error("Authentication failed")]
AuthFailed,
// Metric-specific errors
#[error("'{metric}' not found{}", suggestion.as_ref().map(|s| format!(", did you mean '{s}'?")).unwrap_or_default())]
MetricNotFound {
metric: String,
suggestion: Option<String>,
},
#[error("'{metric}' doesn't support the requested index. Supported indexes: {supported}")]
MetricUnsupportedIndex { metric: String, supported: String },
#[error("No metrics specified")]
NoMetrics,
#[error("Request weight {requested} exceeds maximum {max}")]
WeightExceeded { requested: usize, max: usize },
#[error("Fetch failed after retries: {0}")]
FetchFailed(String),
}
impl From<bitcoin::block::Bip34Error> for Error {
#[inline]
fn from(value: bitcoin::block::Bip34Error) -> Self {
Self::BitcoinBip34Error(value)
}
}
impl From<bitcoin::consensus::encode::Error> for Error {
#[inline]
fn from(value: bitcoin::consensus::encode::Error) -> Self {
Self::BitcoinConsensusEncode(value)
}
}
impl From<bitcoin::consensus::encode::FromHexError> for Error {
#[inline]
fn from(value: bitcoin::consensus::encode::FromHexError) -> Self {
Self::BitcoinHexError(value)
}
}
impl From<bitcoin::hex::HexToArrayError> for Error {
#[inline]
fn from(value: bitcoin::hex::HexToArrayError) -> Self {
Self::BitcoinHexToArrayError(value)
}
}
impl From<bitcoin::address::FromScriptError> for Error {
#[inline]
fn from(value: bitcoin::address::FromScriptError) -> Self {
Self::BitcoinFromScriptError(value)
}
}
impl From<time::SystemTimeError> for Error {
#[inline]
fn from(value: time::SystemTimeError) -> Self {
Self::SystemTimeError(value)
}
}
impl From<serde_json::Error> for Error {
#[inline]
fn from(error: serde_json::Error) -> Self {
Self::SerdeJSON(error)
}
}
impl From<tokio::task::JoinError> for Error {
#[inline]
fn from(error: tokio::task::JoinError) -> Self {
Self::TokioJoin(error)
}
}
impl From<io::Error> for Error {
#[inline]
fn from(value: io::Error) -> Self {
Self::IO(value)
}
}
impl From<vecdb::Error> for Error {
#[inline]
fn from(value: vecdb::Error) -> Self {
Self::VecDB(value)
}
}
impl From<vecdb::RawDBError> for Error {
#[inline]
fn from(value: vecdb::RawDBError) -> Self {
Self::RawDB(value)
}
}
impl From<bitcoincore_rpc::Error> for Error {
#[inline]
fn from(value: bitcoincore_rpc::Error) -> Self {
Self::BitcoinRPC(value)
}
}
impl From<minreq::Error> for Error {
#[inline]
fn from(value: minreq::Error) -> Self {
Self::Minreq(value)
}
}
impl From<jiff::Error> for Error {
#[inline]
fn from(value: jiff::Error) -> Self {
Self::Jiff(value)
}
}
impl From<fjall::Error> for Error {
#[inline]
fn from(value: fjall::Error) -> Self {
Self::Fjall(value)
}
}
impl From<&'static str> for Error {
#[inline]
fn from(value: &'static str) -> Self {
Self::Str(value)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::BitcoinConsensusEncode(error) => Display::fmt(&error, f),
Error::BitcoinBip34Error(error) => Display::fmt(&error, f),
Error::BitcoinFromScriptError(error) => Display::fmt(&error, f),
Error::BitcoinHexError(error) => Display::fmt(&error, f),
Error::BitcoinHexToArrayError(error) => Display::fmt(&error, f),
Error::BitcoinRPC(error) => Display::fmt(&error, f),
Error::Fjall(error) => Display::fmt(&error, f),
Error::IO(error) => Display::fmt(&error, f),
Error::Jiff(error) => Display::fmt(&error, f),
Error::Minreq(error) => Display::fmt(&error, f),
Error::RawDB(error) => Display::fmt(&error, f),
Error::SerdeJSON(error) => Display::fmt(&error, f),
Error::SystemTimeError(error) => Display::fmt(&error, f),
Error::TokioJoin(error) => Display::fmt(&error, f),
Error::VecDB(error) => Display::fmt(&error, f),
Error::Vecs(error) => Display::fmt(&error, f),
Error::ZeroCopyError => write!(f, "ZeroCopy error"),
Error::WrongLength { expected, received } => write!(
f,
"Wrong length, expected: {expected}, received: {received}"
),
Error::QuickCacheError => write!(f, "Quick cache error"),
Error::WrongAddressType => write!(f, "Wrong address type"),
Error::UnindexableDate => write!(
f,
"Date cannot be indexed, must be 2009-01-03, 2009-01-09 or greater"
),
Error::InvalidTxid => write!(f, "The provided TXID appears to be invalid"),
Error::InvalidNetwork => write!(f, "Invalid network"),
Error::InvalidAddress => write!(f, "The provided address appears to be invalid"),
Error::MempoolNotAvailable => write!(f, "Mempool data is not available"),
Error::UnknownAddress => write!(
f,
"Address not found in the blockchain (no transaction history)"
),
Error::UnknownTxid => write!(f, "Failed to find the TXID in the blockchain"),
Error::UnsupportedType(t) => write!(f, "Unsupported type ({t})"),
Error::Str(s) => write!(f, "{s}"),
Error::String(s) => write!(f, "{s}"),
}
}
}
impl std::error::Error for Error {}
impl Error {
/// Returns true if this network/fetch error indicates a permanent/blocking condition

View File

@@ -88,7 +88,7 @@ impl Binance {
.unwrap()
.get(date)
.cloned()
.ok_or(Error::Str("Couldn't find date"))
.ok_or(Error::NotFound("Couldn't find date".into()))
}
pub fn fetch_1d() -> Result<BTreeMap<Date, OHLCCents>> {
@@ -102,7 +102,7 @@ impl Binance {
fn read_har(&self) -> Result<BTreeMap<Timestamp, OHLCCents>> {
if self.path.is_none() {
return Err(Error::Str("Path missing"));
return Err(Error::NotFound("HAR path not configured".into()));
}
info!("Reading Binance har file...");
@@ -116,7 +116,7 @@ impl Binance {
let file = if let Ok(file) = File::open(path_binance_har) {
file
} else {
return Err(Error::Str("Missing binance file"));
return Err(Error::NotFound("Binance HAR file not found".into()));
};
let reader = BufReader::new(file);
@@ -128,13 +128,13 @@ impl Binance {
};
json.get("log")
.ok_or(Error::Str("Expect object to have log attribute"))?
.ok_or(Error::Parse("HAR missing 'log' field".into()))?
.as_object()
.ok_or(Error::Str("Expect to be an object"))?
.ok_or(Error::Parse("HAR 'log' is not an object".into()))?
.get("entries")
.ok_or(Error::Str("Expect object to have entries"))?
.ok_or(Error::Parse("HAR missing 'entries' field".into()))?
.as_array()
.ok_or(Error::Str("Expect to be an array"))?
.ok_or(Error::Parse("HAR 'entries' is not an array".into()))?
.iter()
.filter(|entry| {
entry
@@ -180,7 +180,7 @@ impl Binance {
fn parse_ohlc_array(json: &Value) -> Result<BTreeMap<Timestamp, OHLCCents>> {
let result = json
.as_array()
.ok_or(Error::Str("Expected JSON array"))?
.ok_or(Error::Parse("Expected JSON array".into()))?
.iter()
.filter_map(|v| v.as_array())
.map(|arr| {

View File

@@ -34,7 +34,7 @@ impl BRK {
.unwrap()
.get(usize::from(height.checked_sub(key).unwrap()))
.cloned()
.ok_or(Error::Str("Couldn't find height in BRK"))
.ok_or(Error::NotFound("Couldn't find height in BRK".into()))
}
fn fetch_height_prices(height: Height) -> Result<Vec<OHLCCents>> {
@@ -49,7 +49,7 @@ impl BRK {
let body: Value = serde_json::from_slice(minreq::get(url).send()?.as_bytes())?;
body.as_array()
.ok_or(Error::Str("Expect to be an array"))?
.ok_or(Error::Parse("Expected JSON array".into()))?
.iter()
.map(Self::value_to_ohlc)
.collect::<Result<Vec<_>, _>>()
@@ -74,7 +74,7 @@ impl BRK {
.unwrap()
.get(usize::from(dateindex.checked_sub(key).unwrap()))
.cloned()
.ok_or(Error::Str("Couldn't find date in BRK"))
.ok_or(Error::NotFound("Couldn't find date in BRK".into()))
}
fn fetch_date_prices(dateindex: DateIndex) -> Result<Vec<OHLCCents>> {
@@ -89,7 +89,7 @@ impl BRK {
let body: Value = serde_json::from_slice(minreq::get(url).send()?.as_bytes())?;
body.as_array()
.ok_or(Error::Str("Expect to be an array"))?
.ok_or(Error::Parse("Expected JSON array".into()))?
.iter()
.map(Self::value_to_ohlc)
.collect::<Result<Vec<_>, _>>()
@@ -99,14 +99,14 @@ impl BRK {
fn value_to_ohlc(value: &Value) -> Result<OHLCCents> {
let ohlc = value
.as_array()
.ok_or(Error::Str("Expect as_array to work"))?;
.ok_or(Error::Parse("Expected OHLC array".into()))?;
let get_value = |index: usize| -> Result<_> {
Ok(Cents::from(Dollars::from(
ohlc.get(index)
.ok_or(Error::Str("Expect index key to work"))?
.ok_or(Error::Parse("Missing OHLC value at index".into()))?
.as_f64()
.ok_or(Error::Str("Expect as_f64 to work"))?,
.ok_or(Error::Parse("Invalid OHLC value type".into()))?,
)))
};

View File

@@ -53,7 +53,7 @@ impl Kraken {
.unwrap()
.get(date)
.cloned()
.ok_or(Error::Str("Couldn't find date"))
.ok_or(Error::NotFound("Couldn't find date".into()))
}
pub fn fetch_1d() -> Result<BTreeMap<Date, OHLCCents>> {
@@ -71,7 +71,7 @@ impl Kraken {
.get("result")
.and_then(|r| r.get("XXBTZUSD"))
.and_then(|v| v.as_array())
.ok_or(Error::Str("Invalid Kraken response format"))?
.ok_or(Error::Parse("Invalid Kraken response format".into()))?
.iter()
.filter_map(|v| v.as_array())
.map(|arr| {

View File

@@ -146,7 +146,7 @@ How to fix this:
}
}
Err(Error::String(error_message()))
Err(Error::FetchFailed(error_message()))
}
fn clear_caches(&mut self) {

View File

@@ -38,7 +38,7 @@ pub fn compute_ohlc_from_range(
let last_ohlc = tree.get(&timestamp);
if previous_ohlc.is_none() || last_ohlc.is_none() {
return Err(Error::String(format!(
return Err(Error::NotFound(format!(
"Couldn't find timestamp in {source_name}"
)));
}

View File

@@ -66,7 +66,7 @@ impl<T: PriceSource> TrackedSource<T> {
/// Try to fetch, tracking health state
fn try_fetch<R>(&mut self, fetch: impl FnOnce(&mut T) -> Option<Result<R>>) -> Option<Result<R>> {
if !self.is_healthy() {
return Some(Err(Error::String(format!(
return Some(Err(Error::FetchFailed(format!(
"{} temporarily disabled (recheck in {}s)",
self.name(),
self.remaining_cooldown()

View File

@@ -76,7 +76,7 @@ impl<'a> BlockProcessor<'a> {
.is_some_and(|prev_height| *prev_height != height)
{
error!("BlockHash: {blockhash}");
return Err(Error::Str("Collision, expect prefix to need be set yet"));
return Err(Error::Internal("BlockHash prefix collision"));
}
self.indexes.push_if_needed(self.vecs)?;
@@ -234,7 +234,7 @@ impl<'a> BlockProcessor<'a> {
.tx
.txindex_to_first_txoutindex
.get_pushed_or_read(prev_txindex, &self.readers.txindex_to_first_txoutindex)?
.ok_or(Error::Str("Expect txoutindex to not be none"))?
.ok_or(Error::Internal("Missing txoutindex"))?
+ vout;
let outpoint = OutPoint::new(prev_txindex, vout);
@@ -243,7 +243,7 @@ impl<'a> BlockProcessor<'a> {
.txout
.txoutindex_to_outputtype
.get_pushed_or_read(txoutindex, &self.readers.txoutindex_to_outputtype)?
.ok_or(Error::Str("Expect outputtype to not be none"))?;
.ok_or(Error::Internal("Missing outputtype"))?;
let address_info = if outputtype.is_address() {
let typeindex = self
@@ -251,7 +251,7 @@ impl<'a> BlockProcessor<'a> {
.txout
.txoutindex_to_typeindex
.get_pushed_or_read(txoutindex, &self.readers.txoutindex_to_typeindex)?
.ok_or(Error::Str("Expect typeindex to not be none"))?;
.ok_or(Error::Internal("Missing typeindex"))?;
Some((outputtype, typeindex))
} else {
None
@@ -358,7 +358,7 @@ impl<'a> BlockProcessor<'a> {
)?;
let prev_addressbytes = prev_addressbytes_opt
.as_ref()
.ok_or(Error::Str("Expect to have addressbytes"))?;
.ok_or(Error::Internal("Missing addressbytes"))?;
if self
.stores
@@ -574,7 +574,7 @@ impl<'a> BlockProcessor<'a> {
} else {
let outputtype_typeindex = same_block_output_info
.remove(&outpoint)
.ok_or(Error::Str("should have found addressindex from same block"))
.ok_or(Error::Internal("Same-block addressindex not found"))
.inspect_err(|_| {
dbg!(&same_block_output_info, txin);
})?;
@@ -646,7 +646,7 @@ impl<'a> BlockProcessor<'a> {
let len = self.vecs.tx.txindex_to_txid.len();
let prev_txid = txindex_to_txid_iter
.get(prev_txindex)
.ok_or(Error::Str("To have txid for txindex"))
.ok_or(Error::Internal("Missing txid for txindex"))
.inspect_err(|_| {
dbg!(ct.txindex, len);
})?;
@@ -655,7 +655,7 @@ impl<'a> BlockProcessor<'a> {
if !is_dup {
dbg!(self.height, ct.txindex, prev_txid, prev_txindex);
return Err(Error::Str("Expect none"));
return Err(Error::Internal("Unexpected TXID collision"));
}
}

View File

@@ -37,7 +37,7 @@ impl Query {
let outputtype = OutputType::from(&script);
dbg!(outputtype);
let Ok(bytes) = AddressBytes::try_from((&script, outputtype)) else {
return Err(Error::Str("Failed to convert the address to bytes"));
return Err(Error::InvalidAddress);
};
let addresstype = outputtype;
let hash = AddressHash::from(&bytes);
@@ -116,8 +116,8 @@ impl Query {
let txindex = stores
.txidprefix_to_txindex
.get(&after_txid.into())
.map_err(|_| Error::Str("Failed to look up after_txid"))?
.ok_or(Error::Str("after_txid not found"))?
.map_err(|_| Error::UnknownTxid)?
.ok_or(Error::UnknownTxid)?
.into_owned();
Some(txindex)
} else {
@@ -202,7 +202,7 @@ impl Query {
}
pub fn address_mempool_txids(&self, address: Address) -> Result<Vec<Txid>> {
let mempool = self.mempool().ok_or(Error::Str("Mempool not available"))?;
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
let bytes = AddressBytes::from_str(&address)?;
let addresses = mempool.get_addresses();

View File

@@ -17,7 +17,7 @@ impl Query {
let max_height = self.max_height();
if height > max_height {
return Err(Error::Str("Block height out of range"));
return Err(Error::OutOfRange("Block height out of range".into()));
}
let blockhash = indexer.vecs.block.height_to_blockhash.read_once(height)?;
@@ -68,7 +68,7 @@ impl Query {
.blockhashprefix_to_height
.get(&prefix)?
.map(|h| *h)
.ok_or(Error::Str("Block not found"))
.ok_or(Error::NotFound("Block not found".into()))
}
fn max_height(&self) -> Height {

View File

@@ -24,7 +24,7 @@ impl Query {
.saturating_sub(1),
);
if height > max_height {
return Err(Error::Str("Block height out of range"));
return Err(Error::OutOfRange("Block height out of range".into()));
}
let position = computer.blks.height_to_position.read_once(height)?;

View File

@@ -14,7 +14,7 @@ impl Query {
let max_height_usize: usize = max_height.into();
if max_height_usize == 0 {
return Err(Error::Str("No blocks indexed"));
return Err(Error::NotFound("No blocks indexed".into()));
}
let target = timestamp;

View File

@@ -28,7 +28,7 @@ impl Query {
let max_height = self.height();
if height > max_height {
return Err(Error::Str("Block height out of range"));
return Err(Error::OutOfRange("Block height out of range".into()));
}
let first_txindex = indexer.vecs.tx.height_to_first_txindex.read_once(height)?;
@@ -64,7 +64,7 @@ impl Query {
let max_height = self.height();
if height > max_height {
return Err(Error::Str("Block height out of range"));
return Err(Error::OutOfRange("Block height out of range".into()));
}
let first_txindex = indexer.vecs.tx.height_to_first_txindex.read_once(height)?;
@@ -101,7 +101,7 @@ impl Query {
let max_height = self.height();
if height > max_height {
return Err(Error::Str("Block height out of range"));
return Err(Error::OutOfRange("Block height out of range".into()));
}
let first_txindex = indexer.vecs.tx.height_to_first_txindex.read_once(height)?;
@@ -117,7 +117,7 @@ impl Query {
let tx_count = next - first;
if index >= tx_count {
return Err(Error::Str("Transaction index out of range"));
return Err(Error::OutOfRange("Transaction index out of range".into()));
}
let txindex = TxIndex::from(first + index);

View File

@@ -5,12 +5,12 @@ use crate::Query;
impl Query {
pub fn mempool_info(&self) -> Result<MempoolInfo> {
let mempool = self.mempool().ok_or(Error::Str("Mempool not available"))?;
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
Ok(mempool.get_info())
}
pub fn mempool_txids(&self) -> Result<Vec<Txid>> {
let mempool = self.mempool().ok_or(Error::Str("Mempool not available"))?;
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
let txs = mempool.get_txs();
Ok(txs.keys().cloned().collect())
}
@@ -22,7 +22,7 @@ impl Query {
}
pub fn mempool_blocks(&self) -> Result<Vec<MempoolBlock>> {
let mempool = self.mempool().ok_or(Error::Str("Mempool not available"))?;
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
let block_stats = mempool.get_block_stats();

View File

@@ -25,17 +25,16 @@ impl Query {
// Check if metric exists but with different indexes
if let Some(indexes) = self.vecs().metric_to_indexes(metric.clone()) {
let index_list: Vec<_> = indexes.iter().map(|i| i.to_string()).collect();
return Error::String(format!(
"'{metric}' doesn't support the requested index. Supported indexes: {}",
index_list.join(", ")
));
return Error::MetricUnsupportedIndex {
metric: metric.to_string(),
supported: index_list.join(", "),
};
}
// Metric doesn't exist, suggest alternatives
if let Some(first) = self.match_metric(metric, Limit::MIN).first() {
Error::String(format!("Could not find '{metric}', did you mean '{first}'?"))
} else {
Error::String(format!("Could not find '{metric}'."))
Error::MetricNotFound {
metric: metric.to_string(),
suggestion: self.match_metric(metric, Limit::MIN).first().map(|s| s.to_string()),
}
}
@@ -161,7 +160,7 @@ impl Query {
/// Returns error if no metrics requested or any requested metric is not found.
pub fn search(&self, params: &MetricSelection) -> Result<Vec<&'static dyn AnyExportableVec>> {
if params.metrics.is_empty() {
return Err(Error::String("No metrics specified".to_string()));
return Err(Error::NoMetrics);
}
let mut vecs = Vec::with_capacity(params.metrics.len());
for metric in params.metrics.iter() {
@@ -195,9 +194,10 @@ impl Query {
let weight = Self::weight(&vecs, params.from(), params.to_for_len(metric.len()));
if weight > max_weight {
return Err(Error::String(format!(
"Request too heavy: {weight} bytes exceeds limit of {max_weight} bytes"
)));
return Err(Error::WeightExceeded {
requested: weight,
max: max_weight,
});
}
self.format(*metric, &params.range)
@@ -219,9 +219,10 @@ impl Query {
let min_len = vecs.iter().map(|v| v.len()).min().expect("search guarantees non-empty");
let weight = Self::weight(&vecs, params.from(), params.to_for_len(min_len));
if weight > max_weight {
return Err(Error::String(format!(
"Request too heavy: {weight} bytes exceeds limit of {max_weight} bytes"
)));
return Err(Error::WeightExceeded {
requested: weight,
max: max_weight,
});
}
self.format_bulk(&vecs, &params.range)

View File

@@ -64,9 +64,10 @@ impl Query {
let min_len = vecs.iter().map(|v| v.len()).min().expect("search guarantees non-empty");
let weight = Self::weight(&vecs, params.from(), params.to_for_len(min_len));
if weight > max_weight {
return Err(Error::String(format!(
"Request too heavy: {weight} bytes exceeds limit of {max_weight} bytes"
)));
return Err(Error::WeightExceeded {
requested: weight,
max: max_weight,
});
}
self.format_legacy(&vecs, &params.range)

View File

@@ -8,10 +8,14 @@
#![allow(dead_code)]
use brk_error::Result;
use brk_types::{BlockFeeRatesEntry, FeeRatePercentiles, TimePeriod};
use vecdb::{IterableVec, VecIndex};
use brk_types::{
BlockFeeRatesEntry,
// FeeRatePercentiles,
TimePeriod,
};
// use vecdb::{IterableVec, VecIndex};
use super::dateindex_iter::DateIndexIter;
// use super::dateindex_iter::DateIndexIter;
use crate::Query;
impl Query {

View File

@@ -98,7 +98,7 @@ impl Query {
.pools
.vecs
.get(&slug)
.ok_or_else(|| Error::Str("Pool data not found"))?;
.ok_or_else(|| Error::NotFound("Pool data not found".into()))?;
let mut cumulative = pool_vecs
.indexes_to_blocks_mined

View File

@@ -213,7 +213,7 @@ impl Query {
let buffer = reader.read_raw_bytes(position, *total_size as usize)?;
let mut cursor = Cursor::new(buffer);
let tx = bitcoin::Transaction::consensus_decode(&mut cursor)
.map_err(|_| Error::Str("Failed to decode transaction"))?;
.map_err(|_| Error::Parse("Failed to decode transaction".into()))?;
// For iterating through inputs, we need iterators (multiple lookups)
let mut txindex_to_txid_iter = indexer.vecs.tx.txindex_to_txid.iter()?;

View File

@@ -14,7 +14,7 @@ use std::{
use bitcoin::{block::Header, consensus::Decodable};
use blk_index_to_blk_path::*;
use brk_error::Result;
use brk_error::{Error, Result};
use brk_rpc::Client;
use brk_types::{BlkMetadata, BlkPosition, BlockHash, Height, ReadBlock};
pub use crossbeam::channel::Receiver;
@@ -88,7 +88,7 @@ impl ReaderInner {
let blk_paths = self.blk_index_to_blk_path();
let blk_path = blk_paths
.get(&position.blk_index())
.ok_or("Blk file not found")?;
.ok_or(Error::NotFound("Blk file not found".into()))?;
let mut file = File::open(blk_path)?;
file.seek(SeekFrom::Start(position.offset() as u64))?;
@@ -361,7 +361,7 @@ impl ReaderInner {
loop {
if file.read_exact(&mut byte_buffer).is_err() {
return Err("No magic bytes found".into());
return Err(Error::NotFound("No magic bytes found".into()));
}
current_4bytes.rotate_left(1);

View File

@@ -8,7 +8,7 @@ use bitcoincore_rpc::{
json::{GetBlockHeaderResult, GetBlockResult, GetBlockchainInfoResult, GetTxOutResult},
{Client as CoreClient, Error as RpcError, RpcApi},
};
use brk_error::Result;
use brk_error::{Error, Result};
use brk_types::{
BlockHash, Height, MempoolEntryInfo, Sats, Transaction, TxIn, TxOut, TxStatus, TxWithHex, Txid,
Vout,
@@ -262,7 +262,7 @@ impl Client {
let mut hash = block_info
.previous_block_hash
.map(BlockHash::from)
.ok_or("Genesis block has no previous block")?;
.ok_or(Error::NotFound("Genesis block has no previous block".into()))?;
loop {
if self.is_in_main_chain(&hash)? {
@@ -274,10 +274,10 @@ impl Client {
hash = info
.previous_block_hash
.map(BlockHash::from)
.ok_or("Reached genesis without finding main chain")?;
.ok_or(Error::NotFound("Reached genesis without finding main chain".into()))?;
}
}
Err(_) => Err("Block hash not found in blockchain".into()),
Err(_) => Err(Error::NotFound("Block hash not found in blockchain".into())),
}
}

View File

@@ -179,7 +179,7 @@ impl TryFrom<&str> for Index {
v if (Self::EmptyAddressIndex).possible_values().contains(&v) => {
Self::EmptyAddressIndex
}
_ => return Err(Error::Str("Bad index")),
_ => return Err(Error::Parse(format!("Invalid index: {value}"))),
})
}
}

View File

@@ -78,7 +78,7 @@ impl LoadedAddressData {
pub fn send(&mut self, amount: Sats, previous_price: Option<Dollars>) -> Result<()> {
if self.balance() < amount {
return Err(Error::Str("Previous_amount smaller than sent amount"));
return Err(Error::Internal("Previous amount smaller than sent amount"));
}
self.sent += amount;
self.spent_txo_count += 1;

View File

@@ -907,7 +907,7 @@ impl TryFrom<OutputType> for AddressType {
OutputType::P2TR => Self::P2tr,
OutputType::P2WPKH => Self::P2wpkh,
OutputType::P2WSH => Self::P2wsh,
_ => return Err(Error::Str("Bad output format")),
_ => return Err(Error::UnsupportedType(format!("{:?}", value))),
})
}
}