diff --git a/crates/brk_query/examples/query.rs b/crates/brk_query/examples/query.rs index 2b858255b..b52c170fd 100644 --- a/crates/brk_query/examples/query.rs +++ b/crates/brk_query/examples/query.rs @@ -62,21 +62,19 @@ fn run() -> Result<()> { .approximate_len() ); - let _ = dbg!(query.address(Address { - address: "bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string(), - })); + let _ = dbg!(query.address(Address::from( + "bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string(), + ))); let _ = dbg!(query.address_txids( - Address { - address: "bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string(), - }, + Address::from("bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string()), None, 25 )); - let _ = dbg!(query.address_utxos(Address { - address: "bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string(), - })); + let _ = dbg!(query.address_utxos(Address::from( + "bc1qwzrryqr3ja8w7hnja2spmkgfdcgvqwp5swz4af4ngsjecfz0w0pqud7k38".to_string() + ))); // dbg!(query.search_and_format(MetricSelection { // index: Index::Height, diff --git a/crates/brk_query/src/impl/address.rs b/crates/brk_query/src/impl/address.rs index 12ec6f7a2..2d358a434 100644 --- a/crates/brk_query/src/impl/address.rs +++ b/crates/brk_query/src/impl/address.rs @@ -15,7 +15,7 @@ use crate::Query; const MAX_MEMPOOL_TXIDS: usize = 50; impl Query { - pub fn address(&self, Address { address }: Address) -> Result { + pub fn address(&self, address: Address) -> Result { let indexer = self.indexer(); let computer = self.computer(); let stores = &indexer.stores; @@ -74,7 +74,7 @@ impl Query { }; Ok(AddressStats { - address: address.into(), + address, chain_stats: AddressChainStats { type_index, funded_txo_count: address_data.funded_txo_count, @@ -204,7 +204,7 @@ impl Query { pub fn address_mempool_txids(&self, address: Address) -> Result> { let mempool = self.mempool().ok_or(Error::Str("Mempool not available"))?; - let bytes = AddressBytes::from_str(&address.address)?; + let bytes = AddressBytes::from_str(&address)?; let addresses = mempool.get_addresses(); let txids: Vec = addresses @@ -219,7 +219,7 @@ impl Query { fn resolve_address(&self, address: &Address) -> Result<(OutputType, TypeIndex)> { let stores = &self.indexer().stores; - let bytes = AddressBytes::from_str(&address.address)?; + let bytes = AddressBytes::from_str(address)?; let outputtype = OutputType::from(&bytes); let hash = AddressHash::from(&bytes); diff --git a/crates/brk_server/src/api/metrics/mod.rs b/crates/brk_server/src/api/metrics/mod.rs index c7c172f2f..23a69557f 100644 --- a/crates/brk_server/src/api/metrics/mod.rs +++ b/crates/brk_server/src/api/metrics/mod.rs @@ -116,6 +116,7 @@ impl ApiMetricsRoutes for ApiRouter { }, |op| op .metrics_tag() + // .path_param::() .summary("Search metrics") .description("Fuzzy search for metrics by name. Supports partial matches and typos.") .ok_response::>() diff --git a/crates/brk_server/src/api/mining/mod.rs b/crates/brk_server/src/api/mining/mod.rs index 622b5762f..f0e663ac9 100644 --- a/crates/brk_server/src/api/mining/mod.rs +++ b/crates/brk_server/src/api/mining/mod.rs @@ -8,7 +8,7 @@ use axum::{ use brk_types::{ BlockCountPath, BlockFeeRatesEntry, BlockFeesEntry, BlockRewardsEntry, BlockSizesWeights, DifficultyAdjustment, DifficultyAdjustmentEntry, HashrateSummary, PoolDetail, PoolInfo, - PoolSlugPath, PoolsSummary, RewardStats, TimePeriodPath, + PoolSlugPath, PoolsSummary, RewardStats, TimePeriod, }; use crate::{CacheStrategy, extended::TransformResponseExtended}; @@ -61,8 +61,8 @@ impl MiningRoutes for ApiRouter { .api_route( "/api/v1/mining/pools/{time_period}", get_with( - async |headers: HeaderMap, Path(path): Path, State(state): State| { - state.cached_json(&headers, CacheStrategy::height_with(format!("{:?}", path.time_period)), move |q| q.mining_pools(path.time_period)).await + async |headers: HeaderMap, Path(time_period): Path, State(state): State| { + state.cached_json(&headers, CacheStrategy::height_with(format!("{:?}", time_period)), move |q| q.mining_pools(time_period)).await }, |op| { op.mining_tag() @@ -110,8 +110,8 @@ impl MiningRoutes for ApiRouter { .api_route( "/api/v1/mining/hashrate/{time_period}", get_with( - async |headers: HeaderMap, Path(path): Path, State(state): State| { - state.cached_json(&headers, CacheStrategy::height_with(format!("hashrate-{:?}", path.time_period)), move |q| q.hashrate(Some(path.time_period))).await + async |headers: HeaderMap, Path(time_period): Path, State(state): State| { + state.cached_json(&headers, CacheStrategy::height_with(format!("hashrate-{:?}", time_period)), move |q| q.hashrate(Some(time_period))).await }, |op| { op.mining_tag() @@ -142,8 +142,8 @@ impl MiningRoutes for ApiRouter { .api_route( "/api/v1/mining/difficulty-adjustments/{time_period}", get_with( - async |headers: HeaderMap, Path(path): Path, State(state): State| { - state.cached_json(&headers, CacheStrategy::height_with(format!("diff-adj-{:?}", path.time_period)), move |q| q.difficulty_adjustments(Some(path.time_period))).await + async |headers: HeaderMap, Path(time_period): Path, State(state): State| { + state.cached_json(&headers, CacheStrategy::height_with(format!("diff-adj-{:?}", time_period)), move |q| q.difficulty_adjustments(Some(time_period))).await }, |op| { op.mining_tag() @@ -158,8 +158,8 @@ impl MiningRoutes for ApiRouter { .api_route( "/api/v1/mining/blocks/fees/{time_period}", get_with( - async |headers: HeaderMap, Path(path): Path, State(state): State| { - state.cached_json(&headers, CacheStrategy::height_with(format!("fees-{:?}", path.time_period)), move |q| q.block_fees(path.time_period)).await + async |headers: HeaderMap, Path(time_period): Path, State(state): State| { + state.cached_json(&headers, CacheStrategy::height_with(format!("fees-{:?}", time_period)), move |q| q.block_fees(time_period)).await }, |op| { op.mining_tag() @@ -174,8 +174,8 @@ impl MiningRoutes for ApiRouter { .api_route( "/api/v1/mining/blocks/rewards/{time_period}", get_with( - async |headers: HeaderMap, Path(path): Path, State(state): State| { - state.cached_json(&headers, CacheStrategy::height_with(format!("rewards-{:?}", path.time_period)), move |q| q.block_rewards(path.time_period)).await + async |headers: HeaderMap, Path(time_period): Path, State(state): State| { + state.cached_json(&headers, CacheStrategy::height_with(format!("rewards-{:?}", time_period)), move |q| q.block_rewards(time_period)).await }, |op| { op.mining_tag() @@ -190,8 +190,8 @@ impl MiningRoutes for ApiRouter { .api_route( "/api/v1/mining/blocks/fee-rates/{time_period}", get_with( - async |headers: HeaderMap, Path(path): Path, State(state): State| { - state.cached_json(&headers, CacheStrategy::height_with(format!("feerates-{:?}", path.time_period)), move |q| q.block_fee_rates(path.time_period)).await + async |headers: HeaderMap, Path(time_period): Path, State(state): State| { + state.cached_json(&headers, CacheStrategy::height_with(format!("feerates-{:?}", time_period)), move |q| q.block_fee_rates(time_period)).await }, |op| { op.mining_tag() @@ -206,8 +206,8 @@ impl MiningRoutes for ApiRouter { .api_route( "/api/v1/mining/blocks/sizes-weights/{time_period}", get_with( - async |headers: HeaderMap, Path(path): Path, State(state): State| { - state.cached_json(&headers, CacheStrategy::height_with(format!("sizes-{:?}", path.time_period)), move |q| q.block_sizes_weights(path.time_period)).await + async |headers: HeaderMap, Path(time_period): Path, State(state): State| { + state.cached_json(&headers, CacheStrategy::height_with(format!("sizes-{:?}", time_period)), move |q| q.block_sizes_weights(time_period)).await }, |op| { op.mining_tag() diff --git a/crates/brk_server/src/api/mod.rs b/crates/brk_server/src/api/mod.rs index 06c5613f2..f9458cb88 100644 --- a/crates/brk_server/src/api/mod.rs +++ b/crates/brk_server/src/api/mod.rs @@ -51,7 +51,11 @@ impl ApiRoutes for ApiRouter { "/version", get_with( async |headers: HeaderMap, State(state): State| { - state.cached_json(&headers, CacheStrategy::Static, |_| Ok(env!("CARGO_PKG_VERSION"))).await + state + .cached_json(&headers, CacheStrategy::Static, |_| { + Ok(env!("CARGO_PKG_VERSION")) + }) + .await }, |op| { op.server_tag() diff --git a/crates/brk_types/src/address.rs b/crates/brk_types/src/address.rs index 65a97f451..1b1d3f1fe 100644 --- a/crates/brk_types/src/address.rs +++ b/crates/brk_types/src/address.rs @@ -1,32 +1,49 @@ -use std::{fmt, str::FromStr}; +use std::{borrow::Cow, fmt, str::FromStr}; use bitcoin::ScriptBuf; use brk_error::Error; use derive_deref::Deref; -use schemars::JsonSchema; +use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema}; use serde::{Deserialize, Serialize, Serializer}; use crate::AddressBytes; use super::OutputType; -#[derive(Debug, Deref, Deserialize, JsonSchema)] -pub struct Address { - /// Bitcoin address string - #[schemars(example = &"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f")] - pub address: String, +/// Bitcoin address string +#[derive(Debug, Deref, Deserialize)] +pub struct Address(String); + +impl JsonSchema for Address { + fn schema_name() -> Cow<'static, str> { + Cow::Borrowed("Address") + } + + fn json_schema(_: &mut SchemaGenerator) -> Schema { + json_schema!({ + "type": "object", + "required": ["address"], + "properties": { + "address": { + "type": "string", + "description": "Bitcoin address string", + "examples": ["04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"] + } + } + }) + } } impl fmt::Display for Address { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.address) + f.write_str(&self.0) } } impl From for Address { #[inline] fn from(address: String) -> Self { - Self { address } + Self(address) } } @@ -41,9 +58,7 @@ impl TryFrom<(&ScriptBuf, OutputType)> for Address { type Error = Error; fn try_from((script, outputtype): (&ScriptBuf, OutputType)) -> Result { if outputtype.is_address() { - Ok(Self { - address: script.to_hex_string(), - }) + Ok(Self(script.to_hex_string())) } else { Err(Error::InvalidAddress) } @@ -78,7 +93,7 @@ impl Serialize for Address { where S: Serializer, { - serializer.collect_str(&self.address) + serializer.collect_str(&self.0) } } @@ -87,15 +102,13 @@ impl FromStr for Address { fn from_str(s: &str) -> Result { let _ = AddressBytes::address_to_script(s)?; - Ok(Self { - address: s.to_string(), - }) + Ok(Self(s.to_string())) } } impl Address { /// Get the script for this address pub fn script(&self) -> Result { - AddressBytes::address_to_script(&self.address) + AddressBytes::address_to_script(&self.0) } } diff --git a/crates/brk_types/src/datarange.rs b/crates/brk_types/src/datarange.rs index d4b69ed7e..448ddee1f 100644 --- a/crates/brk_types/src/datarange.rs +++ b/crates/brk_types/src/datarange.rs @@ -1,19 +1,24 @@ use schemars::JsonSchema; use serde::Deserialize; +use crate::{de_unquote_i64, de_unquote_usize}; + /// Range parameters for slicing data #[derive(Default, Debug, Deserialize, JsonSchema)] pub struct DataRange { /// Inclusive starting index, if negative will be from the end - #[serde(default, alias = "f")] + #[serde(default, alias = "f", deserialize_with = "de_unquote_i64")] + #[schemars(example = 0, example = -1, example = -10, example = -1000)] from: Option, /// Exclusive ending index, if negative will be from the end, overrides 'count' - #[serde(default, alias = "t")] + #[serde(default, alias = "t", deserialize_with = "de_unquote_i64")] + #[schemars(example = 1000)] to: Option, /// Number of values requested - #[serde(default, alias = "c")] + #[serde(default, alias = "c", deserialize_with = "de_unquote_usize")] + #[schemars(example = 1, example = 10, example = 100)] count: Option, } diff --git a/crates/brk_types/src/deser.rs b/crates/brk_types/src/deser.rs new file mode 100644 index 000000000..5c6d807a2 --- /dev/null +++ b/crates/brk_types/src/deser.rs @@ -0,0 +1,52 @@ +use serde::{Deserialize, Deserializer}; +use serde_json::Value; + +pub fn de_unquote_i64<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let value: Option = Option::deserialize(deserializer)?; + + if value.is_none() { + return Ok(None); + } + + let value = value.unwrap(); + + if let Some(mut s) = value.as_str().map(|s| s.to_string()) { + if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 { + s = s[1..s.len() - 1].to_string(); + } + s.parse::().map(Some).map_err(serde::de::Error::custom) + } else if let Some(n) = value.as_i64() { + Ok(Some(n)) + } else { + Err(serde::de::Error::custom("expected a string or number")) + } +} + +pub fn de_unquote_usize<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let value: Option = Option::deserialize(deserializer)?; + + if value.is_none() { + return Ok(None); + } + + let value = value.unwrap(); + + if let Some(mut s) = value.as_str().map(|s| s.to_string()) { + if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 { + s = s[1..s.len() - 1].to_string(); + } + s.parse::() + .map(Some) + .map_err(serde::de::Error::custom) + } else if let Some(n) = value.as_u64() { + Ok(Some(n as usize)) + } else { + Err(serde::de::Error::custom("expected a string or number")) + } +} diff --git a/crates/brk_types/src/index.rs b/crates/brk_types/src/index.rs index e012047b0..697e9b6e8 100644 --- a/crates/brk_types/src/index.rs +++ b/crates/brk_types/src/index.rs @@ -13,64 +13,38 @@ use super::{ SemesterIndex, TxIndex, UnknownOutputIndex, WeekIndex, YearIndex, }; -/// Aggregation dimension for querying Bitcoin blockchain data +/// Aggregation dimension for querying metrics. Includes time-based (date, week, month, year), +/// block-based (height, txindex), and address/output type indexes. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, JsonSchema)] #[serde(rename_all = "lowercase")] #[schemars(example = Index::DateIndex)] pub enum Index { - /// Date/day index DateIndex, - /// Decade index DecadeIndex, - /// Difficulty epoch index (equivalent to ~2 weeks) DifficultyEpoch, - /// Empty output index EmptyOutputIndex, - /// Halving epoch index (equivalent to ~4 years) HalvingEpoch, - /// Height/block index Height, - /// Transaction input index (based on total) TxInIndex, - /// Month index MonthIndex, - /// Op return index OpReturnIndex, - /// Transaction output index (based on total) TxOutIndex, - /// Index of P2A address P2AAddressIndex, - /// Index of P2MS output P2MSOutputIndex, - /// Index of P2PK (33 bytes) address P2PK33AddressIndex, - /// Index of P2PK (65 bytes) address P2PK65AddressIndex, - /// Index of P2PKH address P2PKHAddressIndex, - /// Index of P2SH address P2SHAddressIndex, - /// Index of P2TR address P2TRAddressIndex, - /// Index of P2WPKH address P2WPKHAddressIndex, - /// Index of P2WSH address P2WSHAddressIndex, - /// Quarter index QuarterIndex, - /// Semester index SemesterIndex, - /// Transaction index TxIndex, - /// Unknown output index UnknownOutputIndex, - /// Week index WeekIndex, - /// Year index YearIndex, - /// Loaded Address Index LoadedAddressIndex, - /// Empty Address Index EmptyAddressIndex, } diff --git a/crates/brk_types/src/lib.rs b/crates/brk_types/src/lib.rs index c42d6cac1..020606f18 100644 --- a/crates/brk_types/src/lib.rs +++ b/crates/brk_types/src/lib.rs @@ -39,6 +39,7 @@ mod datarangeformat; mod date; mod dateindex; mod decadeindex; +mod deser; mod difficultyadjustment; mod difficultyadjustmententry; mod difficultyentry; @@ -187,6 +188,7 @@ pub use datarangeformat::*; pub use date::*; pub use dateindex::*; pub use decadeindex::*; +pub use deser::*; pub use difficultyadjustment::*; pub use difficultyadjustmententry::*; pub use difficultyentry::*; diff --git a/crates/brk_types/src/limit.rs b/crates/brk_types/src/limit.rs index 5dd7012ed..631e3d4e8 100644 --- a/crates/brk_types/src/limit.rs +++ b/crates/brk_types/src/limit.rs @@ -1,26 +1,39 @@ +use std::borrow::Cow; + use derive_deref::Deref; -use schemars::JsonSchema; +use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema}; use serde::Deserialize; -#[derive(Debug, Deref, Deserialize, JsonSchema)] -pub struct Limit { - /// Maximum number of results to return. Defaults to 100 if not specified. - #[serde(default = "default_search_limit")] - #[schemars( - example = "1", - example = "10", - example = "100", - example = "1000", - example = "10000", - example = "100000" - )] - limit: usize, -} +/// Maximum number of results to return. Defaults to 100 if not specified. +#[derive(Debug, Deref, Deserialize)] +#[serde(default = "default_search_limit")] +pub struct Limit(usize); impl Limit { - pub const MIN: Self = Self { limit: 1 }; + pub const MIN: Self = Self(1); + pub const DEFAULT: Self = Self(100); } -fn default_search_limit() -> usize { - 100 +fn default_search_limit() -> Limit { + Limit::DEFAULT +} + +impl JsonSchema for Limit { + fn schema_name() -> Cow<'static, str> { + Cow::Borrowed("Limit") + } + + fn json_schema(_: &mut SchemaGenerator) -> Schema { + json_schema!({ + "type": "object", + "properties": { + "limit": { + "type": "integer", + "description": "Maximum number of results to return. Defaults to 100 if not specified.", + "default": 100, + "examples": [1, 10, 100, 1000, 10000, 100000] + } + } + }) + } } diff --git a/crates/brk_types/src/metric.rs b/crates/brk_types/src/metric.rs index dea28f57c..fb5d0de5d 100644 --- a/crates/brk_types/src/metric.rs +++ b/crates/brk_types/src/metric.rs @@ -1,34 +1,44 @@ -use std::fmt::Display; +use std::{borrow::Cow, fmt::Display}; use derive_deref::Deref; -use schemars::JsonSchema; +use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema}; use serde::Deserialize; -#[derive(Debug, Clone, Deref, Deserialize, JsonSchema)] -pub struct Metric { - /// Metric name - #[schemars(example = &"price_close", example = &"market_cap", example = &"realized_price")] - metric: String, -} +/// Metric name +#[derive(Debug, Clone, Deref, Deserialize)] +#[serde(transparent)] +pub struct Metric(String); impl From for Metric { #[inline] fn from(metric: String) -> Self { - Self { metric } + Self(metric) } } impl From<&str> for Metric { #[inline] fn from(metric: &str) -> Self { - Self { - metric: metric.to_string(), - } + Self(metric.to_owned()) } } impl Display for Metric { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.metric) + write!(f, "{}", self.0) + } +} + +impl JsonSchema for Metric { + fn schema_name() -> Cow<'static, str> { + Cow::Borrowed("Metric") + } + + fn json_schema(_: &mut SchemaGenerator) -> Schema { + json_schema!({ + "type": "string", + "description": "Metric name", + "examples": ["price_close", "market_cap", "realized_price"] + }) } } diff --git a/crates/brk_types/src/metrics.rs b/crates/brk_types/src/metrics.rs index 205108007..a13b50177 100644 --- a/crates/brk_types/src/metrics.rs +++ b/crates/brk_types/src/metrics.rs @@ -6,11 +6,10 @@ use serde::Deserialize; use super::Metric; +/// A list of metrics #[derive(Debug, Deref, JsonSchema)] -pub struct Metrics { - /// A list of metrics - metrics: Vec, -} +#[schemars(transparent)] +pub struct Metrics(Vec); const MAX_VECS: usize = 32; const MAX_STRING_SIZE: usize = 64 * MAX_VECS; @@ -18,9 +17,7 @@ const MAX_STRING_SIZE: usize = 64 * MAX_VECS; impl From for Metrics { #[inline] fn from(metric: Metric) -> Self { - Self { - metrics: vec![metric], - } + Self(vec![metric]) } } @@ -34,12 +31,12 @@ impl From for Metrics { impl<'a> From> for Metrics { #[inline] fn from(value: Vec<&'a str>) -> Self { - Self { - metrics: value + Self( + value .iter() .map(|s| Metric::from(s.replace("-", "_").to_lowercase())) .collect::>(), - } + ) } } @@ -52,23 +49,23 @@ impl<'de> Deserialize<'de> for Metrics { if let Some(str) = value.as_str() { if str.len() <= MAX_STRING_SIZE { - Ok(Self { - metrics: sanitize(str.split(",").map(|s| s.to_string())) + Ok(Self( + sanitize(str.split(",").map(|s| s.to_string())) .into_iter() .map(Metric::from) .collect(), - }) + )) } else { Err(serde::de::Error::custom("Given parameter is too long")) } } else if let Some(vec) = value.as_array() { if vec.len() <= MAX_VECS { - Ok(Self { - metrics: sanitize(vec.iter().map(|s| s.as_str().unwrap().to_string())) + Ok(Self( + sanitize(vec.iter().map(|s| s.as_str().unwrap().to_string())) .into_iter() .map(Metric::from) .collect(), - }) + )) } else { Err(serde::de::Error::custom("Given parameter is too long")) } @@ -81,7 +78,7 @@ impl<'de> Deserialize<'de> for Metrics { impl fmt::Display for Metrics { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = self - .metrics + .0 .iter() .map(|m| m.to_string()) .collect::>() diff --git a/crates/brk_types/src/poolslug.rs b/crates/brk_types/src/poolslug.rs index 91018ea99..af36905eb 100644 --- a/crates/brk_types/src/poolslug.rs +++ b/crates/brk_types/src/poolslug.rs @@ -4,8 +4,7 @@ use serde::{Deserialize, Serialize}; use strum::Display; use vecdb::{Bytes, Formattable}; -// Created from the list in `pools.rs` -// Can be used as index for said list +// Slug of a mining pool #[allow(clippy::upper_case_acronyms)] #[derive( Debug, diff --git a/crates/brk_types/src/timeperiod.rs b/crates/brk_types/src/timeperiod.rs index 865d41ff8..852a7c477 100644 --- a/crates/brk_types/src/timeperiod.rs +++ b/crates/brk_types/src/timeperiod.rs @@ -5,34 +5,35 @@ use serde::{Deserialize, Serialize}; /// /// Used to specify the lookback window for pool statistics, hashrate calculations, /// and other time-based mining metrics. +/// +/// - `Day` (alias: 24h) - Last 24 hours (~144 blocks) +/// - `ThreeDays` (alias: 3d) - Last 3 days (~432 blocks) +/// - `Week` (alias: 1w) - Last week (~1008 blocks) +/// - `Month` (alias: 1m) - Last month (~4320 blocks) +/// - `ThreeMonths` (alias: 3m) - Last 3 months (~12960 blocks) +/// - `SixMonths` (alias: 6m) - Last 6 months (~25920 blocks) +/// - `Year` (alias: 1y) - Last year (~52560 blocks) +/// - `TwoYears` (alias: 2y) - Last 2 years (~105120 blocks) +/// - `ThreeYears` (alias: 3y) - Last 3 years (~157680 blocks) #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] pub enum TimePeriod { - /// Last 24 hours (~144 blocks) - #[serde(rename = "24h")] + #[serde(alias = "24h")] Day, - /// Last 3 days (~432 blocks) - #[serde(rename = "3d")] + #[serde(alias = "3d")] ThreeDays, - /// Last week (~1008 blocks) - #[serde(rename = "1w")] + #[serde(alias = "1w")] Week, - /// Last month (~4320 blocks) - #[serde(rename = "1m")] + #[serde(alias = "1m")] Month, - /// Last 3 months (~12960 blocks) - #[serde(rename = "3m")] + #[serde(alias = "3m")] ThreeMonths, - /// Last 6 months (~25920 blocks) - #[serde(rename = "6m")] + #[serde(alias = "6m")] SixMonths, - /// Last year (~52560 blocks) - #[serde(rename = "1y")] + #[serde(alias = "1y")] Year, - /// Last 2 years (~105120 blocks) - #[serde(rename = "2y")] + #[serde(alias = "2y")] TwoYears, - /// Last 3 years (~157680 blocks) - #[serde(rename = "3y")] + #[serde(alias = "3y")] ThreeYears, } diff --git a/crates/brk_types/src/txid.rs b/crates/brk_types/src/txid.rs index e140f1130..e31c7914a 100644 --- a/crates/brk_types/src/txid.rs +++ b/crates/brk_types/src/txid.rs @@ -14,6 +14,7 @@ use vecdb::{Bytes, Formattable}; example = "9a0b3b8305bb30cacf9e8443a90d53a76379fb3305047fdeaa4e4b0934a2a1ba" )] #[repr(C)] +#[schemars(transparent, with = "String")] pub struct Txid([u8; 32]); impl Txid {